|
| 1 | +/** |
| 2 | + * An example Custom Component: |
| 3 | + * https://github.com/CarlosNZ/json-edit-react#custom-nodes |
| 4 | + * |
| 5 | + * A date/time picker which can be configure to show (using the |
| 6 | + * CustomNodeDefinitions at the bottom of this file) when an ISO date/time |
| 7 | + * string is present in the JSON data, and present a Date picker interface |
| 8 | + * rather than requiring the user to edit the ISO string directly. |
| 9 | + */ |
| 10 | + |
| 11 | +import React from 'react' |
| 12 | +import DatePicker from 'react-datepicker' |
| 13 | +import { Button } from '@chakra-ui/react' |
| 14 | +import { CustomNodeProps, CustomNodeDefinition } from '../JsonEditImport' |
| 15 | + |
| 16 | +// Styles |
| 17 | +import 'react-datepicker/dist/react-datepicker.css' |
| 18 | +// For better matching with Chakra-UI |
| 19 | +import './style.css' |
| 20 | + |
| 21 | +export const DateTimePicker: React.FC<CustomNodeProps> = ({ |
| 22 | + value, |
| 23 | + setValue, |
| 24 | + handleEdit, |
| 25 | + handleCancel, |
| 26 | + handleKeyPress, |
| 27 | + isEditing, |
| 28 | + setIsEditing, |
| 29 | + styles, |
| 30 | + customProps, |
| 31 | +}) => { |
| 32 | + const { dateFormat = 'MMM d, yyyy h:mm aa', showTimeSelect = true } = customProps ?? {} |
| 33 | + |
| 34 | + const date = new Date(value as string) |
| 35 | + |
| 36 | + return isEditing ? ( |
| 37 | + // Picker only shows up when "editing". Due to the `showOnView: false` in |
| 38 | + // the definition below, this component will not show at all when viewing |
| 39 | + // (and so will show raw ISO strings). However, we've defined an alternative |
| 40 | + // here too, when showOnView == true, in which case the date/time string is |
| 41 | + // shown as a localised date/time. |
| 42 | + <DatePicker |
| 43 | + // Check to prevent invalid date (from previous data value) crashing the |
| 44 | + // component |
| 45 | + selected={isNaN(date as any) ? null : date} |
| 46 | + showTimeSelect={showTimeSelect} |
| 47 | + dateFormat={dateFormat} |
| 48 | + onChange={(date: Date) => setValue(date.toISOString())} |
| 49 | + open={true} |
| 50 | + onKeyDown={handleKeyPress} |
| 51 | + > |
| 52 | + <div style={{ display: 'flex', gap: 20 }}> |
| 53 | + {/* These buttons are not really necessary -- you can either use the |
| 54 | + standard Ok/Cancel icons, or keyboard Enter/Esc, but shown for demo |
| 55 | + purposes */} |
| 56 | + <Button |
| 57 | + color={styles.container.backgroundColor} |
| 58 | + backgroundColor={styles.iconOk.color} |
| 59 | + onClick={handleEdit} |
| 60 | + > |
| 61 | + OK |
| 62 | + </Button> |
| 63 | + <Button |
| 64 | + color={styles.container.backgroundColor} |
| 65 | + backgroundColor={styles.iconCancel.color} |
| 66 | + onClick={handleCancel} |
| 67 | + > |
| 68 | + Cancel |
| 69 | + </Button> |
| 70 | + </div> |
| 71 | + </DatePicker> |
| 72 | + ) : ( |
| 73 | + <div |
| 74 | + // Double-click behaviour same as standard elements |
| 75 | + onDoubleClick={() => setIsEditing(true)} |
| 76 | + className="jer-value-string" |
| 77 | + style={styles.string} |
| 78 | + > |
| 79 | + "{new Date(value as string).toLocaleDateString()}" |
| 80 | + </div> |
| 81 | + ) |
| 82 | +} |
| 83 | + |
| 84 | +// Definition for custom node behaviour |
| 85 | +export const dateNodeDefinition: CustomNodeDefinition = { |
| 86 | + // Condition is a regex to match ISO strings |
| 87 | + condition: ({ value }) => |
| 88 | + typeof value === 'string' && |
| 89 | + /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[\d\.]*(Z?|[\+-][\d:]+)$/.test(value), |
| 90 | + element: DateTimePicker, // the component defined above |
| 91 | + showOnView: false, |
| 92 | + showOnEdit: true, |
| 93 | + name: 'Date', // shown in the Type selector menu |
| 94 | + showInTypesSelector: true, |
| 95 | + defaultValue: new Date().toISOString(), // when instantiated, default to the current date/time |
| 96 | +} |
0 commit comments