Skip to content

Commit aaeb0b3

Browse files
committed
v1.18.0
1 parent 3f82805 commit aaeb0b3

File tree

19 files changed

+549
-46
lines changed

19 files changed

+549
-46
lines changed

components/Html/index.tsx

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ import InputLabel from '@material-ui/core/InputLabel';
22
import Typography from '@material-ui/core/Typography';
33
import FieldCoreBase, { IStateFieldBase } from '@react-form-fields/core/components/FieldCoreBase';
44
import ValidationContextRegister from '@react-form-fields/core/components/ValidationContextRegister';
5-
import { getConfig } from '@react-form-fields/core/config';
65
import * as React from 'react';
76

7+
import { getConfig } from '../../config';
88
import { WithStyles } from '../../decorators/withStyles';
99
import { IBaseFieldProps } from '../../interfaces/props';
10+
import * as styles from './style.css';
1011

1112
interface IState extends IStateFieldBase {
1213
focused: boolean;
@@ -31,16 +32,75 @@ interface IProps extends IBaseFieldProps {
3132
}
3233
}))
3334
export default class FieldHtml extends FieldCoreBase<IProps, IState> {
35+
dependenciesLoaded: Promise<string>;
36+
instance: any;
37+
textareaRef = React.createRef<HTMLTextAreaElement>();
3438

35-
onChange = (value: any) => {
39+
constructor(props: IProps) {
40+
super(props);
41+
this.dependenciesLoaded = this.loadDependencies();
42+
}
43+
44+
loadDependencies = async () => {
45+
if (!window.jQuery) {
46+
window.jQuery = window.$ = await import('jquery') as any;
47+
}
48+
49+
const { loadLocale, loadPlugins } = getConfig().trumbowyg;
50+
const [svgPath] = await Promise.all([
51+
import('trumbowyg/dist/ui/icons.svg'),
52+
import('trumbowyg/dist/trumbowyg.min.js'),
53+
import('trumbowyg/dist/ui/trumbowyg.min.css'),
54+
]);
55+
56+
await Promise.all([
57+
import('trumbowyg/dist/plugins/history/trumbowyg.history.min.js'),
58+
import('trumbowyg/dist/plugins/cleanpaste/trumbowyg.cleanpaste.min.js'),
59+
loadLocale ? loadLocale() : Promise.resolve(),
60+
...(loadPlugins ? loadPlugins() : []),
61+
]);
62+
63+
return svgPath;
64+
}
65+
66+
async componentDidMount() {
67+
const svgPath = await this.dependenciesLoaded;
68+
this.instance = window.jQuery(this.textareaRef.current);
69+
70+
this.instance.trumbowyg({
71+
svgPath,
72+
useComposition: false,
73+
autogrow: true,
74+
...getConfig().trumbowyg.config
75+
}).on('tbwfocus', () => {
76+
this.onFocus();
77+
}).on('tbwchange', () => {
78+
this.onChange(this.instance.trumbowyg('html'));
79+
}).on('tbwblur', () => {
80+
this.onBlur(this.instance.trumbowyg('html'));
81+
});
82+
83+
this.instance.trumbowyg('html', this.props.value);
84+
}
85+
86+
componentDidUpdate() {
87+
this.instance.trumbowyg(this.props.disabled ? 'disable' : 'enable');
88+
89+
if (this.instance.trumbowyg('html') !== this.props.value) {
90+
this.instance.trumbowyg('html', this.props.value);
91+
}
92+
}
93+
94+
onChange = (value: string) => {
3695
getConfig().validationOn === 'onChange' && this.setState({ showError: true });
3796
this.props.onChange(value);
3897
}
3998

40-
onBlur = (e: React.SyntheticEvent) => {
99+
onBlur = (value: string) => {
41100
getConfig().validationOn === 'onBlur' && this.setState({ showError: true });
42101
this.setState({ focused: false });
43-
this.props.onBlur && this.props.onBlur(e);
102+
this.props.onChange(value);
103+
this.props.onBlur && this.props.onBlur(null);
44104
}
45105

46106
onFocus = () => {
@@ -49,11 +109,10 @@ export default class FieldHtml extends FieldCoreBase<IProps, IState> {
49109

50110
render() {
51111
const { focused } = this.state;
52-
const { classes, label, helperText } = this.props;
53-
/* disabled, onChange, onBlur, placeholder */
112+
const { classes, label, helperText, placeholder, disabled } = this.props;
54113

55114
return (
56-
<div>
115+
<div className={styles.component}>
57116

58117
<ValidationContextRegister field={this} />
59118

@@ -67,6 +126,8 @@ export default class FieldHtml extends FieldCoreBase<IProps, IState> {
67126
}
68127
</div>
69128

129+
<textarea ref={this.textareaRef} placeholder={placeholder} disabled={disabled} />
130+
70131
</div>
71132
);
72133
}

components/Html/style.css

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
11
:local(.component) {
22
margin: 16px 0 8px 0;
3+
}
4+
5+
:local(.component) .trumbowyg-box {
6+
margin: 0;
7+
font-family: "Roboto", sans-serif;
8+
}
9+
10+
:local(.component)>textarea {
11+
visibility: hidden;
12+
display: block;
13+
width: 100%;
14+
height: 250px;
315
}

config/builder.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,37 @@ export default class ConfigBuilder extends CoreConfigBuilder {
1313
return this;
1414
}
1515

16-
public setEditorConfig(locale: string, toolbar?: object) {
16+
public setTrumbowygLocale(loadLocale: IConfig['trumbowyg']['loadLocale']) {
17+
const currentConfig = this.config.trumbowyg || {};
1718
this.config = {
1819
...this.config,
19-
editorLocale: locale,
20-
editorToolbar: toolbar || this.config.editorToolbar
20+
trumbowyg: { ...currentConfig, loadLocale }
21+
};
22+
23+
return this;
24+
}
25+
26+
public setTrumbowygPlugins(loadPlugins: IConfig['trumbowyg']['loadPlugins']) {
27+
const currentConfig = this.config.trumbowyg || {};
28+
this.config = {
29+
...this.config,
30+
trumbowyg: { ...currentConfig, loadPlugins }
31+
};
32+
33+
return this;
34+
}
35+
36+
public setTrumbowygConfig(config: IConfig['trumbowyg']['config'], resetConfig: boolean = false) {
37+
const currentConfig = this.config.trumbowyg || {};
38+
this.config = {
39+
...this.config,
40+
trumbowyg: {
41+
...currentConfig,
42+
config: {
43+
...(resetConfig ? {} : (currentConfig.config || {})),
44+
...config
45+
}
46+
}
2147
};
2248

2349
return this;

config/index.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ declare module '@react-form-fields/core/config' {
99
ok: string;
1010
cancel: string
1111
};
12-
editorLocale?: string;
13-
editorToolbar?: object;
12+
trumbowyg?: {
13+
loadLocale?: () => Promise<any>;
14+
loadPlugins?: () => Promise<any>[];
15+
config?: any;
16+
};
1417
validationOn?: 'onChange' | 'onBlur' | 'onSubmit';
1518
}
1619
}
@@ -22,6 +25,11 @@ const defaultConfig: coreConfig.IConfig = {
2225
clear: 'Clear',
2326
ok: 'Ok',
2427
cancel: 'Cancel'
28+
},
29+
trumbowyg: {
30+
loadLocale: () => Promise.resolve(),
31+
loadPlugins: () => [],
32+
config: {}
2533
}
2634
};
2735

declarations/extra.d.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,5 @@ declare module '@material-ui/icons/Search';
44
declare module '@material-ui/icons/Close';
55
declare module '@material-ui/icons/ChevronLeft';
66
declare module '@material-ui/icons/ChevronRight';
7-
declare module 'draftjs-to-html';
8-
declare module 'html-to-draftjs';
9-
declare module 'draft-js-import-html';
7+
declare module 'trumbowyg*';
108
declare module '*.css';

declarations/global.d.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
interface Window extends EventTarget, WindowTimers, WindowSessionStorage, WindowLocalStorage, WindowConsole, GlobalEventHandlers, IDBEnvironment, WindowBase64, GlobalFetch, WindowOrWorkerGlobalScope, WindowEventHandlers {
2+
jQuery?: JQueryStatic;
3+
$?: JQueryStatic;
4+
}
5+
6+
interface JQuery<HTMLTextAreaElement> {
7+
trumbowyg?: any;
8+
}

docs/project/src/components/Form.tsx renamed to docs/project/src/components/Pages/Dev/Form.tsx

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,18 @@ export default class Form extends PureComponent<{}, IState> {
8383

8484
<Card style={{ overflow: 'visible' }}>
8585
<CardContent>
86+
<FieldHtml
87+
label='HTML'
88+
name='html'
89+
placeholder='Your content'
90+
value={model.html}
91+
validation='required'
92+
disabled={model.spam}
93+
onChange={(v => this.setState({ model: { ...model, html: v } }))}
94+
/>
95+
96+
<p>{model.html}</p>
97+
8698
<FieldText
8799
label='Name'
88100
name='name'
@@ -207,7 +219,7 @@ export default class Form extends PureComponent<{}, IState> {
207219
</CardContent>
208220
<Divider />
209221
<CardContent>
210-
<Typography variant='subheading'>Complex Components</Typography>
222+
<Typography variant='subtitle1'>Complex Components</Typography>
211223

212224
<Grid container spacing={24}>
213225
<Grid item xs={12} sm={6}>
@@ -261,15 +273,6 @@ export default class Form extends PureComponent<{}, IState> {
261273
onChange={(v => this.setState({ model: { ...model, autocompleteId2: v } }))}
262274
/>
263275

264-
<FieldHtml
265-
label='HTML'
266-
name='html'
267-
placeholder='Your content'
268-
value={model.html}
269-
validation='required'
270-
onChange={(v => this.setState({ model: { ...model, html: v } }))}
271-
/>
272-
273276
</CardContent>
274277

275278
<CardActions style={{ justifyContent: 'flex-end' }}>
@@ -291,4 +294,5 @@ export default class Form extends PureComponent<{}, IState> {
291294
</FormValidation>
292295
);
293296
}
297+
// tslint:disable-next-line:max-file-line-count
294298
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import Toolbar from 'components/Layout/Toolbar';
2+
import React, { Fragment, PureComponent } from 'react';
3+
4+
import Form from './Form';
5+
6+
export default class DevPage extends PureComponent {
7+
render() {
8+
return (
9+
<Fragment>
10+
<Toolbar title='Dev Page' />
11+
12+
<Form />
13+
</Fragment>
14+
);
15+
}
16+
}

0 commit comments

Comments
 (0)