From de7eec7a4d5c182950c5fa5d78be2a74cd2b296c Mon Sep 17 00:00:00 2001 From: aboveyunhai <35160613+aboveyunhai@users.noreply.github.com> Date: Wed, 7 Aug 2024 02:00:10 -0400 Subject: [PATCH 1/3] add eslint check for development only, not effect on the user side --- .eslintrc.js | 13 +++++++++++++ example/index.tsx | 3 ++- package-lock.json | 23 ++++++++++------------- package.json | 7 ++++--- 4 files changed, 29 insertions(+), 17 deletions(-) create mode 100644 .eslintrc.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..5f979dc --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,13 @@ +module.exports = { + extends: [ + './node_modules\\dts-cli\\conf\\eslint-config-react-app\\index.js', + 'prettier', + 'plugin:prettier/recommended', + 'plugin:react-hooks/recommended', + ], + settings: { + react: { + version: 'detect', + }, + }, +}; diff --git a/example/index.tsx b/example/index.tsx index 6ae63ff..eeae802 100644 --- a/example/index.tsx +++ b/example/index.tsx @@ -48,9 +48,10 @@ import { subDays, addDays, startOfDay, format } from 'date-fns'; type FirstDayOfWeek = DatepickerConfigs['firstDayOfWeek']; const offsets: FirstDayOfWeek[] = [0, 1, 2, 3, 4, 5, 6]; +const demoDate = new Date(); + const App = () => { const { colorMode, toggleColorMode } = useColorMode(); - const demoDate = new Date(); const [date, setDate] = useState(demoDate); const [selectedDates, setSelectedDates] = useState([ new Date(), diff --git a/package-lock.json b/package-lock.json index b6304ab..784814b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,8 @@ "version": "0.3.0", "license": "MIT", "dependencies": { + "date-fns": "^2.23.0", + "dayzed": "^3.2.2", "react-focus-lock": "^2.9.5" }, "devDependencies": { @@ -20,9 +22,8 @@ "@tsconfig/recommended": "^1.0.1", "@types/react": "^17.0.15", "@types/react-dom": "^17.0.9", - "date-fns": "^2.23.0", - "dayzed": "^3.2.2", "dts-cli": "^1.6.3", + "eslint-plugin-react-hooks": "^4.6.2", "framer-motion": "^4.1.17", "husky": "^7.0.4", "react": "^17.0.2", @@ -6531,7 +6532,6 @@ "version": "2.25.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.25.0.tgz", "integrity": "sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w==", - "dev": true, "engines": { "node": ">=0.11" }, @@ -6544,7 +6544,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/dayzed/-/dayzed-3.2.2.tgz", "integrity": "sha512-BzNoj+6+er5DPQ0F82Yh1U8MU/jyOo7R+jIlK9FsSjfk4ZIISalygzMcsXTGTFedm5UfTddQnELMVBQUXZDv9Q==", - "dev": true, "dependencies": { "@babel/runtime": "^7.6.2", "date-fns": "^2.0.0" @@ -7576,9 +7575,9 @@ } }, "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", "dev": true, "engines": { "node": ">=10" @@ -20213,14 +20212,12 @@ "date-fns": { "version": "2.25.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.25.0.tgz", - "integrity": "sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w==", - "dev": true + "integrity": "sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w==" }, "dayzed": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/dayzed/-/dayzed-3.2.2.tgz", "integrity": "sha512-BzNoj+6+er5DPQ0F82Yh1U8MU/jyOo7R+jIlK9FsSjfk4ZIISalygzMcsXTGTFedm5UfTddQnELMVBQUXZDv9Q==", - "dev": true, "requires": { "@babel/runtime": "^7.6.2", "date-fns": "^2.0.0" @@ -21144,9 +21141,9 @@ } }, "eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", "dev": true, "requires": {} }, diff --git a/package.json b/package.json index 8437469..8863bb8 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "@types/react": "^17.0.15", "@types/react-dom": "^17.0.9", "dts-cli": "^1.6.3", + "eslint-plugin-react-hooks": "^4.6.2", "framer-motion": "^4.1.17", "husky": "^7.0.4", "react": "^17.0.2", @@ -75,8 +76,8 @@ "typescript": "^4.4.4" }, "dependencies": { - "react-focus-lock": "^2.9.5", "date-fns": "^2.23.0", - "dayzed": "^3.2.2" + "dayzed": "^3.2.2", + "react-focus-lock": "^2.9.5" } -} +} \ No newline at end of file From db5a81850b18dcb923e41eb7a8314a14dbffa105 Mon Sep 17 00:00:00 2001 From: aboveyunhai <35160613+aboveyunhai@users.noreply.github.com> Date: Wed, 7 Aug 2024 02:01:39 -0400 Subject: [PATCH 2/3] fix input value on reset, enable single-picker input editing --- src/single.tsx | 162 +++++++++++++++++++++++++++---------------------- 1 file changed, 88 insertions(+), 74 deletions(-) diff --git a/src/single.tsx b/src/single.tsx index 8c0e927..95fc1cb 100644 --- a/src/single.tsx +++ b/src/single.tsx @@ -1,4 +1,10 @@ -import React, { useEffect, useState } from 'react'; +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; import { Button, ButtonProps, @@ -45,10 +51,7 @@ interface SingleProps extends DatepickerProps { export type VariantProps = | { - propsConfigs?: PropsConfigs; - } - | { - triggerVariant: 'default'; + triggerVariant?: 'default'; propsConfigs?: PropsConfigs; } | { @@ -70,49 +73,41 @@ const DefaultConfigs: Required = { monthsToDisplay: 1, }; -const defaultProps = { - defaultIsOpen: false, - closeOnSelect: true, - triggerVariant: 'default' as const, -}; - -export const SingleDatepicker: React.FC = (props) => { - const mergedProps = { ...defaultProps, ...props }; - const { - date: selectedDate, - name, - disabled, - onDateChange, - id, - minDate, - maxDate, - configs, - usePortal, - portalRef, - disabledDates, - defaultIsOpen, - triggerVariant, - propsConfigs, - closeOnSelect, - children, - } = mergedProps; - +export const SingleDatepicker: React.FC = ({ + date: selectedDate, + name, + disabled, + onDateChange, + id, + minDate, + maxDate, + configs, + usePortal, + portalRef, + disabledDates, + defaultIsOpen = false, + closeOnSelect = true, + children, + ...restProps +}) => { const [dateInView, setDateInView] = useState(selectedDate); const [offset, setOffset] = useState(0); + const internalUpdate = useRef(false); const { onOpen, onClose, isOpen } = useDisclosure({ defaultIsOpen }); const Icon = - mergedProps.triggerVariant === 'input' && mergedProps.triggerIcon ? ( - mergedProps.triggerIcon - ) : ( - - ); + restProps.triggerVariant === 'input' + ? restProps?.triggerIcon ?? + : null; - const datepickerConfigs = { - ...DefaultConfigs, - ...configs, - }; + const datepickerConfigs = useMemo( + () => ({ + ...DefaultConfigs, + ...configs, + }), + [configs] + ); const [tempInput, setInputVal] = useState( selectedDate ? format(selectedDate, datepickerConfigs.dateFormat) : '' @@ -125,37 +120,54 @@ export const SingleDatepicker: React.FC = (props) => { }; // dayzed utils - const handleOnDateSelected: OnDateSelected = ({ selectable, date }) => { - if (!selectable) return; - if (date instanceof Date && !isNaN(date.getTime())) { - onDateChange(date); - if (closeOnSelect) onClose(); - return; - } - }; + const handleOnDateSelected: OnDateSelected = useCallback( + ({ selectable, date }) => { + if (!selectable) return; + if (date instanceof Date && !isNaN(date.getTime())) { + internalUpdate.current = true; + onDateChange(date); + setInputVal(date ? format(date, datepickerConfigs.dateFormat) : ''); + if (closeOnSelect) onClose(); + return; + } + }, + [closeOnSelect, datepickerConfigs.dateFormat, onClose, onDateChange] + ); - const handleInputChange = (event: React.ChangeEvent) => { - setInputVal(event.target.value); - const newDate = parse( - event.target.value, - datepickerConfigs.dateFormat, - new Date() - ); - if (!(newDate instanceof Date && !isNaN(newDate.getTime()))) { - return; - } - const isDisabled = disabledDates?.has(startOfDay(newDate).getTime()); - if (isDisabled) return; - onDateChange(newDate); - }; + const handleInputChange = useCallback( + (event: React.ChangeEvent) => { + internalUpdate.current = true; + setInputVal(event.target.value); + const newDate = parse( + event.target.value, + datepickerConfigs.dateFormat, + new Date() + ); + if (!(newDate instanceof Date && !isNaN(newDate.getTime()))) { + return; + } + const isDisabled = disabledDates?.has(startOfDay(newDate).getTime()); + if (isDisabled) return; + onDateChange(newDate); + setDateInView(newDate); + }, + [datepickerConfigs.dateFormat, disabledDates, onDateChange] + ); const PopoverContentWrapper = usePortal ? Portal : React.Fragment; useEffect(() => { - if (selectedDate) { - setInputVal(format(selectedDate, datepickerConfigs.dateFormat)); + if (internalUpdate.current) { + internalUpdate.current = false; + return; } - }, [selectedDate, datepickerConfigs.dateFormat]); + setInputVal( + typeof selectedDate !== 'undefined' + ? format(selectedDate, datepickerConfigs.dateFormat) + : '' + ); + setDateInView(selectedDate); + }, [datepickerConfigs.dateFormat, selectedDate]); return ( = (props) => { onClose={onPopoverClose} isLazy > - {!children && triggerVariant === 'default' ? ( + {!children && (restProps.triggerVariant ?? 'default') === 'default' ? ( ) : null} - {!children && triggerVariant === 'input' ? ( + {!children && restProps.triggerVariant === 'input' ? ( = (props) => { value={tempInput} onChange={handleInputChange} paddingRight={'2.5rem'} - {...propsConfigs?.inputProps} + {...restProps.propsConfigs?.inputProps} /> @@ -217,7 +229,7 @@ export const SingleDatepicker: React.FC = (props) => { type="button" disabled={disabled} padding={'8px'} - {...propsConfigs?.triggerIconBtnProps} + {...restProps.propsConfigs?.triggerIconBtnProps} > {Icon} @@ -230,9 +242,11 @@ export const SingleDatepicker: React.FC = (props) => { > - + = (props) => { firstDayOfWeek: datepickerConfigs.firstDayOfWeek, }} configs={datepickerConfigs} - propsConfigs={propsConfigs} + propsConfigs={restProps.propsConfigs} disabledDates={disabledDates} /> From a5a16a817a2df8d5396cd4b3efa86425eb4821d6 Mon Sep 17 00:00:00 2001 From: aboveyunhai <35160613+aboveyunhai@users.noreply.github.com> Date: Wed, 7 Aug 2024 02:07:19 -0400 Subject: [PATCH 3/3] remove extend eslint --- .eslintrc.js | 13 ------------- package-lock.json | 1 - package.json | 3 +-- 3 files changed, 1 insertion(+), 16 deletions(-) delete mode 100644 .eslintrc.js diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 5f979dc..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - extends: [ - './node_modules\\dts-cli\\conf\\eslint-config-react-app\\index.js', - 'prettier', - 'plugin:prettier/recommended', - 'plugin:react-hooks/recommended', - ], - settings: { - react: { - version: 'detect', - }, - }, -}; diff --git a/package-lock.json b/package-lock.json index 784814b..85f8394 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,6 @@ "@types/react": "^17.0.15", "@types/react-dom": "^17.0.9", "dts-cli": "^1.6.3", - "eslint-plugin-react-hooks": "^4.6.2", "framer-motion": "^4.1.17", "husky": "^7.0.4", "react": "^17.0.2", diff --git a/package.json b/package.json index 8863bb8..6f7571c 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,6 @@ "@types/react": "^17.0.15", "@types/react-dom": "^17.0.9", "dts-cli": "^1.6.3", - "eslint-plugin-react-hooks": "^4.6.2", "framer-motion": "^4.1.17", "husky": "^7.0.4", "react": "^17.0.2", @@ -80,4 +79,4 @@ "dayzed": "^3.2.2", "react-focus-lock": "^2.9.5" } -} \ No newline at end of file +}