@sikka/hawa 0.0.231 → 0.0.233
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} +112 -160
- 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.233",
|
|
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
|
}
|
|
@@ -17,8 +17,6 @@ type ComponentTypes = {
|
|
|
17
17
|
foo?: string
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
// TODO: Handle copy pasting by assigning to local storage ?
|
|
21
|
-
|
|
22
20
|
const styleClasses = {
|
|
23
21
|
bold: "font-bold",
|
|
24
22
|
italic: "italic",
|
|
@@ -26,68 +24,101 @@ const styleClasses = {
|
|
|
26
24
|
strike: "line-through",
|
|
27
25
|
}
|
|
28
26
|
|
|
29
|
-
export const
|
|
27
|
+
export const FloatingCommentCE: React.FunctionComponent<ComponentTypes> = (
|
|
30
28
|
props
|
|
31
29
|
) => {
|
|
32
|
-
const [text,
|
|
30
|
+
const [text, _setText] = useState({
|
|
33
31
|
content: "",
|
|
34
32
|
stylings: [], // A styling is an object with 2 indices specifying a substring of text, and the applied effect
|
|
35
33
|
revert: [0, 0],
|
|
36
34
|
})
|
|
37
35
|
|
|
38
36
|
const field = useRef(null)
|
|
37
|
+
const _text = useRef(text)
|
|
38
|
+
const setText = (data) => {
|
|
39
|
+
_text.current = data
|
|
40
|
+
_setText(data)
|
|
41
|
+
}
|
|
39
42
|
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
// Full reversion achieved !
|
|
44
|
+
const getFieldSelection = () => {
|
|
45
|
+
if (document.activeElement != field.current) return [0, 0]
|
|
42
46
|
|
|
43
|
-
|
|
47
|
+
let selection = window.getSelection()
|
|
48
|
+
let nodes = Array.from(field.current.childNodes)
|
|
49
|
+
nodes = nodes.filter(
|
|
50
|
+
(item: any) => !["#text", "BR"].includes(item.nodeName)
|
|
51
|
+
)
|
|
44
52
|
|
|
45
|
-
|
|
46
|
-
|
|
53
|
+
let startParent: any = selection.anchorNode.parentNode
|
|
54
|
+
let startNodeIndex =
|
|
55
|
+
startParent == field.current
|
|
56
|
+
? nodes.length
|
|
57
|
+
: parseInt(startParent.dataset.childIndex)
|
|
58
|
+
|
|
59
|
+
let startPrecedingSum = nodes
|
|
60
|
+
.slice(0, startNodeIndex)
|
|
61
|
+
.map((span: any) => span.textContent.length)
|
|
62
|
+
.reduce((a, b) => a + b, 0)
|
|
63
|
+
|
|
64
|
+
let endParent: any = selection.anchorNode.parentNode
|
|
65
|
+
let endNodeIndex =
|
|
66
|
+
endParent == field.current
|
|
67
|
+
? nodes.length
|
|
68
|
+
: parseInt(endParent.dataset.childIndex)
|
|
69
|
+
|
|
70
|
+
let endPrecedingSum = nodes
|
|
71
|
+
.slice(0, endNodeIndex)
|
|
72
|
+
.map((span: any) => span.textContent.length)
|
|
73
|
+
.reduce((a, b) => a + b, 0)
|
|
74
|
+
|
|
75
|
+
let result = [
|
|
76
|
+
startPrecedingSum + selection.anchorOffset,
|
|
77
|
+
endPrecedingSum + selection.focusOffset,
|
|
78
|
+
]
|
|
47
79
|
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// Add 1 to the index
|
|
52
|
-
// Iterate through each range, and check if the index is greater than the start of the range, and less than or equal the end of the range
|
|
53
|
-
let startNode = null
|
|
54
|
-
let endNode = null
|
|
80
|
+
// Sort to make the minimum selection the start selection
|
|
81
|
+
return result.sort((a, b) => a - b)
|
|
82
|
+
}
|
|
55
83
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
let node: any = nodes[i]
|
|
60
|
-
let sum = node.textContent.length + total
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
setTimeout(function () {
|
|
86
|
+
let [start, end] = text.revert
|
|
61
87
|
|
|
62
|
-
if (start
|
|
63
|
-
startNode = nodes[i]
|
|
64
|
-
}
|
|
88
|
+
if (start == 0 && end == 0) return
|
|
65
89
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
90
|
+
let startNode = null
|
|
91
|
+
let endNode = null
|
|
69
92
|
|
|
70
|
-
total
|
|
71
|
-
|
|
93
|
+
let total = 0
|
|
94
|
+
let nodes = Array.from(field.current.childNodes)
|
|
95
|
+
|
|
96
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
97
|
+
let node: any = nodes[i]
|
|
98
|
+
let sum = node.textContent.length + total
|
|
72
99
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
// )
|
|
100
|
+
if (startNode == null && start >= total && start <= sum) {
|
|
101
|
+
startNode = nodes[i]
|
|
102
|
+
start -= total
|
|
103
|
+
}
|
|
78
104
|
|
|
79
|
-
|
|
80
|
-
|
|
105
|
+
if (endNode == null && end > total && end <= sum) {
|
|
106
|
+
endNode = nodes[i]
|
|
107
|
+
end -= total
|
|
108
|
+
}
|
|
81
109
|
|
|
82
|
-
|
|
83
|
-
|
|
110
|
+
total += node.textContent.length
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
var range = document.createRange()
|
|
114
|
+
var sel = window.getSelection()
|
|
84
115
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
range.collapse(true)
|
|
116
|
+
range.setStart(startNode.firstChild, start)
|
|
117
|
+
range.setEnd(endNode.firstChild, end)
|
|
88
118
|
|
|
89
|
-
|
|
90
|
-
|
|
119
|
+
sel.removeAllRanges()
|
|
120
|
+
sel.addRange(range)
|
|
121
|
+
}, 0)
|
|
91
122
|
}, [text.revert])
|
|
92
123
|
|
|
93
124
|
// utility functions
|
|
@@ -247,6 +278,7 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
247
278
|
setText({
|
|
248
279
|
...text,
|
|
249
280
|
stylings: result,
|
|
281
|
+
revert: [selectionStart, selectionEnd],
|
|
250
282
|
})
|
|
251
283
|
}
|
|
252
284
|
|
|
@@ -279,9 +311,11 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
279
311
|
}
|
|
280
312
|
|
|
281
313
|
const onChange = (value) => {
|
|
314
|
+
let [selectionStart, selectionEnd] = getFieldSelection()
|
|
315
|
+
|
|
282
316
|
let difference = value.length - text.content.length
|
|
283
317
|
|
|
284
|
-
let selection =
|
|
318
|
+
let selection = selectionStart - difference
|
|
285
319
|
|
|
286
320
|
let stylings = text.stylings.slice()
|
|
287
321
|
let succeeding = getSucceedStylings(selection)
|
|
@@ -320,14 +354,21 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
320
354
|
|
|
321
355
|
stylings = stylings.filter((_, index) => !spliced.includes(index))
|
|
322
356
|
|
|
323
|
-
|
|
357
|
+
// if (difference == 1) difference = 0
|
|
358
|
+
|
|
359
|
+
setText({
|
|
360
|
+
...text,
|
|
361
|
+
content: value,
|
|
362
|
+
stylings: stylings,
|
|
363
|
+
revert: [selectionStart, selectionEnd],
|
|
364
|
+
})
|
|
324
365
|
}
|
|
325
366
|
|
|
326
367
|
const getContent = () => {
|
|
327
|
-
let content =
|
|
368
|
+
let content = _text.current.content
|
|
328
369
|
|
|
329
370
|
// Get all styling indices
|
|
330
|
-
let indices =
|
|
371
|
+
let indices = _text.current.stylings
|
|
331
372
|
.map(({ start, finish }) => [start, finish])
|
|
332
373
|
.flat()
|
|
333
374
|
|
|
@@ -343,7 +384,7 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
343
384
|
if (indices[0] != 0) indices.unshift(0)
|
|
344
385
|
|
|
345
386
|
// Add last index if not present
|
|
346
|
-
let last =
|
|
387
|
+
let last = content.length
|
|
347
388
|
if (indices[indices.length - 1] != last) indices.push(last)
|
|
348
389
|
|
|
349
390
|
let result = []
|
|
@@ -355,24 +396,26 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
355
396
|
return result
|
|
356
397
|
}
|
|
357
398
|
|
|
358
|
-
|
|
359
|
-
|
|
399
|
+
// dangerouslySetInnerHTML incorrectly renders when the entire text is highlighted, copied, and then pasted in succession
|
|
400
|
+
useEffect(() => {
|
|
401
|
+
let html = getContent()
|
|
402
|
+
.map((_data, index) => {
|
|
403
|
+
let [start, data] = _data
|
|
360
404
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
let end
|
|
405
|
+
// Get stylings encompassing an index within it's range
|
|
406
|
+
let stylings = getIntersectStylings(start)
|
|
364
407
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
408
|
+
return `<span class="${stylings
|
|
409
|
+
.map((styling) => styleClasses[styling.type])
|
|
410
|
+
.join(" ")}" data-child-index="${index}">${data}</span>`
|
|
411
|
+
})
|
|
412
|
+
.join("")
|
|
370
413
|
|
|
371
|
-
|
|
372
|
-
}
|
|
414
|
+
field.current.innerHTML = html
|
|
415
|
+
}, [text])
|
|
373
416
|
|
|
374
417
|
return (
|
|
375
|
-
<div className="align-center box-border flex h-min w-[400px] flex-col items-center justify-center rounded bg-
|
|
418
|
+
<div className="align-center box-border flex h-min w-[400px] flex-col items-center justify-center rounded bg-blue-300 shadow-md">
|
|
376
419
|
<div className={clsx("flex w-full flex-row justify-start p-2")}>
|
|
377
420
|
<Property
|
|
378
421
|
name="B"
|
|
@@ -383,19 +426,22 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
383
426
|
/>
|
|
384
427
|
<Property
|
|
385
428
|
name="I"
|
|
386
|
-
|
|
429
|
+
onMouseDown={(event) => {
|
|
430
|
+
event.preventDefault()
|
|
387
431
|
perform("italic")
|
|
388
432
|
}}
|
|
389
433
|
/>
|
|
390
434
|
<Property
|
|
391
435
|
name="U"
|
|
392
|
-
|
|
436
|
+
onMouseDown={(event) => {
|
|
437
|
+
event.preventDefault()
|
|
393
438
|
perform("under")
|
|
394
439
|
}}
|
|
395
440
|
/>
|
|
396
441
|
<Property
|
|
397
442
|
name="S"
|
|
398
|
-
|
|
443
|
+
onMouseDown={(event) => {
|
|
444
|
+
event.preventDefault()
|
|
399
445
|
perform("strike")
|
|
400
446
|
}}
|
|
401
447
|
/>
|
|
@@ -405,105 +451,11 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
405
451
|
<div
|
|
406
452
|
ref={field}
|
|
407
453
|
contentEditable="true"
|
|
408
|
-
dangerouslySetInnerHTML={{
|
|
409
|
-
__html: getContent()
|
|
410
|
-
.map((_data, index) => {
|
|
411
|
-
let [start, data] = _data
|
|
412
|
-
|
|
413
|
-
// Get stylings encompassing an index within it's range
|
|
414
|
-
let stylings = getIntersectStylings(start)
|
|
415
|
-
|
|
416
|
-
return `<span class="${stylings
|
|
417
|
-
.map((styling) => styleClasses[styling.type])
|
|
418
|
-
.join("")}">${data}</span>`
|
|
419
|
-
// return `<span
|
|
420
|
-
// class="${stylings
|
|
421
|
-
// .map((styling) => styleClasses[styling.type])
|
|
422
|
-
// .join(" ")}"
|
|
423
|
-
|
|
424
|
-
// >
|
|
425
|
-
// ${data}
|
|
426
|
-
// </span>`
|
|
427
|
-
})
|
|
428
|
-
.join(" "),
|
|
429
|
-
}}
|
|
430
454
|
className="h-[150px] w-full resize-none border-none p-2 outline-none"
|
|
431
|
-
onInput={(event) => {
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
let [start, end] = getFieldSelection()
|
|
435
|
-
|
|
436
|
-
// console.log(target)
|
|
437
|
-
// console.log(target.selectionStart)
|
|
438
|
-
// console.log(target.selectionEnd)
|
|
439
|
-
|
|
440
|
-
setText({
|
|
441
|
-
...text,
|
|
442
|
-
content: target.textContent,
|
|
443
|
-
revert: [start, end],
|
|
444
|
-
})
|
|
455
|
+
onInput={(event: any) => {
|
|
456
|
+
onChange(event.target.textContent)
|
|
445
457
|
}}
|
|
446
458
|
></div>
|
|
447
|
-
|
|
448
|
-
{/* <RichTextarea
|
|
449
|
-
ref={field}
|
|
450
|
-
value={text.content}
|
|
451
|
-
style={{ width: "100%" }} // tailwind w-full does not work
|
|
452
|
-
className="order-none h-[150px] resize-none p-2 outline-none"
|
|
453
|
-
onChange={(e) => {
|
|
454
|
-
onChange(e.target.value)
|
|
455
|
-
}}
|
|
456
|
-
>
|
|
457
|
-
{(value) => {
|
|
458
|
-
// Get all styling indices
|
|
459
|
-
let indices = text.stylings
|
|
460
|
-
.map(({ start, finish }) => [start, finish])
|
|
461
|
-
.flat()
|
|
462
|
-
|
|
463
|
-
// Sort ascendingly
|
|
464
|
-
indices = indices.sort((a, b) => a - b)
|
|
465
|
-
|
|
466
|
-
// Remove duplicates
|
|
467
|
-
indices = indices.filter(
|
|
468
|
-
(element, index) => indices.indexOf(element) == index
|
|
469
|
-
)
|
|
470
|
-
|
|
471
|
-
// Add first index if not present
|
|
472
|
-
if (indices[0] != 0) indices.unshift(0)
|
|
473
|
-
|
|
474
|
-
// Add last index if not present
|
|
475
|
-
let last = text.content.length
|
|
476
|
-
if (indices[indices.length - 1] != last) indices.push(last)
|
|
477
|
-
|
|
478
|
-
let result = []
|
|
479
|
-
|
|
480
|
-
for (let i = 0; i < indices.length - 1; i++) {
|
|
481
|
-
result.push([
|
|
482
|
-
indices[i],
|
|
483
|
-
value.substring(indices[i], indices[i + 1]),
|
|
484
|
-
])
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
return result.map((_data, index) => {
|
|
488
|
-
let [start, data] = _data
|
|
489
|
-
|
|
490
|
-
// Get stylings encompassing an index within it's range
|
|
491
|
-
let stylings = getIntersectStylings(start)
|
|
492
|
-
|
|
493
|
-
return (
|
|
494
|
-
<span
|
|
495
|
-
key={index}
|
|
496
|
-
className={`${stylings
|
|
497
|
-
.map((styling) => styleClasses[styling.type])
|
|
498
|
-
.join(" ")}
|
|
499
|
-
`}
|
|
500
|
-
>
|
|
501
|
-
{data}
|
|
502
|
-
</span>
|
|
503
|
-
)
|
|
504
|
-
})
|
|
505
|
-
}}
|
|
506
|
-
</RichTextarea> */}
|
|
507
459
|
</div>
|
|
508
460
|
<div className="h-[1px] w-full bg-slate-600"> </div>
|
|
509
461
|
<button className="my-1 rounded bg-cyan-800 p-2 py-1 text-white">
|
|
@@ -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));
|