react-bootstrap-front 3.9.1 → 3.9.6
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/CHANGELOG +21 -0
- package/dist/react-bootstrap-front.js +20 -20
- package/package.json +2 -1
- package/src/features/advanced/DropdownWrapper.js +18 -5
- package/src/features/basic/Dropdown.js +2 -2
- package/src/features/basic/InputText.js +1 -1
- package/src/features/draft/ColorPicker.js +2 -2
- package/src/features/draft/FontFamily.js +70 -0
- package/src/features/draft/FontFamily.scss +0 -0
- package/src/features/draft/FontSize.js +8 -4
- package/src/features/draft/Image.js +64 -0
- package/src/features/draft/Image.scss +3 -0
- package/src/features/draft/Inline.js +3 -2
- package/src/features/draft/InputHtml.js +147 -40
- package/src/features/draft/InputHtml.scss +13 -2
- package/src/features/draft/MailMerge.js +54 -0
- package/src/features/draft/MailMerge.scss +0 -0
- package/src/features/draft/index.js +3 -0
- package/src/features/draft/style.scss +4 -0
- package/src/features/inline-list/DefaultHeader.jsx +1 -1
- package/src/features/inline-list/DefaultLine.js +1 -1
- package/src/features/inline-list/DefaultList.jsx +7 -8
- package/src/features/list/DefaultHeader.jsx +4 -4
- package/src/features/list/MobileList.jsx +1 -1
- package/src/features/page/MobilePage.jsx +1 -1
- package/src/styles/mixins/container.scss +22 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-bootstrap-front",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.6",
|
|
4
4
|
"description": "React Bootstrap Components",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Bootstrap 4",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"react-router-dom": "^5.0.1"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
+
"@draft-js-plugins/image": "^4.1.2",
|
|
37
38
|
"@ericblade/quagga2": "^1.4.1",
|
|
38
39
|
"@popperjs/core": "^2.5.4",
|
|
39
40
|
"autosize": "^4.0.2",
|
|
@@ -6,22 +6,32 @@ import { Dropdown } from '../basic';
|
|
|
6
6
|
export default class DropdownWrapper extends Component {
|
|
7
7
|
static propTypes = {
|
|
8
8
|
align: PropTypes.string,
|
|
9
|
-
|
|
9
|
+
autoClose: PropTypes.bool,
|
|
10
10
|
className: PropTypes.string,
|
|
11
11
|
myRef: PropTypes.object,
|
|
12
|
+
open: PropTypes.bool,
|
|
12
13
|
tooltip: PropTypes.string,
|
|
13
14
|
trigger: PropTypes.element.isRequired,
|
|
14
15
|
};
|
|
15
16
|
static defaultProps = {
|
|
16
17
|
align: 'bottom-left',
|
|
18
|
+
autoClose: true,
|
|
17
19
|
className: '',
|
|
18
20
|
myRef: null,
|
|
21
|
+
open: false,
|
|
19
22
|
tooltip: '',
|
|
20
23
|
};
|
|
21
24
|
|
|
25
|
+
static getDerivedStateFromProps(state, props) {
|
|
26
|
+
if (state.origOpen !== props.open && state.open !== props.open) {
|
|
27
|
+
return { open: props.open, origOpen: props.open };
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
22
32
|
constructor(props) {
|
|
23
33
|
super(props);
|
|
24
|
-
this.state = { open: false, ref: props.myRef || React.createRef() };
|
|
34
|
+
this.state = { origOpen: this.props.open, open: this.props.open || false, ref: props.myRef || React.createRef() };
|
|
25
35
|
this.onClose = this.onClose.bind(this);
|
|
26
36
|
this.onClick = this.onClick.bind(this);
|
|
27
37
|
}
|
|
@@ -41,14 +51,17 @@ export default class DropdownWrapper extends Component {
|
|
|
41
51
|
render() {
|
|
42
52
|
const clonedTrigger = React.cloneElement(
|
|
43
53
|
this.props.trigger,
|
|
44
|
-
{ref: this.state.ref, onClick: this.onClick, title: this.props.tooltip}
|
|
54
|
+
{ ref: this.state.ref, onClick: this.onClick, title: this.props.tooltip }
|
|
45
55
|
)
|
|
56
|
+
const { onClose } = this;
|
|
46
57
|
return (
|
|
47
58
|
<>
|
|
48
59
|
{clonedTrigger}
|
|
49
60
|
{this.state.open && (
|
|
50
|
-
<Dropdown align={this.props.align} myRef={this.state.ref} onClose={
|
|
51
|
-
<div onClick={this.
|
|
61
|
+
<Dropdown align={this.props.align} myRef={this.state.ref} onClose={onClose}>
|
|
62
|
+
<div onClick={this.props.autoClose && this.onClose}>
|
|
63
|
+
{typeof this.props.children === 'function' ? this.props.children({ onClose }) : this.props.children}
|
|
64
|
+
</div>
|
|
52
65
|
</Dropdown>
|
|
53
66
|
)}
|
|
54
67
|
</>
|
|
@@ -53,8 +53,8 @@ export default class Dropdown extends Component {
|
|
|
53
53
|
|
|
54
54
|
handleClickOutside(event) {
|
|
55
55
|
const domNode = ReactDOM.findDOMNode(this);
|
|
56
|
-
if (!domNode || !domNode.contains(event.target)) {
|
|
57
|
-
if (this.props.myRef && this.props.myRef.current &&this.props.myRef.current.contains(event.target)) {
|
|
56
|
+
if (!domNode || !domNode.contains(event.target)) {
|
|
57
|
+
if (this.props.myRef && this.props.myRef.current && this.props.myRef.current.contains(event.target)) {
|
|
58
58
|
event.preventDefault();
|
|
59
59
|
event.stopPropagation();
|
|
60
60
|
}
|
|
@@ -35,12 +35,12 @@ export default class ColorPicker extends Component {
|
|
|
35
35
|
type="button"
|
|
36
36
|
className={classnames(this.props.className, 'btn btn-light')}
|
|
37
37
|
>
|
|
38
|
-
Color
|
|
38
|
+
{this.props.config.icon ? this.props.config.icon : 'Color' }
|
|
39
39
|
</button>
|
|
40
40
|
);
|
|
41
41
|
const { color } = this.props.currentState;
|
|
42
42
|
return (
|
|
43
|
-
<DropdownWrapper trigger={trigger} className="
|
|
43
|
+
<DropdownWrapper autoClose={false} trigger={trigger} className="ui-inline-wrapper btn-group pl-2" align="bottom-right" myRef={this.state.myRef}>
|
|
44
44
|
<DropdownMenu>
|
|
45
45
|
<ChromePicker color={color} onChangeComplete={this.onChange} />
|
|
46
46
|
</DropdownMenu>
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React, { Component } from 'react';
|
|
2
|
+
import classnames from 'classnames';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import { DropdownWrapper } from '../advanced'
|
|
5
|
+
import { DropdownMenu, DropdownMenuOption } from '../basic';
|
|
6
|
+
|
|
7
|
+
export default class FontFamily extends Component {
|
|
8
|
+
static propTypes = {
|
|
9
|
+
expanded: PropTypes.bool,
|
|
10
|
+
onExpandEvent: PropTypes.func,
|
|
11
|
+
onChange: PropTypes.func,
|
|
12
|
+
currentState: PropTypes.object,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
constructor(props) {
|
|
16
|
+
super(props);
|
|
17
|
+
this.state = {
|
|
18
|
+
myRef: React.createRef()
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
stopPropagation = (event) => {
|
|
23
|
+
event.stopPropagation();
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
onChange = (family) => {
|
|
27
|
+
const { onChange } = this.props;
|
|
28
|
+
onChange('family', family.hex);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
render() {
|
|
32
|
+
const trigger = (
|
|
33
|
+
<button
|
|
34
|
+
type="button"
|
|
35
|
+
className={classnames(this.props.className, 'btn btn-light')}
|
|
36
|
+
>
|
|
37
|
+
{this.props.icon ? this.props.icon : 'Font' }
|
|
38
|
+
</button>
|
|
39
|
+
);
|
|
40
|
+
const {
|
|
41
|
+
config: { icon, className, dropdownClassName, options, title },
|
|
42
|
+
onChange,
|
|
43
|
+
expanded,
|
|
44
|
+
doCollapse,
|
|
45
|
+
onExpandEvent,
|
|
46
|
+
doExpand,
|
|
47
|
+
translations,
|
|
48
|
+
} = this.props;
|
|
49
|
+
let { currentState: { fontFamily: currentFontFamily } } = this.props;
|
|
50
|
+
let { defaultFontFamily } = this.state;
|
|
51
|
+
currentFontFamily = currentFontFamily ||
|
|
52
|
+
(options && options.indexOf(defaultFontFamily) >= 0 && defaultFontFamily);
|
|
53
|
+
return (
|
|
54
|
+
<DropdownWrapper trigger={trigger} className="ui-inline-wrapper btn-group pl-2" align="bottom-right" myRef={this.state.myRef}>
|
|
55
|
+
<DropdownMenu>
|
|
56
|
+
{options.map((family, index) =>
|
|
57
|
+
(<DropdownMenuOption
|
|
58
|
+
className="rdw-fontfamily-option"
|
|
59
|
+
active={currentFontFamily === family}
|
|
60
|
+
onClick={() => onChange(family)}
|
|
61
|
+
key={index}
|
|
62
|
+
>
|
|
63
|
+
{family}
|
|
64
|
+
</DropdownMenuOption>),
|
|
65
|
+
)}
|
|
66
|
+
</DropdownMenu>
|
|
67
|
+
</DropdownWrapper>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
File without changes
|
|
@@ -23,9 +23,13 @@ export default class FontSize extends Component {
|
|
|
23
23
|
event.stopPropagation();
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
-
onChange = (
|
|
26
|
+
onChange = (size) => {
|
|
27
27
|
const { onChange } = this.props;
|
|
28
|
-
|
|
28
|
+
let mySize = size.hex;
|
|
29
|
+
if (!isNaN(mySize)) {
|
|
30
|
+
mySize += 'px';
|
|
31
|
+
}
|
|
32
|
+
onChange('size', mySize);
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
render() {
|
|
@@ -34,7 +38,7 @@ export default class FontSize extends Component {
|
|
|
34
38
|
type="button"
|
|
35
39
|
className={classnames(this.props.className, 'btn btn-light')}
|
|
36
40
|
>
|
|
37
|
-
Size
|
|
41
|
+
{this.props.config.icon ? this.props.config.icon : 'Size' }
|
|
38
42
|
</button>
|
|
39
43
|
);
|
|
40
44
|
const {
|
|
@@ -52,7 +56,7 @@ export default class FontSize extends Component {
|
|
|
52
56
|
currentFontSize = currentFontSize ||
|
|
53
57
|
(options && options.indexOf(defaultFontSize) >= 0 && defaultFontSize);
|
|
54
58
|
return (
|
|
55
|
-
<DropdownWrapper trigger={trigger} className="
|
|
59
|
+
<DropdownWrapper trigger={trigger} className="ui-inline-wrapper btn-group pl-2" align="bottom-right" myRef={this.state.myRef}>
|
|
56
60
|
<DropdownMenu>
|
|
57
61
|
{options.map((size, index) =>
|
|
58
62
|
(<DropdownMenuOption
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React, { Component } from 'react';
|
|
2
|
+
import classnames from 'classnames';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import { DropdownWrapper } from '../advanced'
|
|
5
|
+
import { DropdownMenu, InputText } from '../basic';
|
|
6
|
+
|
|
7
|
+
export default class Image extends Component {
|
|
8
|
+
static propTypes = {
|
|
9
|
+
expanded: PropTypes.bool,
|
|
10
|
+
onExpandEvent: PropTypes.func,
|
|
11
|
+
onChange: PropTypes.func,
|
|
12
|
+
currentState: PropTypes.object,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
constructor(props) {
|
|
16
|
+
super(props);
|
|
17
|
+
this.state = {
|
|
18
|
+
url: '',
|
|
19
|
+
myRef: React.createRef()
|
|
20
|
+
}
|
|
21
|
+
this.onChange = this.onChange.bind(this);
|
|
22
|
+
this.onAdd = this.onAdd.bind(this);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
onChange(ev) {
|
|
26
|
+
if (ev) {
|
|
27
|
+
ev.preventDefault();
|
|
28
|
+
ev.stopPropagation();
|
|
29
|
+
const value = ev.target.value;
|
|
30
|
+
const name = ev.target.name;
|
|
31
|
+
this.setState({ [name]: value });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
onAdd(ev) {
|
|
36
|
+
const url = this.state.url;
|
|
37
|
+
this.setState({ url: '' });
|
|
38
|
+
this.props.onChange(url);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
render() {
|
|
42
|
+
const trigger = (
|
|
43
|
+
<button
|
|
44
|
+
type="button"
|
|
45
|
+
className={classnames(this.props.className, 'btn btn-light')}
|
|
46
|
+
>
|
|
47
|
+
{this.props.config.icon ? this.props.config.icon : 'Image'}
|
|
48
|
+
</button>
|
|
49
|
+
);
|
|
50
|
+
//console.log(this.props.currentState, this.props.config);
|
|
51
|
+
return (
|
|
52
|
+
<DropdownWrapper autoClose={false} trigger={trigger} className="ui-inline-wrapper btn-group pl-2" align="bottom-right" myRef={this.state.myRef}>
|
|
53
|
+
{({ onClose }) =>
|
|
54
|
+
<DropdownMenu>
|
|
55
|
+
<>
|
|
56
|
+
<InputText labelTop={true} label="Url" name="url" value={this.state.url} onChange={this.onChange} />
|
|
57
|
+
<button type="button" class="btn btn-xs btn-success" onClick={(ev) => { onClose(); this.onAdd(ev); }}>Ok</button>
|
|
58
|
+
</>
|
|
59
|
+
</DropdownMenu>
|
|
60
|
+
}
|
|
61
|
+
</DropdownWrapper>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -18,15 +18,16 @@ export default class Inline extends Component {
|
|
|
18
18
|
}
|
|
19
19
|
render() {
|
|
20
20
|
const { config, currentState, onChange, translations } = this.props;
|
|
21
|
+
const textalign = currentState.textAlignment || '';
|
|
21
22
|
return (
|
|
22
|
-
<div className={classnames('
|
|
23
|
+
<div className={classnames('ui-inline-wrapper btn-group', config.className)} aria-label="rdw-inline-control">
|
|
23
24
|
{
|
|
24
25
|
config.options
|
|
25
26
|
.map((style, index) =>
|
|
26
27
|
(<button
|
|
27
28
|
key={index}
|
|
28
29
|
onClick={() => onChange(style)}
|
|
29
|
-
className={classnames("btn btn-light", config[style].className, (
|
|
30
|
+
className={classnames("btn btn-light", config[style].className, (textalign === true ||
|
|
30
31
|
(style === 'MONOSPACE' && currentState.CODE)) && "active")}
|
|
31
32
|
title={config[style].title || translations[`components.controls.inline.${style}`]}
|
|
32
33
|
>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import React, { Component } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import classnames from 'classnames';
|
|
4
|
+
import { camelCase } from 'lodash';
|
|
4
5
|
import { EditorState, Modifier, CompositeDecorator } from 'draft-js';
|
|
5
6
|
import { Editor } from 'react-draft-wysiwyg';
|
|
6
7
|
import { convertToHTML, convertFromHTML } from 'draft-convert';
|
|
7
8
|
import { htmlToString } from '../helpers';
|
|
8
|
-
import { ColorPicker, Inline, FontSize } from './';
|
|
9
|
-
import '../../../node_modules/react-draft-wysiwyg/dist/react-draft-wysiwyg.css';
|
|
9
|
+
import { ColorPicker, Inline, FontSize, FontFamily, Image, MailMerge as MailMergeOption } from './';
|
|
10
10
|
|
|
11
11
|
const myStyle = {
|
|
12
12
|
height: 'auto',
|
|
@@ -37,23 +37,62 @@ const toHtml = {
|
|
|
37
37
|
case 'color':
|
|
38
38
|
return <span style={{ color: parts[1] }} />;
|
|
39
39
|
case 'fontsize':
|
|
40
|
-
return <span style={{ fontSize: parts[1] }} />;
|
|
40
|
+
return <span style={{ fontSize: parts[1] + 'px' }} />;
|
|
41
|
+
case 'text':
|
|
42
|
+
if (parts[1] === 'align') {
|
|
43
|
+
return <span style={{ textAlign: parts[2] }} />;
|
|
44
|
+
}
|
|
45
|
+
return '';
|
|
41
46
|
default:
|
|
42
47
|
// nothing
|
|
43
48
|
break;
|
|
44
49
|
}
|
|
45
50
|
},
|
|
46
51
|
blockToHTML: block => {
|
|
52
|
+
let styles = {};
|
|
53
|
+
if (block.data && Object.keys(block.data).length > 0) {
|
|
54
|
+
Object.keys(block.data).forEach(key => {
|
|
55
|
+
styles[camelCase(key)] = block.data[key];
|
|
56
|
+
});
|
|
57
|
+
}
|
|
47
58
|
if (block.type === 'PARAGRAPH') {
|
|
48
|
-
return <p />;
|
|
59
|
+
return <p style={styles} />;
|
|
60
|
+
}
|
|
61
|
+
if (block.type === 'atomic') {
|
|
62
|
+
return {
|
|
63
|
+
start: "",
|
|
64
|
+
end: "",
|
|
65
|
+
}
|
|
49
66
|
}
|
|
67
|
+
if (block.type === 'unstyled' && block.text.trim() === '') {
|
|
68
|
+
return <br />;
|
|
69
|
+
}
|
|
70
|
+
if (Object.keys(styles).length > 0) {
|
|
71
|
+
return <p style={styles} />;
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
50
74
|
},
|
|
51
75
|
entityToHTML: (entity, originalText) => {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
76
|
+
switch (entity.type) {
|
|
77
|
+
case 'LINK':
|
|
78
|
+
return <a href={entity.data.url}>{originalText}</a>;
|
|
79
|
+
case 'MAILMERGE':
|
|
80
|
+
return <span data-mailmerge="{originalText}">{originalText}</span>;
|
|
81
|
+
case 'IMAGE':
|
|
82
|
+
let otherDatas = {};
|
|
83
|
+
let alt = '';
|
|
84
|
+
if (entity.data.height) {
|
|
85
|
+
otherDatas['height'] = entity.data.height;
|
|
86
|
+
}
|
|
87
|
+
if (entity.data.width) {
|
|
88
|
+
otherDatas['width'] = entity.data.width;
|
|
89
|
+
}
|
|
90
|
+
if (entity.data.alt) {
|
|
91
|
+
alt = entity.data.alt;
|
|
92
|
+
}
|
|
93
|
+
return <img src={entity.data.src} {...otherDatas} alt={alt} />;
|
|
94
|
+
default:
|
|
95
|
+
break;
|
|
57
96
|
}
|
|
58
97
|
return originalText;
|
|
59
98
|
},
|
|
@@ -99,44 +138,65 @@ const fromHtml = {
|
|
|
99
138
|
if (fontSize && fontSize !== '') {
|
|
100
139
|
style.add(`fontsize-${fontSize.replace(/px$/g, '')}`);
|
|
101
140
|
}
|
|
141
|
+
const textAlign = node.style.textAlign;
|
|
142
|
+
if (textAlign && textAlign !== '') {
|
|
143
|
+
style.add(`textalign-${textAlign}`);
|
|
144
|
+
}
|
|
102
145
|
}
|
|
103
146
|
})
|
|
104
147
|
.toOrderedSet();
|
|
105
148
|
return currentStyle;
|
|
106
149
|
},
|
|
107
150
|
htmlToEntity: (nodeName, node, createEntity) => {
|
|
151
|
+
let entity = null;
|
|
108
152
|
if (nodeName === 'a') {
|
|
109
|
-
|
|
153
|
+
entity = createEntity('LINK', 'MUTABLE', { url: node.href });
|
|
110
154
|
}
|
|
111
155
|
if (nodeName === 'span' && node.dataset && node.dataset.mailmerge) {
|
|
112
|
-
|
|
156
|
+
entity = createEntity('MAILMERGE', 'IMMUTABLE', { mailmerge: node.dataset.mailmerge });
|
|
113
157
|
}
|
|
158
|
+
if (nodeName === 'img') {
|
|
159
|
+
entity = createEntity('IMAGE', 'MUTABLE', { src: node.src });
|
|
160
|
+
}
|
|
161
|
+
return entity;
|
|
114
162
|
},
|
|
115
163
|
textToEntity: (text, createEntity) => {
|
|
116
164
|
const result = [];
|
|
117
|
-
text.replace(/\@(\w+)/g, (match, name, offset) => {
|
|
118
|
-
const entityKey = createEntity('AT-MENTION', 'IMMUTABLE', { name });
|
|
119
|
-
result.push({
|
|
120
|
-
entity: entityKey,
|
|
121
|
-
offset,
|
|
122
|
-
length: match.length,
|
|
123
|
-
result: match,
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
165
|
return result;
|
|
127
166
|
},
|
|
128
167
|
htmlToBlock: (nodeName, node) => {
|
|
168
|
+
if (nodeName === "hr" || nodeName === "img") {
|
|
169
|
+
return "atomic";
|
|
170
|
+
}
|
|
129
171
|
if (nodeName === 'blockquote') {
|
|
130
172
|
return {
|
|
131
173
|
type: 'blockquote',
|
|
132
174
|
data: {},
|
|
133
175
|
};
|
|
134
176
|
}
|
|
177
|
+
if (nodeName === 'br') {
|
|
178
|
+
return {
|
|
179
|
+
type: 'PARAGRAPH',
|
|
180
|
+
data: {},
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
if (nodeName === 'p' && node instanceof HTMLElement) {
|
|
184
|
+
let styles = {};
|
|
185
|
+
if (node.style.textAlign) {
|
|
186
|
+
styles['text-align'] = node.style.textAlign;
|
|
187
|
+
}
|
|
188
|
+
if (Object.keys(styles).length > 0) {
|
|
189
|
+
return {
|
|
190
|
+
type: 'PARAGRAPH',
|
|
191
|
+
data: styles,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return null;
|
|
135
196
|
},
|
|
136
197
|
};
|
|
137
198
|
|
|
138
199
|
function findMailmergeEntities(contentBlock, callback, contentState) {
|
|
139
|
-
console.log(callback);
|
|
140
200
|
contentBlock.findEntityRanges(
|
|
141
201
|
(character) => {
|
|
142
202
|
const entityKey = character.getEntity();
|
|
@@ -156,7 +216,21 @@ const Mailmerge = (props) => {
|
|
|
156
216
|
);
|
|
157
217
|
};
|
|
158
218
|
|
|
159
|
-
|
|
219
|
+
const MailmergeOptions = (props) => {
|
|
220
|
+
if (props.presetTexts && Array.isArray(props.presetTexts) && props.presetTexts.length > 0) {
|
|
221
|
+
return (
|
|
222
|
+
[<MailMergeOption
|
|
223
|
+
icon={props.presetTextIcon}
|
|
224
|
+
options={props.presetTexts}
|
|
225
|
+
onChangeText={(text) => this.onAddPresetText(text)}
|
|
226
|
+
/>]
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
return [];
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
export default class InputHtml extends Component {
|
|
160
234
|
static propTypes = {
|
|
161
235
|
id: PropTypes.string,
|
|
162
236
|
name: PropTypes.string.isRequired,
|
|
@@ -169,8 +243,14 @@ export default class InputTextarea extends Component {
|
|
|
169
243
|
disabled: PropTypes.bool,
|
|
170
244
|
clearIcon: PropTypes.element,
|
|
171
245
|
toolbarIcon: PropTypes.element,
|
|
246
|
+
sizeIcon: PropTypes.element,
|
|
247
|
+
fontIcon: PropTypes.element,
|
|
248
|
+
colorIcon: PropTypes.element,
|
|
249
|
+
imageIcon: PropTypes.element,
|
|
172
250
|
presetTextIcon: PropTypes.element,
|
|
251
|
+
presetTexts: PropTypes.array,
|
|
173
252
|
onPresetText: PropTypes.func,
|
|
253
|
+
t: PropTypes.func,
|
|
174
254
|
};
|
|
175
255
|
|
|
176
256
|
static defaultProps = {
|
|
@@ -184,8 +264,14 @@ export default class InputTextarea extends Component {
|
|
|
184
264
|
required: false,
|
|
185
265
|
clearIcon: null,
|
|
186
266
|
toolbarIcon: null,
|
|
267
|
+
sizeIcon: null,
|
|
268
|
+
fontIcon: null,
|
|
269
|
+
colorIcon: null,
|
|
270
|
+
imageIcon: null,
|
|
187
271
|
presetTextIcon: null,
|
|
272
|
+
presetTexts: [],
|
|
188
273
|
onPresetText: null,
|
|
274
|
+
t: () => {},
|
|
189
275
|
};
|
|
190
276
|
|
|
191
277
|
constructor(props) {
|
|
@@ -211,9 +297,7 @@ export default class InputTextarea extends Component {
|
|
|
211
297
|
this.onChange = this.onChange.bind(this);
|
|
212
298
|
this.onToolbar = this.onToolbar.bind(this);
|
|
213
299
|
this.onClear = this.onClear.bind(this);
|
|
214
|
-
this.onPresetText = this.onPresetText.bind(this);
|
|
215
300
|
this.onAddPresetText = this.onAddPresetText.bind(this);
|
|
216
|
-
this.onPresetTextClose = this.onPresetTextClose.bind(this);
|
|
217
301
|
}
|
|
218
302
|
|
|
219
303
|
onEditorStateChange(editorState) {
|
|
@@ -249,11 +333,6 @@ export default class InputTextarea extends Component {
|
|
|
249
333
|
this.props.onChange(event);
|
|
250
334
|
}
|
|
251
335
|
|
|
252
|
-
onPresetText() {
|
|
253
|
-
this.props.onPresetText();
|
|
254
|
-
this.setState({ presetText: true });
|
|
255
|
-
}
|
|
256
|
-
|
|
257
336
|
onAddPresetText(contentMore) {
|
|
258
337
|
const editorState = this.state.editorState;
|
|
259
338
|
let content = editorState.getCurrentContent();
|
|
@@ -271,27 +350,54 @@ export default class InputTextarea extends Component {
|
|
|
271
350
|
this.props.onChange(event);
|
|
272
351
|
}
|
|
273
352
|
|
|
274
|
-
onPresetTextClose() {
|
|
275
|
-
this.setState({ presetText: false });
|
|
276
|
-
}
|
|
277
|
-
|
|
278
353
|
render() {
|
|
279
354
|
//<div className={classnames('input-group', (props.error || props.warning) && 'is-invalid')}>
|
|
280
355
|
const { editorState, toolbar } = this.state;
|
|
356
|
+
const { t } = this.props;
|
|
281
357
|
const editorToolbar = {
|
|
282
|
-
options: ['inline','fontSize','colorPicker'],
|
|
358
|
+
options: ['inline','fontSize', 'fontFamily', 'list', 'textAlign', 'colorPicker', 'image'],
|
|
283
359
|
inline: {
|
|
284
360
|
inDropdown: false,
|
|
285
361
|
component: Inline,
|
|
286
|
-
options: ['bold', 'italic', 'underline', 'superscript', 'subscript'],
|
|
362
|
+
options: ['bold', 'italic', 'underline', 'strikethrough', 'monospace', 'superscript', 'subscript'],
|
|
363
|
+
bold: { title: t({ id: 'ui.textarea.draft.toolbar.bold', defaultMessage: 'Bold' }) },
|
|
364
|
+
italic: { title: t({ id: 'ui.textarea.draft.toolbar.italic', defaultMessage: 'Italic' }) },
|
|
365
|
+
underline: { title: t({ id: 'ui.textarea.draft.toolbar.underline', defaultMessage: 'Underline' }) },
|
|
366
|
+
strikethrough: { title: t({ id: 'ui.textarea.draft.toolbar.strikethrough', defaultMessage: 'Underline' }) },
|
|
367
|
+
monospace: { title: t({ id: 'ui.textarea.draft.toolbar.monospace', defaultMessage: 'monospace' }) },
|
|
368
|
+
superscript: { title: t({ id: 'ui.textarea.draft.toolbar.superscript', defaultMessage: 'Superscript' }) },
|
|
369
|
+
subscript: { title: t({ id: 'ui.textarea.draft.toolbar.subscript', defaultMessage: 'Subscript' }) },
|
|
287
370
|
},
|
|
288
371
|
fontSize: {
|
|
289
372
|
component: FontSize,
|
|
290
373
|
options: [7, 8, 9, 10, 11, 12, 14, 16, 18, 24, 30, 36, 48, 60, 72, 96],
|
|
374
|
+
icon: this.props.sizeIcon,
|
|
375
|
+
},
|
|
376
|
+
fontFamily: {
|
|
377
|
+
component: FontFamily,
|
|
378
|
+
options: ['Arial', 'Georgia', 'Impact', 'Tahoma', 'Times New Roman', 'Verdana'],
|
|
379
|
+
},
|
|
380
|
+
list: {
|
|
381
|
+
inDropdown: false,
|
|
382
|
+
component: Inline,
|
|
383
|
+
options: ['unordered', 'ordered'],
|
|
384
|
+
},
|
|
385
|
+
textAlign: {
|
|
386
|
+
inDropdown: false,
|
|
387
|
+
component: Inline,
|
|
388
|
+
options: ['left', 'center', 'right'],
|
|
291
389
|
},
|
|
292
390
|
colorPicker: {
|
|
293
|
-
component: ColorPicker
|
|
294
|
-
|
|
391
|
+
component: ColorPicker,
|
|
392
|
+
icon: this.props.colorIcon,
|
|
393
|
+
},
|
|
394
|
+
image: {
|
|
395
|
+
component: Image,
|
|
396
|
+
inputAccept: 'image/gif,image/jpeg,image/jpg,image/png,image/svg',
|
|
397
|
+
alt: { present: false, mandatory: false },
|
|
398
|
+
previewImage: true,
|
|
399
|
+
icon: this.props.imageIcon,
|
|
400
|
+
},
|
|
295
401
|
};
|
|
296
402
|
return (
|
|
297
403
|
<div className={classnames('form-group', !this.props.labelTop && 'row')}>
|
|
@@ -309,8 +415,9 @@ export default class InputTextarea extends Component {
|
|
|
309
415
|
<Editor
|
|
310
416
|
toolbarHidden={!toolbar}
|
|
311
417
|
toolbar={editorToolbar}
|
|
418
|
+
toolbarCustomButtons={MailmergeOptions(this.props)}
|
|
312
419
|
editorState={editorState}
|
|
313
|
-
wrapperClassName="form-control border-
|
|
420
|
+
wrapperClassName="form-control border-ui h-auto"
|
|
314
421
|
onEditorStateChange={this.onEditorStateChange}
|
|
315
422
|
onBlur={this.onChange}
|
|
316
423
|
/>
|
|
@@ -318,7 +425,7 @@ export default class InputTextarea extends Component {
|
|
|
318
425
|
<button
|
|
319
426
|
type="button"
|
|
320
427
|
className={classnames(
|
|
321
|
-
'btn btn-input btn-outline-
|
|
428
|
+
'btn btn-input btn-outline-ui bg-light',
|
|
322
429
|
this.props.size === 'sm' && `btn-${this.props.size}`
|
|
323
430
|
)}
|
|
324
431
|
onClick={this.onToolbar}
|
|
@@ -328,7 +435,7 @@ export default class InputTextarea extends Component {
|
|
|
328
435
|
<button
|
|
329
436
|
type="button"
|
|
330
437
|
className={classnames(
|
|
331
|
-
'btn btn-input btn-outline-
|
|
438
|
+
'btn btn-input btn-outline-ui bg-light',
|
|
332
439
|
this.props.size === 'sm' && `btn-${this.props.size}`
|
|
333
440
|
)}
|
|
334
441
|
onClick={this.onClear}
|
|
@@ -3,10 +3,21 @@
|
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
.rdw-editor-toolbar {
|
|
6
|
-
padding:
|
|
7
|
-
border:
|
|
6
|
+
padding: 0px;
|
|
7
|
+
border: 0px solid theme-color('secondary-light') !important;
|
|
8
|
+
|
|
9
|
+
.advanced-dropdown-wrapper {
|
|
10
|
+
margin-left: 5px;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
button {
|
|
14
|
+
height: 100%;
|
|
15
|
+
}
|
|
8
16
|
}
|
|
9
17
|
|
|
10
18
|
.rbf-mailmerge {
|
|
11
19
|
color: #105a1c;
|
|
20
|
+
}
|
|
21
|
+
.DraftEditor-root {
|
|
22
|
+
overflow: hidden;
|
|
12
23
|
}
|