diff --git a/packages/date-picker/date-picker-input.js b/packages/date-picker/date-picker-input.js index 376df69..b5ca2a2 100644 --- a/packages/date-picker/date-picker-input.js +++ b/packages/date-picker/date-picker-input.js @@ -3,8 +3,30 @@ import { styled } from '@stitches/react'; import { parseDate } from './processor.js'; import { dateOptions } from '../support/date.js'; -const AmsDatePickerInputContainer = styled('input', {}); +const AmsDatePickerInputContainer = styled('input', { + outline: 'none', + border: 'none', + backgroundColor: 'transparent', +}); +/** + * [Ams] The headless date picker component. + * @param {string} className + * @param {string} id + * @param {object} style + * @param {any} value + * @param {any} baseDate + * @param {function} onChange - Callback function to be called when the date is changed (only when finalized). + * @param {function} onError - Callback function when the error is occurring in user's input (neither functionality error nor development error). + * @param {function} onKeyPress + * @param {function} onFocus + * @param {function} onBlur + * @param {object} dateOption - (TBD) The date option for formatting the date. + * @param {function} onShouldOpenSelector + * @param {function} onShouldCloseSelector + * @param {any} props + * @return {JSX.Element} + */ export const AmsDatePickerInput = ({ className, id, @@ -16,13 +38,19 @@ export const AmsDatePickerInput = ({ onKeyPress, onFocus, onBlur, + dateOption = dateOptions, onShouldOpenSelector, onShouldCloseSelector, + ...props }) => { - const [inputValue, setInputValue] = useState(value); + const [inputValue, setInputValue] = useState(''); useEffect(() => { - setInputValue(value.toLocaleString('en-US', dateOptions)); + if (value) { + setInputValue(value.toLocaleString('en-US', dateOption)); + } else { + setInputValue(''); + } }, [value]); // This function is a callback when the input is finished by user (on finalizing or on blurring). @@ -34,29 +62,35 @@ export const AmsDatePickerInput = ({ onChange(parsedDate); } } catch (e) { - onError(e); // Return error. + if (onError) { + onError(e); // Return error. + } else { + console.error('AmsDatePicker:', e); // Log error. + } } }; - // This function is used to handle the close action of the date selector. - const handleCloseDateSelector = () => { - // TODO. + // This function is used to handle the close action of the date selector or the blur action of input. + const handleEscape = () => { + // TODO: Blur the input when needed. + // TODO: Call back the onShouldCloseSelector callback with some conditions. }; // This function should be called to determine if we should finish the input on blur. const isValidOnBlur = () => { return ( inputValue.length > 0 - && !inputValue.match(/^\d{1,2}\/\d{1,2}\/\d{4}, \d{1,2}:\d{2}(?::\d{2})? (?:AM|PM)?$/) + && inputValue.match(/^\d{1,2}\/\d{1,2}\/\d{4},? \d{1,2}:\d{2}(?::\d{2})? ?(?:AM|PM)?$/) ); }; - // TODO: Make the input element style-less. + // This input element is style-less. return ( { setInputValue(e.target.value); }} @@ -64,6 +98,9 @@ export const AmsDatePickerInput = ({ if (e.key === 'Enter') { onInputFinish(inputValue); } + if (e.key === 'Escape') { + handleEscape(); + } if (onKeyPress) { onKeyPress(e); } @@ -75,7 +112,7 @@ export const AmsDatePickerInput = ({ } }} onBlur={(e) => { - // TODO: Determine if we should close the data selector. + // Determine if we should close the data selector. if (isValidOnBlur()) { onInputFinish(inputValue); } @@ -83,6 +120,10 @@ export const AmsDatePickerInput = ({ onBlur(e); } }} + { + ...props + // TODO: Handle potential conflicts with props. + } /> ); }; diff --git a/packages/date-picker/date-picker.js b/packages/date-picker/date-picker.js index 05b6248..0807395 100644 --- a/packages/date-picker/date-picker.js +++ b/packages/date-picker/date-picker.js @@ -1,83 +1,101 @@ -import React, { useEffect, useRef, useState } from 'react'; +import React, { useEffect, useState } from 'react'; +import { AmsDatePickerInput } from './date-picker-input'; +import { Layout } from './layout-support.js'; +import { AmsDesign } from '../support/standards.js'; /** * [Ams] (WIP) Magic Date Picker Component. * + * @param {string|undefined} className * @param {string|undefined} id - * @param {string} label * @param {Date|undefined} value * @param {function} onChange - * @param {string|null} hint - * @param {string|null} error * @param {Date|undefined} baseDate + * @param {object} layoutStyle + * @param {object} style + * @param {any} props * @return {JSX.Element} */ export const AmsDatePicker = ({ + className, id = 'ams-date-picker', - label, value, onChange, - hint, - error, baseDate, + layoutStyle, + style, + ...props }) => { // Date picker value state. - const [valueState, setValueState] = useState(null); + const [valueState, setValueState] = useState(value); // Date picker open state. const [isOpen, setIsOpen] = useState(false); - // Date picker hint state. - const [hintState, setHintState] = useState(null); - - // Date picker input field error state. - const [errorState, setErrorState] = useState(null); - - // Date picker anchor element. - const boxRef = useRef(null); - const handlePopoverClose = () => { setIsOpen(false); }; - // Update hint state when hint prop changes. - useEffect(() => { - if (hint) { - setHintState(hint); - } - }, [hint]); - - // Update error state when error prop changes. - useEffect(() => { - if (error) { - setErrorState(error); - } - }, [error]); - // Process the datepicker value into input value. useEffect(() => { if (valueState) { - setHintState(null); - setErrorState(null); if (onChange) { // Call the onChange callback with Date object. // It will always be called nevertheless it is inputted by typing or selecting. onChange(valueState); + } else { + console.warn('ams:', 'onChange callback is not defined.'); + console.log('ams:', 'valueState:', valueState); } } }, [valueState]); return ( -
- {/* TODO */} -
+ {/* TODO: Replenish necessary APIs */} + { + setValueState(value); + }} + style={{ + width: '100%', + height: '100%', + padding: '10px 14px', + fontSize: '$lg', + fontWeight: '400', + ...style, + }} + {...props} + /> + ); }; diff --git a/packages/support/date.js b/packages/support/date.js index 5139543..fa2c49b 100644 --- a/packages/support/date.js +++ b/packages/support/date.js @@ -1,7 +1,7 @@ export const dateOptions = { year: 'numeric', - month: 'numeric', - day: 'numeric', + month: '2-digit', + day: '2-digit', weekday: undefined, hour: 'numeric', minute: 'numeric', diff --git a/packages/support/stitches.config.js b/packages/support/stitches.config.js index fd17606..8c3d37b 100644 --- a/packages/support/stitches.config.js +++ b/packages/support/stitches.config.js @@ -30,9 +30,9 @@ export const { black: '#000', }, shadows: { - 'sm': '0 5px 6px 0 rgba(0, 0, 0, 0.03)', - 'md': '0 6px 8px 0 rgba(0, 0, 0, 0.03)', - 'lg': '0px 10px 16px rgba(0, 0, 0, 0.03)', + 'sm': '0 4px 10px 0 rgba(0, 0, 0, 0.03)', + 'md': '0 6px 14px 0 rgba(0, 0, 0, 0.03)', + 'lg': '0px 10px 20px rgba(0, 0, 0, 0.03)', }, fontSizes: { 'xxs': '11px', @@ -68,7 +68,7 @@ export const { }, }); -export const amsDarkTheme = createTheme('ams-dark-theme', { +export const amsDarkTheme = createTheme('dark', { colors: { ...grayDark, ...blueDark, diff --git a/packages/user-manual/index.js b/packages/user-manual/index.js index 4b55278..87eb7a4 100644 --- a/packages/user-manual/index.js +++ b/packages/user-manual/index.js @@ -1,7 +1,7 @@ import React from 'react'; import { styled } from '@stitches/react'; import * as Dialog from '@radix-ui/react-dialog'; -import { IconQuestionMark } from '@tabler/icons'; +import { IconHelp, IconQuestionMark } from '@tabler/icons'; import { AmsDesign } from '../support/standards.js'; @@ -71,7 +71,9 @@ export const AmsUserManual = ({ style, children }) => { css={style} > {children ?? ( - + )} diff --git a/pages/index.js b/pages/index.js index a795957..7ed6eef 100644 --- a/pages/index.js +++ b/pages/index.js @@ -10,6 +10,8 @@ import { AmsWebsiteStandards } from '../support/website-standards'; import { IconCopy, IconLivePhoto } from '@tabler/icons'; import { getHeadTitle } from '../support/head'; import { Layout } from '../components/layout'; +import { AmsDatePicker } from '../packages/date-picker/date-picker'; +import { isInDaylightSavingConflictTime } from '../packages/date-picker/processor'; const HeroTitleTag = styled('div', { fontSize: '14px', @@ -34,7 +36,9 @@ const HeroSubtitle = styled('div', { }); const InstallCommandBox = styled('div', { - fontFamily: 'Fira Code, monospace', + '& code': { + fontFamily: '"Fira Code", monospace', + }, fontSize: '14px', fontWeight: '500', color: AmsDesign.color.black, @@ -95,7 +99,7 @@ const SectionTitle = styled('div', { }); export default function Home() { - const [date, setDate] = useState(moment('11/07/2021 1:00 AM')); + const [date, setDate] = useState(moment()); return (
- { - setDate(moment(newDate)); + + Departure Date + + +
+ > + setDate(moment(newDate))} + /> + {isInDaylightSavingConflictTime(date.toDate()) && ( + { + setDate(moment(newDate)); + }} + /> + )} +
-
- + npm install ams-date-picker - + - + yarn add ams-date-picker - +