Skip to content

Commit

Permalink
[form-builder] [schema] Add datetime type with default input (#275)
Browse files Browse the repository at this point in the history
* [base] Get rid of deprecatedDate type

* [date-input] Rename common CSS file used by date input components

* [schema] Enable the string-based date type

* [date-input] Define string date part

* [schema] RichDate type uses date internally

* [date-input] Implement new string-based date type

* [test-studio] Add string-based date type to test studio schema

* [date-input] Include moment for a thinner Date.js

* [date-input] Use moment without timezone db

* [test-studio] Split dates schema

* [date-input] Refactor out some common date methods to a shared file

* [date-input] Move simple date input to form-builder and rename @santy/date-input to @sanity/rich-date-input

* [base] Import richDate legacy schema from deprecated @sanity/date-input package

* [form-builder] Add converter for richDate <=> datetime

* [form-buidler] Remove inputUtc option

* [form-builder] Disable keyboard navigation in date input

* [form-builder] Simplify conversion from richDate to datetime
  • Loading branch information
Thomas Drevon authored and bjoerge committed Oct 19, 2017
1 parent 9c5c16e commit 58493b8
Show file tree
Hide file tree
Showing 45 changed files with 966 additions and 208 deletions.
5 changes: 2 additions & 3 deletions packages/@sanity/base/src/schema/createSchema.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import geopoint from './types/geopoint'
import richDate from './types/richDate'
import imageAsset from './types/imageAsset'
import fileAsset from './types/fileAsset'
import Schema from '@sanity/schema'
import deprecatedDate from './types/deprecatedDate'
import legacyRichDate from 'part:@sanity/form-builder/input/legacy-date/schema?'

module.exports = schemaDef => Schema.compile({
name: schemaDef.name,
types: [...schemaDef.types, geopoint, richDate, deprecatedDate, imageAsset, fileAsset]
types: [...schemaDef.types, geopoint, legacyRichDate, imageAsset, fileAsset].filter(Boolean)
})
5 changes: 0 additions & 5 deletions packages/@sanity/base/src/schema/types/deprecatedDate.js

This file was deleted.

6 changes: 2 additions & 4 deletions packages/@sanity/cli/src/commands/init/templates/clean.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
export const dependencies = {
'@sanity/date-input': '^0.99.0'
}
export const dependencies = {}

export const generateSanityManifest = base => ({
...base,
plugins: base.plugins.concat(['@sanity/date-input'])
plugins: base.plugins
})
7 changes: 1 addition & 6 deletions packages/@sanity/cli/src/commands/init/templates/moviedb.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,12 @@ const datasetUrl = 'https://storage.googleapis.com/sanity/docsite-assets/moviedb
const indent = line => ` ${line}`

export const dependencies = {
'@sanity/date-input': '^0.99.0',
'@sanity/google-maps-input': '^0.99.0',
}

export const generateSanityManifest = base => ({
...base,

plugins: base.plugins.concat([
'@sanity/date-input',
'@sanity/google-maps-input'
])
plugins: base.plugins.concat(['@sanity/google-maps-input'])
})

export const getSuccessMessage = (opts, context) => {
Expand Down
6 changes: 1 addition & 5 deletions packages/@sanity/cli/templates/moviedb/schemas/movie.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,7 @@ export default {
{
name: 'releaseDate',
title: 'Release date',
type: 'richDate',
options: {
inputTime: false,
inputUtc: true
}
type: 'datetime'
},
{
name: 'externalId',
Expand Down
4 changes: 2 additions & 2 deletions packages/@sanity/cli/templates/moviedb/schemas/screening.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ export default {
{
name: 'beginAt',
title: 'Starts at',
type: 'richDate',
type: 'datetime',
description: 'When does the screening start?'
},
{
name: 'endAt',
title: 'Ends at',
type: 'richDate',
type: 'datetime',
description: 'When does the screening end?'
},
{
Expand Down
16 changes: 1 addition & 15 deletions packages/@sanity/date-input/.gitignore
Original file line number Diff line number Diff line change
@@ -1,16 +1,2 @@
# Logs
logs
*.log

# Coverage directory used by tools like istanbul
coverage

# Grunt intermediate storage
.grunt

# Dependency directories
node_modules

# Compiled source
lib

node_modules
33 changes: 2 additions & 31 deletions packages/@sanity/date-input/README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,3 @@
# @sanity/date-input
### @sanity/date-input

Date/time input components for Sanity form builder

Typical data output:

```js
{
local: '2017-02-21T10:15:00+01:00',
utc: '2017-02-12T09:15:00Z',
timezone: 'Europe/Oslo',
offset: 60
}
```

Using https://github.com/dubert/react-kronos for date/time input.

## Options

This component accepts the following options via the Sanity schema:

```
options.dateFormat || 'YYYY-MM-DD'
options.timeFormat || 'HH:mm'
options.calendarTodayLabel || 'Today'
options.timeStep || 15
options.inputUtc || false
options.inputDate || true
options.inputTime || true
options.placeholderDate || moment().format(options.dateFormat)
options.placeholderTime || moment().format(options.timeFormat)
```
[DEPRECATED]: Use [@sanity/rich-date-input instead](https://www.npmjs.com/package/@sanity/rich-date-input)
9 changes: 9 additions & 0 deletions packages/@sanity/date-input/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// NO ES6
var generateHelpUrl = require('@sanity/generate-help-url')

// eslint-disable-next-line no-console, prefer-template
console.warn('👋 Hi there! You are using the plugin @sanity/date-input.'
+ ' It has been renamed to @sanity/rich-date-input. You should update your studio to use the rich-date plugin.'
+ ' For more info, see ' + generateHelpUrl('deprecated-sanity-date-input'))

module.exports = require('@sanity/rich-date-input')
30 changes: 5 additions & 25 deletions packages/@sanity/date-input/package.json
Original file line number Diff line number Diff line change
@@ -1,34 +1,14 @@
{
"name": "@sanity/date-input",
"version": "0.116.2",
"description": "Date/time input components for Sanity form builder",
"main": "lib/index.js",
"description": "[DEPRECATED] Use @sanity/rich-date-input instead",
"main": "index.js",
"author": "Sanity.io <hello@sanity.io>",
"license": "MIT",
"scripts": {
"clean": "rimraf lib",
"prepublish": "in-publish && sanity-check || not-in-publish",
"test": "eslint ."
},
"keywords": [
"sanity",
"sanity-plugin"
],
"dependencies": {
"@sanity/form-builder": "^0.116.2",
"@sanity/generate-help-url": "^0.116.0",
"lodash": "^4.17.4",
"moment": "^2.18.1",
"moment-timezone": "^0.5.11",
"postcss-cssnext": "^3.0.2",
"prop-types": "^15.5.10",
"react-datepicker": "^0.55.0"
},
"devDependencies": {
"@sanity/check": "^0.116.0",
"in-publish": "^2.0.0",
"rimraf": "^2.6.1"
},
"@sanity/rich-date-input": "^0.116.2",
"@sanity/generate-help-url": "^0.116.0"
},
"repository": {
"type": "git",
"url": "git@github.com:sanity-io/sanity.git"
Expand Down
12 changes: 4 additions & 8 deletions packages/@sanity/date-input/sanity.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
{
"paths": {
"source": "./src",
"compiled": "./lib"
},

"parts": [
{
"implements": "part:@sanity/form-builder/input/rich-date",
"path": "inputs/RichDate"
"path": "./index.js"
},
{
"implements": "part:@sanity/base/component",
"path": "inputs/story.js"
"implements": "part:@sanity/form-builder/input/legacy-date/schema",
"path": "./schema"
}

]
}
1 change: 1 addition & 0 deletions packages/@sanity/date-input/schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('@sanity/rich-date-input/schema')
3 changes: 3 additions & 0 deletions packages/@sanity/form-builder/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"attr-accept": "^1.1.0",
"canvas-to-blob": "^0.0.0",
"classnames": "^2.2.5",
"date-fns": "^1.29.0",
"debug": "^2.6.3",
"exif-component": "^1.0.1",
"get-random-values": "^1.2.0",
Expand All @@ -39,6 +40,8 @@
"nano-pubsub": "^1.0.1",
"object-inspect": "^1.2.1",
"react-click-outside": "^2.3.1",
"moment": "^2.19.1",
"react-datepicker": "^0.56.0",
"react-portal": "^3.0.0",
"shallow-equals": "^1.0.0",
"slate": "^0.25.2",
Expand Down
136 changes: 136 additions & 0 deletions packages/@sanity/form-builder/src/inputs/DateTime/DateTimeInput.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// @flow
import moment from 'moment'
import type Moment from 'moment'
import DatePicker from 'react-datepicker'
import 'react-datepicker/dist/react-datepicker-cssmodules.css' // eslint-disable-line import/no-unassigned-import
import {uniqueId} from 'lodash'
import React from 'react'
import FormField from 'part:@sanity/components/formfields/default'
import styles from './styles/DateTimeInput.css'
import PatchEvent, {set, unset} from '../../PatchEvent'

type ParsedOptions = {
dateFormat: string,
timeFormat: string,
timeStep: number,
calendarTodayLabel: string
}

type SchemaOptions = {
dateFormat?: string,
timeFormat?: string,
timeStep?: number,
calendarTodayLabel?: string
}

const DEFAULT_DATE_FORMAT = 'YYYY-MM-DD'
const DEFAULT_TIME_FORMAT = 'HH:mm'

type Props = {
value: string,
type: {
name: string,
title: string,
description: string,
options?: SchemaOptions,
},
onChange: PatchEvent => void,
level: number
}


function parseOptions(options: SchemaOptions = {}): ParsedOptions {
return {
dateFormat: options.dateFormat || DEFAULT_DATE_FORMAT,
timeFormat: options.timeFormat || DEFAULT_TIME_FORMAT,
timeStep: (('timeStep' in options) && Number(options.timeStep)) || 15,
calendarTodayLabel: options.calendarTodayLabel || 'Today'
}
}

const getFormat = (options: ParsedOptions) => `${options.dateFormat} ${options.timeFormat}`

type State = {
inputValue: ?string
}

export default class DateInput extends React.Component<Props, State> {
inputId: string = uniqueId('date-input')

state = {
inputValue: null
}

handleInputChange = (event: SyntheticEvent<HTMLInputElement>) => {
const inputValue = event.currentTarget.value
const parsed = moment(inputValue, getFormat(parseOptions(this.props.type.options)), true)
if (parsed.isValid()) {
this.setMoment(parsed)
} else {
this.setState({inputValue: inputValue})
}
}

handleChange = (nextMoment?: Moment) => {
this.setState({inputValue: null})
if (nextMoment) {
this.setMoment(nextMoment)
} else {
this.unset()
}
}
handleBlur = () => {
this.setState({inputValue: null})
}

setMoment(nextMoment: Moment) {
this.set(nextMoment.toDate().toJSON())
this.setState({inputValue: null})
}

set(value: string) {
this.props.onChange(PatchEvent.from([set(value)]))
}

unset() {
this.props.onChange(PatchEvent.from([unset()]))
}

render() {
const {value, type, level} = this.props
const {inputValue} = this.state
const {title, description} = type

const momentValue: ?Moment = value ? moment(value) : null

const options = parseOptions(type.options)

const placeholder = type.placeholder || `e.g. ${moment().format(getFormat(options))}`

return (
<FormField labelFor={this.inputId} label={title} level={level} description={description}>
<div className={styles.root}>
<DatePicker
{...options}
showMonthDropdown
showYearDropdown
todayButton={options.calendarTodayLabel}
selected={momentValue || undefined}
placeholderText={placeholder}
calendarClassName={styles.datepicker}
className={styles.input}
onChange={this.handleChange}
onChangeRaw={this.handleInputChange}
value={inputValue ? inputValue : (momentValue && momentValue.format(getFormat(options)))}
showTimeSelect
disabledKeyboardNavigation
dateFormat={options.dateFormat}
timeFormat={options.timeFormat}
timeIntervals={options.timeStep}
onBlur={this.handleBlur}
/>
</div>
</FormField>
)
}
}
1 change: 1 addition & 0 deletions packages/@sanity/form-builder/src/inputs/DateTime/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {default} from './DateTimeInput'

0 comments on commit 58493b8

Please sign in to comment.