playbook_ui 12.17.1 → 12.18.0.pre.alpha.PLAY603datepickerquickpickinputpresetdropdown626
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/index.js +1 -1
- data/app/pb_kits/playbook/pb_avatar_action_button/avatar_action_button.html.erb +1 -2
- data/app/pb_kits/playbook/pb_collapsible/_collapsible.tsx +2 -2
- data/app/pb_kits/playbook/pb_date_picker/_date_picker.scss +26 -0
- data/app/pb_kits/playbook/pb_date_picker/_date_picker.tsx +99 -95
- data/app/pb_kits/playbook/pb_date_picker/date_picker.html.erb +18 -3
- data/app/pb_kits/playbook/pb_date_picker/date_picker.rb +1 -1
- data/app/pb_kits/playbook/pb_date_picker/date_picker.test.js +44 -1
- data/app/pb_kits/playbook/pb_date_picker/date_picker_helper.ts +34 -2
- data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick.html.erb +8 -0
- data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick.jsx +18 -0
- data/app/pb_kits/playbook/pb_date_picker/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_date_picker/docs/index.js +2 -1
- data/app/pb_kits/playbook/pb_date_picker/plugins/quickPick.tsx +161 -0
- data/app/pb_kits/playbook/pb_date_picker/sass_partials/_calendar_input_icon.scss +4 -3
- data/app/pb_kits/playbook/pb_date_picker/sass_partials/_quick_pick_styles.scss +75 -0
- data/app/pb_kits/playbook/pb_docs/kit_api.html.erb +48 -36
- data/app/pb_kits/playbook/pb_docs/kit_api.rb +97 -9
- data/app/pb_kits/playbook/pb_docs/kit_example.html.erb +1 -1
- data/app/pb_kits/playbook/pb_docs/kit_example.rb +9 -5
- data/app/pb_kits/playbook/pb_lightbox/_lightbox.tsx +8 -0
- data/app/pb_kits/playbook/pb_lightbox/docs/_lightbox_current_photo.jsx +121 -0
- data/app/pb_kits/playbook/pb_lightbox/docs/_lightbox_current_photo.md +1 -0
- data/app/pb_kits/playbook/pb_lightbox/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_lightbox/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_nav/_item.tsx +7 -7
- data/app/pb_kits/playbook/pb_nav/_nav.tsx +4 -4
- data/app/pb_kits/playbook/pb_nav/_subtle_mixin.scss +1 -1
- data/app/pb_kits/playbook/pb_rich_text_editor/TipTap/EditorButton.tsx +49 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/TipTap/EditorTypes.ts +9 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/TipTap/Toolbar.tsx +62 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/TipTap/ToolbarDropdown.tsx +139 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/TipTap/ToolbarHistory.tsx +45 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/TipTap/ToolbarNodes.tsx +59 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.scss +1 -1
- data/app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.tsx +28 -12
- data/app/pb_kits/playbook/pb_rich_text_editor/_tiptap_styles.scss +231 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_description.md +1 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_default.jsx +36 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_default.md +4 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_time_range_inline/_time_range_inline.tsx +185 -0
- data/app/pb_kits/playbook/pb_time_range_inline/time_range_inline.test.js +85 -0
- data/app/pb_kits/playbook/pb_title/_title.tsx +1 -1
- data/app/pb_kits/playbook/pb_title_detail/_title_detail.tsx +45 -0
- data/app/pb_kits/playbook/pb_title_detail/title_detail.test.js +71 -0
- data/app/pb_kits/playbook/pb_toggle/{_toggle.jsx → _toggle.tsx} +20 -22
- data/app/pb_kits/playbook/pb_toggle/toggle.test.js +67 -0
- data/app/pb_kits/playbook/pb_tooltip/_tooltip.scss +11 -6
- data/app/pb_kits/playbook/pb_tooltip/docs/_tooltip_default.html.erb +4 -4
- data/app/pb_kits/playbook/pb_tooltip/docs/_tooltip_with_icon_circle.html.erb +1 -2
- data/app/pb_kits/playbook/pb_tooltip/docs/example.yml +0 -1
- data/app/pb_kits/playbook/pb_user/_user.tsx +1 -1
- data/lib/playbook/markdown/helper.rb +50 -71
- data/lib/playbook/markdown.rb +0 -1
- data/lib/playbook/number_spacing.rb +10 -10
- data/lib/playbook/position.rb +10 -10
- data/lib/playbook/spacing.rb +10 -10
- data/lib/playbook/version.rb +2 -2
- data/lib/playbook/z_index.rb +10 -10
- metadata +31 -14
- data/app/pb_kits/playbook/pb_time_range_inline/_time_range_inline.jsx +0 -172
- data/app/pb_kits/playbook/pb_title_detail/_title_detail.jsx +0 -44
- data/app/pb_kits/playbook/pb_tooltip/docs/_tooltip_white.html.erb +0 -9
- data/lib/playbook/markdown/template_handler.rb +0 -47
@@ -0,0 +1,121 @@
|
|
1
|
+
/* @flow */
|
2
|
+
/* eslint-disable jsx-control-statements/jsx-use-if-tag */
|
3
|
+
import React, { useState } from 'react'
|
4
|
+
import { Flex, Image, Button, Body, FlexItem } from '../../'
|
5
|
+
import Lightbox from '../_lightbox.tsx'
|
6
|
+
|
7
|
+
const LightboxCurrentPhoto = (props) => {
|
8
|
+
const photos = [
|
9
|
+
'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80',
|
10
|
+
'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80',
|
11
|
+
'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80',
|
12
|
+
'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80',
|
13
|
+
'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80',
|
14
|
+
'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80',
|
15
|
+
'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80',
|
16
|
+
'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80',
|
17
|
+
'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80',
|
18
|
+
'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80',
|
19
|
+
'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80',
|
20
|
+
'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80',
|
21
|
+
'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80',
|
22
|
+
'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80',
|
23
|
+
'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80',
|
24
|
+
'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80',
|
25
|
+
'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80',
|
26
|
+
'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80',
|
27
|
+
'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80',
|
28
|
+
'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80',
|
29
|
+
'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80',
|
30
|
+
'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80',
|
31
|
+
]
|
32
|
+
const [light, toggleLight] = useState(false)
|
33
|
+
//Setting state with the index of the current slide exposed by the onChange prop
|
34
|
+
const [active, setActive] = useState(0)
|
35
|
+
//Setting state for the current photo to pass to the kit
|
36
|
+
const [currentPhoto, setCurrentPhoto] = useState(active)
|
37
|
+
|
38
|
+
const handleCloseLightbox = () => {
|
39
|
+
toggleLight(!light)
|
40
|
+
}
|
41
|
+
|
42
|
+
const onPhotoClick = () => {
|
43
|
+
toggleLight(!light)
|
44
|
+
}
|
45
|
+
|
46
|
+
const exampleStyles = {
|
47
|
+
width: "100%",
|
48
|
+
overflow: "auto"
|
49
|
+
}
|
50
|
+
|
51
|
+
return (
|
52
|
+
<div className="lightbox_doc_example_custom">
|
53
|
+
{light ? (
|
54
|
+
<>
|
55
|
+
<Flex alignItems="center"
|
56
|
+
className='custom_lightbox_sidebar'
|
57
|
+
justifyContent="center"
|
58
|
+
>
|
59
|
+
<Flex margin='lg'
|
60
|
+
orientation='column'
|
61
|
+
>
|
62
|
+
<Body marginBottom='md'>
|
63
|
+
This UI is for demonstration purposes only to demonstrate how external buttons can be used to change the slides.
|
64
|
+
</Body>
|
65
|
+
<FlexItem alignSelf="center">
|
66
|
+
<Flex justifyContent="center">
|
67
|
+
<Button
|
68
|
+
onClick={()=> setCurrentPhoto(active > 0 ? active - 1 : 0)}
|
69
|
+
>
|
70
|
+
Back
|
71
|
+
</Button>
|
72
|
+
<Button marginLeft='sm'
|
73
|
+
onClick={() => setCurrentPhoto(active < photos.length - 1 ? active + 1 : photos.length - 1)}
|
74
|
+
>
|
75
|
+
Next
|
76
|
+
</Button>
|
77
|
+
</Flex>
|
78
|
+
</FlexItem>
|
79
|
+
</Flex>
|
80
|
+
</Flex>
|
81
|
+
<Lightbox
|
82
|
+
currentPhotoIndex={currentPhoto}
|
83
|
+
icon="times"
|
84
|
+
onChange={(index) => setActive(index)}
|
85
|
+
onClose={handleCloseLightbox}
|
86
|
+
photos={photos}
|
87
|
+
{...props}
|
88
|
+
/>
|
89
|
+
</>
|
90
|
+
) : (
|
91
|
+
<div
|
92
|
+
className="PhotoViewer"
|
93
|
+
style={exampleStyles}
|
94
|
+
>
|
95
|
+
<Flex>
|
96
|
+
{photos.map((photo, index) => {
|
97
|
+
return (
|
98
|
+
<div
|
99
|
+
key={index}
|
100
|
+
onClick={() => onPhotoClick(index)}
|
101
|
+
>
|
102
|
+
<Image
|
103
|
+
cursor="pointer"
|
104
|
+
marginRight="xl"
|
105
|
+
rounded
|
106
|
+
size="lg"
|
107
|
+
url={photo}
|
108
|
+
/>
|
109
|
+
|
110
|
+
<div className="overlay" />
|
111
|
+
</div>
|
112
|
+
)
|
113
|
+
})}
|
114
|
+
</Flex>
|
115
|
+
</div>
|
116
|
+
)}
|
117
|
+
</div>
|
118
|
+
)
|
119
|
+
}
|
120
|
+
|
121
|
+
export default LightboxCurrentPhoto
|
@@ -0,0 +1 @@
|
|
1
|
+
The `currentPhotoIndex` prop allows the user to pass a number to the lightbox that will set the current slide by index. This can be leveraged if the user wants to change slides using custom buttons. To do this, the user must also make use of the current slide's index that is exposed by the `onChange` prop.
|
@@ -2,3 +2,4 @@ export { default as LightboxDefault } from './_lightbox_default.jsx'
|
|
2
2
|
export { default as LightboxMultiple } from './_lightbox_multiple.jsx'
|
3
3
|
export { default as LightboxCompoundComponent } from './_lightbox_compound_component.jsx'
|
4
4
|
export { default as LightboxCustomHeader } from './_lightbox_custom_header'
|
5
|
+
export { default as LightboxCurrentPhoto } from './_lightbox_current_photo'
|
@@ -2,7 +2,7 @@ import React from 'react'
|
|
2
2
|
import classnames from 'classnames'
|
3
3
|
|
4
4
|
import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
|
5
|
-
import { globalProps } from '../utilities/globalProps'
|
5
|
+
import { globalProps, GlobalProps } from '../utilities/globalProps'
|
6
6
|
|
7
7
|
import Icon from '../pb_icon/_icon'
|
8
8
|
import Image from '../pb_image/_image'
|
@@ -13,15 +13,15 @@ type NavItemProps = {
|
|
13
13
|
children?: React.ReactNode[] | React.ReactNode,
|
14
14
|
className?: string,
|
15
15
|
data?: object,
|
16
|
-
iconLeft
|
17
|
-
iconRight
|
16
|
+
iconLeft?: string,
|
17
|
+
iconRight?: string,
|
18
18
|
id?: string,
|
19
|
-
imageUrl
|
20
|
-
link
|
19
|
+
imageUrl?: string,
|
20
|
+
link?: string,
|
21
21
|
onClick?: React.MouseEventHandler<HTMLElement>,
|
22
22
|
target?: '_blank' | '_self' | '_parent' | '_top',
|
23
23
|
text: string,
|
24
|
-
}
|
24
|
+
} & GlobalProps
|
25
25
|
|
26
26
|
const NavItem = (props: NavItemProps) => {
|
27
27
|
const {
|
@@ -87,7 +87,7 @@ const NavItem = (props: NavItemProps) => {
|
|
87
87
|
<span className="pb_nav_list_item_text">
|
88
88
|
{text || children}
|
89
89
|
</span>
|
90
|
-
|
90
|
+
|
91
91
|
{iconRight &&
|
92
92
|
<div
|
93
93
|
className="pb_nav_list_item_icon_section"
|
@@ -2,7 +2,7 @@ import React from 'react'
|
|
2
2
|
import classnames from 'classnames'
|
3
3
|
|
4
4
|
import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
|
5
|
-
import { globalProps } from '../utilities/globalProps'
|
5
|
+
import { globalProps, GlobalProps } from '../utilities/globalProps'
|
6
6
|
|
7
7
|
import Caption from '../pb_caption/_caption'
|
8
8
|
|
@@ -17,10 +17,10 @@ type NavProps = {
|
|
17
17
|
id?: string,
|
18
18
|
onClick?: React.MouseEventHandler<HTMLElement>,
|
19
19
|
orientation?: "vertical" | "horizontal",
|
20
|
-
link
|
21
|
-
title
|
20
|
+
link?: string,
|
21
|
+
title?: string,
|
22
22
|
variant?: "normal" | "subtle",
|
23
|
-
}
|
23
|
+
} & GlobalProps
|
24
24
|
|
25
25
|
const Nav = (props: NavProps) => {
|
26
26
|
const {
|
@@ -0,0 +1,49 @@
|
|
1
|
+
import React from "react";
|
2
|
+
|
3
|
+
import Icon from "../../pb_icon/_icon";
|
4
|
+
import Flex from "../../pb_flex/_flex";
|
5
|
+
import Tooltip from "../../pb_tooltip/_tooltip";
|
6
|
+
|
7
|
+
|
8
|
+
type EditorButtonProps = {
|
9
|
+
classname?: string,
|
10
|
+
onclick?: () => {} | void,
|
11
|
+
icon?: string;
|
12
|
+
text?: string;
|
13
|
+
disable?: boolean
|
14
|
+
};
|
15
|
+
|
16
|
+
const EditorButton = ({
|
17
|
+
classname,
|
18
|
+
disable,
|
19
|
+
onclick,
|
20
|
+
icon,
|
21
|
+
text,
|
22
|
+
}: EditorButtonProps) => {
|
23
|
+
return (
|
24
|
+
<Tooltip
|
25
|
+
delay={{
|
26
|
+
open: 2000
|
27
|
+
}}
|
28
|
+
interaction
|
29
|
+
placement="top"
|
30
|
+
text={text}
|
31
|
+
>
|
32
|
+
<button
|
33
|
+
className={classname}
|
34
|
+
onClick={onclick}
|
35
|
+
disabled={disable}
|
36
|
+
>
|
37
|
+
<Flex
|
38
|
+
align="center"
|
39
|
+
className="toolbar_button_icon"
|
40
|
+
justify="center"
|
41
|
+
>
|
42
|
+
<Icon icon={icon} size="lg" />
|
43
|
+
</Flex>
|
44
|
+
</button>
|
45
|
+
</Tooltip>
|
46
|
+
);
|
47
|
+
};
|
48
|
+
|
49
|
+
export default EditorButton
|
@@ -0,0 +1,62 @@
|
|
1
|
+
import React from "react";
|
2
|
+
import Background from "../../pb_background/_background";
|
3
|
+
import Flex from "../../pb_flex/_flex";
|
4
|
+
import FlexItem from "../../pb_flex/_flex_item";
|
5
|
+
import SectionSeparator from "../../pb_section_separator/_section_separator";
|
6
|
+
|
7
|
+
import EditorButton from "./EditorButton";
|
8
|
+
import ToolbarDropdown from "./ToolbarDropdown";
|
9
|
+
import ToolbarNodes from "./ToolbarNodes";
|
10
|
+
import { ToolbarTypes } from "./EditorTypes";
|
11
|
+
import ToolbarHistoryItems from "./ToolbarHistory";
|
12
|
+
|
13
|
+
const EditorToolbar = ({ editor }:any) => {
|
14
|
+
const toolbaritems = [
|
15
|
+
{
|
16
|
+
icon: "bold",
|
17
|
+
text: "Bold",
|
18
|
+
classname:`toolbar_button ${editor.isActive('bold') ? 'is-active' : ''}`,
|
19
|
+
onclick:()=>editor.chain().focus().toggleBold().run(),
|
20
|
+
},
|
21
|
+
{
|
22
|
+
icon: "italic",
|
23
|
+
text: "Italic",
|
24
|
+
classname:`toolbar_button ${editor.isActive('italic') ? 'is-active' : ''}`,
|
25
|
+
onclick:() => editor.chain().focus().toggleItalic().run(),
|
26
|
+
},
|
27
|
+
{
|
28
|
+
icon: "strikethrough",
|
29
|
+
text: "Strikethrough",
|
30
|
+
classname:`toolbar_button ${editor.isActive('strike') ? 'is-active' : ''}`,
|
31
|
+
onclick:() => editor.chain().focus().toggleStrike().run(),
|
32
|
+
},
|
33
|
+
]
|
34
|
+
|
35
|
+
return (
|
36
|
+
<Background backgroundColor="white" className="toolbar">
|
37
|
+
<Flex flex="0" justify="between" paddingX="sm" paddingY="xxs">
|
38
|
+
<FlexItem className="toolbar_block" displayFlex>
|
39
|
+
<ToolbarDropdown editor={editor}/>
|
40
|
+
<SectionSeparator orientation="vertical" />
|
41
|
+
{toolbaritems && toolbaritems.map(
|
42
|
+
({ icon, text, classname, onclick}:ToolbarTypes, index:number) => (
|
43
|
+
<EditorButton
|
44
|
+
classname={classname}
|
45
|
+
icon={icon}
|
46
|
+
key={index}
|
47
|
+
text={text}
|
48
|
+
onclick={onclick}
|
49
|
+
/>
|
50
|
+
)
|
51
|
+
)}
|
52
|
+
<SectionSeparator orientation="vertical" />
|
53
|
+
<ToolbarNodes editor={editor} />
|
54
|
+
</FlexItem>
|
55
|
+
<ToolbarHistoryItems editor={editor} />
|
56
|
+
</Flex>
|
57
|
+
{/* <SectionSeparator /> */}
|
58
|
+
</Background>
|
59
|
+
);
|
60
|
+
};
|
61
|
+
|
62
|
+
export default EditorToolbar
|
@@ -0,0 +1,139 @@
|
|
1
|
+
import React, { useState } from 'react'
|
2
|
+
|
3
|
+
import Flex from '../../pb_flex/_flex'
|
4
|
+
import PbReactPopover from '../../pb_popover/_popover'
|
5
|
+
import Button from '../../pb_button/_button'
|
6
|
+
import Icon from '../../pb_icon/_icon'
|
7
|
+
import Nav from '../../pb_nav/_nav'
|
8
|
+
import NavItem from '../../pb_nav/_item'
|
9
|
+
|
10
|
+
import { ToolbarTypes } from './EditorTypes'
|
11
|
+
|
12
|
+
const ToolbarDropdown = ({editor}: any) => {
|
13
|
+
const [showPopover, setShowPopover] = useState(false)
|
14
|
+
|
15
|
+
const toolbarDropdownItems = [
|
16
|
+
{
|
17
|
+
node: "paragraph",
|
18
|
+
icon: "paragraph",
|
19
|
+
isActive: editor.isActive("paragraph"),
|
20
|
+
text: "Paragraph",
|
21
|
+
onclick: () => editor.chain().focus().setParagraph().run(),
|
22
|
+
},
|
23
|
+
{
|
24
|
+
node: "heading-1",
|
25
|
+
icon: "h1",
|
26
|
+
isActive: editor.isActive("heading", {level: 1}),
|
27
|
+
text: "Heading 1",
|
28
|
+
onclick: () => editor.chain().focus().toggleHeading({level:1}).run(),
|
29
|
+
},
|
30
|
+
{
|
31
|
+
node: "heading-2",
|
32
|
+
icon: "h2",
|
33
|
+
isActive: editor.isActive("heading", {level: 2}),
|
34
|
+
text: "Heading 2",
|
35
|
+
onclick: () => editor.chain().focus().toggleHeading({level:2}).run(),
|
36
|
+
},
|
37
|
+
{
|
38
|
+
node: "heading-3",
|
39
|
+
icon: "h3",
|
40
|
+
isActive: editor.isActive("heading", {level: 3}),
|
41
|
+
text: "Heading 3",
|
42
|
+
onclick: () => editor.chain().focus().toggleHeading({level:3}).run(),
|
43
|
+
},
|
44
|
+
{
|
45
|
+
node: "bulletList",
|
46
|
+
icon: "list",
|
47
|
+
isActive: editor.isActive("bulletList"),
|
48
|
+
text: "Bullet List",
|
49
|
+
onclick: () => editor.chain().focus().toggleBulletList().run(),
|
50
|
+
},
|
51
|
+
{
|
52
|
+
node: "orderedList",
|
53
|
+
icon: "list-ol",
|
54
|
+
isActive: editor.isActive("orderedList"),
|
55
|
+
text: "Ordered List",
|
56
|
+
onclick: () => editor.chain().focus().toggleOrderedList().run()
|
57
|
+
,
|
58
|
+
},
|
59
|
+
{
|
60
|
+
node: "blockquote",
|
61
|
+
icon: "block-quote",
|
62
|
+
isActive: editor.isActive("blockquote"),
|
63
|
+
text: "Block Quote",
|
64
|
+
onclick: () => editor.chain().focus().toggleBlockquote().run(),
|
65
|
+
},
|
66
|
+
]
|
67
|
+
|
68
|
+
|
69
|
+
const handleTogglePopover = () => {
|
70
|
+
setShowPopover(true)
|
71
|
+
}
|
72
|
+
|
73
|
+
const handlePopoverClose = (shouldClosePopover: boolean) => {
|
74
|
+
setShowPopover(!shouldClosePopover)
|
75
|
+
}
|
76
|
+
|
77
|
+
let activeCount = 0;
|
78
|
+
const activeItems = [];
|
79
|
+
|
80
|
+
for (const { text, isActive, icon } of toolbarDropdownItems) {
|
81
|
+
if (isActive) {
|
82
|
+
activeCount ++
|
83
|
+
activeItems.push(
|
84
|
+
<Flex align="center" key={icon} gap="xs">
|
85
|
+
<Icon icon={icon} size="lg" />
|
86
|
+
<div>{text}</div>
|
87
|
+
<Flex className={showPopover ? "fa-flip-vertical" : ""} display="inline_flex">
|
88
|
+
<Icon fixedWidth icon="angle-down" margin-left="xs" />
|
89
|
+
</Flex>
|
90
|
+
</Flex>
|
91
|
+
);
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
const popoverReference = (
|
96
|
+
<Button className="editor-dropdown-button" onClick={handleTogglePopover} variant="secondary">
|
97
|
+
{
|
98
|
+
activeCount === 2 ? (
|
99
|
+
activeItems[1]
|
100
|
+
) : (
|
101
|
+
activeItems[0] || null
|
102
|
+
)
|
103
|
+
}
|
104
|
+
</Button>
|
105
|
+
);
|
106
|
+
|
107
|
+
return (
|
108
|
+
<PbReactPopover
|
109
|
+
closeOnClick='outside'
|
110
|
+
padding='none'
|
111
|
+
placement="bottom"
|
112
|
+
reference={popoverReference}
|
113
|
+
shouldClosePopover={handlePopoverClose}
|
114
|
+
show={showPopover}
|
115
|
+
>
|
116
|
+
<Nav
|
117
|
+
paddingTop="xs"
|
118
|
+
paddingBottom="xs"
|
119
|
+
variant="subtle"
|
120
|
+
>
|
121
|
+
{toolbarDropdownItems.map(({ icon, text, onclick, isActive}:ToolbarTypes, index:number) => (
|
122
|
+
<NavItem
|
123
|
+
cursor="pointer"
|
124
|
+
className={`pb_tiptap_toolbar_dropdown_list_item ${isActive ? "is-active" : ""}`}
|
125
|
+
iconLeft={icon}
|
126
|
+
key={`${text}_${index}`}
|
127
|
+
margin='none'
|
128
|
+
onClick={()=> {onclick(); setShowPopover(false)}}
|
129
|
+
text={text}
|
130
|
+
paddingTop='xxs'
|
131
|
+
paddingBottom='xxs'
|
132
|
+
/>
|
133
|
+
))}
|
134
|
+
</Nav>
|
135
|
+
</PbReactPopover>
|
136
|
+
)
|
137
|
+
}
|
138
|
+
|
139
|
+
export default ToolbarDropdown
|
@@ -0,0 +1,45 @@
|
|
1
|
+
import React from "react";
|
2
|
+
import FlexItem from "../../pb_flex/_flex_item";
|
3
|
+
import EditorButton from "./EditorButton";
|
4
|
+
import { ToolbarTypes } from "./EditorTypes";
|
5
|
+
|
6
|
+
const ToolbarHistoryItems = ({editor}:any) => {
|
7
|
+
|
8
|
+
const toolbarHistoryItems = [
|
9
|
+
{
|
10
|
+
classname: `toolbar_button`,
|
11
|
+
icon: "undo",
|
12
|
+
text: "Undo",
|
13
|
+
onclick: () => editor.chain().focus().undo().run(),
|
14
|
+
disable: !editor.can().chain().focus().undo().run()
|
15
|
+
},
|
16
|
+
{
|
17
|
+
classname: `toolbar_button`,
|
18
|
+
icon: "redo",
|
19
|
+
text: "Redo",
|
20
|
+
onclick: () => editor.chain().focus().redo().run(),
|
21
|
+
disable: !editor.can().chain().focus().redo().run()
|
22
|
+
},
|
23
|
+
];
|
24
|
+
|
25
|
+
return (
|
26
|
+
<>
|
27
|
+
<FlexItem displayFlex>
|
28
|
+
{toolbarHistoryItems.map(
|
29
|
+
({ onclick, classname, disable, icon, text }:ToolbarTypes, index:number) => (
|
30
|
+
<EditorButton
|
31
|
+
classname={classname}
|
32
|
+
onclick={onclick}
|
33
|
+
disable={disable}
|
34
|
+
icon={icon}
|
35
|
+
key={index}
|
36
|
+
text={text}
|
37
|
+
/>
|
38
|
+
)
|
39
|
+
)}
|
40
|
+
</FlexItem>
|
41
|
+
</>
|
42
|
+
)
|
43
|
+
}
|
44
|
+
|
45
|
+
export default ToolbarHistoryItems
|
@@ -0,0 +1,59 @@
|
|
1
|
+
import React, {useCallback} from "react";
|
2
|
+
import EditorButton from "./EditorButton";
|
3
|
+
import { ToolbarTypes } from "./EditorTypes";
|
4
|
+
|
5
|
+
const ToolbarNodes = ({editor}:any) => {
|
6
|
+
|
7
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
8
|
+
const setLink = useCallback(() => {
|
9
|
+
const previousUrl = editor.getAttributes("link").href;
|
10
|
+
const url = window.prompt("URL", previousUrl);
|
11
|
+
|
12
|
+
// cancelled
|
13
|
+
if (url === null) {
|
14
|
+
return;
|
15
|
+
}
|
16
|
+
|
17
|
+
// empty
|
18
|
+
if (url === "") {
|
19
|
+
editor.chain().focus().extendMarkRange("link").unsetLink().run();
|
20
|
+
|
21
|
+
return;
|
22
|
+
}
|
23
|
+
|
24
|
+
// update link
|
25
|
+
editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
|
26
|
+
}, [editor]);
|
27
|
+
|
28
|
+
const toolbarNodesItems = [
|
29
|
+
{
|
30
|
+
onclick: () => editor.chain().focus().toggleCodeBlock().run(),
|
31
|
+
icon: "code",
|
32
|
+
isActive: editor.isActive("codeBlock"),
|
33
|
+
text: "Codeblock",
|
34
|
+
},
|
35
|
+
{
|
36
|
+
onclick: setLink,
|
37
|
+
icon: "link",
|
38
|
+
isActive: editor.isActive("link"),
|
39
|
+
text: "Link",
|
40
|
+
},
|
41
|
+
];
|
42
|
+
|
43
|
+
return (
|
44
|
+
<>
|
45
|
+
{toolbarNodesItems.map(({ onclick, icon, text, isActive }:ToolbarTypes, index:number) => (
|
46
|
+
<EditorButton
|
47
|
+
classname={`toolbar_button ${isActive ? 'is-active' : ''}`}
|
48
|
+
onclick={onclick}
|
49
|
+
icon={icon}
|
50
|
+
key={index}
|
51
|
+
text={text}
|
52
|
+
/>
|
53
|
+
))}
|
54
|
+
</>
|
55
|
+
)
|
56
|
+
}
|
57
|
+
|
58
|
+
|
59
|
+
export default ToolbarNodes
|
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react'
|
|
2
2
|
import classnames from 'classnames'
|
3
3
|
import inlineFocus from './inlineFocus'
|
4
4
|
import useFocus from './useFocus'
|
5
|
-
import { globalProps } from '../utilities/globalProps'
|
5
|
+
import { globalProps, GlobalProps } from '../utilities/globalProps'
|
6
6
|
import { buildAriaProps, buildDataProps, noop } from '../utilities/props'
|
7
7
|
|
8
8
|
try {
|
@@ -14,6 +14,7 @@ try {
|
|
14
14
|
} catch (_e) { /* do nothing */ }
|
15
15
|
|
16
16
|
import { TrixEditor } from "react-trix"
|
17
|
+
import EditorToolbar from './TipTap/Toolbar'
|
17
18
|
|
18
19
|
type Editor = {
|
19
20
|
attributeIsActive?: Function,
|
@@ -27,7 +28,9 @@ type Editor = {
|
|
27
28
|
|
28
29
|
type RichTextEditorProps = {
|
29
30
|
aria?: { [key: string]: string },
|
31
|
+
advancedEditor?: any,
|
30
32
|
toolbarBottom?: Boolean,
|
33
|
+
children?: React.ReactNode | React.ReactNode[]
|
31
34
|
className?: string,
|
32
35
|
data?: { [key: string]: string },
|
33
36
|
focus?: boolean,
|
@@ -40,12 +43,15 @@ type RichTextEditorProps = {
|
|
40
43
|
sticky?: boolean,
|
41
44
|
template: string,
|
42
45
|
value?: string,
|
43
|
-
|
46
|
+
maxWidth?: string
|
47
|
+
} & GlobalProps
|
44
48
|
|
45
49
|
const RichTextEditor = (props: RichTextEditorProps) => {
|
46
50
|
const {
|
47
51
|
aria = {},
|
52
|
+
advancedEditor,
|
48
53
|
toolbarBottom = false,
|
54
|
+
children,
|
49
55
|
className,
|
50
56
|
data = {},
|
51
57
|
focus = false,
|
@@ -57,6 +63,7 @@ const RichTextEditor = (props: RichTextEditorProps) => {
|
|
57
63
|
sticky = false,
|
58
64
|
template = '',
|
59
65
|
value = '',
|
66
|
+
maxWidth="md"
|
60
67
|
} = props
|
61
68
|
|
62
69
|
const ariaProps = buildAriaProps(aria),
|
@@ -135,7 +142,7 @@ const RichTextEditor = (props: RichTextEditorProps) => {
|
|
135
142
|
inlineClass = inline ? 'inline' : '',
|
136
143
|
toolbarBottomClass = toolbarBottom ? 'toolbar-bottom' : ''
|
137
144
|
|
138
|
-
let css = classnames(globalProps(props), className)
|
145
|
+
let css = classnames(globalProps(props, {maxWidth}), className)
|
139
146
|
css = classnames(
|
140
147
|
richTextEditorClass,
|
141
148
|
simpleClass,
|
@@ -152,15 +159,24 @@ const RichTextEditor = (props: RichTextEditorProps) => {
|
|
152
159
|
{...dataProps}
|
153
160
|
className={css}
|
154
161
|
>
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
162
|
+
{
|
163
|
+
advancedEditor ? (
|
164
|
+
<div className='pb_rich_text_editor_advanced_container'>
|
165
|
+
<EditorToolbar editor={advancedEditor}/>
|
166
|
+
{ children }
|
167
|
+
</div>
|
168
|
+
) : (
|
169
|
+
<TrixEditor
|
170
|
+
className=""
|
171
|
+
fileParamName={name}
|
172
|
+
mergeTags={[]}
|
173
|
+
onChange={onChange}
|
174
|
+
onEditorReady={handleOnEditorReady}
|
175
|
+
placeholder={placeholder}
|
176
|
+
value={value}
|
177
|
+
/>
|
178
|
+
)
|
179
|
+
}
|
164
180
|
</div>
|
165
181
|
)
|
166
182
|
}
|