Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions example/src/examples/date-time/form-data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"native": {},
"alternative": {}
}
10 changes: 10 additions & 0 deletions example/src/examples/date-time/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import schema from './schema.json';
import uiSchema from './ui-schema.json';
import formData from './form-data.json';

export default {
title: 'Date & time',
schema,
uiSchema,
formData,
};
36 changes: 36 additions & 0 deletions example/src/examples/date-time/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"title": "Date and time widgets",
"type": "object",
"properties": {
"native": {
"title": "Native",
"description": "May not work on some browsers, notably Firefox Desktop and IE.",
"type": "object",
"properties": {
"datetime": {
"type": "string",
"format": "date-time"
},
"date": {
"type": "string",
"format": "date"
}
}
},
"alternative": {
"title": "Alternative",
"description": "These work on most platforms.",
"type": "object",
"properties": {
"alt-datetime": {
"type": "string",
"format": "date-time"
},
"alt-date": {
"type": "string",
"format": "date"
}
}
}
}
}
16 changes: 16 additions & 0 deletions example/src/examples/date-time/ui-schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"alternative": {
"alt-datetime": {
"ui:widget": "alt-datetime",
"ui:options": {
"yearsRange": [1980, 2030]
}
},
"alt-date": {
"ui:widget": "alt-date",
"ui:options": {
"yearsRange": [1980, 2030]
}
}
}
}
2 changes: 2 additions & 0 deletions example/src/examples/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import arrays from './arrays';
import budget from './budget';
import dateTime from './date-time';
import nested from './nested';
import numbers from './numbers';
import multipleChoice from './multiple-choice';
Expand All @@ -10,6 +11,7 @@ import validation from './validation';
export default {
arrays,
budget,
dateTime,
nested,
numbers,
multipleChoice,
Expand Down
180 changes: 180 additions & 0 deletions src/AltDateWidget/AltDateWidget.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import React, { Component } from 'react';

import Grid from '@material-ui/core/Grid';
import Button from '@material-ui/core/Button';

import {
parseDateString,
toDateString,
pad,
} from 'react-jsonschema-form/lib/utils';

function rangeOptions(start: any, stop: any) {
let options = [];
for (let i = start; i <= stop; i++) {
options.push({ value: i, label: pad(i, 2) });
}
return options;
}

function readyForChange(state: any) {
return Object.keys(state).every(key => state[key] !== -1);
}

function DateElement({
type,
range,
value,
select,
rootId,
disabled,
readonly,
autofocus,
registry,
onBlur,
}: any) {
const id = rootId + '_' + type;
const { SelectWidget } = registry.widgets;

return (
<SelectWidget
schema={{ type: 'integer' }}
id={id}
className="form-control"
label={type}
options={{ enumOptions: rangeOptions(range[0], range[1]) }}
placeholder={type}
value={value}
disabled={disabled}
readonly={readonly}
autofocus={autofocus}
onChange={(value: any) => select(type, value)}
onBlur={onBlur}
/>
);
}

class AltDateWidget extends Component<any, any> {
static defaultProps = {
time: false,
disabled: false,
readonly: false,
autofocus: false,
options: {
yearsRange: [1900, new Date().getFullYear() + 2],
},
};

constructor(props: any) {
super(props);

this.state = parseDateString(props.value, props.time);
}

componentWillReceiveProps(nextProps: any) {
this.setState(parseDateString(nextProps.value, nextProps.time));
}

onChange = (property: any, value: any) => {
this.setState(
{ [property]: typeof value === 'undefined' ? -1 : value },
() => {
// Only propagate to parent state if we have a complete date{time}
if (readyForChange(this.state)) {
this.props.onChange(toDateString(this.state, this.props.time));
}
}
);
};

setNow = (event: any) => {
event.preventDefault();
const { time, disabled, readonly, onChange } = this.props;
if (disabled || readonly) {
return;
}
const nowDateObj = parseDateString(new Date().toJSON(), time);
this.setState(nowDateObj, () => onChange(toDateString(this.state, time)));
};

clear = (event: any) => {
event.preventDefault();
const { time, disabled, readonly, onChange } = this.props;
if (disabled || readonly) {
return;
}
this.setState(parseDateString('', time), () => onChange(undefined));
};

get dateElementProps() {
const { time, options } = this.props;
const { year, month, day, hour, minute, second } = this.state;
const data = [
{
type: 'year',
range: options.yearsRange,
value: year,
},
{ type: 'month', range: [1, 12], value: month },
{ type: 'day', range: [1, 31], value: day },
];
if (time) {
data.push(
{ type: 'hour', range: [0, 23], value: hour },
{ type: 'minute', range: [0, 59], value: minute },
{ type: 'second', range: [0, 59], value: second }
);
}
return data;
}

render() {
const {
id,
disabled,
readonly,
autofocus,
registry,
onBlur,
options,
} = this.props;
return (
<Grid container alignItems="center" spacing={8}>
{this.dateElementProps.map((elemProps, i) => (
<Grid item key={i}>
<DateElement
rootId={id}
select={this.onChange}
{...elemProps}
disabled={disabled}
readonly={readonly}
registry={registry}
onBlur={onBlur}
autofocus={autofocus && i === 0}
/>
</Grid>
))}
{(options.hideNowButton !== 'undefined'
? !options.hideNowButton
: true) && (
<Grid item>
<Button onClick={this.setNow} variant="outlined" size="small">
Now
</Button>
</Grid>
)}
{(options.hideClearButton !== 'undefined'
? !options.hideClearButton
: true) && (
<Grid item>
<Button onClick={this.clear} variant="outlined" size="small">
Clear
</Button>
</Grid>
)}
</Grid>
);
}
}

export default AltDateWidget;
2 changes: 2 additions & 0 deletions src/AltDateWidget/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default } from './AltDateWidget';
export * from './AltDateWidget';
2 changes: 2 additions & 0 deletions src/Widgets/Widgets.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import AltDateWidget from '../AltDateWidget/AltDateWidget';
import CheckboxWidget from '../CheckboxWidget/CheckboxWidget';
import CheckboxesWidget from '../CheckboxesWidget/CheckboxesWidget';
import PasswordWidget from '../PasswordWidget/PasswordWidget';
Expand All @@ -9,6 +10,7 @@ import TextWidget from '../TextWidget/TextWidget';
import UpDownWidget from '../UpDownWidget/UpDownWidget';

export default {
AltDateWidget,
CheckboxWidget,
CheckboxesWidget,
PasswordWidget,
Expand Down
10 changes: 10 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
declare module 'react-jsonschema-form/lib/utils' {
export function parseDateString(
dateString: string,
includeTime: boolean
): any;

export function toDateString(obj: any, time: boolean): any;

export function pad(num: number, size: number): string;
}