@axdspub/axiom-ui-forms 0.1.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.
Files changed (68) hide show
  1. package/.dockerignore +4 -0
  2. package/.env +1 -0
  3. package/.eslintrc.json +37 -0
  4. package/.gitlab-ci.yml +72 -0
  5. package/.storybook/main.ts +43 -0
  6. package/.storybook/preview.ts +16 -0
  7. package/.vscode/extensions.json +5 -0
  8. package/.vscode/settings.json +10 -0
  9. package/Dockerfile +34 -0
  10. package/README.md +19 -0
  11. package/craco.config.js +42 -0
  12. package/docker/nginx/conf.d/default.conf +46 -0
  13. package/docker-compose.yml +13 -0
  14. package/package.json +103 -0
  15. package/public/exampleForm.json +77 -0
  16. package/public/favicon.ico +0 -0
  17. package/public/index.html +43 -0
  18. package/public/logo192.png +0 -0
  19. package/public/logo512.png +0 -0
  20. package/public/manifest.json +25 -0
  21. package/public/robots.txt +3 -0
  22. package/rollup.config.mjs +108 -0
  23. package/src/App.tsx +25 -0
  24. package/src/Form/Components/FieldCreator.tsx +206 -0
  25. package/src/Form/Components/FieldLabel.tsx +14 -0
  26. package/src/Form/Components/Inputs/Boolean.tsx +13 -0
  27. package/src/Form/Components/Inputs/JSONString.tsx +40 -0
  28. package/src/Form/Components/Inputs/LongString.tsx +22 -0
  29. package/src/Form/Components/Inputs/Number.tsx +22 -0
  30. package/src/Form/Components/Inputs/Object.tsx +56 -0
  31. package/src/Form/Components/Inputs/RadioGroup.tsx +24 -0
  32. package/src/Form/Components/Inputs/SingleSelect.tsx +24 -0
  33. package/src/Form/Components/Inputs/String.tsx +18 -0
  34. package/src/Form/Components/Inputs/index.tsx +6 -0
  35. package/src/Form/Components/Inputs/inputMap.ts +23 -0
  36. package/src/Form/Components/index.tsx +2 -0
  37. package/src/Form/FormCreator.tsx +62 -0
  38. package/src/Form/FormCreatorTypes.ts +187 -0
  39. package/src/Form/FormMappingTypes.ts +17 -0
  40. package/src/Form/Manage/CopyableJSONOutput.tsx +75 -0
  41. package/src/Form/Manage/FormConfigInput.tsx +61 -0
  42. package/src/Form/Manage/FormMappedOutput.tsx +131 -0
  43. package/src/Form/Manage/FormMappingInput.tsx +60 -0
  44. package/src/Form/Manage/Manage.tsx +132 -0
  45. package/src/Form/Manage/RawFormOutput.tsx +20 -0
  46. package/src/Form/MapTester.tsx +107 -0
  47. package/src/Form/SchemaToForm.tsx +348 -0
  48. package/src/Form/formDefinition.json +8 -0
  49. package/src/Form/helpers.ts +85 -0
  50. package/src/Form/index.ts +1 -0
  51. package/src/Form/testData/assetData.json +65 -0
  52. package/src/Form/testData/exampleParticle.json +112 -0
  53. package/src/Form/testData/fields.json +151 -0
  54. package/src/Form/testData/nestedForm.json +156 -0
  55. package/src/Form/testData/testSchema.json +89 -0
  56. package/src/SetTester.tsx +61 -0
  57. package/src/helpers.ts +36 -0
  58. package/src/index.css +39 -0
  59. package/src/index.tsx +19 -0
  60. package/src/library.ts +3 -0
  61. package/src/reportWebVitals.ts +15 -0
  62. package/src/state/formAtom.ts +21 -0
  63. package/src/state/formMappingAtom.ts +21 -0
  64. package/src/state/formValuesAtom.ts +22 -0
  65. package/src/types/generate-schema.d.ts +8 -0
  66. package/tailwind.config.js +11 -0
  67. package/tsconfig.json +32 -0
  68. package/tsconfig.paths.json +19 -0
