@axdspub/axiom-ui-forms 0.2.1-alpha.6 → 0.2.1-alpha.7
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/package.json +5 -2
- package/.env +0 -1
- package/.eslintrc.json +0 -37
- package/.gitlab-ci.yml +0 -41
- package/craco.config.js +0 -42
- package/docker-compose.yml +0 -13
- package/rollup.config.mjs +0 -120
- package/src/App.tsx +0 -57
- package/src/Form/Components/FieldCreator.tsx +0 -206
- package/src/Form/Components/FieldLabel.tsx +0 -14
- package/src/Form/Components/Inputs/Boolean.tsx +0 -13
- package/src/Form/Components/Inputs/Date.tsx +0 -111
- package/src/Form/Components/Inputs/DateTime.tsx +0 -104
- package/src/Form/Components/Inputs/GeoJSON.tsx +0 -535
- package/src/Form/Components/Inputs/GeoJSONInputLoader.tsx +0 -16
- package/src/Form/Components/Inputs/JSONString.tsx +0 -40
- package/src/Form/Components/Inputs/LongString.tsx +0 -22
- package/src/Form/Components/Inputs/Number.tsx +0 -22
- package/src/Form/Components/Inputs/Object.tsx +0 -56
- package/src/Form/Components/Inputs/RadioGroup.tsx +0 -24
- package/src/Form/Components/Inputs/SingleSelect.tsx +0 -24
- package/src/Form/Components/Inputs/String.tsx +0 -18
- package/src/Form/Components/Inputs/Time.tsx +0 -107
- package/src/Form/Components/Inputs/index.tsx +0 -10
- package/src/Form/Components/Inputs/inputMap.ts +0 -30
- package/src/Form/Components/index.tsx +0 -2
- package/src/Form/Creator/FormCreator.tsx +0 -60
- package/src/Form/Creator/FormCreatorTypes.ts +0 -225
- package/src/Form/Creator/FormFields.tsx +0 -37
- package/src/Form/Creator/FormHeader.tsx +0 -29
- package/src/Form/Creator/FormSection.tsx +0 -60
- package/src/Form/Creator/Page.tsx +0 -132
- package/src/Form/Creator/Wizard.tsx +0 -157
- package/src/Form/Creator/utils.ts +0 -0
- package/src/Form/FormMappingTypes.ts +0 -17
- package/src/Form/Manage/CopyableJSONOutput.tsx +0 -75
- package/src/Form/Manage/FormConfigInput.tsx +0 -56
- package/src/Form/Manage/FormMappedOutput.tsx +0 -133
- package/src/Form/Manage/FormMappingInput.tsx +0 -60
- package/src/Form/Manage/Manage.tsx +0 -133
- package/src/Form/Manage/RawFormOutput.tsx +0 -22
- package/src/Form/MapTester.tsx +0 -107
- package/src/Form/SchemaToForm.tsx +0 -176
- package/src/Form/formDefinition.json +0 -8
- package/src/Form/helpers.ts +0 -122
- package/src/Form/index.ts +0 -2
- package/src/Form/schemaToFormHelpers.ts +0 -216
- package/src/Form/testData/assetData.json +0 -65
- package/src/Form/testData/exampleParticle.json +0 -112
- package/src/Form/testData/fields.json +0 -151
- package/src/Form/testData/nestedForm.json +0 -156
- package/src/Form/testData/pagedForm.json +0 -182
- package/src/Form/testData/testSchema.json +0 -89
- package/src/Form/testData/wizardForm.json +0 -217
- package/src/SetTester.tsx +0 -61
- package/src/helpers.ts +0 -36
- package/src/index.css +0 -39
- package/src/index.tsx +0 -19
- package/src/library.ts +0 -4
- package/src/reportWebVitals.ts +0 -15
- package/src/state/formAtom.ts +0 -21
- package/src/state/formMappingAtom.ts +0 -21
- package/src/state/formValuesAtom.ts +0 -22
- package/src/types/generate-schema.d.ts +0 -8
- package/tailwind.config.js +0 -11
- package/tsconfig.json +0 -32
- package/tsconfig.paths.json +0 -19
package/package.json
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
{
|
2
2
|
"name": "@axdspub/axiom-ui-forms",
|
3
|
-
"version": "0.2.1-alpha.
|
3
|
+
"version": "0.2.1-alpha.7",
|
4
4
|
"private": false,
|
5
5
|
"main": "./library/umd/library.js",
|
6
|
-
"module": "./library/
|
6
|
+
"module": "./library/esm/library.js",
|
7
7
|
"types": "./library/axiom-ui-forms.d.ts",
|
8
|
+
"files": [
|
9
|
+
"library/**"
|
10
|
+
],
|
8
11
|
"peerDependencies": {
|
9
12
|
"lodash": "^4.17.21",
|
10
13
|
"react": "^18.0.0",
|
package/.env
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
PORT=3080
|
package/.eslintrc.json
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"env": {
|
3
|
-
"browser": true,
|
4
|
-
"es2021": true
|
5
|
-
},
|
6
|
-
"extends": [
|
7
|
-
"plugin:react/recommended",
|
8
|
-
"standard-with-typescript"
|
9
|
-
],
|
10
|
-
"overrides": [],
|
11
|
-
"parserOptions": {
|
12
|
-
"ecmaVersion": "latest",
|
13
|
-
"sourceType": "module",
|
14
|
-
"project": [
|
15
|
-
"./tsconfig.json"
|
16
|
-
]
|
17
|
-
},
|
18
|
-
"plugins": [
|
19
|
-
"react"
|
20
|
-
],
|
21
|
-
"rules": {
|
22
|
-
"ignoreIIFE": 0,
|
23
|
-
"@typescript-eslint/strict-boolean-expressions": 0,
|
24
|
-
"@typescript-eslint/no-misused-promises": [2, {
|
25
|
-
"checksVoidReturn": {
|
26
|
-
"attributes": false
|
27
|
-
}
|
28
|
-
}]
|
29
|
-
|
30
|
-
},
|
31
|
-
"ignorePatterns": [
|
32
|
-
"**/build/*",
|
33
|
-
"**/library/*",
|
34
|
-
"**/node_modules/*",
|
35
|
-
"**/.yalc/*"
|
36
|
-
]
|
37
|
-
}
|
package/.gitlab-ci.yml
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
stages:
|
2
|
-
- build
|
3
|
-
- test
|
4
|
-
- push
|
5
|
-
- clean
|
6
|
-
- deploy
|
7
|
-
|
8
|
-
build_image:
|
9
|
-
stage: build
|
10
|
-
script:
|
11
|
-
- docker build -f Dockerfile -t $CI_PROJECT_NAME:$CI_PIPELINE_ID .
|
12
|
-
|
13
|
-
test:
|
14
|
-
stage: test
|
15
|
-
image: $CI_PROJECT_NAME:$CI_PIPELINE_ID
|
16
|
-
script:
|
17
|
-
- test -e /usr/share/nginx/html/index.html
|
18
|
-
- test -e /usr/share/nginx/html/asset-manifest.json
|
19
|
-
|
20
|
-
push_latest:
|
21
|
-
stage: push
|
22
|
-
only:
|
23
|
-
- main
|
24
|
-
script:
|
25
|
-
- docker tag $CI_PROJECT_NAME:$CI_PIPELINE_ID registry.axiom/$CI_PROJECT_NAME:latest
|
26
|
-
- docker push registry.axiom/$CI_PROJECT_NAME:latest
|
27
|
-
|
28
|
-
clean_latest:
|
29
|
-
stage: clean
|
30
|
-
only:
|
31
|
-
- main
|
32
|
-
script:
|
33
|
-
- docker rmi --no-prune $CI_PROJECT_NAME:$CI_PIPELINE_ID
|
34
|
-
- docker rmi --no-prune registry.axiom/$CI_PROJECT_NAME:latest
|
35
|
-
|
36
|
-
deploy_app:
|
37
|
-
stage: deploy
|
38
|
-
only:
|
39
|
-
- main
|
40
|
-
script:
|
41
|
-
- aps apps-prod axiom-ui-forms
|
package/craco.config.js
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
const path = require('path')
|
2
|
-
|
3
|
-
// someday, clean up the the FOUR! repeated declarations of aliases (others are is in tsconfig.paths.json => tsconfig.json and .storybook/main.ts)
|
4
|
-
// https://stackoverflow.com/a/71892901
|
5
|
-
|
6
|
-
module.exports = {
|
7
|
-
webpack: {
|
8
|
-
eslint: {
|
9
|
-
enable: false
|
10
|
-
},
|
11
|
-
alias: {
|
12
|
-
'@': path.resolve(__dirname, 'src/'),
|
13
|
-
'@Components': path.resolve(__dirname, 'src/Components'),
|
14
|
-
'@State': path.resolve(__dirname, 'src/State')
|
15
|
-
},
|
16
|
-
configure: {
|
17
|
-
ignoreWarnings: [/Failed to parse source map/],
|
18
|
-
resolve: {
|
19
|
-
fallback: {
|
20
|
-
https: false,
|
21
|
-
http: false,
|
22
|
-
path: false,
|
23
|
-
zlib: false
|
24
|
-
}
|
25
|
-
},
|
26
|
-
module: {
|
27
|
-
// this silences a warning (Critical dependency: require function is used in a way in which dependencies cannot be statically extracted) that comes up with the cesium build included with @axdspubs/axiom-maps
|
28
|
-
unknownContextCritical: false
|
29
|
-
}
|
30
|
-
}
|
31
|
-
},
|
32
|
-
jest: {
|
33
|
-
configure: {
|
34
|
-
verbose: true,
|
35
|
-
moduleNameMapper: {
|
36
|
-
'^@/(.*)$': '<rootDir>/src/$1',
|
37
|
-
'^@Components/(.*)$': '<rootDir>/src/State/$1',
|
38
|
-
'^@State/(.*)$': '<rootDir>/src/State/$1'
|
39
|
-
}
|
40
|
-
}
|
41
|
-
}
|
42
|
-
}
|
package/docker-compose.yml
DELETED
package/rollup.config.mjs
DELETED
@@ -1,120 +0,0 @@
|
|
1
|
-
import resolve from '@rollup/plugin-node-resolve'
|
2
|
-
import commonjs from '@rollup/plugin-commonjs'
|
3
|
-
import babel from '@rollup/plugin-babel'
|
4
|
-
import typescript from '@rollup/plugin-typescript'
|
5
|
-
import dts from 'rollup-plugin-dts'
|
6
|
-
import json from '@rollup/plugin-json'
|
7
|
-
import alias from '@rollup/plugin-alias'
|
8
|
-
import nodePolyfills from 'rollup-plugin-polyfill-node'
|
9
|
-
// import packageJson from './package.json'
|
10
|
-
|
11
|
-
const globals = {
|
12
|
-
'react/jsx-runtime': 'JSXRuntime',
|
13
|
-
react: 'React',
|
14
|
-
'react-dom': 'ReactDOM',
|
15
|
-
lodash: 'lodash'
|
16
|
-
}
|
17
|
-
|
18
|
-
const external = [
|
19
|
-
'react',
|
20
|
-
'react-dom',
|
21
|
-
'react-scripts',
|
22
|
-
'react/jsx-runtime',
|
23
|
-
'lodash'
|
24
|
-
]
|
25
|
-
|
26
|
-
const config = [
|
27
|
-
{
|
28
|
-
external,
|
29
|
-
input: 'src/library.ts',
|
30
|
-
onwarn: function (warning, warn) {
|
31
|
-
if (warning.code === 'MODULE_LEVEL_DIRECTIVE') {
|
32
|
-
return
|
33
|
-
}
|
34
|
-
// got same warning as with d3.. assuming same deal for now (bostock sez: it's allowed in the spec, not gonna fix. just supress it)
|
35
|
-
// https://github.com/d3/d3-selection/issues/168#issuecomment-451983830
|
36
|
-
if (warning.code === 'CIRCULAR_DEPENDENCY') return
|
37
|
-
|
38
|
-
warn(warning)
|
39
|
-
},
|
40
|
-
output: [
|
41
|
-
/* {
|
42
|
-
file: 'library/cjs.js',
|
43
|
-
format: 'cjs',
|
44
|
-
sourcemap: true,
|
45
|
-
globals
|
46
|
-
}, */
|
47
|
-
{
|
48
|
-
dir: 'library/esm',
|
49
|
-
format: 'esm',
|
50
|
-
sourcemap: true,
|
51
|
-
chunkFileNames: 'chunks/[name]-[hash].js',
|
52
|
-
// inlineDynamicImports: true,
|
53
|
-
globals
|
54
|
-
}//,
|
55
|
-
/* {
|
56
|
-
file: 'library/browser.js',
|
57
|
-
format: 'iife',
|
58
|
-
name: 'AxiomUIforms',
|
59
|
-
sourcemap: true,
|
60
|
-
globals
|
61
|
-
}, */
|
62
|
-
/* {
|
63
|
-
dir: 'library/umd',
|
64
|
-
format: 'umd',
|
65
|
-
name: 'AxiomUIforms',
|
66
|
-
sourcemap: true,
|
67
|
-
// inlineDynamicImports: true,
|
68
|
-
globals
|
69
|
-
} */
|
70
|
-
],
|
71
|
-
plugins: [
|
72
|
-
nodePolyfills(),
|
73
|
-
json(),
|
74
|
-
resolve({ preferBuiltins: false, browser: true }),
|
75
|
-
commonjs(),
|
76
|
-
/* babel({
|
77
|
-
babelHelpers: 'bundled',
|
78
|
-
presets: ['@babel/preset-react']
|
79
|
-
}), */
|
80
|
-
alias({
|
81
|
-
entries: {
|
82
|
-
'@/*': './src'
|
83
|
-
}
|
84
|
-
}),
|
85
|
-
typescript({ tsconfig: './tsconfig.json' })
|
86
|
-
]
|
87
|
-
},
|
88
|
-
{
|
89
|
-
external,
|
90
|
-
input: 'src/library.ts',
|
91
|
-
output: [{
|
92
|
-
file: 'library/axiom-ui-forms.d.ts',
|
93
|
-
format: 'esm',
|
94
|
-
globals
|
95
|
-
}],
|
96
|
-
plugins: [
|
97
|
-
json(),
|
98
|
-
dts({
|
99
|
-
compilerOptions: {
|
100
|
-
// enabling declaration (.d.ts) emit
|
101
|
-
declaration: true,
|
102
|
-
|
103
|
-
// optional - in general it's a good practice to decouple declaration files from your actual transpiled JavaScript files
|
104
|
-
declarationDir: 'library',
|
105
|
-
|
106
|
-
// optional if you're using babel to transpile TS -> JS
|
107
|
-
emitDeclarationOnly: true,
|
108
|
-
|
109
|
-
paths: {
|
110
|
-
'@/*': [
|
111
|
-
'./src/*'
|
112
|
-
]
|
113
|
-
}
|
114
|
-
}
|
115
|
-
})
|
116
|
-
]
|
117
|
-
}
|
118
|
-
]
|
119
|
-
|
120
|
-
export default config
|
package/src/App.tsx
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
import FormManager from '@/Form/Manage/Manage'
|
2
|
-
import React, { useState, type ReactElement } from 'react'
|
3
|
-
import { BrowserRouter, Route, Routes } from 'react-router-dom'
|
4
|
-
import SetTester from '@/SetTester'
|
5
|
-
import MapTester from '@/Form/MapTester'
|
6
|
-
import SchemaToForm from '@/Form/SchemaToForm'
|
7
|
-
import pagedFormJson from '@/Form/testData/pagedForm.json'
|
8
|
-
import wizardFormJson from '@/Form/testData/wizardForm.json'
|
9
|
-
import { type IForm, type IFormValues } from '@/Form/Creator/FormCreatorTypes'
|
10
|
-
import Form from '@/Form/Creator/FormCreator'
|
11
|
-
|
12
|
-
const PagedFormWrap = (): ReactElement => {
|
13
|
-
const formValueState = useState<IFormValues>({})
|
14
|
-
return (
|
15
|
-
<div>
|
16
|
-
<Form form={pagedFormJson as IForm} formValueState={formValueState} className='p-20' />
|
17
|
-
<pre className='p-20 bg-slate-200 text-xs'>{JSON.stringify(formValueState[0], null, 2)}</pre>
|
18
|
-
</div>
|
19
|
-
)
|
20
|
-
}
|
21
|
-
|
22
|
-
const WizardFormWrap = (): ReactElement => {
|
23
|
-
const formValueState = useState<IFormValues>({})
|
24
|
-
return (
|
25
|
-
<div>
|
26
|
-
<Form form={wizardFormJson as IForm} formValueState={formValueState} className='p-20' />
|
27
|
-
<pre className='p-20 bg-slate-200 text-xs'>{JSON.stringify(formValueState[0], null, 2)}</pre>
|
28
|
-
</div>
|
29
|
-
)
|
30
|
-
}
|
31
|
-
|
32
|
-
const App = (): ReactElement => {
|
33
|
-
return (
|
34
|
-
|
35
|
-
<div className='h-screen flex flex-col gap-4'>
|
36
|
-
<BrowserRouter>
|
37
|
-
<Routes>
|
38
|
-
<Route path='/' element={<FormManager />}>
|
39
|
-
<Route path='*' element={<FormManager />} />
|
40
|
-
</Route>
|
41
|
-
<Route path='/schema-to-form' element={<SchemaToForm />} />
|
42
|
-
<Route path="/set-tester" element={<SetTester />} />
|
43
|
-
<Route path="/map-tester" element={<MapTester />} />
|
44
|
-
<Route path="/page-form/" element={<PagedFormWrap />}>
|
45
|
-
<Route path='*' element={<PagedFormWrap />} />
|
46
|
-
</Route>
|
47
|
-
<Route path='/wizard-form' element={<WizardFormWrap />}>
|
48
|
-
<Route path='*' element={<WizardFormWrap />} />
|
49
|
-
</Route>
|
50
|
-
</Routes>
|
51
|
-
</BrowserRouter>
|
52
|
-
</div>
|
53
|
-
|
54
|
-
)
|
55
|
-
}
|
56
|
-
|
57
|
-
export default App
|
@@ -1,206 +0,0 @@
|
|
1
|
-
import inputMap from '@/Form/Components/Inputs/inputMap'
|
2
|
-
import { type IFormValues, type IFieldInputProps, type IFormField, type IValueChangeFn, type IValueType, type IForm, type IFormValueState } from '@/Form/Creator/FormCreatorTypes'
|
3
|
-
import { checkCondition, cleanUnusedDependenciesFromFormValues, getFieldValue, getPathFromField } from '@/Form/helpers'
|
4
|
-
import { Button, utils } from '@axdspub/axiom-ui-utilities'
|
5
|
-
import { CheckIcon, CopyIcon, Cross1Icon, PlusIcon, TrashIcon } from '@radix-ui/react-icons'
|
6
|
-
import { set } from 'lodash'
|
7
|
-
import React, { useState, type ReactElement } from 'react'
|
8
|
-
|
9
|
-
interface IFieldCreator {
|
10
|
-
field: IFormField
|
11
|
-
form: IForm
|
12
|
-
onChange?: IValueChangeFn
|
13
|
-
className?: string
|
14
|
-
defaultClassName?: string
|
15
|
-
value?: IValueType | IValueType[]
|
16
|
-
formValueState: IFormValueState
|
17
|
-
}
|
18
|
-
|
19
|
-
const toolButtonClass = 'border-white hover:border-single hover:border-1 hover:border-slate-400'
|
20
|
-
|
21
|
-
const DeleteMultiple = ({
|
22
|
-
doDelete
|
23
|
-
}: {
|
24
|
-
doDelete: () => void
|
25
|
-
}): ReactElement => {
|
26
|
-
const [confirm, setConfirm] = useState(false)
|
27
|
-
|
28
|
-
return (
|
29
|
-
<>
|
30
|
-
{
|
31
|
-
confirm
|
32
|
-
? <p className='flex flex-row gap-2 text-sm'><span className='text-slate-600'>Deleting: </span> Are you sure?
|
33
|
-
<Button size='xs' type='submit'
|
34
|
-
onClick={() => {
|
35
|
-
doDelete()
|
36
|
-
setConfirm(false)
|
37
|
-
}}>Yes <CheckIcon className='inline ml-2' />
|
38
|
-
</Button>
|
39
|
-
<Button size='xs' type='alert'
|
40
|
-
onClick={() => {
|
41
|
-
setConfirm(false)
|
42
|
-
}}>Cancel <Cross1Icon className='inline ml-2' />
|
43
|
-
</Button>
|
44
|
-
</p>
|
45
|
-
: <Button size='xs' className={toolButtonClass} onClick={() => { setConfirm(true) }}>
|
46
|
-
Delete <TrashIcon className='inline ml-2 fill-white' />
|
47
|
-
</Button>
|
48
|
-
}
|
49
|
-
</>
|
50
|
-
)
|
51
|
-
}
|
52
|
-
|
53
|
-
const OneOfMultiple = ({
|
54
|
-
InputComponent,
|
55
|
-
field,
|
56
|
-
form,
|
57
|
-
value,
|
58
|
-
index,
|
59
|
-
onChange,
|
60
|
-
values,
|
61
|
-
formValueState
|
62
|
-
|
63
|
-
}: {
|
64
|
-
InputComponent: React.FC<IFieldInputProps>
|
65
|
-
field: IFormField
|
66
|
-
form: IForm
|
67
|
-
value: IValueType
|
68
|
-
index: number
|
69
|
-
onChange: (v: IValueType[] | undefined) => void
|
70
|
-
values: IValueType[]
|
71
|
-
formValueState: [IFormValues, (v: IFormValues) => void]
|
72
|
-
|
73
|
-
}): ReactElement => {
|
74
|
-
const addValue = (v: IValueType | null): void => {
|
75
|
-
const newValues = [...values]
|
76
|
-
newValues.splice(index + 1, 0, v)
|
77
|
-
onChange(newValues)
|
78
|
-
}
|
79
|
-
|
80
|
-
return (
|
81
|
-
<div className='flex flex-col gap-2'>
|
82
|
-
<InputComponent
|
83
|
-
formValueState={formValueState}
|
84
|
-
form={form}
|
85
|
-
field={{
|
86
|
-
...field,
|
87
|
-
required: false,
|
88
|
-
label: index > 0 ? null : field.label,
|
89
|
-
id: `${field.id}-${index}`
|
90
|
-
}}
|
91
|
-
value={value}
|
92
|
-
onChange={(v) => {
|
93
|
-
const newValues = [...values]
|
94
|
-
newValues[index] = v as IValueType
|
95
|
-
onChange(newValues)
|
96
|
-
}}
|
97
|
-
/>
|
98
|
-
|
99
|
-
<div className='flex flex-row justify-between w-full p-2'>
|
100
|
-
{index > 0 && (
|
101
|
-
<DeleteMultiple doDelete={() => {
|
102
|
-
const newValues = [...values]
|
103
|
-
newValues.splice(index, 1)
|
104
|
-
onChange(newValues)
|
105
|
-
}} />
|
106
|
-
)}
|
107
|
-
<div className='ml-auto flex gap-2'>
|
108
|
-
<Button
|
109
|
-
size='xs'
|
110
|
-
className={toolButtonClass}
|
111
|
-
onClick={() => {
|
112
|
-
addValue(null)
|
113
|
-
}}>Add <PlusIcon className='inline ml-2' /></Button>
|
114
|
-
<Button
|
115
|
-
size='xs'
|
116
|
-
className={toolButtonClass}
|
117
|
-
onClick={() => {
|
118
|
-
addValue(structuredClone(value))
|
119
|
-
}}>Duplicate <CopyIcon className='inline ml-2' />
|
120
|
-
</Button>
|
121
|
-
</div>
|
122
|
-
</div>
|
123
|
-
</div>
|
124
|
-
)
|
125
|
-
}
|
126
|
-
|
127
|
-
const MultipleFieldCreator = ({ form, field, onChange, value, formValueState }: IFieldCreator): ReactElement => {
|
128
|
-
const [formValues, setFormValues] = formValueState
|
129
|
-
const defaultOnChange = (v: IValueType[] | undefined): void => {
|
130
|
-
const formValuesCopy = structuredClone(formValues)
|
131
|
-
set(formValuesCopy, getPathFromField(field), v)
|
132
|
-
setFormValues(formValuesCopy)
|
133
|
-
}
|
134
|
-
|
135
|
-
const initialVal = value !== undefined ? value : getFieldValue(field, formValues)
|
136
|
-
const initialValues = (initialVal !== undefined ? (Array.isArray(initialVal) ? initialVal : [initialVal]) : [null])
|
137
|
-
|
138
|
-
/* const initialValues = (
|
139
|
-
formValues[getPathFromField(field)] !== undefined
|
140
|
-
? Array.isArray(formValues[getPathFromField(field)])
|
141
|
-
? formValues[getPathFromField(field)]
|
142
|
-
: [formValues[getPathFromField(field)]]
|
143
|
-
: [null]
|
144
|
-
) as IValueType[] */
|
145
|
-
|
146
|
-
const InputComponent = inputMap[field.type]
|
147
|
-
|
148
|
-
return <div>
|
149
|
-
{
|
150
|
-
initialValues?.map((value, index) => {
|
151
|
-
return <OneOfMultiple
|
152
|
-
formValueState={formValueState}
|
153
|
-
key={`${field.id}-${index}`}
|
154
|
-
InputComponent={InputComponent}
|
155
|
-
form={form}
|
156
|
-
field={field}
|
157
|
-
value={value}
|
158
|
-
index={index}
|
159
|
-
onChange={onChange ?? defaultOnChange}
|
160
|
-
values={initialValues}
|
161
|
-
/>
|
162
|
-
})
|
163
|
-
}
|
164
|
-
</div>
|
165
|
-
}
|
166
|
-
|
167
|
-
const FieldCreator = ({
|
168
|
-
field,
|
169
|
-
form,
|
170
|
-
value,
|
171
|
-
onChange,
|
172
|
-
className,
|
173
|
-
defaultClassName = 'py-2 flex flex-col gap-8',
|
174
|
-
formValueState
|
175
|
-
}: IFieldCreator): ReactElement | null => {
|
176
|
-
const [formValues, setFormValues] = formValueState
|
177
|
-
const InputComponent = inputMap[field.type]
|
178
|
-
|
179
|
-
const updateFormValues = (v: IFormValues): void => {
|
180
|
-
setFormValues(cleanUnusedDependenciesFromFormValues(form, v))
|
181
|
-
}
|
182
|
-
|
183
|
-
if (!checkCondition(field, formValues)) {
|
184
|
-
return null
|
185
|
-
}
|
186
|
-
|
187
|
-
const defaultOnChange = (v: IValueType | IValueType[] | undefined): void => {
|
188
|
-
const formValuesCopy = structuredClone(formValues)
|
189
|
-
set(formValuesCopy, getPathFromField(field), v)
|
190
|
-
updateFormValues(formValuesCopy)
|
191
|
-
}
|
192
|
-
const initialValue = value !== undefined ? value : getFieldValue(field, formValues)
|
193
|
-
return InputComponent !== undefined
|
194
|
-
? <div className={utils.makeClassName({
|
195
|
-
className,
|
196
|
-
defaultClassName
|
197
|
-
})}>{
|
198
|
-
field.multiple === true
|
199
|
-
? <MultipleFieldCreator field={field} form={form} onChange={onChange} value={initialValue} formValueState={formValueState} />
|
200
|
-
: <InputComponent field={field} form={form} onChange={onChange ?? defaultOnChange} value={Array.isArray(initialValue) ? initialValue[0] : initialValue} formValueState={formValueState} />
|
201
|
-
|
202
|
-
}</div>
|
203
|
-
: <p>No component definition for {field.type} ({field.id})</p>
|
204
|
-
}
|
205
|
-
|
206
|
-
export default FieldCreator
|
@@ -1,14 +0,0 @@
|
|
1
|
-
import { type IFormField } from '@/Form/Creator/FormCreatorTypes'
|
2
|
-
import React, { type ReactElement } from 'react'
|
3
|
-
|
4
|
-
export const FieldLabelText = (field: IFormField): ReactElement => {
|
5
|
-
return (
|
6
|
-
<strong>{field.label} { field.required === true ? <span className='text-red-500'>*</span> : ''}</strong>
|
7
|
-
)
|
8
|
-
}
|
9
|
-
|
10
|
-
const FieldLabel = (field: IFormField): ReactElement => {
|
11
|
-
return <p className='pb-2'><FieldLabelText {...field} /></p>
|
12
|
-
}
|
13
|
-
|
14
|
-
export default FieldLabel
|
@@ -1,13 +0,0 @@
|
|
1
|
-
import { FieldLabelText } from '@/Form/Components/FieldLabel'
|
2
|
-
import { type IFieldInputProps } from '@/Form/Creator/FormCreatorTypes'
|
3
|
-
import { Checkbox } from '@axdspub/axiom-ui-utilities'
|
4
|
-
import React, { type ReactElement } from 'react'
|
5
|
-
|
6
|
-
const BooleanInput = ({ field, onChange, value }: IFieldInputProps): ReactElement => {
|
7
|
-
const initialValue = value !== undefined ? value : false
|
8
|
-
return <Checkbox id={field.id} testId={field.id} label={<FieldLabelText {...field} />} value={Boolean(initialValue)} onChange={(e) => {
|
9
|
-
onChange(e)
|
10
|
-
}} />
|
11
|
-
}
|
12
|
-
|
13
|
-
export default BooleanInput
|
@@ -1,111 +0,0 @@
|
|
1
|
-
import FieldLabel from '@/Form/Components/FieldLabel'
|
2
|
-
import { type IFieldInputProps } from '@/Form/Creator/FormCreatorTypes'
|
3
|
-
import React, { type ReactElement, useState, useEffect } from 'react'
|
4
|
-
|
5
|
-
const DateInput = ({ field, onChange, value }: IFieldInputProps): ReactElement => {
|
6
|
-
if (field.type !== 'date') {
|
7
|
-
return <p>Field config for {field.id} is missing 'options'</p>
|
8
|
-
}
|
9
|
-
const [inputValue, setInputValue] = useState('')
|
10
|
-
const [error, setError] = useState<string | null>(null)
|
11
|
-
const { minDate, maxDate } = field.constraints ?? {}
|
12
|
-
|
13
|
-
useEffect(() => {
|
14
|
-
setInputValue(formatValue(value as string))
|
15
|
-
}, [value])
|
16
|
-
|
17
|
-
// Convert the value to the format expected by date input (YYYY-MM-DD)
|
18
|
-
const formatValue = (val: string | undefined | null): string => {
|
19
|
-
if (!val) return ''
|
20
|
-
try {
|
21
|
-
// Ensure the value is in the correct format
|
22
|
-
const date = new Date(val)
|
23
|
-
if (isNaN(date.getTime())) return ''
|
24
|
-
|
25
|
-
// Format to YYYY-MM-DD using UTC to avoid timezone issues
|
26
|
-
const year = date.getUTCFullYear()
|
27
|
-
const month = String(date.getUTCMonth() + 1).padStart(2, '0')
|
28
|
-
const day = String(date.getUTCDate()).padStart(2, '0')
|
29
|
-
|
30
|
-
return `${year}-${month}-${day}`
|
31
|
-
} catch {
|
32
|
-
return ''
|
33
|
-
}
|
34
|
-
}
|
35
|
-
|
36
|
-
const validateDate = (dateStr: string): string | null => {
|
37
|
-
if (!minDate && !maxDate) return null
|
38
|
-
|
39
|
-
const inputDate = new Date(dateStr + 'T00:00:00Z')
|
40
|
-
const minDateObj = minDate ? new Date(minDate) : null
|
41
|
-
const maxDateObj = maxDate ? new Date(maxDate) : null
|
42
|
-
|
43
|
-
if (minDateObj && inputDate < minDateObj) {
|
44
|
-
return `Date must be after ${formatValue(minDate)}`
|
45
|
-
}
|
46
|
-
if (maxDateObj && inputDate > maxDateObj) {
|
47
|
-
return `Date must be before ${formatValue(maxDate)}`
|
48
|
-
}
|
49
|
-
return null
|
50
|
-
}
|
51
|
-
|
52
|
-
const handleChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
53
|
-
const newInputValue = e.target.value
|
54
|
-
setInputValue(newInputValue)
|
55
|
-
|
56
|
-
// Only notify parent of change if we have a complete valid date
|
57
|
-
if (newInputValue) {
|
58
|
-
// Create date in UTC by appending T00:00:00Z to the input value
|
59
|
-
const date = new Date(newInputValue + 'T00:00:00Z')
|
60
|
-
// Check if it's a valid date and the year is reasonable (4 digits)
|
61
|
-
if (!isNaN(date.getTime()) && date.getUTCFullYear() > 999) {
|
62
|
-
const validationError = validateDate(newInputValue)
|
63
|
-
setError(validationError)
|
64
|
-
if (!validationError) {
|
65
|
-
onChange(date.toISOString())
|
66
|
-
}
|
67
|
-
}
|
68
|
-
} else {
|
69
|
-
setError(null)
|
70
|
-
onChange(undefined)
|
71
|
-
}
|
72
|
-
}
|
73
|
-
|
74
|
-
const getConstraintMessage = (): string | null => {
|
75
|
-
if (!minDate && !maxDate) return null
|
76
|
-
const parts = []
|
77
|
-
if (minDate) parts.push(`after ${formatValue(minDate)}`)
|
78
|
-
if (maxDate) parts.push(`before ${formatValue(maxDate)}`)
|
79
|
-
return `Must be ${parts.join(' and ')}`
|
80
|
-
}
|
81
|
-
|
82
|
-
const constraintMessage = getConstraintMessage()
|
83
|
-
|
84
|
-
return (
|
85
|
-
<div>
|
86
|
-
<div className="flex flex-wrap items-baseline gap-2">
|
87
|
-
<label htmlFor={field.id} className="flex-1 min-w-[200px]">
|
88
|
-
<FieldLabel {...field} />
|
89
|
-
</label>
|
90
|
-
{constraintMessage && (
|
91
|
-
<span className="text-sm text-slate-500 italic">
|
92
|
-
{constraintMessage}
|
93
|
-
</span>
|
94
|
-
)}
|
95
|
-
</div>
|
96
|
-
<input
|
97
|
-
id={field.id}
|
98
|
-
className={`border ${error ? 'border-red-500' : 'border-slate-300'} p-2 w-full`}
|
99
|
-
data-testid={field.id}
|
100
|
-
type="date"
|
101
|
-
value={inputValue}
|
102
|
-
onChange={handleChange}
|
103
|
-
min={minDate ? formatValue(minDate) : undefined}
|
104
|
-
max={maxDate ? formatValue(maxDate) : undefined}
|
105
|
-
/>
|
106
|
-
{error && <p className="text-red-500 text-sm mt-1">{error}</p>}
|
107
|
-
</div>
|
108
|
-
)
|
109
|
-
}
|
110
|
-
|
111
|
-
export default DateInput
|