playbook_ui 16.4.0.pre.rc.2 → 16.4.0.pre.rc.3
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.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/pb_dialog/docs/_dialog_compound_components.html.erb +1 -1
- data/app/pb_kits/playbook/pb_dialog/docs/_dialog_compound_components.jsx +6 -3
- data/app/pb_kits/playbook/pb_dialog/docs/_dialog_full_height.html.erb +3 -3
- data/app/pb_kits/playbook/pb_dialog/docs/_dialog_full_height.jsx +6 -3
- data/app/pb_kits/playbook/pb_dialog/docs/_dialog_full_height_placement.html.erb +3 -3
- data/app/pb_kits/playbook/pb_dialog/docs/_dialog_full_height_placement.jsx +6 -3
- data/app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.tsx +35 -134
- data/app/pb_kits/playbook/pb_rich_text_editor/_tiptap_editor.tsx +51 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/_trix_editor.tsx +206 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_default.jsx +56 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_default.md +1 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/example.yml +13 -21
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/index.js +0 -10
- data/app/pb_kits/playbook/pb_rich_text_editor/inlineFocus.ts +5 -4
- data/dist/chunks/{_pb_line_graph-BGY7jEks.js → _pb_line_graph-BI5wY8Wj.js} +1 -1
- data/dist/chunks/_typeahead-8CvXJGlb.js +1 -0
- data/dist/chunks/{globalProps-CK2YuA9O.js → globalProps-Bn1WUHLp.js} +1 -1
- data/dist/chunks/{lib-DspaUdlc.js → lib-qwWYiGtH.js} +1 -1
- data/dist/chunks/vendor.js +4 -4
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/lib/playbook/version.rb +1 -1
- metadata +9 -30
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_attributes.html.erb +0 -5
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_attributes.jsx +0 -15
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_default.html.erb +0 -1
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_focus.html.erb +0 -3
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_focus.jsx +0 -17
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_inline.html.erb +0 -6
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_inline.jsx +0 -16
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_label.jsx +0 -28
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_label.md +0 -1
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_preview.html.erb +0 -35
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_preview.jsx +0 -45
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_required_indicator.html.erb +0 -10
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_required_indicator.jsx +0 -22
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_required_indicator.md +0 -3
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_simple.html.erb +0 -1
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_simple.jsx +0 -13
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_sticky.html.erb +0 -1
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_sticky.jsx +0 -15
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_templates.html.erb +0 -115
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_templates.jsx +0 -42
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_toolbar_bottom.html.erb +0 -4
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_toolbar_bottom.jsx +0 -14
- data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.html.erb +0 -6
- data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.rb +0 -63
- data/dist/chunks/_typeahead-DdGKR1rQ.js +0 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ae3803bd5b745bfb80cc3735185a84ad54261d66a835da1430b4a9e490e99a79
|
|
4
|
+
data.tar.gz: b43613542fe8f44fb33f03ceefb5e2420ad38e371e4489fc4085187cdcd12361
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9d563bf3c9b4ce0829a5dca7747f5365507a24fa0bfeed2a6caaef00ab51f52aeae7df2664060159995d041bced0a521bd0c9fbf0b2bb907386d0e8071184988
|
|
7
|
+
data.tar.gz: ad84d871ff6f43acdf3da0898888ec99e6b173bc68c71334932dc3a59f938e3bac7f4023028727ca2e6462c5a607c02dc254c768e740d5c2b7f03862edbaffaa
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
<% end %>
|
|
29
29
|
<%= pb_rails("dialog/dialog_body") do %>
|
|
30
30
|
<%= pb_rails("caption", props: { text: "Description", margin_bottom: "xs" }) %>
|
|
31
|
-
<%= pb_rails("
|
|
31
|
+
<%= pb_rails("textarea", props: {id: "default"}) %>
|
|
32
32
|
<%= pb_rails("caption", props: { text: "Type in a word or term too help find tickets later. ex. training, phone setup, hr", margin_bottom: "xs", margin_top: "sm" }) %>
|
|
33
33
|
<%= pb_rails("typeahead", props: { placeholder: "Tags.."}) %>
|
|
34
34
|
<%= pb_rails("dropdown", props: {options: options, autocomplete: true}) %>
|
|
@@ -4,7 +4,7 @@ import Body from '../../pb_body/_body'
|
|
|
4
4
|
import Button from '../../pb_button/_button'
|
|
5
5
|
import Caption from '../../pb_caption/_caption'
|
|
6
6
|
import Dialog from '../../pb_dialog/_dialog'
|
|
7
|
-
import
|
|
7
|
+
import Textarea from '../../pb_textarea/_textarea'
|
|
8
8
|
import Typeahead from '../../pb_typeahead/_typeahead'
|
|
9
9
|
|
|
10
10
|
const DialogCompound = () => {
|
|
@@ -25,8 +25,11 @@ const DialogCompound = () => {
|
|
|
25
25
|
<Body>{'What do you need us to take care of?'}</Body>
|
|
26
26
|
</Dialog.Header>
|
|
27
27
|
<Dialog.Body>
|
|
28
|
-
<
|
|
29
|
-
|
|
28
|
+
<Textarea
|
|
29
|
+
id="default-example-1"
|
|
30
|
+
label="Description"
|
|
31
|
+
rows={4}
|
|
32
|
+
/>
|
|
30
33
|
<br />
|
|
31
34
|
<Caption>
|
|
32
35
|
{
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<% end %>
|
|
13
13
|
<%= pb_rails("dialog/dialog_body") do %>
|
|
14
14
|
<%= pb_rails("caption", props: { text: "Description", margin_bottom: "xs" }) %>
|
|
15
|
-
<%= pb_rails("
|
|
15
|
+
<%= pb_rails("textarea", props: {id: "default-7"}) %>
|
|
16
16
|
<%= pb_rails("caption", props: { text: "Type in a word or term too help find tickets later. ex. training, phone setup, hr", margin_bottom: "xs", margin_top: "sm" }) %>
|
|
17
17
|
<%= pb_rails("typeahead", props: { placeholder: "Tags.."}) %>
|
|
18
18
|
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
<% end %>
|
|
32
32
|
<%= pb_rails("dialog/dialog_body") do %>
|
|
33
33
|
<%= pb_rails("caption", props: { text: "Description", margin_bottom: "xs" }) %>
|
|
34
|
-
<%= pb_rails("
|
|
34
|
+
<%= pb_rails("textarea", props: {id: "default-8"}) %>
|
|
35
35
|
<%= pb_rails("caption", props: { text: "Type in a word or term too help find tickets later. ex. training, phone setup, hr", margin_bottom: "xs", margin_top: "sm" }) %>
|
|
36
36
|
<%= pb_rails("typeahead", props: { placeholder: "Tags.."}) %>
|
|
37
37
|
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
<% end %>
|
|
50
50
|
<%= pb_rails("dialog/dialog_body") do %>
|
|
51
51
|
<%= pb_rails("caption", props: { text: "Description", margin_bottom: "xs" }) %>
|
|
52
|
-
<%= pb_rails("
|
|
52
|
+
<%= pb_rails("textarea", props: {id: "default-9"}) %>
|
|
53
53
|
<%= pb_rails("caption", props: { text: "Type in a word or term too help find tickets later. ex. training, phone setup, hr", margin_bottom: "xs", margin_top: "sm" }) %>
|
|
54
54
|
<%= pb_rails("typeahead", props: { placeholder: "Tags.."}) %>
|
|
55
55
|
|
|
@@ -5,7 +5,7 @@ import Button from '../../pb_button/_button'
|
|
|
5
5
|
import Dialog from '../../pb_dialog/_dialog'
|
|
6
6
|
import Flex from '../../pb_flex/_flex'
|
|
7
7
|
import Caption from '../../pb_caption/_caption'
|
|
8
|
-
import
|
|
8
|
+
import Textarea from '../../pb_textarea/_textarea'
|
|
9
9
|
import Typeahead from '../../pb_typeahead/_typeahead'
|
|
10
10
|
|
|
11
11
|
const useDialog = (visible = false) => {
|
|
@@ -77,8 +77,11 @@ const DialogFullHeight = () => {
|
|
|
77
77
|
<Body>{title}</Body>
|
|
78
78
|
</Dialog.Header>
|
|
79
79
|
<Dialog.Body>
|
|
80
|
-
<
|
|
81
|
-
|
|
80
|
+
<Textarea
|
|
81
|
+
id="default-example-1"
|
|
82
|
+
label="Description"
|
|
83
|
+
rows={4}
|
|
84
|
+
/>
|
|
82
85
|
<br />
|
|
83
86
|
<Caption>
|
|
84
87
|
{
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
<% end %>
|
|
14
14
|
<%= pb_rails("dialog/dialog_body") do %>
|
|
15
15
|
<%= pb_rails("caption", props: { text: "Description", margin_bottom: "xs" }) %>
|
|
16
|
-
<%= pb_rails("
|
|
16
|
+
<%= pb_rails("textarea", props: {id: "default-2"}) %>
|
|
17
17
|
<%= pb_rails("caption", props: { text: "Type in a word or term too help find tickets later. ex. training, phone setup, hr", margin_bottom: "xs", margin_top: "sm" }) %>
|
|
18
18
|
<%= pb_rails("typeahead", props: { placeholder: "Tags.."}) %>
|
|
19
19
|
<% end %>
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
<% end %>
|
|
33
33
|
<%= pb_rails("dialog/dialog_body") do %>
|
|
34
34
|
<%= pb_rails("caption", props: { text: "Description", margin_bottom: "xs" }) %>
|
|
35
|
-
<%= pb_rails("
|
|
35
|
+
<%= pb_rails("textarea", props: {id: "default-3"}) %>
|
|
36
36
|
<%= pb_rails("caption", props: { text: "Type in a word or term too help find tickets later. ex. training, phone setup, hr", margin_bottom: "xs", margin_top: "sm" }) %>
|
|
37
37
|
<%= pb_rails("typeahead", props: { placeholder: "Tags.."}) %>
|
|
38
38
|
<% end %>
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
<% end %>
|
|
51
51
|
<%= pb_rails("dialog/dialog_body") do %>
|
|
52
52
|
<%= pb_rails("caption", props: { text: "Description", margin_bottom: "xs" }) %>
|
|
53
|
-
<%= pb_rails("
|
|
53
|
+
<%= pb_rails("textarea", props: {id: "default-4"}) %>
|
|
54
54
|
<%= pb_rails("caption", props: { text: "Type in a word or term too help find tickets later. ex. training, phone setup, hr", margin_bottom: "xs", margin_top: "sm" }) %>
|
|
55
55
|
<%= pb_rails("typeahead", props: { placeholder: "Tags.."}) %>
|
|
56
56
|
<% end %>
|
|
@@ -5,7 +5,7 @@ import Button from '../../pb_button/_button'
|
|
|
5
5
|
import Dialog from '../../pb_dialog/_dialog'
|
|
6
6
|
import Flex from '../../pb_flex/_flex'
|
|
7
7
|
import Caption from '../../pb_caption/_caption'
|
|
8
|
-
import
|
|
8
|
+
import Textarea from "../../pb_textarea/_textarea";
|
|
9
9
|
import Typeahead from '../../pb_typeahead/_typeahead'
|
|
10
10
|
|
|
11
11
|
const useDialog = (visible = false) => {
|
|
@@ -76,8 +76,11 @@ const DialogFullHeightPlacement = () => {
|
|
|
76
76
|
<Body>{title}</Body>
|
|
77
77
|
</Dialog.Header>
|
|
78
78
|
<Dialog.Body>
|
|
79
|
-
<
|
|
80
|
-
|
|
79
|
+
<Textarea
|
|
80
|
+
id={`default-example-2-${index}`}
|
|
81
|
+
label="Description"
|
|
82
|
+
rows={4}
|
|
83
|
+
/>
|
|
81
84
|
<br />
|
|
82
85
|
<Caption>
|
|
83
86
|
{
|
|
@@ -1,33 +1,12 @@
|
|
|
1
1
|
import React, { useEffect, useState, useRef } from 'react'
|
|
2
2
|
import classnames from 'classnames'
|
|
3
|
-
import { TrixEditor } from 'react-trix'
|
|
4
3
|
|
|
5
|
-
import inlineFocus from './inlineFocus'
|
|
6
|
-
import useFocus from './useFocus'
|
|
7
4
|
import Caption from '../pb_caption/_caption'
|
|
8
5
|
import colors from '../tokens/exports/_colors.module.scss'
|
|
9
6
|
import { globalProps, GlobalProps } from '../utilities/globalProps'
|
|
10
7
|
import { buildAriaProps, buildDataProps, noop, buildHtmlProps } from '../utilities/props'
|
|
11
|
-
|
|
12
|
-
import
|
|
13
|
-
import './_dedupe_trix_toolbar'
|
|
14
|
-
|
|
15
|
-
Trix.config.textAttributes.inlineCode = {
|
|
16
|
-
tagName: 'code',
|
|
17
|
-
inheritable: true,
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
import EditorToolbar from './TipTap/Toolbar'
|
|
21
|
-
|
|
22
|
-
type Editor = {
|
|
23
|
-
attributeIsActive?: ([any]: string) => boolean,
|
|
24
|
-
element?: HTMLElement,
|
|
25
|
-
getSelectedDocument?: () => any,
|
|
26
|
-
getSelectedRange?: () => Array<number>,
|
|
27
|
-
insertHTML?: ([any]: string) => void,
|
|
28
|
-
loadHTML?: ([any]: string) => void,
|
|
29
|
-
setSelectedRange?: (range: Array<number>) => void,
|
|
30
|
-
}
|
|
8
|
+
import TipTapEditor from './_tiptap_editor'
|
|
9
|
+
import TrixTextEditor from './_trix_editor'
|
|
31
10
|
|
|
32
11
|
type RichTextEditorProps = {
|
|
33
12
|
aria?: { [key: string]: string },
|
|
@@ -55,6 +34,8 @@ type RichTextEditorProps = {
|
|
|
55
34
|
template: string,
|
|
56
35
|
value?: string,
|
|
57
36
|
maxWidth?: string
|
|
37
|
+
TrixEditor?: React.ComponentType<any>,
|
|
38
|
+
trixInstance?: any,
|
|
58
39
|
} & GlobalProps
|
|
59
40
|
|
|
60
41
|
const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
|
|
@@ -84,50 +65,19 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
|
|
|
84
65
|
maxWidth = "md",
|
|
85
66
|
requiredIndicator = false,
|
|
86
67
|
label,
|
|
68
|
+
TrixEditor,
|
|
69
|
+
trixInstance: trixInstance = undefined,
|
|
87
70
|
} = props
|
|
88
71
|
|
|
89
72
|
const ariaProps = buildAriaProps(aria),
|
|
90
73
|
dataProps = buildDataProps(data),
|
|
91
|
-
[editor, setEditor] = useState<Editor>(),
|
|
92
74
|
[showToolbarOnFocus, setShowToolbarOnFocus] = useState(false),
|
|
93
75
|
containerRef = useRef<HTMLDivElement>(null)
|
|
94
76
|
|
|
95
77
|
const htmlProps = buildHtmlProps(htmlOptions)
|
|
96
78
|
|
|
97
79
|
const fieldId = id ? (id as string) : null
|
|
98
|
-
const labelElementId = fieldId ? `${fieldId}-label` :
|
|
99
|
-
|
|
100
|
-
const handleOnEditorReady = (editorInstance: Editor) => {
|
|
101
|
-
setEditor(editorInstance)
|
|
102
|
-
|
|
103
|
-
setTimeout(() => {
|
|
104
|
-
const oldId = editorInstance.element?.getAttribute("input")
|
|
105
|
-
if (!oldId) return
|
|
106
|
-
|
|
107
|
-
const hiddenInput = document.getElementById(oldId) as HTMLElement | null
|
|
108
|
-
if (!hiddenInput) return
|
|
109
|
-
|
|
110
|
-
const hiddenInputId = (inputOptions.id as string) || oldId
|
|
111
|
-
|
|
112
|
-
if (hiddenInputId !== oldId) {
|
|
113
|
-
hiddenInput.id = hiddenInputId
|
|
114
|
-
editorInstance.element?.setAttribute("input", hiddenInputId)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (inputOptions.name) {
|
|
118
|
-
hiddenInput.setAttribute("name", inputOptions.name as string)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const editorDomId = (id as string) || `${hiddenInputId}_trix`
|
|
122
|
-
const trixLabelId = ((id as string) || hiddenInputId) + "-label"
|
|
123
|
-
|
|
124
|
-
if (label) {
|
|
125
|
-
editorInstance.element?.setAttribute("aria-labelledby", trixLabelId)
|
|
126
|
-
}
|
|
127
|
-
editorInstance.element!.id = editorDomId
|
|
128
|
-
})
|
|
129
|
-
}
|
|
130
|
-
|
|
80
|
+
const labelElementId = fieldId ? `${fieldId}-label` : undefined
|
|
131
81
|
useEffect(() => {
|
|
132
82
|
if (!advancedEditor || !fieldId || !labelElementId) return
|
|
133
83
|
|
|
@@ -139,34 +89,6 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
|
|
|
139
89
|
dom.setAttribute("aria-multiline", "true")
|
|
140
90
|
}, [advancedEditor, fieldId, labelElementId])
|
|
141
91
|
|
|
142
|
-
// DOM manipulation must wait for editor to be ready
|
|
143
|
-
if (editor && editor.element) {
|
|
144
|
-
const toolbarElement = editor.element.parentElement.querySelector('trix-toolbar') as HTMLElement,
|
|
145
|
-
blockCodeButton = toolbarElement.querySelector('[data-trix-attribute=code]') as HTMLElement
|
|
146
|
-
|
|
147
|
-
// replace default trix "block code" button with "inline code" button
|
|
148
|
-
let inlineCodeButton = toolbarElement.querySelector('[data-trix-attribute=inlineCode]') as HTMLElement
|
|
149
|
-
if (!inlineCodeButton) {
|
|
150
|
-
inlineCodeButton = blockCodeButton.cloneNode(true) as HTMLElement
|
|
151
|
-
blockCodeButton.hidden = true
|
|
152
|
-
// set button attributes
|
|
153
|
-
inlineCodeButton.dataset.trixAttribute = 'inlineCode'
|
|
154
|
-
blockCodeButton.insertAdjacentElement('afterend', inlineCodeButton)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (toolbarBottom) editor.element.after(toolbarElement)
|
|
158
|
-
|
|
159
|
-
focus
|
|
160
|
-
? (document.addEventListener('trix-focus', useFocus),
|
|
161
|
-
document.addEventListener('trix-blur', useFocus),
|
|
162
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
163
|
-
useFocus())
|
|
164
|
-
: null
|
|
165
|
-
|
|
166
|
-
document.addEventListener('trix-focus', inlineFocus)
|
|
167
|
-
document.addEventListener('trix-blur', inlineFocus)
|
|
168
|
-
}
|
|
169
|
-
|
|
170
92
|
//===========focus prop with advanced editor=================
|
|
171
93
|
const isClickInPopover = (event: Event): boolean => {
|
|
172
94
|
return !!(event.target as Element).closest('.pb_tiptap_toolbar_dropdown_popover')
|
|
@@ -203,26 +125,6 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
|
|
|
203
125
|
|
|
204
126
|
//============= end focus prop with advanced editor=================
|
|
205
127
|
|
|
206
|
-
useEffect(() => {
|
|
207
|
-
if (!editor || !template) return
|
|
208
|
-
editor.loadHTML('')
|
|
209
|
-
editor.setSelectedRange([0, 0])
|
|
210
|
-
editor.insertHTML(template)
|
|
211
|
-
}, [editor, template])
|
|
212
|
-
|
|
213
|
-
useEffect(() => {
|
|
214
|
-
if (!editor?.element) return
|
|
215
|
-
editor.element.addEventListener('click', ({ target }: Event) => {
|
|
216
|
-
const trixEditorContainer = (target as Element).closest('.pb_rich_text_editor_kit')
|
|
217
|
-
if (!trixEditorContainer) return
|
|
218
|
-
|
|
219
|
-
const anchorElement = (target as Element).closest('a')
|
|
220
|
-
if (!anchorElement) return
|
|
221
|
-
|
|
222
|
-
if (anchorElement.hasAttribute('href')) window.open(anchorElement.href)
|
|
223
|
-
})
|
|
224
|
-
}, [editor])
|
|
225
|
-
|
|
226
128
|
// Generate CSS classes
|
|
227
129
|
const css = classnames(
|
|
228
130
|
'pb_rich_text_editor_kit',
|
|
@@ -279,35 +181,34 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
|
|
|
279
181
|
|
|
280
182
|
</label>
|
|
281
183
|
)}
|
|
282
|
-
{
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
{
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
}
|
|
184
|
+
{advancedEditor ? (
|
|
185
|
+
<TipTapEditor
|
|
186
|
+
editor={advancedEditor}
|
|
187
|
+
extensions={extensions}
|
|
188
|
+
inputHeight={inputHeight}
|
|
189
|
+
inputMinHeight={inputMinHeight}
|
|
190
|
+
shouldShowToolbar={shouldShowToolbar}
|
|
191
|
+
simple={simple}
|
|
192
|
+
sticky={sticky}
|
|
193
|
+
>
|
|
194
|
+
{children}
|
|
195
|
+
</TipTapEditor>
|
|
196
|
+
) : (
|
|
197
|
+
<TrixTextEditor
|
|
198
|
+
TrixEditor={TrixEditor}
|
|
199
|
+
focus={focus}
|
|
200
|
+
id={id}
|
|
201
|
+
inputOptions={inputOptions}
|
|
202
|
+
label={label}
|
|
203
|
+
name={name}
|
|
204
|
+
onChange={onChange}
|
|
205
|
+
placeholder={placeholder}
|
|
206
|
+
template={template}
|
|
207
|
+
toolbarBottom={toolbarBottom}
|
|
208
|
+
trixInstance={trixInstance}
|
|
209
|
+
value={value}
|
|
210
|
+
/>
|
|
211
|
+
)}
|
|
311
212
|
</div>
|
|
312
213
|
)
|
|
313
214
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import classnames from 'classnames'
|
|
3
|
+
|
|
4
|
+
import EditorToolbar from './TipTap/Toolbar'
|
|
5
|
+
|
|
6
|
+
type TipTapEditorProps = {
|
|
7
|
+
children?: React.ReactNode | React.ReactNode[],
|
|
8
|
+
editor: unknown,
|
|
9
|
+
extensions?: { [key: string]: string }[],
|
|
10
|
+
inputHeight?: 'sm' | 'md' | 'lg',
|
|
11
|
+
inputMinHeight?: 'sm' | 'md' | 'lg',
|
|
12
|
+
shouldShowToolbar: boolean,
|
|
13
|
+
simple?: boolean,
|
|
14
|
+
sticky?: boolean,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const TipTapEditor = ({
|
|
18
|
+
children,
|
|
19
|
+
editor,
|
|
20
|
+
extensions,
|
|
21
|
+
inputHeight,
|
|
22
|
+
inputMinHeight,
|
|
23
|
+
shouldShowToolbar,
|
|
24
|
+
simple = false,
|
|
25
|
+
sticky = false,
|
|
26
|
+
}: TipTapEditorProps): React.ReactElement => {
|
|
27
|
+
return (
|
|
28
|
+
<div
|
|
29
|
+
className={classnames(
|
|
30
|
+
'pb_rich_text_editor_advanced_container',
|
|
31
|
+
{
|
|
32
|
+
[`input_height_${inputHeight}`]: !!inputHeight,
|
|
33
|
+
[`input_min_height_${inputMinHeight}`]: !!inputMinHeight,
|
|
34
|
+
'toolbar-active': shouldShowToolbar,
|
|
35
|
+
}
|
|
36
|
+
)}
|
|
37
|
+
>
|
|
38
|
+
{shouldShowToolbar && (
|
|
39
|
+
<EditorToolbar
|
|
40
|
+
editor={editor}
|
|
41
|
+
extensions={extensions}
|
|
42
|
+
simple={simple}
|
|
43
|
+
sticky={sticky}
|
|
44
|
+
/>
|
|
45
|
+
)}
|
|
46
|
+
{children}
|
|
47
|
+
</div>
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export default TipTapEditor
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
import inlineFocus from './inlineFocus'
|
|
4
|
+
import applyFocusState from './useFocus'
|
|
5
|
+
import './_dedupe_trix_toolbar'
|
|
6
|
+
|
|
7
|
+
type Editor = {
|
|
8
|
+
element?: HTMLElement,
|
|
9
|
+
insertHTML?: (html: string) => void,
|
|
10
|
+
loadHTML?: (html: string) => void,
|
|
11
|
+
setSelectedRange?: (range: Array<number>) => void,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type TrixConfig = {
|
|
15
|
+
textAttributes?: {
|
|
16
|
+
inlineCode?: {
|
|
17
|
+
tagName: string,
|
|
18
|
+
inheritable: boolean,
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type TrixInstance = {
|
|
24
|
+
config: TrixConfig,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
type TrixEditorComponentProps = {
|
|
28
|
+
className: string,
|
|
29
|
+
fileParamName?: string,
|
|
30
|
+
mergeTags: unknown[],
|
|
31
|
+
onChange: (html: string, text: string) => void,
|
|
32
|
+
onEditorReady: (editorInstance: Editor) => void,
|
|
33
|
+
placeholder?: string,
|
|
34
|
+
value?: string,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type TrixTextEditorProps = {
|
|
38
|
+
TrixEditor?: React.ComponentType<TrixEditorComponentProps>,
|
|
39
|
+
focus?: boolean,
|
|
40
|
+
id?: string,
|
|
41
|
+
inputOptions?: { [key: string]: string | number | boolean | (() => void) },
|
|
42
|
+
label?: string,
|
|
43
|
+
name?: string,
|
|
44
|
+
onChange: (html: string, text: string) => void,
|
|
45
|
+
placeholder?: string,
|
|
46
|
+
template: string,
|
|
47
|
+
toolbarBottom?: boolean,
|
|
48
|
+
trixInstance?: TrixInstance,
|
|
49
|
+
value?: string,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const TrixTextEditor = ({
|
|
53
|
+
TrixEditor,
|
|
54
|
+
focus = false,
|
|
55
|
+
id,
|
|
56
|
+
inputOptions = {},
|
|
57
|
+
label,
|
|
58
|
+
name,
|
|
59
|
+
onChange,
|
|
60
|
+
placeholder,
|
|
61
|
+
template,
|
|
62
|
+
toolbarBottom = false,
|
|
63
|
+
trixInstance = undefined,
|
|
64
|
+
value = '',
|
|
65
|
+
}: TrixTextEditorProps): React.ReactElement => {
|
|
66
|
+
const [editor, setEditor] = useState<Editor>()
|
|
67
|
+
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
const textAttributes = trixInstance?.config?.textAttributes
|
|
70
|
+
if (!textAttributes) return
|
|
71
|
+
|
|
72
|
+
textAttributes.inlineCode = {
|
|
73
|
+
tagName: 'code',
|
|
74
|
+
inheritable: true,
|
|
75
|
+
}
|
|
76
|
+
}, [trixInstance])
|
|
77
|
+
|
|
78
|
+
const handleOnEditorReady = (editorInstance: Editor) => {
|
|
79
|
+
setEditor(editorInstance)
|
|
80
|
+
|
|
81
|
+
setTimeout(() => {
|
|
82
|
+
const oldId = editorInstance.element?.getAttribute('input')
|
|
83
|
+
if (!oldId) return
|
|
84
|
+
|
|
85
|
+
const hiddenInput = document.getElementById(oldId) as HTMLElement | null
|
|
86
|
+
if (!hiddenInput) return
|
|
87
|
+
|
|
88
|
+
const hiddenInputId = (inputOptions.id as string) || oldId
|
|
89
|
+
|
|
90
|
+
if (hiddenInputId !== oldId) {
|
|
91
|
+
hiddenInput.id = hiddenInputId
|
|
92
|
+
editorInstance.element?.setAttribute('input', hiddenInputId)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (inputOptions.name) {
|
|
96
|
+
hiddenInput.setAttribute('name', inputOptions.name as string)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const editorDomId = (id as string) || `${hiddenInputId}_trix`
|
|
100
|
+
const trixLabelId = ((id as string) || hiddenInputId) + '-label'
|
|
101
|
+
|
|
102
|
+
if (label) {
|
|
103
|
+
editorInstance.element?.setAttribute('aria-labelledby', trixLabelId)
|
|
104
|
+
}
|
|
105
|
+
if (editorInstance.element) {
|
|
106
|
+
editorInstance.element.id = editorDomId
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
if (!editor || !editor.element) return
|
|
113
|
+
|
|
114
|
+
const toolbarElement = editor.element.parentElement?.querySelector('trix-toolbar') as HTMLElement | null
|
|
115
|
+
if (!toolbarElement) return
|
|
116
|
+
|
|
117
|
+
const blockCodeButton = toolbarElement.querySelector('[data-trix-attribute=code]') as HTMLElement | null
|
|
118
|
+
if (!blockCodeButton) return
|
|
119
|
+
|
|
120
|
+
let inlineCodeButton = toolbarElement.querySelector('[data-trix-attribute=inlineCode]') as HTMLElement | null
|
|
121
|
+
if (!inlineCodeButton) {
|
|
122
|
+
inlineCodeButton = blockCodeButton.cloneNode(true) as HTMLElement
|
|
123
|
+
blockCodeButton.hidden = true
|
|
124
|
+
inlineCodeButton.dataset.trixAttribute = 'inlineCode'
|
|
125
|
+
blockCodeButton.insertAdjacentElement('afterend', inlineCodeButton)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (toolbarBottom) {
|
|
129
|
+
editor.element.after(toolbarElement)
|
|
130
|
+
}
|
|
131
|
+
}, [editor, toolbarBottom])
|
|
132
|
+
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
if (!focus) return
|
|
135
|
+
|
|
136
|
+
document.addEventListener('trix-focus', applyFocusState)
|
|
137
|
+
document.addEventListener('trix-blur', applyFocusState)
|
|
138
|
+
applyFocusState()
|
|
139
|
+
|
|
140
|
+
return () => {
|
|
141
|
+
document.removeEventListener('trix-focus', applyFocusState)
|
|
142
|
+
document.removeEventListener('trix-blur', applyFocusState)
|
|
143
|
+
}
|
|
144
|
+
}, [focus])
|
|
145
|
+
|
|
146
|
+
useEffect(() => {
|
|
147
|
+
document.addEventListener('trix-focus', inlineFocus)
|
|
148
|
+
document.addEventListener('trix-blur', inlineFocus)
|
|
149
|
+
|
|
150
|
+
return () => {
|
|
151
|
+
document.removeEventListener('trix-focus', inlineFocus)
|
|
152
|
+
document.removeEventListener('trix-blur', inlineFocus)
|
|
153
|
+
}
|
|
154
|
+
}, [])
|
|
155
|
+
|
|
156
|
+
useEffect(() => {
|
|
157
|
+
if (!editor || !template) return
|
|
158
|
+
editor.loadHTML && editor.loadHTML('')
|
|
159
|
+
editor.setSelectedRange && editor.setSelectedRange([0, 0])
|
|
160
|
+
editor.insertHTML && editor.insertHTML(template)
|
|
161
|
+
}, [editor, template])
|
|
162
|
+
|
|
163
|
+
useEffect(() => {
|
|
164
|
+
if (!editor?.element) return
|
|
165
|
+
|
|
166
|
+
const clickHandler = ({ target }: Event) => {
|
|
167
|
+
const trixEditorContainer = (target as Element).closest('.pb_rich_text_editor_kit')
|
|
168
|
+
if (!trixEditorContainer) return
|
|
169
|
+
|
|
170
|
+
const anchorElement = (target as Element).closest('a') as HTMLAnchorElement | null
|
|
171
|
+
if (!anchorElement) return
|
|
172
|
+
|
|
173
|
+
if (anchorElement.hasAttribute('href')) window.open(anchorElement.href)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
editor.element.addEventListener('click', clickHandler)
|
|
177
|
+
|
|
178
|
+
return () => {
|
|
179
|
+
editor.element?.removeEventListener('click', clickHandler)
|
|
180
|
+
}
|
|
181
|
+
}, [editor])
|
|
182
|
+
|
|
183
|
+
if (!TrixEditor) {
|
|
184
|
+
return (
|
|
185
|
+
<div style={{ color: 'red', padding: '1em', border: '1px solid #f00', background: '#fff0f0' }}>
|
|
186
|
+
<strong>Trix Editor is not available.</strong>
|
|
187
|
+
<br />
|
|
188
|
+
Please import <code>TrixEditor</code> from <code>react-trix</code> and pass it as a prop to <code>RichTextEditor</code>.
|
|
189
|
+
<br />
|
|
190
|
+
<pre>{`import { TrixEditor } from 'react-trix';\n<RichTextEditor TrixEditor={TrixEditor} ... />`}</pre>
|
|
191
|
+
</div>
|
|
192
|
+
)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return React.createElement(TrixEditor, {
|
|
196
|
+
className: '',
|
|
197
|
+
fileParamName: name,
|
|
198
|
+
mergeTags: [],
|
|
199
|
+
onChange,
|
|
200
|
+
onEditorReady: handleOnEditorReady,
|
|
201
|
+
placeholder,
|
|
202
|
+
value,
|
|
203
|
+
})
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export default TrixTextEditor
|