@@ -0,0 +1,112 @@
1
+ {
2
+ "label": "New Form",
3
+ "id": "newForm",
4
+ "fields": [
5
+ {
6
+ "id": "title",
7
+ "label": "Title",
8
+ "type": "text",
9
+ "required": true
10
+ },
11
+ {
12
+ "id": "scenario",
13
+ "label": "Scenario",
14
+ "type": "select",
15
+ "required": true,
16
+ "options": [
17
+ { "label": "Larval Fish", "value": "larval_fish" },
18
+ { "label": "Search and Rescue", "value": "search_and_rescue" },
19
+ { "label": "Oil Spill", "value": "oil_spill" },
20
+ { "label": "Physics", "value": "physics" }
21
+ ]
22
+ },
23
+ {
24
+ "id": "hatched",
25
+ "label": "Hatched",
26
+ "type": "boolean",
27
+ "conditions": { "dependsOn": "scenario", "value": "larval_fish" }
28
+ },
29
+ {
30
+ "id": "emulsification",
31
+ "label": "Emulsification",
32
+ "type": "boolean",
33
+ "conditions": { "dependsOn": "scenario", "value": "oil_spill" }
34
+ },
35
+ {
36
+ "id": "dispersion",
37
+ "label": "Dispersion",
38
+ "type": "boolean",
39
+ "conditions": { "dependsOn": "scenario", "value": "oil_spill" }
40
+ },
41
+ {
42
+ "id": "evaporation",
43
+ "label": "Evaporation",
44
+ "type": "boolean",
45
+ "conditions": { "dependsOn": "scenario", "value": "oil_spill" }
46
+ },
47
+ {
48
+ "id": "update_oil_film_thickness",
49
+ "label": "Update Oil Film Thickness",
50
+ "type": "boolean",
51
+ "conditions": { "dependsOn": "scenario", "value": "oil_spill" }
52
+ },
53
+ {
54
+ "id": "biodegradation",
55
+ "label": "Biodegradation",
56
+ "type": "boolean",
57
+ "conditions": { "dependsOn": "scenario", "value": "oil_spill" }
58
+ },
59
+ {
60
+ "id": "object_type",
61
+ "label": "Object Type",
62
+ "type": "select",
63
+ "required": true,
64
+ "conditions": { "dependsOn": "scenario", "value": "search_and_rescue" },
65
+ "options": [
66
+ { "label": "Person", "value": "person" },
67
+ { "label": "Boat", "value": "boat" },
68
+ { "label": "Aircraft", "value": "aircraft" },
69
+ { "label": "Vehicle", "value": "vehicle" }
70
+ ]
71
+ },
72
+ {
73
+ "id": "test_section",
74
+ "label": "Test Section",
75
+ "type": "object",
76
+ "skip_path": true,
77
+ "conditions": { "dependsOn": "scenario", "value": "oil_spill" },
78
+ "fields": [
79
+ {
80
+ "id": "test_field",
81
+ "label": "Test Field",
82
+ "type": "text"
83
+ },
84
+ {
85
+ "id": "test_field_2",
86
+ "label": "Something about biodegradation",
87
+ "description": "This field won't get cleaned up when we change from oil",
88
+ "type": "text",
89
+ "conditions": {
90
+ "dependsOn": "biodegradation"
91
+ }
92
+
93
+ },
94
+ {
95
+ "id": "sub_container",
96
+ "type": "object",
97
+ "skip_path": true,
98
+ "label": "Sub Container",
99
+ "fields": [
100
+ {
101
+ "id": "sub_sub_field",
102
+ "label": "Sub Field",
103
+ "type": "text"
104
+ }
105
+ ]
106
+ }
107
+ ]
108
+ }
109
+ ]
110
+ }
111
+
112
+
@@ -0,0 +1,151 @@
1
+ [
2
+ {
3
+ "id": "short",
4
+ "label": "Test component",
5
+ "type": "text",
6
+ "required": false
7
+ },
8
+ {
9
+ "id": "long",
10
+ "label": "Long string component",
11
+ "type": "long_text",
12
+ "required": false,
13
+ "multiple": false
14
+ },
15
+ {
16
+ "id": "description",
17
+ "label": "Description",
18
+ "type": "long_text",
19
+ "required": false
20
+ },
21
+ {
22
+ "id": "agree",
23
+ "label": "Do u agree?",
24
+ "type": "boolean",
25
+ "required": true
26
+ },
27
+ {
28
+ "label": "Select one",
29
+ "id": "color",
30
+ "type": "select",
31
+ "required": true,
32
+ "multiple": false,
33
+ "options": [
34
+ {
35
+ "label": "Red",
36
+ "value": "red"
37
+ },
38
+ {
39
+ "label": "Green",
40
+ "value": "green"
41
+ },
42
+ {
43
+ "label": "Blue",
44
+ "value": "blue"
45
+ }
46
+ ]
47
+ },
48
+ {
49
+ "label": "Pick a size",
50
+ "id": "size",
51
+ "type": "radio",
52
+ "required": false,
53
+ "layout": "vertical",
54
+ "multiple": true,
55
+ "options": [
56
+ {
57
+ "label": "Small",
58
+ "value": "small"
59
+ },
60
+ {
61
+ "label": "Medium",
62
+ "value": "medium"
63
+ },
64
+ {
65
+ "label": "Large",
66
+ "value": "large"
67
+ }
68
+ ]
69
+ },
70
+ {
71
+ "label": "Address",
72
+ "id": "address",
73
+ "type": "object",
74
+ "required": true,
75
+ "layout": "vertical",
76
+ "multiple": true,
77
+ "fields": [
78
+ {
79
+ "id": "street",
80
+ "label": "Street",
81
+ "type": "text",
82
+ "required": true
83
+ },
84
+ {
85
+ "id": "city_state_zip",
86
+ "type": "object",
87
+ "required": false,
88
+ "layout": "horizontal",
89
+ "label": "",
90
+ "fields": [
91
+ {
92
+ "id": "city",
93
+ "label": "City",
94
+ "type": "text",
95
+ "required": true
96
+ },
97
+ {
98
+ "id": "state",
99
+ "label": "State",
100
+ "type": "text",
101
+ "required": true
102
+ },
103
+ {
104
+ "id": "zip",
105
+ "label": "Zip",
106
+ "type": "text",
107
+ "required": true
108
+ }
109
+ ]
110
+ },
111
+ {
112
+ "id": "notes",
113
+ "label": "Notes",
114
+ "type": "text",
115
+ "multiple": true
116
+ },
117
+ {
118
+ "id": "family",
119
+ "label": "Family members",
120
+ "type": "object",
121
+ "multiple": true,
122
+ "fields": [
123
+ {
124
+ "id": "name",
125
+ "label": "Name",
126
+ "type": "object",
127
+ "layout": "horizontal",
128
+ "fields": [
129
+ {
130
+ "id": "firstName",
131
+ "label": "First name",
132
+ "type": "text"
133
+ },
134
+ {
135
+ "id": "lastName",
136
+ "label": "Last name",
137
+ "type": "text"
138
+ }
139
+ ]
140
+ },
141
+ {
142
+ "id": "age",
143
+ "label": "Age",
144
+ "type": "text",
145
+ "required": true
146
+ }
147
+ ]
148
+ }
149
+ ]
150
+ }
151
+ ]
@@ -0,0 +1,156 @@
1
+ {
2
+ "label": "Nested test form",
3
+ "id": "nestedTestForm",
4
+ "fields": [
5
+ {
6
+ "id": "short",
7
+ "label": "Test component",
8
+ "type": "text",
9
+ "required": false
10
+ },
11
+ {
12
+ "id": "long",
13
+ "label": "Long string component",
14
+ "type": "long_text",
15
+ "required": false,
16
+ "multiple": false
17
+ },
18
+ {
19
+ "id": "description",
20
+ "label": "Description",
21
+ "type": "long_text",
22
+ "required": false
23
+ },
24
+ {
25
+ "id": "agree",
26
+ "label": "Do u agree?",
27
+ "type": "boolean",
28
+ "required": true
29
+ },
30
+ {
31
+ "label": "Select one",
32
+ "id": "color",
33
+ "type": "select",
34
+ "required": true,
35
+ "multiple": false,
36
+ "options": [
37
+ {
38
+ "label": "Red",
39
+ "value": "red"
40
+ },
41
+ {
42
+ "label": "Green",
43
+ "value": "green"
44
+ },
45
+ {
46
+ "label": "Blue",
47
+ "value": "blue"
48
+ }
49
+ ]
50
+ },
51
+ {
52
+ "label": "Pick a size",
53
+ "id": "size",
54
+ "type": "radio",
55
+ "required": false,
56
+ "layout": "vertical",
57
+ "multiple": true,
58
+ "options": [
59
+ {
60
+ "label": "Small",
61
+ "value": "small"
62
+ },
63
+ {
64
+ "label": "Medium",
65
+ "value": "medium"
66
+ },
67
+ {
68
+ "label": "Large",
69
+ "value": "large"
70
+ }
71
+ ]
72
+ },
73
+ {
74
+ "label": "Address",
75
+ "id": "address",
76
+ "type": "object",
77
+ "required": true,
78
+ "layout": "vertical",
79
+ "multiple": true,
80
+ "fields": [
81
+ {
82
+ "id": "street",
83
+ "label": "Street",
84
+ "type": "text",
85
+ "required": true
86
+ },
87
+ {
88
+ "id": "city_state_zip",
89
+ "type": "object",
90
+ "required": false,
91
+ "layout": "horizontal",
92
+ "label": "",
93
+ "fields": [
94
+ {
95
+ "id": "city",
96
+ "label": "City",
97
+ "type": "text",
98
+ "required": true
99
+ },
100
+ {
101
+ "id": "state",
102
+ "label": "State",
103
+ "type": "text",
104
+ "required": true
105
+ },
106
+ {
107
+ "id": "zip",
108
+ "label": "Zip",
109
+ "type": "text",
110
+ "required": true
111
+ }
112
+ ]
113
+ },
114
+ {
115
+ "id": "notes",
116
+ "label": "Notes",
117
+ "type": "text",
118
+ "multiple": true
119
+ },
120
+ {
121
+ "id": "family",
122
+ "label": "Family members",
123
+ "type": "object",
124
+ "multiple": true,
125
+ "fields": [
126
+ {
127
+ "id": "name",
128
+ "label": "Name",
129
+ "type": "object",
130
+ "layout": "horizontal",
131
+ "fields": [
132
+ {
133
+ "id": "firstName",
134
+ "label": "First name",
135
+ "type": "text"
136
+ },
137
+ {
138
+ "id": "lastName",
139
+ "label": "Last name",
140
+ "type": "text"
141
+ }
142
+ ]
143
+ },
144
+ {
145
+ "id": "age",
146
+ "label": "Age",
147
+ "type": "text",
148
+ "required": true
149
+ }
150
+ ]
151
+ }
152
+ ]
153
+ }
154
+ ]
155
+
156
+ }
@@ -0,0 +1,89 @@
1
+ {
2
+ "$id": "/axds/test.schema.json",
3
+ "type": "object",
4
+ "required": [ "short", "long", "size" ],
5
+ "properties": {
6
+ "short":{
7
+ "type": "string",
8
+ "maxLength": 100
9
+ },
10
+ "long": {
11
+ "type": "string"
12
+ },
13
+ "description": {
14
+ "type": "string"
15
+ },
16
+ "agree": {
17
+ "type": "boolean"
18
+ },
19
+ "color": {
20
+ "type": "string",
21
+ "enum": [
22
+ {"const": "red"},
23
+ {"const": "blue"},
24
+ {"const": "green"}
25
+ ]
26
+ },
27
+ "size": {
28
+ "type": "array",
29
+ "items": {
30
+ "type": "string",
31
+ "enum": [
32
+ {"const": "small"},
33
+ {"const": "medium"},
34
+ {"const": "large"}
35
+ ]
36
+ }
37
+ },
38
+ "address": {
39
+ "type": "array",
40
+ "items": {
41
+ "type": "object",
42
+ "properties": {
43
+ "street": {
44
+ "type": "string",
45
+ "maxLength": 100
46
+ },
47
+ "city": {
48
+ "type": "string",
49
+ "maxLength": 100
50
+ },
51
+ "state": {
52
+ "type": "string",
53
+ "maxLength": 20
54
+ },
55
+ "zip": {
56
+ "type": "string",
57
+ "maxLength": 20
58
+ },
59
+ "notes": {
60
+ "type": "array",
61
+ "items": {
62
+ "type": "string"
63
+ }
64
+ },
65
+ "family": {
66
+ "type": "array",
67
+ "items": {
68
+ "type": "object",
69
+ "properties": {
70
+ "firstName": {
71
+ "type": "string",
72
+ "maxLength": 100
73
+ },
74
+ "lastname": {
75
+ "type": "string",
76
+ "maxLength": 100
77
+ },
78
+ "age": {
79
+ "type": "integer"
80
+ }
81
+ }
82
+ }
83
+ }
84
+ }
85
+ }
86
+ }
87
+
88
+ }
89
+ }
@@ -0,0 +1,61 @@
1
+ import { TextArea } from '@axdspub/axiom-ui-utilities'
2
+ import { set, isArray, isObject } from 'lodash'
3
+ import React, { type ReactElement, useEffect, useState } from 'react'
4
+
5
+ function flattenObjectToPaths (obj: any, prefix: string = ''): Record<string, any> {
6
+ return Object.keys(obj).reduce((acc: Record<string, any>, key) => {
7
+ const value = obj[key]
8
+ const newKey = prefix.length > 0 ? `${prefix}.${key}` : key
9
+
10
+ if (isObject(value) && !isArray(value)) {
11
+ Object.assign(acc, flattenObjectToPaths(value, newKey))
12
+ } else {
13
+ acc[newKey] = value
14
+ }
15
+
16
+ return acc
17
+ }, {})
18
+ }
19
+
20
+ const SetTester = (): ReactElement => {
21
+ const [vals, setVals] = useState('')
22
+ const [paths, setPaths] = useState('')
23
+ const [out, setOut] = useState({})
24
+ useEffect(() => {
25
+ const newOut = {}
26
+ const pathsToEval = paths.split('\n')
27
+ const valsToEval = vals.split('\n')
28
+ pathsToEval.forEach((path, i) => {
29
+ set(newOut, path.replace(/\s+/g, ''), valsToEval[i] ?? '')
30
+ })
31
+ setOut(newOut)
32
+ }, [paths, vals])
33
+ return (
34
+ <div className='p-20'>
35
+ <h1 className='font-bold font-xl mb-4'>Set Tester</h1>
36
+ <div className='flex flex-col gap-4'>
37
+ <TextArea id='value' testId='value' label='Value' value={vals} onChange={(e) => {
38
+ setVals(e ?? '')
39
+ }} />
40
+ <TextArea id='path' testId='path' label='Path' value={paths} onChange={(e) => {
41
+ setPaths(e ?? '')
42
+ }} />
43
+ <div>
44
+ <p>Output</p>
45
+ <pre className='p-10 bg-slate-200'>
46
+ {JSON.stringify(out, null, 2)}
47
+ </pre>
48
+ <div>
49
+ <p>Reverse</p>
50
+ <pre className='p-10 bg-slate-200'>
51
+ {JSON.stringify(flattenObjectToPaths(out), null, 2)}
52
+ </pre>
53
+
54
+ </div>
55
+ </div>
56
+ </div>
57
+ </div>
58
+ )
59
+ }
60
+
61
+ export default SetTester
package/src/helpers.ts ADDED
@@ -0,0 +1,36 @@
1
+ import { type IValueType, type IFormValues } from '@/Form/FormCreatorTypes'
2
+ import { decode, encode } from 'cbor-x'
3
+
4
+ export function jsonToBase64<T = JSON> (json: T): string {
5
+ const buffer = encode(json)
6
+ // https://github.com/hildjj/cbor2/blob/ef0e9f710a2a1c1be7c6c8c3b3665998b51921bc/web/src/encode.js#L15
7
+ const binString = Array.from(buffer, byte => String.fromCodePoint(byte)).join('')
8
+ return btoa(binString)
9
+ }
10
+
11
+ export function base64ToJson<T = JSON> (base64: string): T {
12
+ const decodedBinString = atob(base64)
13
+ const decodedBuffer = new Uint8Array(decodedBinString.split('').map(char => char.codePointAt(0) as number))
14
+ return decode(decodedBuffer) as T
15
+ }
16
+
17
+ export function updateUrlParam (param: string, value?: string | boolean | number | null): void {
18
+ const u = new URL(window.location.href)
19
+ if (value === null || value === undefined) {
20
+ u.searchParams.delete(param)
21
+ } else {
22
+ u.searchParams.set(param, String(value))
23
+ }
24
+ window.history.replaceState({}, '', u.toString())
25
+ }
26
+
27
+ export function getQueryParam (param: string): string | null {
28
+ const u = new URL(window.location.href)
29
+ return u.searchParams.get(param)
30
+ }
31
+
32
+ export function typeToFormValues (m: any = {}): IFormValues {
33
+ return Object.fromEntries(Object.keys(m).map(k => {
34
+ return [String(k), m[k] as IValueType]
35
+ }))
36
+ }
package/src/index.css ADDED
@@ -0,0 +1,39 @@
1
+ @tailwind base;
2
+
3
+
4
+ /**
5
+ From: https://scottspence.com/posts/change-scrollbar-color-tailwind-css
6
+ tailwind-scrollbar is still installed and can be used
7
+ -w-* and -rounded-* don't seem to work with tailwind-scrollbar
8
+ **/
9
+
10
+ /* Firefox */
11
+ body * {
12
+ scrollbar-width: thin;
13
+ scrollbar-color: #CCC;
14
+ }
15
+
16
+ /* Chrome, Edge, and Safari */
17
+ body *::-webkit-scrollbar {
18
+ width: 8px;
19
+ height: 8px;
20
+ }
21
+
22
+ body *::-webkit-scrollbar-track {
23
+ background: #EDEDED;
24
+ border-radius: 5px;
25
+ }
26
+
27
+ body *::-webkit-scrollbar-thumb {
28
+ background-color: #999;
29
+ border-radius: 14px;
30
+ border: 0px solid #999;
31
+ }
32
+
33
+ #root {
34
+ height: calc(100vh);
35
+ width: calc(100vw);
36
+ }
37
+
38
+ @tailwind components;
39
+ @tailwind utilities;
package/src/index.tsx ADDED
@@ -0,0 +1,19 @@
1
+ import React from 'react'
2
+ import ReactDOM from 'react-dom/client'
3
+ import App from './App'
4
+ import './index.css'
5
+ // import reportWebVitals from './reportWebVitals'
6
+
7
+ const root = ReactDOM.createRoot(
8
+ document.getElementById('root') as HTMLElement
9
+ )
10
+ root.render(
11
+ <React.StrictMode>
12
+ <App />
13
+ </React.StrictMode>
14
+ )
15
+
16
+ // If you want to start measuring performance in your app, pass a function
17
+ // to log results (for example: reportWebVitals(console.log))
18
+ // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
19
+ // reportWebVitals(console.log).then(() => { }).catch(e => { console.log(e) })
package/src/library.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from '@/Form'
2
+ export * from '@/Form/Components'
3
+ export * from '@/Form/FormCreatorTypes'
@@ -0,0 +1,15 @@
1
+ import { type ReportHandler } from 'web-vitals'
2
+
3
+ const reportWebVitals = async (onPerfEntry?: ReportHandler): Promise<void> => {
4
+ if ((onPerfEntry != null) && onPerfEntry instanceof Function) {
5
+ await import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
6
+ getCLS(onPerfEntry)
7
+ getFID(onPerfEntry)
8
+ getFCP(onPerfEntry)
9
+ getLCP(onPerfEntry)
10
+ getTTFB(onPerfEntry)
11
+ })
12
+ }
13
+ }
14
+
15
+ export default reportWebVitals