@scenid/react-formulator 0.1.14 → 0.2.0
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/.babelrc +30 -0
- package/.eslintrc +1 -1
- package/dist/index.cjs.js +195 -196
- package/dist/index.esm.js +128 -153
- package/package.json +10 -2
- package/src/Editable/FormField.jsx +28 -21
- package/src/Editable/FormRepeater.jsx +1 -1
- package/src/FormSectionBlock.jsx +2 -1
- package/src/FormulatorFormSection.jsx +21 -76
- package/src/ReadOnly/FormReadOnlyField.jsx +1 -1
- package/stories/CustomRenderField.jsx +30 -0
- package/stories/Forms.stories.jsx +35 -32
- package/stories/forms/types.schemas.js +17 -8
|
@@ -50,7 +50,7 @@ const FormControlField = ({
|
|
|
50
50
|
onChange
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
const isRender = type === 'render'
|
|
53
|
+
const isRender = type === '@@render'
|
|
54
54
|
|
|
55
55
|
if (validating) {
|
|
56
56
|
finalProps.endAdornment = [(
|
|
@@ -62,29 +62,36 @@ const FormControlField = ({
|
|
|
62
62
|
|
|
63
63
|
let control
|
|
64
64
|
if (isRender) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
65
|
+
try {
|
|
66
|
+
control = React.cloneElement(
|
|
67
|
+
component,
|
|
68
|
+
{
|
|
69
|
+
variant,
|
|
70
|
+
...finalProps,
|
|
71
|
+
label,
|
|
72
|
+
hasErrors,
|
|
73
|
+
errors,
|
|
74
|
+
dirty
|
|
75
|
+
}
|
|
76
|
+
)
|
|
77
|
+
} catch (e) {
|
|
78
|
+
throw new Error(`error creating control for field "${name}": ${e.message}`)
|
|
79
|
+
}
|
|
76
80
|
} else {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
try {
|
|
82
|
+
control = React.createElement(
|
|
83
|
+
component,
|
|
84
|
+
{
|
|
85
|
+
variant,
|
|
86
|
+
...finalProps
|
|
87
|
+
}
|
|
88
|
+
)
|
|
89
|
+
} catch (e) {
|
|
90
|
+
throw new Error(`error creating control for field "${name}": ${e.message}`)
|
|
91
|
+
}
|
|
84
92
|
}
|
|
85
|
-
|
|
86
93
|
const isSwitch = type === 'boolean'
|
|
87
|
-
const isRepeater = type === 'array'
|
|
94
|
+
const isRepeater = type === 'array'
|
|
88
95
|
|
|
89
96
|
if (isRepeater || isRender) {
|
|
90
97
|
return control
|
|
@@ -182,7 +182,7 @@ const FormRepeater = ({ variant, name, value, catalog, onChange }) => {
|
|
|
182
182
|
FormRepeater.propTypes = {
|
|
183
183
|
variant: PropTypes.oneOf(['standard', 'filled', 'outlined']),
|
|
184
184
|
name: PropTypes.string.isRequired,
|
|
185
|
-
value: PropTypes.any
|
|
185
|
+
value: PropTypes.any,
|
|
186
186
|
catalog: PropTypes.object,
|
|
187
187
|
onChange: PropTypes.func.isRequired
|
|
188
188
|
}
|
package/src/FormSectionBlock.jsx
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import PropTypes from 'prop-types'
|
|
3
3
|
|
|
4
|
-
import { Box
|
|
4
|
+
import { Box } from '@material-ui/core'
|
|
5
|
+
import { makeStyles } from '@material-ui/core/styles'
|
|
5
6
|
|
|
6
7
|
import FormGroupHeader from './FormGroupHeader'
|
|
7
8
|
|
|
@@ -64,18 +64,8 @@ class FormulatorFormSection extends React.Component {
|
|
|
64
64
|
renderComponentMap
|
|
65
65
|
} = this.props
|
|
66
66
|
|
|
67
|
-
let field = fieldEntry, specialProps = {}
|
|
67
|
+
let field = fieldEntry, isRender = false, specialProps = {}
|
|
68
68
|
if (Array.isArray(fieldEntry)) {
|
|
69
|
-
if (fieldEntry[0] === '@@render') {
|
|
70
|
-
field = fieldEntry[1]
|
|
71
|
-
return ({
|
|
72
|
-
type: 'render',
|
|
73
|
-
name: field,
|
|
74
|
-
component: renderComponentMap[field],
|
|
75
|
-
componentProps: fieldEntry[2] || {}
|
|
76
|
-
})
|
|
77
|
-
}
|
|
78
|
-
|
|
79
69
|
if (fieldEntry[0] === '@@markdown') {
|
|
80
70
|
return ({
|
|
81
71
|
type: 'markdown',
|
|
@@ -87,10 +77,16 @@ class FormulatorFormSection extends React.Component {
|
|
|
87
77
|
})
|
|
88
78
|
}
|
|
89
79
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
80
|
+
if (fieldEntry[0] === '@@render') {
|
|
81
|
+
if (!fieldEntry[1]) throw new Error(`render field "${field}" has no name`)
|
|
82
|
+
field = fieldEntry[1]
|
|
83
|
+
specialProps = fieldEntry[2] || {}
|
|
84
|
+
isRender = true
|
|
85
|
+
} else {
|
|
86
|
+
field = fieldEntry[0]
|
|
87
|
+
if (!fieldEntry[1]) throw new Error(`field "${field}" is defined in an array, but has no props definition`)
|
|
88
|
+
specialProps = fieldEntry[1]
|
|
89
|
+
}
|
|
94
90
|
}
|
|
95
91
|
|
|
96
92
|
const { hidden, hideLabel, ...extraProps } = specialProps
|
|
@@ -104,13 +100,14 @@ class FormulatorFormSection extends React.Component {
|
|
|
104
100
|
const { type, default: defaultValue } = schema.properties[field]
|
|
105
101
|
|
|
106
102
|
let mapKey
|
|
107
|
-
if (
|
|
103
|
+
if (isRender) mapKey = '@@render'
|
|
104
|
+
else if (componentMap[field] !== undefined) mapKey = field
|
|
108
105
|
else if (typeof type === 'string' && componentMap[type] !== undefined) mapKey = type
|
|
109
106
|
else if (Array.isArray(type)) mapKey = 'select'
|
|
110
107
|
else if (componentMap.default !== undefined) mapKey = 'default'
|
|
111
108
|
else throw new Error(`Could not find a Component to render for "${field}"`)
|
|
112
109
|
|
|
113
|
-
const mapEntry = componentMap[mapKey]
|
|
110
|
+
const mapEntry = isRender ? renderComponentMap[field] : componentMap[mapKey]
|
|
114
111
|
let component = mapEntry, props = {}
|
|
115
112
|
|
|
116
113
|
if (mapKey === 'select') {
|
|
@@ -133,8 +130,10 @@ class FormulatorFormSection extends React.Component {
|
|
|
133
130
|
/* eslint-enable prefer-destructuring */
|
|
134
131
|
}
|
|
135
132
|
|
|
133
|
+
if (!component) throw new Error(`could not find component for field "${field}"`)
|
|
134
|
+
|
|
136
135
|
return {
|
|
137
|
-
type: mapKey,
|
|
136
|
+
type: isRender ? '@@render' : mapKey,
|
|
138
137
|
name: field,
|
|
139
138
|
label: hideLabel !== true && ((translations.labels && translations.labels[field]) || field),
|
|
140
139
|
defaultValue,
|
|
@@ -193,60 +192,6 @@ class FormulatorFormSection extends React.Component {
|
|
|
193
192
|
fields.map((fieldEntry, fieldIndex) => {
|
|
194
193
|
if (fieldEntry === false) return false
|
|
195
194
|
|
|
196
|
-
if (Array.isArray(fieldEntry) && fieldEntry[0] === '@@render') {
|
|
197
|
-
const cKey = fieldEntry[1]
|
|
198
|
-
const component = renderComponentMap && renderComponentMap[cKey]
|
|
199
|
-
if (!component) throw new Error(`Could not find Component for render field "${cKey}"`)
|
|
200
|
-
|
|
201
|
-
const fieldProps = this.getFieldProps(fieldEntry)
|
|
202
|
-
|
|
203
|
-
const {
|
|
204
|
-
type,
|
|
205
|
-
name,
|
|
206
|
-
componentProps,
|
|
207
|
-
label,
|
|
208
|
-
value,
|
|
209
|
-
required,
|
|
210
|
-
hasErrors,
|
|
211
|
-
errors,
|
|
212
|
-
validating,
|
|
213
|
-
dirty
|
|
214
|
-
} = fieldProps
|
|
215
|
-
|
|
216
|
-
if (readOnly) {
|
|
217
|
-
if (!value) return false
|
|
218
|
-
if (Array.isArray(obscuredFields) && obscuredFields.includes(name)) {
|
|
219
|
-
return <HiddenData subject="Das Feld" label={label} />
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
return React.createElement(
|
|
224
|
-
readOnly ? FormReadOnlyField : FormField,
|
|
225
|
-
{
|
|
226
|
-
key: `form-render-component-${cKey}`,
|
|
227
|
-
variant: inputVariant,
|
|
228
|
-
name,
|
|
229
|
-
type,
|
|
230
|
-
label,
|
|
231
|
-
value,
|
|
232
|
-
required,
|
|
233
|
-
hasErrors,
|
|
234
|
-
errors,
|
|
235
|
-
validating,
|
|
236
|
-
dirty,
|
|
237
|
-
component,
|
|
238
|
-
componentProps,
|
|
239
|
-
disabled,
|
|
240
|
-
readOnly,
|
|
241
|
-
fields,
|
|
242
|
-
results,
|
|
243
|
-
data,
|
|
244
|
-
fieldStates,
|
|
245
|
-
onChange
|
|
246
|
-
}
|
|
247
|
-
)
|
|
248
|
-
}
|
|
249
|
-
|
|
250
195
|
if (typeof fieldEntry !== 'string' && !Array.isArray(fieldEntry)) {
|
|
251
196
|
return (
|
|
252
197
|
<FormulatorFormSection
|
|
@@ -437,10 +382,10 @@ class FormulatorFormSection extends React.Component {
|
|
|
437
382
|
return (
|
|
438
383
|
<FormSectionBlock
|
|
439
384
|
key={`form-section-${sectionId}`}
|
|
440
|
-
label={
|
|
441
|
-
labelVariant={
|
|
442
|
-
desc={
|
|
443
|
-
descVariant={
|
|
385
|
+
label={label}
|
|
386
|
+
labelVariant={labelVariant}
|
|
387
|
+
desc={desc}
|
|
388
|
+
descVariant={descVariant}
|
|
444
389
|
textAlign={textAlign}
|
|
445
390
|
>
|
|
446
391
|
{sectionContent}
|
|
@@ -28,7 +28,7 @@ const FormControlField = ({
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
let control
|
|
31
|
-
if (type === 'render') control = React.cloneElement(component, finalProps)
|
|
31
|
+
if (type === '@@render') control = React.cloneElement(component, finalProps);
|
|
32
32
|
else control = React.createElement(component, finalProps)
|
|
33
33
|
|
|
34
34
|
return (
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
|
|
4
|
+
import { TextField } from '@material-ui/core'
|
|
5
|
+
import { makeStyles } from '@material-ui/core/styles'
|
|
6
|
+
|
|
7
|
+
const CustomRenderField = ({ name, value, onChange, ...props }) => {
|
|
8
|
+
const [deg, setDeg] = useState(value || '')
|
|
9
|
+
|
|
10
|
+
const handleChange = e => {
|
|
11
|
+
onChange({ target: { name, value: e.target.value } })
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<TextField
|
|
16
|
+
// eslint-disable-next-line react/jsx-props-no-spreading
|
|
17
|
+
{...props}
|
|
18
|
+
type="text"
|
|
19
|
+
onChange={handleChange}
|
|
20
|
+
/>
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
CustomRenderField.propTypes = {
|
|
25
|
+
name: PropTypes.string.isRequired,
|
|
26
|
+
value: PropTypes.string,
|
|
27
|
+
onChange: PropTypes.func.isRequired
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default CustomRenderField
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
|
|
3
|
-
import ReactMarkdown from 'react-markdown'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
4
3
|
|
|
5
4
|
import StoryBase from './StoryBase'
|
|
6
5
|
import { FormulatorForm } from '../src/index'
|
|
7
6
|
|
|
8
|
-
import getTypesSchemas from './forms/types.schemas
|
|
7
|
+
import getTypesSchemas from './forms/types.schemas'
|
|
9
8
|
|
|
10
9
|
import markdownValidation from './forms/markdown.validation.schema.json'
|
|
11
10
|
import markdownRender from './forms/markdown.render.schema.json'
|
|
@@ -20,6 +19,8 @@ import rlpValidation from './forms/rlp.validation.schema.json'
|
|
|
20
19
|
import rlpRender from './forms/rlp.render.schema.json'
|
|
21
20
|
import rlpTranslations from './forms/rlp.translations.json'
|
|
22
21
|
|
|
22
|
+
import CustomRenderField from './CustomRenderField'
|
|
23
|
+
|
|
23
24
|
const {
|
|
24
25
|
validation: typesValidation,
|
|
25
26
|
render: typesRender,
|
|
@@ -53,17 +54,21 @@ const schemas = {
|
|
|
53
54
|
export default {
|
|
54
55
|
title: 'Formulator/Forms',
|
|
55
56
|
component: FormulatorForm,
|
|
56
|
-
parameters: {
|
|
57
|
-
layout: 'fullscreen'
|
|
58
|
-
}
|
|
57
|
+
parameters: { layout: 'fullscreen' }
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
const Template = ({ baseProps, ...props }) => (
|
|
61
|
+
// eslint-disable-next-line react/jsx-props-no-spreading
|
|
62
62
|
<StoryBase {...baseProps}>
|
|
63
|
+
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
|
|
63
64
|
<FormulatorForm {...props} />
|
|
64
65
|
</StoryBase>
|
|
65
66
|
)
|
|
66
67
|
|
|
68
|
+
Template.propTypes = {
|
|
69
|
+
baseProps: PropTypes.object
|
|
70
|
+
}
|
|
71
|
+
|
|
67
72
|
export const Types = Template.bind({})
|
|
68
73
|
Types.args = {
|
|
69
74
|
id: 'unique-form-id',
|
|
@@ -71,7 +76,7 @@ Types.args = {
|
|
|
71
76
|
renderSchema: schemas.types.render,
|
|
72
77
|
inputVariant: 'filled',
|
|
73
78
|
renderComponentMap: {
|
|
74
|
-
|
|
79
|
+
customRenderField: <CustomRenderField />
|
|
75
80
|
},
|
|
76
81
|
translations: typesTranslations,
|
|
77
82
|
data: {}
|
|
@@ -128,9 +133,7 @@ Register.args = {
|
|
|
128
133
|
passwordConfirm: 'Passwort bestätigen'
|
|
129
134
|
}
|
|
130
135
|
},
|
|
131
|
-
errorMessages: {
|
|
132
|
-
Email: 'Ungültige E-Mail-Adresse'
|
|
133
|
-
},
|
|
136
|
+
errorMessages: { Email: 'Ungültige E-Mail-Adresse' },
|
|
134
137
|
data: {}
|
|
135
138
|
}
|
|
136
139
|
|
|
@@ -147,14 +150,14 @@ RLP.args = {
|
|
|
147
150
|
required: 'Pflichtfeld',
|
|
148
151
|
IBAN: 'IBAN bitte ohne Sonder- und Trennzeichen angeben',
|
|
149
152
|
Int: 'Bitte geben Sie ein gültige Zahl ein',
|
|
150
|
-
URL:
|
|
151
|
-
Email:
|
|
152
|
-
Date:
|
|
153
|
-
Length:
|
|
154
|
-
RegExp:
|
|
155
|
-
'invalid-email':
|
|
156
|
-
'invalid-phone':
|
|
157
|
-
'invalid-fax':
|
|
153
|
+
URL: 'Ungültiger Link',
|
|
154
|
+
Email: 'Ungültige E-Mail Adresse',
|
|
155
|
+
Date: 'Ungültiges Datum',
|
|
156
|
+
Length: 'Länge muss zwischen {{min}} und {{max}} liegen',
|
|
157
|
+
RegExp: 'Ungültiges Format oder Zeichen',
|
|
158
|
+
'invalid-email': 'Ungültige E-Mail Adresse',
|
|
159
|
+
'invalid-phone': 'Ungültige Telefonnummer',
|
|
160
|
+
'invalid-fax': 'Ungültige Faxnummer'
|
|
158
161
|
},
|
|
159
162
|
obscuredFields: [
|
|
160
163
|
'reportingPin',
|
|
@@ -174,19 +177,19 @@ RLP.args = {
|
|
|
174
177
|
// reporterId: <FormUnique entityType="ou" />,
|
|
175
178
|
// iknr: <FormUnique entityType="ou" />,
|
|
176
179
|
// bsnr: <FormUnique entityType="ou" excludeInactive />,
|
|
177
|
-
contacts: <div/>,
|
|
178
|
-
reporterId: <div/>,
|
|
179
|
-
iknr: <div/>,
|
|
180
|
-
bsnr: <div
|
|
181
|
-
productOwner: <div />,
|
|
182
|
-
inheritedIKNR: <div />,
|
|
183
|
-
inheritedBSNR: <div />,
|
|
184
|
-
reportingCodesTrigger: (
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
)
|
|
180
|
+
contacts: <div />,
|
|
181
|
+
reporterId: <div />,
|
|
182
|
+
iknr: <div />,
|
|
183
|
+
bsnr: <div />
|
|
184
|
+
// productOwner: <div />,
|
|
185
|
+
// inheritedIKNR: <div />,
|
|
186
|
+
// inheritedBSNR: <div />,
|
|
187
|
+
// reportingCodesTrigger: (
|
|
188
|
+
// <div className="action-group right">
|
|
189
|
+
// <Button onClick={() => {}}>
|
|
190
|
+
// Automatisch generieren
|
|
191
|
+
// </Button>
|
|
192
|
+
// </div>
|
|
193
|
+
// )
|
|
191
194
|
}
|
|
192
195
|
}
|
|
@@ -15,7 +15,7 @@ const inputs = [
|
|
|
15
15
|
multiline: true,
|
|
16
16
|
minRows: 5
|
|
17
17
|
}
|
|
18
|
-
]
|
|
18
|
+
]
|
|
19
19
|
],
|
|
20
20
|
validation: { type: 'string' }
|
|
21
21
|
},
|
|
@@ -83,9 +83,7 @@ const inputs = [
|
|
|
83
83
|
desc: 'Values are automatically sorted with [localeCompare](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare).',
|
|
84
84
|
key: 'simpleSelect',
|
|
85
85
|
render: ['simpleSelect'],
|
|
86
|
-
validation: {
|
|
87
|
-
type: ['Citrus', 'Banana', 'Apple', 'Date']
|
|
88
|
-
}
|
|
86
|
+
validation: { type: ['Citrus', 'Banana', 'Apple', 'Date'] }
|
|
89
87
|
},
|
|
90
88
|
{
|
|
91
89
|
label: 'Date',
|
|
@@ -114,6 +112,17 @@ const inputs = [
|
|
|
114
112
|
key: 'arrayRepeater',
|
|
115
113
|
render: ['arrayRepeater'],
|
|
116
114
|
validation: { type: 'array' }
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
label: 'Custom Render Field',
|
|
118
|
+
key: 'customRenderField',
|
|
119
|
+
render: [
|
|
120
|
+
[
|
|
121
|
+
'@@render',
|
|
122
|
+
'customRenderField'
|
|
123
|
+
]
|
|
124
|
+
],
|
|
125
|
+
validation: { type: 'string' }
|
|
117
126
|
}
|
|
118
127
|
]
|
|
119
128
|
|
|
@@ -142,8 +151,8 @@ export default () => {
|
|
|
142
151
|
label,
|
|
143
152
|
fields: [
|
|
144
153
|
[
|
|
145
|
-
|
|
146
|
-
|
|
154
|
+
'@@markdown',
|
|
155
|
+
'mmd-id',
|
|
147
156
|
`\`\`\`json\n/* validation schema */\n${validationJSON}\n\n/* render schema */\n${renderJSON}\n\`\`\``
|
|
148
157
|
],
|
|
149
158
|
render[0]
|
|
@@ -152,8 +161,8 @@ export default () => {
|
|
|
152
161
|
|
|
153
162
|
if (desc) {
|
|
154
163
|
renderEntry.fields.unshift([
|
|
155
|
-
|
|
156
|
-
|
|
164
|
+
'@@markdown',
|
|
165
|
+
'mmd-desc-id',
|
|
157
166
|
desc
|
|
158
167
|
])
|
|
159
168
|
}
|