@sijanbhattarai/veda-utils 1.0.35
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/dist/ChartContext.d.ts +13 -0
- package/dist/CreateInterface.d.ts +25 -0
- package/dist/MapContext.d.ts +13 -0
- package/dist/content.d.ts +15 -0
- package/dist/data.d.ts +6 -0
- package/dist/extractImports.d.ts +1 -0
- package/dist/groupElements.d.ts +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +1625 -0
- package/dist/index.js.map +1 -0
- package/dist/index.umd.js +32 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/inputValidation.d.ts +6 -0
- package/dist/lib/index.d.ts +9 -0
- package/dist/parseTwoColumn.d.ts +1 -0
- package/dist/reserializeMDast.d.ts +1 -0
- package/dist/wrapComponent.d.ts +6 -0
- package/package.json +59 -0
- package/src/ChartContext.tsx +29 -0
- package/src/CreateInterface.tsx +300 -0
- package/src/MapContext.tsx +29 -0
- package/src/content.tsx +18 -0
- package/src/data.tsx +36 -0
- package/src/extractImports.tsx +45 -0
- package/src/groupElements.tsx +90 -0
- package/src/index.ts +13 -0
- package/src/inputValidation.tsx +148 -0
- package/src/lib/index.ts +89 -0
- package/src/parseTwoColumn.tsx +26 -0
- package/src/reserializeMDast.tsx +107 -0
- package/src/wrapComponent.tsx +25 -0
- package/tsconfig.json +25 -0
- package/vite.config.ts +50 -0
@@ -0,0 +1,300 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import React, { useEffect, useRef, useState } from 'react';
|
4
|
+
|
5
|
+
import {
|
6
|
+
TextInput,
|
7
|
+
TextInputMask,
|
8
|
+
Textarea,
|
9
|
+
Label,
|
10
|
+
DatePicker,
|
11
|
+
Checkbox,
|
12
|
+
Select,
|
13
|
+
} from '@trussworks/react-uswds';
|
14
|
+
import {
|
15
|
+
handleMapDateValidation,
|
16
|
+
handleMapArrayValidation,
|
17
|
+
handleChartDateValidation,
|
18
|
+
} from './inputValidation';
|
19
|
+
|
20
|
+
interface FieldProps {
|
21
|
+
fieldName: string;
|
22
|
+
value: string;
|
23
|
+
hint?: string;
|
24
|
+
onChange: (value: string) => void;
|
25
|
+
isRequired?: boolean;
|
26
|
+
isDate?: boolean;
|
27
|
+
numeric?: boolean;
|
28
|
+
onBlur?: (value: string) => void;
|
29
|
+
onFocus?: (value: string) => void;
|
30
|
+
type?: string;
|
31
|
+
componentProps: any;
|
32
|
+
propName: string;
|
33
|
+
customClass?: string;
|
34
|
+
placeHolder?: string;
|
35
|
+
draftInputs?: any;
|
36
|
+
inputErrors?: any;
|
37
|
+
setDraftInputs?: (value: any) => void;
|
38
|
+
setInputErrors?: (value: any) => void;
|
39
|
+
options?: string[];
|
40
|
+
}
|
41
|
+
const checkRequired = (isRequired, value) => {
|
42
|
+
return isRequired && !value ? { validationStatus: 'error' } : '';
|
43
|
+
};
|
44
|
+
|
45
|
+
const colorSchemes = [
|
46
|
+
'Blues',
|
47
|
+
'Greens',
|
48
|
+
'Greys',
|
49
|
+
'Oranges',
|
50
|
+
'Purples',
|
51
|
+
'Reds',
|
52
|
+
'Turbo',
|
53
|
+
'Viridis',
|
54
|
+
'Inferno',
|
55
|
+
'Magma',
|
56
|
+
'Plasma',
|
57
|
+
'Cividis',
|
58
|
+
'Warm',
|
59
|
+
'Cool',
|
60
|
+
'CubehelixDefault',
|
61
|
+
];
|
62
|
+
|
63
|
+
const setInput = (props) => {
|
64
|
+
const {
|
65
|
+
value,
|
66
|
+
isRequired,
|
67
|
+
type,
|
68
|
+
fieldName,
|
69
|
+
hint,
|
70
|
+
onChange,
|
71
|
+
componentProps,
|
72
|
+
propName,
|
73
|
+
placeHolder,
|
74
|
+
validateAgainst,
|
75
|
+
draftInputs,
|
76
|
+
setDraftInputs,
|
77
|
+
inputErrors,
|
78
|
+
setInputErrors,
|
79
|
+
options,
|
80
|
+
} = props;
|
81
|
+
|
82
|
+
if (options && Array.isArray(options)) {
|
83
|
+
return (
|
84
|
+
<>
|
85
|
+
<Label htmlFor={propName} className='margin-top-2'>
|
86
|
+
{fieldName}
|
87
|
+
</Label>
|
88
|
+
<span className='usa-hint'>{hint}</span>
|
89
|
+
<Select
|
90
|
+
id={propName}
|
91
|
+
name={propName}
|
92
|
+
value={value}
|
93
|
+
onChange={(e) =>
|
94
|
+
onChange({ ...componentProps, [propName]: e.target.value })
|
95
|
+
}
|
96
|
+
{...checkRequired(isRequired, value)}
|
97
|
+
>
|
98
|
+
<option value=''>- Select option -</option>
|
99
|
+
{options.map((option) => {
|
100
|
+
// Check if option is a string or an object with value/label
|
101
|
+
const value = typeof option === 'object' ? option.value : option;
|
102
|
+
const label = typeof option === 'object' ? option.label : option;
|
103
|
+
|
104
|
+
return (
|
105
|
+
<option key={value} value={value}>
|
106
|
+
{label}
|
107
|
+
</option>
|
108
|
+
);
|
109
|
+
})}
|
110
|
+
</Select>
|
111
|
+
</>
|
112
|
+
);
|
113
|
+
}
|
114
|
+
|
115
|
+
const cleanedType = type !== undefined && type.toLowerCase();
|
116
|
+
|
117
|
+
const [draft, setDraft] = useState(value);
|
118
|
+
|
119
|
+
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
120
|
+
|
121
|
+
useEffect(() => {
|
122
|
+
|
123
|
+
if (propName === 'dateFormat' && draft != draftInputs.draftDateFormat) {
|
124
|
+
setDraftInputs({ ...draftInputs, draftDateFormat: draft });
|
125
|
+
}
|
126
|
+
if (
|
127
|
+
propName === 'highlightStart' &&
|
128
|
+
draft != draftInputs.draftHighlightStart
|
129
|
+
) {
|
130
|
+
setDraftInputs({ ...draftInputs, draftHighlightStart: draft });
|
131
|
+
}
|
132
|
+
if (propName === 'highlightEnd' && draft != draftInputs.draftHighlightEnd) {
|
133
|
+
setDraftInputs({ ...draftInputs, draftHighlightEnd: draft });
|
134
|
+
}
|
135
|
+
clearTimeout(timeoutRef.current);
|
136
|
+
timeoutRef.current = setTimeout(() => {
|
137
|
+
|
138
|
+
if (validateAgainst) {
|
139
|
+
if (
|
140
|
+
propName === 'dateFormat' ||
|
141
|
+
propName === 'highlightStart' ||
|
142
|
+
propName === 'highlightEnd'
|
143
|
+
) {
|
144
|
+
handleChartDateValidation(
|
145
|
+
propName,
|
146
|
+
draftInputs,
|
147
|
+
setInputErrors,
|
148
|
+
inputErrors,
|
149
|
+
draft,
|
150
|
+
onChange,
|
151
|
+
componentProps,
|
152
|
+
);
|
153
|
+
} else if (validateAgainst === 'defaultDateFormat') {
|
154
|
+
handleMapDateValidation(
|
155
|
+
propName,
|
156
|
+
draftInputs,
|
157
|
+
inputErrors,
|
158
|
+
setInputErrors,
|
159
|
+
draft,
|
160
|
+
onChange,
|
161
|
+
componentProps,
|
162
|
+
);
|
163
|
+
} else if (validateAgainst === 'centerFormat') {
|
164
|
+
handleMapArrayValidation(
|
165
|
+
propName,
|
166
|
+
draftInputs,
|
167
|
+
inputErrors,
|
168
|
+
setInputErrors,
|
169
|
+
draft,
|
170
|
+
onChange,
|
171
|
+
componentProps,
|
172
|
+
);
|
173
|
+
} else {
|
174
|
+
onChange({ ...componentProps, [propName]: draft });
|
175
|
+
}
|
176
|
+
}
|
177
|
+
}, 400);
|
178
|
+
|
179
|
+
return () => clearTimeout(timeoutRef.current);
|
180
|
+
}, [draft, draftInputs]);
|
181
|
+
|
182
|
+
//Format date and submitted dates need to work or else the chart will throw an error.
|
183
|
+
|
184
|
+
switch (cleanedType) {
|
185
|
+
case 'date':
|
186
|
+
return (
|
187
|
+
//CHORE: Need to clean up or delete
|
188
|
+
<>
|
189
|
+
<Label htmlFor='input-type-text' className='margin-top-2'>
|
190
|
+
{fieldName}
|
191
|
+
</Label>
|
192
|
+
|
193
|
+
<span className='usa-hint'>{hint}</span>
|
194
|
+
|
195
|
+
<DatePicker
|
196
|
+
defaultValue={value}
|
197
|
+
onChange={(e) => console.log('DatePicker', e)}
|
198
|
+
{...checkRequired(isRequired, value)}
|
199
|
+
/>
|
200
|
+
</>
|
201
|
+
);
|
202
|
+
break;
|
203
|
+
case 'checkbox':
|
204
|
+
return (
|
205
|
+
<Checkbox
|
206
|
+
id={fieldName}
|
207
|
+
name='checkbox'
|
208
|
+
label={fieldName}
|
209
|
+
onChange={(e) =>
|
210
|
+
onChange({ ...componentProps, [propName]: e.target.value })
|
211
|
+
}
|
212
|
+
/>
|
213
|
+
);
|
214
|
+
break;
|
215
|
+
case 'select':
|
216
|
+
return (
|
217
|
+
<>
|
218
|
+
<Label htmlFor='input-type-text' className='margin-top-2'>
|
219
|
+
{fieldName}
|
220
|
+
</Label>
|
221
|
+
<span className='usa-hint'>{hint}</span>
|
222
|
+
<Select
|
223
|
+
id={fieldName}
|
224
|
+
name={fieldName}
|
225
|
+
onChange={(e) =>
|
226
|
+
onChange({ ...componentProps, [propName]: e.target.value })
|
227
|
+
}
|
228
|
+
>
|
229
|
+
{colorSchemes.map((scheme) => {
|
230
|
+
return (
|
231
|
+
<option key={scheme} value={scheme}>
|
232
|
+
{scheme}
|
233
|
+
</option>
|
234
|
+
);
|
235
|
+
})}
|
236
|
+
</Select>
|
237
|
+
</>
|
238
|
+
);
|
239
|
+
break;
|
240
|
+
case 'area':
|
241
|
+
return (
|
242
|
+
<>
|
243
|
+
<Label htmlFor='input-type-text' className='margin-top-2'>
|
244
|
+
{fieldName}
|
245
|
+
</Label>
|
246
|
+
<span className='usa-hint'>{hint}</span>
|
247
|
+
<Textarea
|
248
|
+
id='input-type-text'
|
249
|
+
name='input-type-text'
|
250
|
+
value={value}
|
251
|
+
onChange={(e) => {
|
252
|
+
onChange({ ...componentProps, [propName]: e.target.value });
|
253
|
+
}}
|
254
|
+
className=''
|
255
|
+
{...checkRequired(isRequired, value)}
|
256
|
+
/>
|
257
|
+
</>
|
258
|
+
);
|
259
|
+
break;
|
260
|
+
default:
|
261
|
+
return (
|
262
|
+
<>
|
263
|
+
<Label htmlFor='input-type-text' className='margin-top-2'>
|
264
|
+
{fieldName}
|
265
|
+
</Label>
|
266
|
+
|
267
|
+
<span className='usa-hint'>{hint}</span>
|
268
|
+
<TextInput
|
269
|
+
id='input-type-text'
|
270
|
+
name='input-type-text'
|
271
|
+
type='text'
|
272
|
+
value={validateAgainst ? draft : value}
|
273
|
+
onChange={(e) => {
|
274
|
+
if (validateAgainst) {
|
275
|
+
|
276
|
+
setDraft(e.target.value);
|
277
|
+
} else {
|
278
|
+
|
279
|
+
onChange({ ...componentProps, [propName]: e.target.value });
|
280
|
+
}
|
281
|
+
}}
|
282
|
+
placeholder={placeHolder}
|
283
|
+
{...checkRequired(isRequired, value)}
|
284
|
+
validationStatus={
|
285
|
+
validateAgainst && (inputErrors[propName] ? 'error' : undefined)
|
286
|
+
}
|
287
|
+
/>
|
288
|
+
</>
|
289
|
+
);
|
290
|
+
}
|
291
|
+
};
|
292
|
+
export const InputField: React.FC<FieldProps> = (props) => {
|
293
|
+
const { propName, customClass } = props;
|
294
|
+
|
295
|
+
return (
|
296
|
+
<div key={propName} className={customClass}>
|
297
|
+
{setInput(props)}
|
298
|
+
</div>
|
299
|
+
);
|
300
|
+
};
|
@@ -0,0 +1,29 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import React, { createContext, useContext } from 'react';
|
4
|
+
import { LexicalEditor, LexicalNode } from 'lexical';
|
5
|
+
|
6
|
+
interface MapContextValue {
|
7
|
+
parentEditor: LexicalEditor;
|
8
|
+
lexicalNode: LexicalNode;
|
9
|
+
}
|
10
|
+
|
11
|
+
const MapContext = createContext<MapContextValue | null>(null);
|
12
|
+
|
13
|
+
export const MapContextProvider = ({
|
14
|
+
children,
|
15
|
+
value,
|
16
|
+
}: {
|
17
|
+
children: React.ReactNode;
|
18
|
+
value: MapContextValue;
|
19
|
+
}) => {
|
20
|
+
return <MapContext.Provider value={value}>{children}</MapContext.Provider>;
|
21
|
+
};
|
22
|
+
|
23
|
+
export const useMapContext = () => {
|
24
|
+
const context = useContext(MapContext);
|
25
|
+
if (!context) {
|
26
|
+
throw new Error('useMapContext must be used within a MapContextProvider');
|
27
|
+
}
|
28
|
+
return context;
|
29
|
+
};
|
package/src/content.tsx
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
import type { DatasetData, StoryData } from './lib';
|
2
|
+
|
3
|
+
interface MetadataWithSlug<T> {
|
4
|
+
metadata: T;
|
5
|
+
slug: string;
|
6
|
+
}
|
7
|
+
|
8
|
+
interface WithContent<T> extends MetadataWithSlug<T> {
|
9
|
+
content: string;
|
10
|
+
}
|
11
|
+
|
12
|
+
export type DatasetMetadata = MetadataWithSlug<DatasetData>;
|
13
|
+
export type DatasetWithContent = WithContent<DatasetData>;
|
14
|
+
|
15
|
+
export type StoryMetadata = MetadataWithSlug<StoryData>;
|
16
|
+
export type StoryWithContent = WithContent<StoryData>;
|
17
|
+
|
18
|
+
export type ContentMetadata = MetadataWithSlug<DatasetData | StoryData>;
|
package/src/data.tsx
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
import type { DatasetData, StoryData, VedaData } from '@lib';
|
2
|
+
import type { DatasetMetadata, DatasetWithContent } from './content';
|
3
|
+
|
4
|
+
export function processTaxonomies(data): DatasetData | StoryData {
|
5
|
+
const updatedTax = data.taxonomy.map((t) => {
|
6
|
+
const updatedVals = t.values.map((v) => {
|
7
|
+
return {
|
8
|
+
id: v.replace(/ /g, '_').toLowerCase(),
|
9
|
+
name: v,
|
10
|
+
};
|
11
|
+
});
|
12
|
+
return { ...t, values: updatedVals };
|
13
|
+
});
|
14
|
+
return { ...data, taxonomy: updatedTax };
|
15
|
+
}
|
16
|
+
|
17
|
+
export const transformToDatasetsList = (
|
18
|
+
content: DatasetMetadata[],
|
19
|
+
): DatasetData[] => {
|
20
|
+
return content?.map((post) => ({
|
21
|
+
...post.metadata,
|
22
|
+
}));
|
23
|
+
};
|
24
|
+
|
25
|
+
export const transformToVedaData = (
|
26
|
+
datasets: DatasetMetadata[] | undefined,
|
27
|
+
): VedaData<DatasetData> => {
|
28
|
+
const transformed = {};
|
29
|
+
datasets?.map((dataset) => {
|
30
|
+
const id = dataset.metadata.id;
|
31
|
+
transformed[id] = {
|
32
|
+
data: dataset.metadata,
|
33
|
+
};
|
34
|
+
});
|
35
|
+
return transformed;
|
36
|
+
};
|
@@ -0,0 +1,45 @@
|
|
1
|
+
export const extractImports = (ast) => {
|
2
|
+
const imports: any = [];
|
3
|
+
const visit = (node, parent, index) => {
|
4
|
+
// If it's a text node with 'import' in its value
|
5
|
+
if (
|
6
|
+
node.type === 'text' &&
|
7
|
+
node.value &&
|
8
|
+
node.value.includes('import') &&
|
9
|
+
node.value.includes('from')
|
10
|
+
) {
|
11
|
+
if (
|
12
|
+
parent &&
|
13
|
+
Array.isArray(parent.children) &&
|
14
|
+
typeof index === 'number'
|
15
|
+
) {
|
16
|
+
// Remove the node from its original position
|
17
|
+
parent.children.splice(index, 1);
|
18
|
+
// Wrap it in a paragraph or keep as-is depending on your use case
|
19
|
+
imports.push({
|
20
|
+
type: 'paragraph',
|
21
|
+
children: [node],
|
22
|
+
});
|
23
|
+
return; // Skip deeper recursion into removed node
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
// Recurse through children if they exist
|
28
|
+
if (node.children && Array.isArray(node.children)) {
|
29
|
+
// Copy to avoid mutation issues when removing nodes
|
30
|
+
const childrenCopy = [...node.children];
|
31
|
+
for (let i = 0; i < childrenCopy.length; i++) {
|
32
|
+
visit(childrenCopy[i], node, i);
|
33
|
+
}
|
34
|
+
}
|
35
|
+
};
|
36
|
+
|
37
|
+
visit(ast, null, null);
|
38
|
+
|
39
|
+
// Prepend extracted imports to top-level children
|
40
|
+
if (ast.type === 'root' && Array.isArray(ast.children)) {
|
41
|
+
ast.children = [...imports, ...ast.children];
|
42
|
+
}
|
43
|
+
|
44
|
+
return ast;
|
45
|
+
};
|
@@ -0,0 +1,90 @@
|
|
1
|
+
import { handleTwoColumn } from './parseTwoColumn';
|
2
|
+
import { wrapComponent } from './wrapComponent';
|
3
|
+
|
4
|
+
export const groupByBreakIntoBlocks = (ast) => {
|
5
|
+
const result: any = [];
|
6
|
+
const proseWrapper = (children) => {
|
7
|
+
return {
|
8
|
+
type: 'mdxJsxFlowElement',
|
9
|
+
name: 'Prose',
|
10
|
+
children: [...children],
|
11
|
+
};
|
12
|
+
};
|
13
|
+
|
14
|
+
const groupChildren = (children) => {
|
15
|
+
const groups: any = [];
|
16
|
+
let currentGroup: any = [];
|
17
|
+
|
18
|
+
for (const child of children) {
|
19
|
+
if (
|
20
|
+
child.type === 'mdxJsxTextElement' ||
|
21
|
+
child.type === 'mdxJsxFlowElement'
|
22
|
+
) {
|
23
|
+
if (child.name === 'Break') {
|
24
|
+
if (currentGroup.length > 0) {
|
25
|
+
groups.push([proseWrapper(currentGroup)]);
|
26
|
+
currentGroup = [];
|
27
|
+
}
|
28
|
+
} else if (
|
29
|
+
child.name === 'Block' ||
|
30
|
+
child.name === 'Chart' ||
|
31
|
+
child.name === 'Map' ||
|
32
|
+
child.name === 'MapBlock' ||
|
33
|
+
child.name === 'TwoColumn'
|
34
|
+
) {
|
35
|
+
groups.push([proseWrapper(currentGroup)]);
|
36
|
+
|
37
|
+
if (child.name === 'Chart' || child.name === 'Map') {
|
38
|
+
groups.push([wrapComponent(child)]);
|
39
|
+
} else if (child.name === 'TwoColumn') {
|
40
|
+
const parsedColumn = handleTwoColumn(child);
|
41
|
+
groups.push(parsedColumn);
|
42
|
+
}
|
43
|
+
currentGroup = [];
|
44
|
+
}
|
45
|
+
} else {
|
46
|
+
currentGroup.push(child);
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
if (currentGroup.length > 0) {
|
51
|
+
groups.push([...currentGroup]);
|
52
|
+
}
|
53
|
+
return groups;
|
54
|
+
};
|
55
|
+
|
56
|
+
if (ast.type === 'root' && Array.isArray(ast.children)) {
|
57
|
+
const groups = groupChildren(ast.children);
|
58
|
+
|
59
|
+
for (const group of groups) {
|
60
|
+
// Check for prose wrapper inside group If no prose wrapper
|
61
|
+
// then wrap group inside prose object before adding to block element
|
62
|
+
|
63
|
+
if (
|
64
|
+
group.some((item) => {
|
65
|
+
return item.name === 'Prose';
|
66
|
+
})
|
67
|
+
) {
|
68
|
+
result.push({
|
69
|
+
type: 'mdxJsxFlowElement',
|
70
|
+
name: 'Block',
|
71
|
+
children: [...group],
|
72
|
+
});
|
73
|
+
} else {
|
74
|
+
result.push({
|
75
|
+
type: 'mdxJsxFlowElement',
|
76
|
+
name: 'Block',
|
77
|
+
children: [
|
78
|
+
{
|
79
|
+
type: 'mdxJsxFlowElement',
|
80
|
+
name: 'Prose',
|
81
|
+
children: [...group],
|
82
|
+
},
|
83
|
+
],
|
84
|
+
});
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
return result;
|
90
|
+
};
|
package/src/index.ts
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
// Export all utilities
|
2
|
+
export * from './reserializeMDast';
|
3
|
+
export * from './parseTwoColumn';
|
4
|
+
export * from './ChartContext';
|
5
|
+
export * from './MapContext';
|
6
|
+
export * from './CreateInterface';
|
7
|
+
export * from './extractImports';
|
8
|
+
export * from './groupElements';
|
9
|
+
export * from './inputValidation';
|
10
|
+
export * from './wrapComponent';
|
11
|
+
export * from './data';
|
12
|
+
export * from './content';
|
13
|
+
export * from './lib';
|
@@ -0,0 +1,148 @@
|
|
1
|
+
export const inputValidation = () => {};
|
2
|
+
|
3
|
+
export const dateStringToregex = (format) => {
|
4
|
+
const tokens = {
|
5
|
+
'%d': '(0[1-9]|[12][0-9]|3[01])',
|
6
|
+
'%m': '(0[1-9]|1[0-2])',
|
7
|
+
'%Y': '\\d{4}',
|
8
|
+
'%y': '\\d{2}',
|
9
|
+
'%H': '([01][0-9]|2[0-3])',
|
10
|
+
'%M': '([0-5][0-9])',
|
11
|
+
'%S': '([0-5][0-9])',
|
12
|
+
};
|
13
|
+
|
14
|
+
const escape = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
15
|
+
|
16
|
+
let pattern = '';
|
17
|
+
|
18
|
+
for (let i = 0; i < format.length; i++) {
|
19
|
+
if (format[i] === '%' && i < format.length - 1) {
|
20
|
+
const directive = format[i] + format[i + 1];
|
21
|
+
pattern += tokens[directive] || escape(directive); // unknown: treat literally
|
22
|
+
i++; // skip the directive's second char
|
23
|
+
} else {
|
24
|
+
pattern += escape(format[i]);
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
return new RegExp(`^${pattern}$`);
|
29
|
+
};
|
30
|
+
|
31
|
+
export const dateFormatValidation = (format, input) => {
|
32
|
+
const regexToTest = dateStringToregex(format);
|
33
|
+
|
34
|
+
//return false no errors if regex passes, return true there are erros if fails
|
35
|
+
return regexToTest.test(input) ? false : true;
|
36
|
+
};
|
37
|
+
|
38
|
+
export const handleChartDateValidation = (
|
39
|
+
propName,
|
40
|
+
draftInputs,
|
41
|
+
setInputErrors,
|
42
|
+
inputErrors,
|
43
|
+
draft,
|
44
|
+
onChange,
|
45
|
+
chartProps,
|
46
|
+
) => {
|
47
|
+
if (propName === 'highlightStart' || propName === 'highlightEnd') {
|
48
|
+
if (dateFormatValidation(draftInputs.draftDateFormat, draft) === false) {
|
49
|
+
setInputErrors({
|
50
|
+
highlightStart: dateFormatValidation(
|
51
|
+
draftInputs.draftDateFormat,
|
52
|
+
draftInputs.draftHighlightStart,
|
53
|
+
),
|
54
|
+
highlightEnd: dateFormatValidation(
|
55
|
+
draftInputs.draftDateFormat,
|
56
|
+
draftInputs.draftHighlightEnd,
|
57
|
+
),
|
58
|
+
});
|
59
|
+
if (
|
60
|
+
inputErrors.highlightStart == false &&
|
61
|
+
inputErrors.highlightEnd == false
|
62
|
+
) {
|
63
|
+
onChange({
|
64
|
+
...chartProps,
|
65
|
+
dateFormat: draftInputs.draftDateFormat,
|
66
|
+
highlightStart: draftInputs.draftHighlightStart,
|
67
|
+
highlightEnd: draftInputs.draftHighlightEnd,
|
68
|
+
});
|
69
|
+
}
|
70
|
+
} else {
|
71
|
+
setInputErrors({
|
72
|
+
highlightStart: dateFormatValidation(
|
73
|
+
draftInputs.draftDateFormat,
|
74
|
+
draftInputs.draftHighlightStart,
|
75
|
+
),
|
76
|
+
highlightEnd: dateFormatValidation(
|
77
|
+
draftInputs.draftDateFormat,
|
78
|
+
draftInputs.draftHighlightEnd,
|
79
|
+
),
|
80
|
+
});
|
81
|
+
}
|
82
|
+
} else if (propName === 'dateFormat') {
|
83
|
+
setInputErrors({
|
84
|
+
highlightStart: dateFormatValidation(draft, chartProps.highlightStart),
|
85
|
+
highlightEnd: dateFormatValidation(draft, chartProps.highlightEnd),
|
86
|
+
});
|
87
|
+
} else if (
|
88
|
+
inputErrors.highlightStart == false &&
|
89
|
+
inputErrors.highlightEnd == false
|
90
|
+
) {
|
91
|
+
onChange({
|
92
|
+
...chartProps,
|
93
|
+
dateFormat: draftInputs.draftDateFormat,
|
94
|
+
highlightStart: draftInputs.draftHighlightStart,
|
95
|
+
highlightEnd: draftInputs.draftHighlightEnd,
|
96
|
+
});
|
97
|
+
}
|
98
|
+
};
|
99
|
+
export const handleMapDateValidation = (
|
100
|
+
propName,
|
101
|
+
draftInputs,
|
102
|
+
inputErrors,
|
103
|
+
setInputErrors,
|
104
|
+
draft,
|
105
|
+
onChange,
|
106
|
+
componentProps,
|
107
|
+
) => {
|
108
|
+
if (
|
109
|
+
dateFormatValidation(draftInputs.defaultDateFormat, draft) === false ||
|
110
|
+
draft === ''
|
111
|
+
) {
|
112
|
+
setInputErrors({ ...inputErrors, [propName]: false });
|
113
|
+
onChange({ ...componentProps, [propName]: draft });
|
114
|
+
} else {
|
115
|
+
setInputErrors({ ...inputErrors, [propName]: true });
|
116
|
+
}
|
117
|
+
};
|
118
|
+
|
119
|
+
export const handleMapArrayValidation = (
|
120
|
+
propName,
|
121
|
+
draftInputs,
|
122
|
+
inputErrors,
|
123
|
+
setInputErrors,
|
124
|
+
draft,
|
125
|
+
onChange,
|
126
|
+
componentProps,
|
127
|
+
) => {
|
128
|
+
const numberPattern =
|
129
|
+
/^\[[+-]?(0|[1-9][0-9]*)(\.[0-9]+)?(?:,\s*[+-]?(0|[1-9][0-9]*)(\.[0-9]+)?)*\]$/;
|
130
|
+
//This regex checks that the input is wrapped in [...]
|
131
|
+
//Checks for no trailing decimal points ex: -91.
|
132
|
+
//Checks that there is no leading 0 unless followed by a . ex 0.12 or 0 are acceptable
|
133
|
+
const cleanedDraft = draft.replace(/\s/g, '');
|
134
|
+
if (numberPattern.test(cleanedDraft)) {
|
135
|
+
const parsedValues = JSON.parse(cleanedDraft);
|
136
|
+
const checkLong = (long) => (long <= 180 && long >= -180 ? true : false);
|
137
|
+
const checkLat = (lat) => (lat <= 90 && lat >= -90 ? true : false);
|
138
|
+
//validating upper and lower limits of long and lat
|
139
|
+
if (checkLong(parsedValues[0]) && checkLat(parsedValues[1])) {
|
140
|
+
setInputErrors({ ...inputErrors, [propName]: false });
|
141
|
+
onChange({ ...componentProps, [propName]: draft });
|
142
|
+
} else {
|
143
|
+
setInputErrors({ ...inputErrors, [propName]: true });
|
144
|
+
}
|
145
|
+
} else {
|
146
|
+
setInputErrors({ ...inputErrors, [propName]: true });
|
147
|
+
}
|
148
|
+
};
|