Skip to content

Commit 7639578

Browse files
authored
Alter the RJSFB library to allow the setting of ui:placeholder elements (#155)
Alter the RJSFB library to allow the setting of ui:placeholder elements
1 parent b9b16c4 commit 7639578

File tree

10 files changed

+191
-61
lines changed

10 files changed

+191
-61
lines changed

flow-libdef/@ginkgo-bioworks/react-json-schema-form-builder_v2.x.x/test_react-json-schema-form-builder_v2.x.x.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ describe('@ginkgo-bioworks/react-json-schema-form-builder', () => {
9393
objectNameLabel: 'alternative object name label',
9494
displayNameLabel: 'alternative display name label',
9595
descriptionLabel: 'alternative description label',
96-
inputTypeLabel: 'alternative input type lablel',
96+
inputTypeLabel: 'alternative input type label',
9797
},
9898
showFormHead: false,
9999
deactivatedFormInputs: ['shortAnswer'],

src/formBuilder/CardGeneralParameterInputs.js

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -174,18 +174,20 @@ export default function CardGeneralParameterInputs({
174174
type='help'
175175
/>
176176
</h5>
177-
<Input
178-
value={descriptionState || ''}
179-
placeholder='Description'
180-
type='text'
181-
onChange={(ev: SyntheticInputEvent<HTMLInputElement>) =>
182-
setDescriptionState(ev.target.value)
183-
}
184-
onBlur={(ev: SyntheticInputEvent<HTMLInputElement>) => {
185-
onChange({ ...parameters, description: ev.target.value });
186-
}}
187-
className='card-text'
188-
/>
177+
<FormGroup>
178+
<Input
179+
value={descriptionState || ''}
180+
placeholder='Description'
181+
type='text'
182+
onChange={(ev: SyntheticInputEvent<HTMLInputElement>) =>
183+
setDescriptionState(ev.target.value)
184+
}
185+
onBlur={(ev: SyntheticInputEvent<HTMLInputElement>) => {
186+
onChange({ ...parameters, description: ev.target.value });
187+
}}
188+
className='card-text'
189+
/>
190+
</FormGroup>
189191
</div>
190192
<div
191193
className={classnames('card-entry', {

src/formBuilder/FormBuilder.test.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,4 +323,50 @@ describe('FormBuilder', () => {
323323
.map((error) => error.text());
324324
expect(errors).toEqual([]);
325325
});
326+
327+
it('should support placeholder in the UI schema', () => {
328+
const jsonSchema = {
329+
$schema: 'http://json-schema.org/draft-07/schema#',
330+
type: 'object',
331+
properties: {
332+
input1: {
333+
$ref: '#/definitions/name',
334+
title: 'First Name',
335+
description: 'Please enter your first name',
336+
},
337+
input2: {
338+
title: 'Last Name',
339+
type: 'string',
340+
},
341+
},
342+
};
343+
344+
const uischema = {
345+
input1: {
346+
'ui:placeholder': 'Reference Placeholder',
347+
},
348+
input2: {
349+
'ui:placeholder': 'ShortAnswer Placeholder',
350+
},
351+
'ui:order': ['input1', 'input2'],
352+
};
353+
354+
const props = {
355+
schema: JSON.stringify(jsonSchema),
356+
uiSchema: JSON.stringify(uischema),
357+
onChange: jest.fn(() => {}),
358+
mods: {},
359+
className: 'my-form-builder',
360+
};
361+
362+
const div = document.createElement('div');
363+
document.body.appendChild(div);
364+
const wrapper = mount(<FormBuilder {...props} />, { attachTo: div });
365+
const errors = wrapper
366+
.find('.alert-warning')
367+
.first()
368+
.find('li')
369+
.map((error) => error.text());
370+
expect(errors).toEqual([]);
371+
});
326372
});

src/formBuilder/defaults/defaultFormInputs.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import longAnswerInputs from './longAnswerInputs';
44
import numberInputs from './numberInputs';
55
import arrayInputs from './arrayInputs';
66
import defaultInputs from './defaultInputs';
7+
import referenceInputs from './referenceInputs';
78
import type { FormInput } from '../types';
89

910
const DEFAULT_FORM_INPUTS = ({
1011
...defaultInputs,
12+
...referenceInputs,
1113
...shortAnswerInputs,
1214
...longAnswerInputs,
1315
...numberInputs,

src/formBuilder/defaults/defaultInputs.js

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -177,34 +177,6 @@ function MultipleChoice({
177177
);
178178
}
179179

180-
function RefChoice({
181-
parameters,
182-
onChange,
183-
}: {
184-
parameters: Parameters,
185-
onChange: (newParams: Parameters) => void,
186-
}) {
187-
return (
188-
<div className='card-select'>
189-
<Select
190-
value={{
191-
value: parameters.$ref,
192-
label: parameters.$ref,
193-
}}
194-
placeholder='Reference'
195-
options={Object.keys(parameters.definitionData || {}).map((key) => ({
196-
value: `#/definitions/${key}`,
197-
label: `#/definitions/${key}`,
198-
}))}
199-
onChange={(val: any) => {
200-
onChange({ ...parameters, $ref: val.value });
201-
}}
202-
className='card-select'
203-
/>
204-
</div>
205-
);
206-
}
207-
208180
const defaultInputs: { [string]: FormInput } = {
209181
dateTime: {
210182
displayName: 'Date-Time',
@@ -267,24 +239,6 @@ const defaultInputs: { [string]: FormInput } = {
267239
cardBody: Checkbox,
268240
modalBody: CardDefaultParameterInputs,
269241
},
270-
ref: {
271-
displayName: 'Reference',
272-
matchIf: [
273-
{
274-
types: ['null'],
275-
$ref: true,
276-
},
277-
],
278-
defaultDataSchema: {
279-
$ref: '',
280-
title: '',
281-
description: '',
282-
},
283-
defaultUiSchema: {},
284-
type: 'string',
285-
cardBody: RefChoice,
286-
modalBody: CardDefaultParameterInputs,
287-
},
288242
radio: {
289243
displayName: 'Radio',
290244
matchIf: [

src/formBuilder/defaults/longAnswerInputs.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// @flow
22

33
import React, { useState } from 'react';
4-
import Select from 'react-select';
54
import { Input } from 'reactstrap';
65
import FBCheckbox from '../checkbox/FBCheckbox';
76
import Tooltip from '../Tooltip';
87
import { getRandomId } from '../utils';
98
import type { Parameters, FormInput } from '../types';
9+
import { PlaceholderInput } from '../inputs/PlaceholderInput';
1010

1111
// specify the inputs required for a string type object
1212
function CardLongAnswerParameterInputs({
@@ -70,6 +70,7 @@ function CardLongAnswerParameterInputs({
7070
}}
7171
className='card-modal-text'
7272
/>
73+
<PlaceholderInput parameters={parameters} onChange={onChange} />
7374
<div className='card-modal-boolean'>
7475
<FBCheckbox
7576
onChangeValue={() => {
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// @flow
2+
3+
import type { FormInput, Parameters } from '../types';
4+
import Select from 'react-select';
5+
import React, { useState } from 'react';
6+
import type { Node } from 'react';
7+
import { PlaceholderInput } from '../inputs/PlaceholderInput';
8+
9+
export function CardReferenceParameterInputs({
10+
parameters,
11+
onChange,
12+
}: {
13+
parameters: Parameters,
14+
onChange: (Parameters) => void,
15+
}): Node {
16+
return (
17+
<div>
18+
<PlaceholderInput parameters={parameters} onChange={onChange} />
19+
</div>
20+
);
21+
}
22+
23+
function RefChoice({
24+
parameters,
25+
onChange,
26+
}: {
27+
parameters: Parameters,
28+
onChange: (newParams: Parameters) => void,
29+
}) {
30+
return (
31+
<div className='card-select'>
32+
<Select
33+
value={{
34+
value: parameters.$ref,
35+
label: parameters.$ref,
36+
}}
37+
placeholder='Reference'
38+
options={Object.keys(parameters.definitionData || {}).map((key) => ({
39+
value: `#/definitions/${key}`,
40+
label: `#/definitions/${key}`,
41+
}))}
42+
onChange={(val: any) => {
43+
onChange({ ...parameters, $ref: val.value });
44+
}}
45+
className='card-select'
46+
/>
47+
</div>
48+
);
49+
}
50+
51+
const referenceInputs: { [string]: FormInput } = {
52+
ref: {
53+
displayName: 'Reference',
54+
matchIf: [
55+
{
56+
types: ['null'],
57+
$ref: true,
58+
},
59+
],
60+
defaultDataSchema: {
61+
$ref: '',
62+
title: '',
63+
description: '',
64+
},
65+
defaultUiSchema: {},
66+
type: 'string',
67+
cardBody: RefChoice,
68+
modalBody: CardReferenceParameterInputs,
69+
},
70+
};
71+
72+
export default referenceInputs;

src/formBuilder/defaults/shortAnswerInputs.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import FBCheckbox from '../checkbox/FBCheckbox';
77
import Tooltip from '../Tooltip';
88
import { getRandomId } from '../utils';
99
import type { Parameters, FormInput } from '../types';
10+
import { PlaceholderInput } from '../inputs/PlaceholderInput';
1011

1112
const formatDictionary = {
1213
'': 'None',
@@ -176,6 +177,7 @@ function CardShortAnswerParameterInputs({
176177
}}
177178
className='card-modal-select'
178179
/>
180+
<PlaceholderInput parameters={parameters} onChange={onChange} />
179181
<h4>
180182
Column Size{' '}
181183
<a
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// @flow
2+
3+
import React, { useState } from 'react';
4+
import type { Node } from 'react';
5+
import type { Parameters } from '../types';
6+
import { getRandomId } from '../utils';
7+
import Tooltip from '../Tooltip';
8+
import { Input } from 'reactstrap';
9+
10+
export function PlaceholderInput({
11+
parameters,
12+
onChange,
13+
}: {
14+
parameters: Parameters,
15+
onChange: (Parameters) => void,
16+
}): Node {
17+
const [elementId] = useState(getRandomId());
18+
return (
19+
<React.Fragment>
20+
<h4>
21+
Placeholder{' '}
22+
<a
23+
href='https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-placeholder'
24+
target='_blank'
25+
rel='noopener noreferrer'
26+
>
27+
<Tooltip
28+
id={`${elementId}_placeholder`}
29+
type='help'
30+
text='Hint to the user as to what kind of information is expected in the field'
31+
/>
32+
</a>
33+
</h4>
34+
<Input
35+
value={parameters['ui:placeholder']}
36+
placeholder='Placeholder'
37+
key='placeholder'
38+
type='text'
39+
onChange={(ev: SyntheticInputEvent<HTMLInputElement>) => {
40+
onChange({
41+
...parameters,
42+
'ui:placeholder': ev.target.value,
43+
});
44+
}}
45+
className='card-modal-text'
46+
/>
47+
</React.Fragment>
48+
);
49+
}

src/formBuilder/utils.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ const supportedUiParameters = new Set([
156156
'ui:autocomplete',
157157
'ui:options',
158158
'ui:field',
159+
'ui:placeholder',
159160
'ui:column',
160161
'items',
161162
'definitions',
@@ -808,7 +809,8 @@ export function generateUiSchemaFromElementProps(
808809
typeof element.$ref === 'string' ? element.$ref.split('/') : [];
809810
if (definitions && definitions[pathArr[2]])
810811
uiSchema[element.name] = definitions[pathArr[2]];
811-
} else if (element.propType === 'card' && element.uiOptions) {
812+
}
813+
if (element.propType === 'card' && element.uiOptions) {
812814
Object.keys(element.uiOptions).forEach((uiOption) => {
813815
if (!uiSchema[element.name]) uiSchema[element.name] = {};
814816
if (uiOption.startsWith('ui:*')) {

0 commit comments

Comments
 (0)