Lightcord/LightcordApi/src/components/inputs/DateInput.tsx

354 lines
11 KiB
TypeScript

/** TODO: Finish DateInput */
import * as React from "react"
import { DateConstants } from "./DateRange"
import WebpackLoader from "../../modules/WebpackLoader"
import { getInternalTextInput } from "./TextInput"
import Button from "./Button"
import ReactDOM = require("react-dom")
import * as DatePicker from "react-datepicker";
export type DateInputProps = {
className?: string,
dateFormat?: string,
defaultValue: Date,
filterDate?: () => any,
isModalInput?: boolean,
maxDate?: Date,
minDate?: Date,
onChange?: (value:Date, name:string) => void,
selectsStart?: boolean,
showMonthYearPicker?: boolean,
startDate?: Date,
endDate?: Date
style?: React.CSSProperties,
name: string,
selectsEnd?: boolean
}
let _datefns
export function getDateFNS():typeof import("date-fns"){
return _datefns || (_datefns = require("date-fns"))
}
export function getEmotion():typeof import("emotion"){
return window["__SECRET_EMOTION__"]
}
let DateInputModules
export default class DateInput extends React.Component<DateInputProps, {
inputResetKey: number,
isCalendarPickerOpen: boolean,
calendarRight: number,
calendarTop: number,
value: Date
}> {
static defaultProps:Partial<DateInputProps> = {
dateFormat: DateConstants.DATE_FORMAT,
isModalInput: true
}
constructor(props:DateInputProps){
super(props)
this.state = {
inputResetKey: 0,
isCalendarPickerOpen: false,
calendarRight: null,
calendarTop: null,
value: props.defaultValue
}
}
get modules(){
return DateInputModules || (DateInputModules = [
WebpackLoader.find(e => e.default && e.default.displayName === "Clickable"),
WebpackLoader.find(e => e.default && e.default.displayName === "TransitionGroup")
])
}
inputRef:React.Component
componentDidUpdate(e:DateInputProps){
const defaultValue = this.props.defaultValue
const dateFormat = this.props.dateFormat
if (e.defaultValue !== defaultValue && null != defaultValue) {
if(!this.inputRef)return
let str = getDateFNS().format(defaultValue, dateFormat)
this.inputRef["value"] = str
}
}
closeCalendarPicker(){
this.setState({
isCalendarPickerOpen: false
})
}
getCurrentValue(){
let value = this.state.value
let dateFormat = this.props.dateFormat;
if(!value)return
if(isDateValid(value))return getDateFNS().format(value, dateFormat)
return null
}
handleDateChange(value){
this.closeCalendarPicker()
const onChange = this.props.onChange
const name = this.props.name
this.setState((state) => {
return {
value: value,
inputResetKey: state.inputResetKey + 1
}
}, function() {
null != onChange && onChange(value, name)
})
}
handleInputBlur(ev){
const value = this.state.value
const newvalue = ev.currentTarget.value
const iso = getDateFNS().parseISO(newvalue);
if(isDateValid(iso) && value){
if(iso.valueOf() !== value.valueOf())this.setState(function(state) {
return {
value: iso,
inputResetKey: state.inputResetKey + 1
}
}, function() {
const props = this.props
const onChange = props.onChange
const name = props.name;
if(onChange)onChange(iso, name)
})
}
}
toggleCalendarVisibility(ev){
const rect:DOMRect = ev.currentTarget.getBoundingClientRect()
const bottom = rect.bottom
const right = rect.right
const innerWidth = window.innerWidth;
this.setState(function(state) {
return {
isCalendarPickerOpen: !state.isCalendarPickerOpen,
calendarRight: innerWidth - right,
calendarTop: bottom
}
})
}
setRef(ref){
this.inputRef = ref
}
renderCalendarPicker(){
let state = this.state
let calendarRight = state.calendarRight
let calendarTop = state.calendarTop
let isCalendarPickerOpen = state.isCalendarPickerOpen
let value = state.value
let props = this.props
let minDate = props.minDate
let maxDate = props.maxDate
let endDate = props.endDate
let filterDate = props.filterDate
let startDate = props.startDate
let selectsEnd = props.selectsEnd
let selectsStart = props.selectsStart
let isModalInput = props.isModalInput
let y = props.showMonthYearPicker;
return isCalendarPickerOpen ? React.createElement(AnimatedCalendarPicker, {
value: value ? value : undefined,
onClickOutside: this.closeCalendarPicker.bind(this),
onSelect: this.handleDateChange.bind(this),
minDate: minDate,
maxDate: maxDate,
endDate: endDate,
filterDate: filterDate,
startDate: startDate,
selectsEnd: selectsEnd,
selectsStart: selectsStart,
right: calendarRight,
top: calendarTop,
isModalInput: isModalInput,
showMonthYearPicker: y
}) : null
}
render(){
const [
Clickable,
TransitionGroup
] = this.modules
let name = this.props.name
return React.createElement(Clickable.default, {
className: getEmotion().css({
position: "relative"
})
}, React.createElement(getInternalTextInput(), {
inputClassName: getEmotion().css({
paddingRight: "32px"
}),
name: name,
onBlur: this.handleInputBlur.bind(this),
defaultValue: this.getCurrentValue(),
inputRef: this.setRef.bind(this)
}), React.createElement(Button, {
className: getEmotion().css({
"&:hover": {
opacity: 1
},
position: "absolute",
right: 0,
top: "50%",
opacity: .6,
padding: "8px",
transform: "translateY(-50%)",
transition: "opacity .125s"
}),
color: "transparent",
onMouseDown: this.toggleCalendarVisibility.bind(this),
wrapper: false
}, /*React.createElement(v.default, {
className: _.default.calendarIcon,
name: v.IconNames.CALENDAR
})*/), ReactDOM.createPortal(React.createElement(TransitionGroup.default, {
component: "div",
transitionAppear: false
}, this.renderCalendarPicker()), window.document.body))
}
}
export function isDateValid(date:Date){
return (date instanceof Date || typeof date === "object" || Object.prototype.toString.call(date) === "[object Date]") && !isNaN(date.valueOf())
}
let AnimatedCalendarPickerModules
export class AnimatedCalendarPicker extends React.Component<any, {
menuAnimation: any
}> {
static displayName = "AnimatedCalendarPicker"
constructor(props){
super(props)
this.state = {
menuAnimation: new this.modules[0].default.Value(0)
}
}
get modules(){
return AnimatedCalendarPickerModules || (AnimatedCalendarPickerModules = [
WebpackLoader.findByUniqueProperties(["Value","timing"])
])
}
componentWillEnter(ev){
this.modules[0].default.timing(this.state.menuAnimation, {
toValue: 1,
duration: 150
}).start(ev)
}
componentWillLeave(e){
this.modules[0].default.timing(this.state.menuAnimation, {
toValue: 0,
duration: 150
}).start(e)
}
render(){
let props = this.props,
r = props.value,
n = props.onClickOutside,
a = props.onSelect,
i = props.minDate,
o = props.maxDate,
u = props.endDate,
f = props.filterDate,
c = props.startDate,
d = props.selectsEnd,
y = props.selectsStart,
v = props.top,
g = props.right,
isModalInput = props.isModalInput,
h = props.showMonthYearPicker,
menuAnimation = this.state.menuAnimation,
E = menuAnimation.interpolate({
inputRange: [0, 1],
outputRange: ["-10px", "0px"]
});
const emotion = getEmotion()
return React.createElement(this.modules[0].default.div, {
className: [emotion.css({
marginRight: "1px",
margintop: "6px",
position: "fixed",
zIndex: 2
}), isModalInput ? emotion.css({
zIndex: 10000
}) : null].filter(e=>e).join(" "),
style: {
opacity: menuAnimation,
right: g,
top: v,
transform: [{
translateY: E
}]
}
}, React.createElement(CalendarPicker, {
minDate: i,
maxDate: o,
endDate: u,
filterDate: f,
startDate: c,
selectsEnd: d,
selectsStart: y,
value: r,
onSelect: a,
onClickOutside: n,
showMonthYearPicker: h,
onChange: console.log
}))
}
}
export class CalendarPicker extends React.Component<any> {
static defaultProps = {
value: new Date()
}
static displayName = "CalendarPicker"
render(){
var e = this.props
, t = e.onClickOutside
, r = e.onSelect
, n = e.locale
, l = e.value
, o = e.endDate
, u = e.filterDate
, f = e.startDate
, c = e.minDate
, d = e.maxDate
, p = e.selectsEnd
, y = e.selectsStart
, v = e.showMonthYearPicker;
return React.createElement("div", {
className: "lc-calendarPicker"
}, React.createElement(DatePicker.default, {
fixedHeight: true,
inline: true,
selected: l,
locale: n,
onClickOutside: t,
onSelect: r,
onChange: r,
endDate: o,
filterDate: u,
startDate: f,
minDate: c,
maxDate: d,
selectsEnd: p,
selectsStart: y,
showMonthYearPicker: v
}))
}
}