Skip to content

Commit 40fc2fd

Browse files
mauriciominellan1k0
authored andcommitted
Onfocus support (rjsf-team#657)
1 parent 9d79b71 commit 40fc2fd

File tree

15 files changed

+136
-0
lines changed

15 files changed

+136
-0
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,10 @@ If you plan on being notified everytime the form data are updated, you can pass
213213

214214
Sometimes you may want to trigger events or modify external state when a field has been touched, so you can pass an `onBlur` handler, which will receive the id of the input that was blurred and the field value.
215215

216+
#### Form field focus events
217+
218+
Sometimes you may want to trigger events or modify external state when a field has been focused, so you can pass an `onFocus` handler, which will receive the id of the input that is focused and the field value.
219+
216220
## Form customization
217221

218222
### The `uiSchema` object
@@ -954,6 +958,7 @@ The following props are passed to custom widget components:
954958
- `readonly`: `true` if the widget is read-only;
955959
- `onChange`: The value change event handler; call it with the new value everytime it changes;
956960
- `onBlur`: The input blur event handler; call it with the the widget id and value;
961+
- `onFocus`: The input focus event handler; call it with the the widget id and value;
957962
- `options`: A map of options passed as a prop to the component (see [Custom widget options](#custom-widget-options)).
958963
- `formContext`: The `formContext` object that you passed to Form.
959964

playground/app.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,8 @@ class App extends Component {
477477
validate={validate}
478478
onBlur={(id, value) =>
479479
console.log(`Touched ${id} with value ${value}`)}
480+
onFocus={(id, value) =>
481+
console.log(`Focused ${id} with value ${value}`)}
480482
transformErrors={transformErrors}
481483
onError={log("errors")}>
482484
<div className="row">

src/components/Form.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ export default class Form extends Component {
115115
}
116116
};
117117

118+
onFocus = (...args) => {
119+
if (this.props.onFocus) {
120+
this.props.onFocus(...args);
121+
}
122+
};
123+
118124
onSubmit = event => {
119125
event.preventDefault();
120126
this.setState({ status: "submitted" });
@@ -195,6 +201,7 @@ export default class Form extends Component {
195201
formData={formData}
196202
onChange={this.onChange}
197203
onBlur={this.onBlur}
204+
onFocus={this.onFocus}
198205
registry={registry}
199206
safeRenderCompletion={safeRenderCompletion}
200207
/>

src/components/fields/ArrayField.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ class ArrayField extends Component {
304304
registry = getDefaultRegistry(),
305305
formContext,
306306
onBlur,
307+
onFocus,
307308
} = this.props;
308309
const title = schema.title === undefined ? name : schema.title;
309310
const { ArrayFieldTemplate, definitions, fields } = registry;
@@ -326,6 +327,7 @@ class ArrayField extends Component {
326327
itemUiSchema: uiSchema.items,
327328
autofocus: autofocus && index === 0,
328329
onBlur,
330+
onFocus,
329331
});
330332
}),
331333
className: `field field-array field-array-of-${itemsSchema.type}`,
@@ -357,6 +359,7 @@ class ArrayField extends Component {
357359
readonly,
358360
autofocus,
359361
onBlur,
362+
onFocus,
360363
registry = getDefaultRegistry(),
361364
} = this.props;
362365
const items = this.props.formData;
@@ -374,6 +377,7 @@ class ArrayField extends Component {
374377
multiple
375378
onChange={this.onSelectChange}
376379
onBlur={onBlur}
380+
onFocus={onFocus}
377381
options={options}
378382
schema={schema}
379383
value={items}
@@ -395,6 +399,7 @@ class ArrayField extends Component {
395399
readonly,
396400
autofocus,
397401
onBlur,
402+
onFocus,
398403
registry = getDefaultRegistry(),
399404
} = this.props;
400405
const title = schema.title || name;
@@ -409,6 +414,7 @@ class ArrayField extends Component {
409414
multiple
410415
onChange={this.onSelectChange}
411416
onBlur={onBlur}
417+
onFocus={onFocus}
412418
schema={schema}
413419
title={title}
414420
value={items}
@@ -433,6 +439,7 @@ class ArrayField extends Component {
433439
autofocus,
434440
registry = getDefaultRegistry(),
435441
onBlur,
442+
onFocus,
436443
} = this.props;
437444
const title = schema.title || name;
438445
let items = this.props.formData;
@@ -481,6 +488,7 @@ class ArrayField extends Component {
481488
itemErrorSchema,
482489
autofocus: autofocus && index === 0,
483490
onBlur,
491+
onFocus,
484492
});
485493
}),
486494
onAddClick: this.onAddClick,
@@ -510,6 +518,7 @@ class ArrayField extends Component {
510518
itemErrorSchema,
511519
autofocus,
512520
onBlur,
521+
onFocus,
513522
} = props;
514523
const {
515524
disabled,
@@ -541,6 +550,7 @@ class ArrayField extends Component {
541550
required={this.isItemRequired(itemSchema)}
542551
onChange={this.onChangeForIndex(index)}
543552
onBlur={onBlur}
553+
onFocus={onFocus}
544554
registry={this.props.registry}
545555
disabled={this.props.disabled}
546556
readonly={this.props.readonly}
@@ -592,6 +602,7 @@ if (process.env.NODE_ENV !== "production") {
592602
errorSchema: PropTypes.object,
593603
onChange: PropTypes.func.isRequired,
594604
onBlur: PropTypes.func,
605+
onFocus: PropTypes.func,
595606
formData: PropTypes.array,
596607
required: PropTypes.bool,
597608
disabled: PropTypes.bool,

src/components/fields/ObjectField.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class ObjectField extends Component {
4343
disabled,
4444
readonly,
4545
onBlur,
46+
onFocus,
4647
registry = getDefaultRegistry(),
4748
} = this.props;
4849
const { definitions, fields, formContext } = registry;
@@ -94,6 +95,7 @@ class ObjectField extends Component {
9495
formData={formData[name]}
9596
onChange={this.onPropertyChange(name)}
9697
onBlur={onBlur}
98+
onFocus={onFocus}
9799
registry={registry}
98100
disabled={disabled}
99101
readonly={readonly}

src/components/fields/StringField.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ function StringField(props) {
2222
autofocus,
2323
onChange,
2424
onBlur,
25+
onFocus,
2526
registry = getDefaultRegistry(),
2627
} = props;
2728
const { title, format } = schema;
@@ -42,6 +43,7 @@ function StringField(props) {
4243
value={formData}
4344
onChange={onChange}
4445
onBlur={onBlur}
46+
onFocus={onFocus}
4547
required={required}
4648
disabled={disabled}
4749
readonly={readonly}
@@ -60,6 +62,7 @@ if (process.env.NODE_ENV !== "production") {
6062
idSchema: PropTypes.object,
6163
onChange: PropTypes.func.isRequired,
6264
onBlur: PropTypes.func,
65+
onFocus: PropTypes.func,
6366
formData: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
6467
registry: PropTypes.shape({
6568
widgets: PropTypes.objectOf(

src/components/widgets/BaseInput.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ function BaseInput(props) {
1010
disabled,
1111
autofocus,
1212
onBlur,
13+
onFocus,
1314
options,
1415
schema,
1516
formContext,
@@ -31,6 +32,7 @@ function BaseInput(props) {
3132
{...inputProps}
3233
onChange={_onChange}
3334
onBlur={onBlur && (event => onBlur(inputProps.id, event.target.value))}
35+
onFocus={onFocus && (event => onFocus(inputProps.id, event.target.value))}
3436
/>
3537
);
3638
}
@@ -54,6 +56,7 @@ if (process.env.NODE_ENV !== "production") {
5456
autofocus: PropTypes.bool,
5557
onChange: PropTypes.func,
5658
onBlur: PropTypes.func,
59+
onFocus: PropTypes.func,
5760
};
5861
}
5962

src/components/widgets/SelectWidget.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ function SelectWidget(props) {
4848
autofocus,
4949
onChange,
5050
onBlur,
51+
onFocus,
5152
placeholder,
5253
} = props;
5354
const { enumOptions } = options;
@@ -68,6 +69,13 @@ function SelectWidget(props) {
6869
onBlur(id, processValue(schema, newValue));
6970
})
7071
}
72+
onFocus={
73+
onFocus &&
74+
(event => {
75+
const newValue = getValue(event, multiple);
76+
onFocus(id, processValue(schema, newValue));
77+
})
78+
}
7179
onChange={event => {
7280
const newValue = getValue(event, multiple);
7381
onChange(processValue(schema, newValue));
@@ -107,6 +115,7 @@ if (process.env.NODE_ENV !== "production") {
107115
autofocus: PropTypes.bool,
108116
onChange: PropTypes.func,
109117
onBlur: PropTypes.func,
118+
onFocus: PropTypes.func,
110119
};
111120
}
112121

src/components/widgets/TextareaWidget.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ function TextareaWidget(props) {
1313
autofocus,
1414
onChange,
1515
onBlur,
16+
onFocus,
1617
} = props;
1718
const _onChange = ({ target: { value } }) => {
1819
return onChange(value === "" ? options.emptyValue : value);
@@ -29,6 +30,7 @@ function TextareaWidget(props) {
2930
autoFocus={autofocus}
3031
rows={options.rows}
3132
onBlur={onBlur && (event => onBlur(id, event.target.value))}
33+
onFocus={onFocus && (event => onFocus(id, event.target.value))}
3234
onChange={_onChange}
3335
/>
3436
);
@@ -54,6 +56,7 @@ if (process.env.NODE_ENV !== "production") {
5456
autofocus: PropTypes.bool,
5557
onChange: PropTypes.func,
5658
onBlur: PropTypes.func,
59+
onFocus: PropTypes.func,
5760
};
5861
}
5962

test/ArrayField_test.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,24 @@ describe("ArrayField", () => {
618618
expect(onBlur.calledWith(select.id, ["foo", "bar"])).to.be.true;
619619
});
620620

621+
it("should handle a focus event", () => {
622+
const onFocus = sandbox.spy();
623+
const { node } = createFormComponent({ schema, onFocus });
624+
625+
const select = node.querySelector(".field select");
626+
Simulate.focus(select, {
627+
target: {
628+
options: [
629+
{ selected: true, value: "foo" },
630+
{ selected: true, value: "bar" },
631+
{ selected: false, value: "fuzz" },
632+
],
633+
},
634+
});
635+
636+
expect(onFocus.calledWith(select.id, ["foo", "bar"])).to.be.true;
637+
});
638+
621639
it("should fill field with data", () => {
622640
const { node } = createFormComponent({
623641
schema,

0 commit comments

Comments
 (0)