Skip to content

Commit b3dc1ba

Browse files
authored
Added textarea widget (#442)
* Add maxLength for text widget * Add missing support of disabled list items in AntD * defaultTextWidth, defaultSliderWidth * . * Flex used to fullWidth * fix css * fullWidth (for textarea) * . * removed defaultTextWidth * Added textarea widget, with maxRows option * doc * 4.2.0
1 parent d7b572f commit b3dc1ba

28 files changed

+278
-34
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# Changelog
2+
- 4.2.0
3+
- Added `textarea` widget
24
- 4.1.1
35
- Fix warning about showSearch in MUI theme
46
- Fix incorrect override of vanilla button label (issue #347)

CONFIG.adoc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ const {
9595
},
9696
widgets: {
9797
text,
98+
textarea,
9899
number,
99100
slider,
100101
rangeslider, // missing in `BasicConfig`
@@ -186,7 +187,8 @@ Example:
186187
|tooltip | | |Optional tooltip to be displayed in field list by hovering on item
187188
|fieldSettings | | |Settings for widgets, will be passed as props. Example: `{min: 1, max: 10}` +
188189
Available settings for Number and Slider widgets: `min`, `max`, `step`. Slider also supports `marks` (example: `{ 0: "0%", 100: "100%" }`). +
189-
Available settings for date/time widgets: `timeFormat`, `dateFormat`, `valueFormat`, `use12Hours`, `useKeyboard`.
190+
Available settings for date/time widgets: `timeFormat`, `dateFormat`, `valueFormat`, `use12Hours`, `useKeyboard`. +
191+
Available settings for text widget: `maxLength`, `maxRows`.
190192
|fieldSettings.listValues |+ for (multi)select, tree (multi)select | |List of values for (multi)select widget. +
191193
Example for select/multiselect: `[{value: 'yellow', title: 'Yellow'}, {value: 'green', title: 'Green'}]`
192194
(or alternatively `{ yellow: 'Yellow', green: 'Green' }`) +
@@ -329,6 +331,7 @@ Render settings:
329331
|renderAfterWidget| |
330332
|renderBeforeActions| |
331333
|renderAfterActions| |
334+
|defaultSliderWidth|"200px" |Width for slider
332335
|===
333336

334337
Other settings:
@@ -552,6 +555,8 @@ const {
552555
`(mixed val, Object fieldDef, Object wgtDef, string op, Object opDef) => any`
553556
|valueLabel | |`config.settings.valueLabel` |Common option, text to be placed on top of widget if `config.settings.showLabels` is true
554557
|valuePlaceholder | |`config.settings.valuePlaceholder` |Common option, placeholder text to be shown in widget for empty value
558+
|maxLength | | |Option for `<TextWidget>`, `<TextAreaWidget>`
559+
|maxRows | | |Option for `<TextAreaWidget>`
555560
|timeFormat | |`HH:mm:ss` |Option for `<TimeWidget>`, `<DateTimeWidget>` to display time in widget. Example: `'HH:mm'`
556561
|use12Hours | |`false` |Option for `<TimeWidget>`
557562
|useKeyboard | |`true` |Option for Material-UI date/time pickers, `false` disables input with keyboard, only picker use is allowed
@@ -609,7 +614,7 @@ To enable this feature set `valueSources` of type to `['value', 'func']` (see be
609614
|valueSources | |keys of `valueSourcesInfo` at link:#configsettings[config.settings] |Array with values `'value'`, `'field'`, `'func'`. If `'value'` is included, you can compare field with values. If `'field'` is included, you can compare field with another field of same type. If `'func'` is included, you can compare field with result of function (see link:#configfuncs[config.funcs]).
610615
|defaultOperator | | |If specified, it will be auto selected when user selects field
611616
|widgets.* |+ | |Available widgets for current type and their config. +
612-
Normally there is only 1 widget per type. But see type `number` at https://github.com/ukrbublik/react-awesome-query-builder/tree/master/examples/demo/config.tsx[`examples/demo`] - it has 3 widhets `number`, `slider`, `rangeslider`. +
617+
Normally there is only 1 widget per type. But see type `number` at https://github.com/ukrbublik/react-awesome-query-builder/tree/master/examples/demo/config.tsx[`examples/demo`] - it has 3 widgets `number`, `slider`, `rangeslider`. +
613618
Or see type `select` - it has widget `select` for operator `=` and widget `multiselect` for operator `IN`.
614619
|widgets.<widget>.operators | | |List of operators for widget, described in link:#configoperators[config.operators]
615620
|widgets.<widget>.widgetProps | | |Can be used to override config of corresponding widget specified in link:#configwidgets[config.widgets]. Example: `{timeFormat: 'h:mm:ss A'}` for time field with AM/PM.

css/styles.scss

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ ul.ant-select-selection__rendered {
351351
margin-left: auto;
352352
display: flex;
353353
align-items: center;
354+
padding-left: 10px;
354355
}
355356

356357
.rule--drag-handler {
@@ -607,3 +608,35 @@ $rule_actions: ".widget--valuesrc", ".rule--drag-handler", ".rule--header";
607608
margin-top: 10px;
608609
margin-bottom: 10px;
609610
}
611+
612+
613+
/******************************************************************************/
614+
/** Shrink textarea ***********************************************************/
615+
/******************************************************************************/
616+
617+
.rule--body.can--shrink--value {
618+
display: flex;
619+
align-items: center;
620+
.rule--value {
621+
flex: 1;
622+
}
623+
.rule--value > .rule--widget {
624+
display: flex;
625+
.widget--widget {
626+
flex: 1;
627+
}
628+
}
629+
.rule--value > .rule--widget > .widget--valuesrc {
630+
display: flex;
631+
align-items: center;
632+
}
633+
}
634+
635+
.rule--value > .rule--widget > .widget--valuesrc {
636+
.anticon {
637+
height: 100%;
638+
svg {
639+
height: 100%;
640+
}
641+
}
642+
}

examples/demo/config.tsx

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -79,19 +79,17 @@ export default (skin: string) => {
7979
...InitialConfig.widgets,
8080
// examples of overriding
8181
text: {
82-
...InitialConfig.widgets.text,
82+
...InitialConfig.widgets.text
83+
},
84+
textarea: {
85+
...InitialConfig.widgets.textarea,
86+
maxRows: 3
8387
},
8488
slider: {
85-
...InitialConfig.widgets.slider,
86-
customProps: {
87-
width: "300px"
88-
}
89+
...InitialConfig.widgets.slider
8990
},
9091
rangeslider: {
91-
...InitialConfig.widgets.rangeslider,
92-
customProps: {
93-
width: "300px"
94-
},
92+
...InitialConfig.widgets.rangeslider
9593
},
9694
date: {
9795
...InitialConfig.widgets.date,
@@ -185,6 +183,8 @@ export default (skin: string) => {
185183
...InitialConfig.settings,
186184
...localeSettings,
187185

186+
defaultSliderWidth: "200px",
187+
188188
valueSourcesInfo: {
189189
value: {
190190
label: "Value"
@@ -249,6 +249,14 @@ export default (skin: string) => {
249249
}
250250
}
251251
},
252+
bio: {
253+
label: "Bio",
254+
type: "text",
255+
preferWidgets: ["textarea"],
256+
fieldSettings: {
257+
maxLength: 1000,
258+
}
259+
},
252260
results: {
253261
label: "Results",
254262
type: "!group",

examples/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,5 @@
1212
"dependencies": {
1313
"react-awesome-query-builder": "file:.."
1414
},
15-
"devDependencies": {
16-
}
15+
"devDependencies": {}
1716
}

modules/components/item/Rule.jsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {getFieldConfig, getOperatorConfig, getFieldWidgetConfig} from "../../uti
1010
import {getFieldPathLabels} from "../../utils/ruleUtils";
1111
import {useOnPropsChanged} from "../../utils/reactUtils";
1212
import {Col, DragIcon, dummyFn, ConfirmFn} from "../utils";
13+
const classNames = require("classnames");
1314

1415

1516
@RuleContainer
@@ -248,6 +249,10 @@ class Rule extends PureComponent {
248249
}
249250

250251
render () {
252+
const { showOperatorOptions, selectedFieldWidgetConfig } = this.meta;
253+
const { valueSrc, value } = this.props;
254+
const canShrinkValue = valueSrc.first() == 'value' && !showOperatorOptions && value.size == 1 && selectedFieldWidgetConfig.fullWidth;
255+
251256
const parts = [
252257
this.renderField(),
253258
this.renderOperator(),
@@ -256,12 +261,12 @@ class Rule extends PureComponent {
256261
this.renderAfterWidget(),
257262
this.renderOperatorOptions(),
258263
];
259-
const body = <div key="rule-body" className="rule--body">{parts}</div>;
264+
const body = <div key="rule-body" className={classNames("rule--body", canShrinkValue && "can--shrink--value")}>{parts}</div>;
260265

261266
const error = this.renderError();
262267
const drag = this.renderDrag();
263268
const del = this.renderDel();
264-
269+
265270
return (
266271
<>
267272
{drag}

modules/components/widgets/antd/core/FieldDropdown.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export default class FieldDropdown extends PureComponent {
3232
renderMenuItems(fields) {
3333
return keys(fields).map(fieldKey => {
3434
const field = fields[fieldKey];
35-
const {items, key, path, label, fullLabel, altLabel, tooltip} = field;
35+
const {items, key, path, label, fullLabel, altLabel, tooltip, disabled} = field;
3636
const pathKey = path || key;
3737
const option = tooltip ? <Tooltip title={tooltip}>{label}</Tooltip> : label;
3838

@@ -46,6 +46,7 @@ export default class FieldDropdown extends PureComponent {
4646
} else {
4747
return <MenuItem
4848
key={pathKey}
49+
disabled={disabled}
4950
>
5051
{option}
5152
</MenuItem>;

modules/components/widgets/antd/core/FieldSelect.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export default class FieldSelect extends PureComponent {
8181
renderSelectItems(fields) {
8282
return keys(fields).map(fieldKey => {
8383
const field = fields[fieldKey];
84-
const {items, key, path, label, fullLabel, altLabel, tooltip, grouplabel} = field;
84+
const {items, key, path, label, fullLabel, altLabel, tooltip, grouplabel, disabled} = field;
8585
const pathKey = path || key;
8686
if (items) {
8787
return <OptGroup
@@ -98,6 +98,7 @@ export default class FieldSelect extends PureComponent {
9898
title={altLabel}
9999
grouplabel={grouplabel}
100100
label={label}
101+
disabled={disabled}
101102
>
102103
{option}
103104
</Option>;

modules/components/widgets/antd/core/FieldTreeSelect.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export default class FieldTreeSelect extends PureComponent {
4848
getTreeData(fields, fn = null) {
4949
return keys(fields).map(fieldKey => {
5050
const field = fields[fieldKey];
51-
const {items, key, path, label, fullLabel, altLabel, tooltip} = field;
51+
const {items, key, path, label, fullLabel, altLabel, tooltip, disabled} = field;
5252
if (fn)
5353
fn(field);
5454
const pathKey = path || key;
@@ -63,6 +63,7 @@ export default class FieldTreeSelect extends PureComponent {
6363
altLabel: altLabel,
6464
fullLabel: fullLabel,
6565
label: label,
66+
disabled: disabled,
6667
};
6768
} else {
6869
return {
@@ -71,6 +72,7 @@ export default class FieldTreeSelect extends PureComponent {
7172
altLabel: altLabel,
7273
fullLabel: fullLabel,
7374
label: label,
75+
disabled: disabled,
7476
};
7577
}
7678
});

modules/components/widgets/antd/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import DateTimeWidget from "./value/DateTime";
66
import TimeWidget from "./value/Time";
77
import SelectWidget from "./value/Select";
88
import TextWidget from "./value/Text";
9+
import TextAreaWidget from "./value/TextArea";
910
import NumberWidget from "./value/Number";
1011
import SliderWidget from "./value/Slider";
1112
import RangeWidget from "./value/Range";
@@ -35,6 +36,7 @@ export default {
3536
TimeWidget,
3637
SelectWidget,
3738
TextWidget,
39+
TextAreaWidget,
3840
NumberWidget,
3941
SliderWidget,
4042
RangeWidget,

modules/components/widgets/antd/value/Range.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export default class RangeWidget extends PureComponent {
7777

7878
render() {
7979
const {config, placeholders, customProps, value, min, max, step, marks, textSeparators, readonly} = this.props;
80-
const {renderSize} = config.settings;
80+
const {renderSize, defaultSliderWidth} = config.settings;
8181
const {width, ...rest} = customProps || {};
8282
const customInputProps = rest.input || {};
8383
const customSliderProps = rest.slider || rest;
@@ -117,7 +117,7 @@ export default class RangeWidget extends PureComponent {
117117
{...customInputProps}
118118
/>
119119
</Col>
120-
<Col style={{float: "left", width: width || "300px"}}>
120+
<Col style={{float: "left", width: width || defaultSliderWidth}}>
121121
<Slider
122122
disabled={readonly}
123123
value={aValue}

modules/components/widgets/antd/value/Slider.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export default class SliderWidget extends PureComponent {
6161

6262
render() {
6363
const {config, placeholder, customProps, value, min, max, step, marks, readonly, valueError} = this.props;
64-
const {renderSize, showErrorMessage} = config.settings;
64+
const {renderSize, showErrorMessage, defaultSliderWidth} = config.settings;
6565
const {width, ...rest} = customProps || {};
6666
const customInputProps = rest.input || {};
6767
const customSliderProps = rest.slider || rest;
@@ -87,7 +87,7 @@ export default class SliderWidget extends PureComponent {
8787
{...customInputProps}
8888
/>
8989
</Col>
90-
<Col style={{float: "left", width: width || "300px"}}>
90+
<Col style={{float: "left", width: width || defaultSliderWidth}}>
9191
<Slider
9292
disabled={readonly}
9393
value={sliderValue}

modules/components/widgets/antd/value/Text.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export default class TextWidget extends PureComponent {
1111
field: PropTypes.string.isRequired,
1212
readonly: PropTypes.bool,
1313
customProps: PropTypes.object,
14+
maxLength: PropTypes.number,
1415
};
1516

1617
handleChange = (ev) => {
@@ -20,7 +21,7 @@ export default class TextWidget extends PureComponent {
2021
}
2122

2223
render() {
23-
const {config, placeholder, customProps, value, readonly} = this.props;
24+
const {config, placeholder, customProps, value, readonly, maxLength} = this.props;
2425
const {renderSize} = config.settings;
2526
const aValue = value != undefined ? value : null;
2627

@@ -33,6 +34,7 @@ export default class TextWidget extends PureComponent {
3334
type={"text"}
3435
value={aValue}
3536
placeholder={placeholder}
37+
maxLength={maxLength}
3638
onChange={this.handleChange}
3739
{...customProps}
3840
/>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React, { PureComponent } from "react";
2+
import PropTypes from "prop-types";
3+
import { Input, Col } from "antd";
4+
const { TextArea } = Input;
5+
const defaultMaxRows = 5;
6+
7+
export default class TextAreaWidget extends PureComponent {
8+
static propTypes = {
9+
setValue: PropTypes.func.isRequired,
10+
placeholder: PropTypes.string,
11+
config: PropTypes.object.isRequired,
12+
value: PropTypes.string,
13+
field: PropTypes.string.isRequired,
14+
readonly: PropTypes.bool,
15+
customProps: PropTypes.object,
16+
maxLength: PropTypes.number,
17+
maxRows: PropTypes.number,
18+
};
19+
20+
handleChange = (ev) => {
21+
const v = ev.target.value;
22+
const val = v === "" ? undefined : v; // don't allow empty value
23+
this.props.setValue(val);
24+
}
25+
26+
render() {
27+
const {config, placeholder, customProps, value, readonly, maxLength, maxRows, fullWidth} = this.props;
28+
const {renderSize} = config.settings;
29+
const aValue = value != undefined ? value : null;
30+
31+
return (
32+
<Col>
33+
<TextArea
34+
autoSize={{minRows: 1, maxRows: maxRows || defaultMaxRows}}
35+
maxLength={maxLength}
36+
disabled={readonly}
37+
key="widget-textarea"
38+
size={renderSize}
39+
value={aValue}
40+
placeholder={placeholder}
41+
onChange={this.handleChange}
42+
{...customProps}
43+
/>
44+
</Col>
45+
);
46+
}
47+
}

modules/components/widgets/material/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import MomentUtils from "@date-io/moment";
77

88
// value widgets
99
import MaterialTextWidget from "./value/MaterialText";
10+
import MaterialTextAreaWidget from "./value/MaterialTextArea";
1011
import MaterialDateWidget from "./value/MaterialDate";
1112
import MaterialDateTimeWidget from "./value/MaterialDateTime";
1213
import MaterialTimeWidget from "./value/MaterialTime";
@@ -56,6 +57,7 @@ const MaterialProvider = ({config, children}) => {
5657

5758
export default {
5859
MaterialTextWidget,
60+
MaterialTextAreaWidget,
5961
MaterialDateWidget,
6062
MaterialDateTimeWidget,
6163
MaterialTimeWidget,

0 commit comments

Comments
 (0)