Skip to content

Commit

Permalink
Rework React Material pickers
Browse files Browse the repository at this point in the history
Reworks date, time and date-time support in the React Material
renderer set. The controls now support many customization options
and can be invoked separately via the ui schema.

We now use the much smaller 'dayjs' library (compared to 'moment')
for Javascript date support. It can be configured globally and is
therefore easily customizable on client side.

The date, time and date-time controls now use a similar layout
structure as normal controls, leading to a unified layout.

Also streamlines the label prop which was only supporting string for
a long time now. Additionally the unnecessary uuid dependency 
is removed from React Material.
  • Loading branch information
sdirix authored Jul 30, 2021
1 parent d6edf4b commit fc2d67f
Show file tree
Hide file tree
Showing 29 changed files with 882 additions and 198 deletions.
31 changes: 13 additions & 18 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions packages/angular/src/abstract-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import {
Actions,
computeLabel,
ControlElement,
isPlainLabel,
JsonFormsState,
JsonSchema,
OwnPropsOfControl,
Expand Down Expand Up @@ -110,7 +109,7 @@ export abstract class JsonFormsAbstractControl<
config
} = props;
this.label = computeLabel(
isPlainLabel(label) ? label : label.default,
label,
required,
config ? config.hideRequiredAsterisk : false
);
Expand Down
32 changes: 19 additions & 13 deletions packages/core/src/testers/testers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,13 +284,6 @@ export const isOneOfControl = and(
schemaMatches(schema => schema.hasOwnProperty('oneOf'))
);

/**
* Tests whether the given UI schema is of type Control and if the schema
* has a 'date' format.
* @type {Tester}
*/
export const isDateControl = and(uiTypeIs('Control'), formatIs('date'));

/**
* Tests whether the given UI schema is of type Control and if the schema
* has an enum.
Expand Down Expand Up @@ -352,20 +345,33 @@ export const isMultiLineControl = and(
);

/**
* Tests whether the given UI schema is of type Control and if the schema
* has a 'time' format.
* Tests whether the given UI schema is of type Control and whether the schema
* or uischema options has a 'date' format.
* @type {Tester}
*/
export const isTimeControl = and(uiTypeIs('Control'), formatIs('time'));
export const isDateControl = and(
uiTypeIs('Control'),
or(formatIs('date'), optionIs('format', 'date'))
);

/**
* Tests whether the given UI schema is of type Control and if the schema
* has a 'date-time' format.
* Tests whether the given UI schema is of type Control and whether the schema
* or the uischema options has a 'time' format.
* @type {Tester}
*/
export const isTimeControl = and(
uiTypeIs('Control'),
or(formatIs('time'), optionIs('format', 'time'))
);

/**
* Tests whether the given UI schema is of type Control and whether the schema
* or the uischema options has a 'date-time' format.
* @type {Tester}
*/
export const isDateTimeControl = and(
uiTypeIs('Control'),
formatIs('date-time')
or(formatIs('date-time'), optionIs('format', 'date-time'))
);

/**
Expand Down
11 changes: 1 addition & 10 deletions packages/core/src/util/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,6 @@ import { JsonFormsState } from '../store';

export { JsonFormsRendererRegistryEntry, JsonFormsCellRendererRegistryEntry };

export interface Labels {
default: string;
[additionalLabels: string]: string;
}

export const isPlainLabel = (label: string | Labels): label is string => {
return typeof label === 'string';
};

const isRequired = (
schema: JsonSchema,
schemaPath: string,
Expand Down Expand Up @@ -317,7 +308,7 @@ export interface StatePropsOfControl extends StatePropsOfScopedRenderer {
/**
* The label for the rendered element.
*/
label: string | Labels;
label: string;

/**
* Description of input cell
Expand Down
5 changes: 5 additions & 0 deletions packages/example/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ import { getExamples } from '@jsonforms/examples';
import { AdditionalStoreParams, exampleReducer } from './reduxUtil';
import { enhanceExample, ReactExampleDescription } from './util';

import dayjs from 'dayjs';
import 'dayjs/locale/de';
import 'dayjs/locale/en';
dayjs.locale('de');

const setupStore = (
exampleData: ReactExampleDescription[],
cells: JsonFormsCellRendererRegistryEntry[],
Expand Down
98 changes: 81 additions & 17 deletions packages/examples/src/dates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,46 @@
THE SOFTWARE.
*/
import { registerExamples } from './register';
import moment from 'moment';

const schema = {
type: 'object',
properties: {
date: {
type: 'string',
format: 'date'
},
time: {
type: 'string',
format: 'time'
schemaBased: {
type: 'object',
properties: {
date: {
type: 'string',
format: 'date',
description: 'schema-based date picker'
},
time: {
type: 'string',
format: 'time',
description: 'schema-based time picker'
},
datetime: {
type: 'string',
format: 'date-time',
description: 'schema-based datetime picker'
}
}
},
datetime: {
type: 'string',
format: 'date-time'
uiSchemaBased: {
type: 'object',
properties: {
date: {
type: 'string',
description: 'does not allow to select days'
},
time: {
type: 'string',
description: '24 hour format'
},
datetime: {
type: 'string',
description: 'uischema-based datetime picker'
}
}
}
}
};
Expand All @@ -50,11 +74,15 @@ const uischema = {
elements: [
{
type: 'Control',
scope: '#/properties/date'
scope: '#/properties/schemaBased/properties/date'
},
{
type: 'Control',
scope: '#/properties/schemaBased/properties/time'
},
{
type: 'Control',
scope: '#/properties/time'
scope: '#/properties/schemaBased/properties/datetime'
}
]
},
Expand All @@ -63,16 +91,52 @@ const uischema = {
elements: [
{
type: 'Control',
scope: '#/properties/datetime'
scope: '#/properties/uiSchemaBased/properties/date',
label: 'Year Month Picker',
options: {
format: 'date',
clearLabel: 'Clear it!',
cancelLabel: 'Abort',
okLabel: 'Do it',
views: ['year', 'month'],
dateFormat: 'YYYY.MM',
dateSaveFormat: 'YYYY-MM'
},
},
{
type: 'Control',
scope: '#/properties/uiSchemaBased/properties/time',
options: {
format: 'time',
ampm: true
}
},
{
type: 'Control',
scope: '#/properties/uiSchemaBased/properties/datetime',
options: {
format: 'date-time',
dateTimeFormat: 'DD-MM-YY hh:mm:a',
dateTimeSaveFormat: 'YYYY/MM/DD h:mm a',
ampm: true
}
}
]
}
]
};

const data = {
date: new Date().toISOString().substr(0, 10),
time: '13:37',
datetime: moment().format()
schemaBased: {
date: new Date().toISOString().substr(0, 10),
time: '13:37',
datetime: new Date().toISOString()
},
uiSchemaBased: {
date: new Date().toISOString().substr(0, 10),
time: '13:37',
datetime: '1999/12/11 10:05 am'
}
};
registerExamples([
{
Expand Down
11 changes: 5 additions & 6 deletions packages/material/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,15 @@
]
},
"dependencies": {
"@date-io/moment": "1.3.11",
"@material-ui/pickers": "^3.2.8",
"@types/uuid": "^3.4.6",
"moment": "^2.24.0",
"uuid": "^3.3.3"
"@date-io/dayjs": "1.3.13",
"dayjs": "1.10.6"
},
"peerDependencies": {
"@jsonforms/core": "^3.0.0-alpha.0",
"@jsonforms/react": "^3.0.0-alpha.0",
"@material-ui/core": "^4.7.0",
"@material-ui/icons": "^4.5.1"
"@material-ui/icons": "^4.5.1",
"@material-ui/pickers": "^3.3.10"
},
"optionalPeerDependencies": {
"@material-ui/lab": "^4.0.0-alpha.56"
Expand All @@ -85,6 +83,7 @@
"@jsonforms/react": "^3.0.0-alpha.0",
"@material-ui/core": "^4.7.0",
"@material-ui/icons": "^4.5.1",
"@material-ui/pickers": "^3.2.8",
"@material-ui/lab": "^4.0.0-alpha.56",
"@types/enzyme": "^3.10.3",
"@types/enzyme-adapter-react-16": "^1.0.5",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import {
createDefaultValue,
findUISchema,
isObjectArray,
isPlainLabel,
RankedTester,
rankWith,
uiTypeIs
Expand Down Expand Up @@ -101,7 +100,7 @@ export const MaterialListWithDetailRenderer = ({
<Hidden xsUp={!visible}>
<ArrayLayoutToolbar
label={computeLabel(
isPlainLabel(label) ? label : label.default,
label,
required,
appliedUiSchemaOptions.hideRequiredAsterisk
)}
Expand Down
3 changes: 1 addition & 2 deletions packages/material/src/complex/MaterialObjectRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import {
findUISchema,
GroupLayout,
isObjectControl,
isPlainLabel,
RankedTester,
rankWith,
StatePropsOfControlWithDetail
Expand Down Expand Up @@ -64,7 +63,7 @@ const MaterialObjectRenderer = ({
if (isEmpty(path)) {
detailUiSchema.type = 'VerticalLayout';
} else {
(detailUiSchema as GroupLayout).label = isPlainLabel(label) ? label : label.default;
(detailUiSchema as GroupLayout).label = label;
}
return (
<Hidden xsUp={!visible}>
Expand Down
3 changes: 1 addition & 2 deletions packages/material/src/complex/TableToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import {
ControlElement,
createDefaultValue,
JsonSchema,
Labels
} from '@jsonforms/core';
import IconButton from '@material-ui/core/IconButton';
import { Grid, Hidden, Typography } from '@material-ui/core';
Expand All @@ -40,7 +39,7 @@ import NoBorderTableCell from './NoBorderTableCell';
export interface MaterialTableToolbarProps {
numColumns: number;
errors: string;
label: string | Labels;
label: string;
path: string;
uischema: ControlElement;
schema: JsonSchema;
Expand Down
Loading

0 comments on commit fc2d67f

Please sign in to comment.