Skip to content

Commit

Permalink
fix popover + minor popover performance change
Browse files Browse the repository at this point in the history
  • Loading branch information
benrandja-akram committed Jun 21, 2024
1 parent 7d99446 commit 5f11d49
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 139 deletions.
3 changes: 1 addition & 2 deletions __tests__/dropdown.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,7 @@ test('Renders <Dropdown /> and calls a function on item click, closes the dropdo
value: 'hello',
icon: 'SunCloudyLine',
onClick,
}),
expect.anything()
})
);
});
expect(document.querySelectorAll('.reqore-popover-content').length).toBe(0);
Expand Down
20 changes: 5 additions & 15 deletions src/components/DatePicker/MonthYearDropdowns.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ZonedDateTime } from '@internationalized/date';
import { toDate } from '.';
import { getPreviousYears, months } from '../../helpers/dates';
import ReqoreControlGroup from '../ControlGroup';
import ReqoreDropdown from '../Dropdown';

Expand All @@ -15,26 +16,14 @@ export const YearMonthDropdowns = ({
setIsYearDropdownOpen(open: boolean): void;
}) => {
const value = _value ?? toDate(new Date());
const months = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
];

const currentYear = new Date().getFullYear();
const years = new Array(currentYear - 1900 + 1).fill(null).map((_, index) => currentYear - index);
const years = getPreviousYears(1900);

return (
<ReqoreControlGroup gapSize='small'>
<ReqoreDropdown
delay={0}
compact
filterable
caretPosition='right'
Expand All @@ -55,6 +44,7 @@ export const YearMonthDropdowns = ({
onToggleChange={setIsMonthDropdownOpen}
/>
<ReqoreDropdown
delay={0}
compact
filterable
caretPosition='right'
Expand Down
228 changes: 120 additions & 108 deletions src/components/DatePicker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
toZoned,
ZonedDateTime,
} from '@internationalized/date';
import React, { useLayoutEffect, useMemo, useReducer, useRef, useState } from 'react';
import React, { useLayoutEffect, useMemo, useRef, useState } from 'react';
import {
Button,
Calendar,
Expand Down Expand Up @@ -167,11 +167,10 @@ export const DatePicker = <T extends TDateValue>({
value?.millisecond ?? 0
);
});

const [focusedValue, setFocusedValue] = useState(value);
const [isMonthDropdownOpen, setIsMonthDropdownOpen] = useState(false);
const [isYearDropdownOpen, setIsYearDropdownOpen] = useState(false);
// a key to reset calendar component to reflect the month/year change so it can show the current month correctly
const [calendarKey, changeCalendarKey] = useReducer((c) => c + 1, 0);

const theme = useReqoreTheme('main', customTheme, intent);
const popoverData = useRef({} as IPopoverControls);
Expand All @@ -194,12 +193,12 @@ export const DatePicker = <T extends TDateValue>({
if (date) setTime(new Time(value?.hour, value?.minute, value?.second, value?.millisecond));
}
onChange?.((isStringRef.current ? date?.toISOString() : date) as T);
setFocusedValue(value);

if (closeOnSelect && !showTime && close) {
popoverData.current?.close();
}
};

const onTimeChange = (time: Time | null) => {
if (!time) return;

Expand All @@ -216,7 +215,15 @@ export const DatePicker = <T extends TDateValue>({
};
const onMonthYearChange = (date) => {
handleDateChange(date, false);
changeCalendarKey();
};
const onToggleChange = (open: boolean) => {
// reset focusedvalue state on popover close
if (!open) {
setFocusedValue(null);
}
};
const handleCalendarDateChange = (date: ZonedDateTime) => {
handleDateChange(value ? toZoned(toCalendarDateTime(date, time), getLocalTimeZone()) : date);
};

return (
Expand All @@ -232,7 +239,7 @@ export const DatePicker = <T extends TDateValue>({
ref={(node) => setContainerRef(node)}
{...props}
>
<DatePickerTooltip targetElement={containerRef} tooltip={tooltip} />
{tooltip && <DatePickerTooltip targetElement={containerRef} tooltip={tooltip} />}
<ReqorePopover
component={ReqoreInput}
componentProps={{
Expand All @@ -250,118 +257,123 @@ export const DatePicker = <T extends TDateValue>({
...inputProps,
}}
closeOnOutsideClick={!isMonthDropdownOpen && !isYearDropdownOpen}
closeOnAnyClick={false}
passPopoverData={(data) => (popoverData.current = data)}
isReqoreComponent
noWrapper
handler='click'
placement='bottom-start'
noArrow
onToggleChange={onToggleChange}
{...popoverProps}
content={
<Calendar<ZonedDateTime> key={calendarKey} defaultFocusedValue={value}>
<ReqorePanel
responsiveActionsWrapperProps={{ fluid: false }}
minimal
size='small'
responsiveTitle={false}
intent={intent}
label={
<YearMonthDropdowns
value={value}
onValueChange={onMonthYearChange}
setIsMonthDropdownOpen={setIsMonthDropdownOpen}
setIsYearDropdownOpen={setIsYearDropdownOpen}
/>
}
{...pickerProps}
actions={[
{
group: [
{
as: ReqoreButton,
props: {
as: Button,
customTheme: theme,
slot: 'previous',
icon: 'ArrowLeftFill',
size: 'normal',
compact: true,
content={useMemo(
() => (
<Calendar<ZonedDateTime>
defaultFocusedValue={value}
onChange={handleCalendarDateChange}
focusedValue={focusedValue}
onFocusChange={(date) => setFocusedValue(toZoned(date, getLocalTimeZone()))}
>
<ReqorePanel
responsiveActionsWrapperProps={{ fluid: false }}
minimal
size='small'
responsiveTitle={false}
intent={intent}
label={
<YearMonthDropdowns
value={focusedValue}
onValueChange={onMonthYearChange}
setIsMonthDropdownOpen={setIsMonthDropdownOpen}
setIsYearDropdownOpen={setIsYearDropdownOpen}
/>
}
{...pickerProps}
actions={[
{
group: [
{
as: ReqoreButton,
props: {
as: Button,
customTheme: theme,
slot: 'previous',
icon: 'ArrowLeftFill',
size: 'normal',
compact: true,
},
},
},
{
as: ReqoreButton,
props: {
as: Button,
customTheme: theme,
slot: 'next',
icon: 'ArrowRightFill',
size: 'normal',
compact: true,
{
as: ReqoreButton,
props: {
as: Button,
customTheme: theme,
slot: 'next',
icon: 'ArrowRightFill',
size: 'normal',
compact: true,
},
},
},
],
},
]}
>
<StyledCalendarGrid>
{(date) => {
const isSelected = value && isSameDay(date, value);
return (
<StyledCalendarCell
data-selected={isSelected}
date={date}
key={date.toString()}
>
<ReqoreButton
key={date.toString()}
customTheme={isSelected ? theme : { main: 'transparent' }}
label={date.day}
onClick={() => handleDateChange(toZoned(date, getLocalTimeZone()))}
active={isSelected}
textAlign='center'
circle
minimal
flat
compact
{...(isSelected ? pickerActiveDayProps : pickerDayProps)}
/>
</StyledCalendarCell>
);
}}
</StyledCalendarGrid>
{showTime && (
<ReqoreControlGroup fluid>
<StyledTimeField
value={time}
onChange={onTimeChange}
granularity={granularity}
hideTimeZone={hideTimeZone}
shouldForceLeadingZeros={shouldForceLeadingZeros}
hourCycle={hourCycle}
aria-label='Time'
{...timeFieldProps}
>
<ReqoreInput
icon='TimeLine'
fluid
as={StyledDateInput}
flat={flat}
rounded={rounded}
minimal={minimal}
size={size}
pill={pill}
intent={intent}
theme={theme}
{...timeInputProps}
],
},
]}
>
<StyledCalendarGrid>
{(date) => {
const isSelected = value && isSameDay(date, value);
return (
<StyledCalendarCell data-selected={isSelected} date={date}>
<ReqoreButton
key={date.toString()}
customTheme={isSelected ? theme : { main: 'transparent' }}
label={date.day}
active={isSelected}
textAlign='center'
circle
minimal
flat
compact
{...(isSelected ? pickerActiveDayProps : pickerDayProps)}
/>
</StyledCalendarCell>
);
}}
</StyledCalendarGrid>
{showTime && (
<ReqoreControlGroup fluid>
<StyledTimeField
value={time}
onChange={onTimeChange}
granularity={granularity}
hideTimeZone={hideTimeZone}
shouldForceLeadingZeros={shouldForceLeadingZeros}
hourCycle={hourCycle}
aria-label='Time'
{...timeFieldProps}
>
{(segment) => <StyledDateSegment segment={segment} />}
</ReqoreInput>
</StyledTimeField>
</ReqoreControlGroup>
)}
</ReqorePanel>
</Calendar>
}
<ReqoreInput
icon='TimeLine'
fluid
as={StyledDateInput}
flat={flat}
rounded={rounded}
minimal={minimal}
size={size}
pill={pill}
intent={intent}
theme={theme}
{...timeInputProps}
>
{(segment) => <StyledDateSegment segment={segment} />}
</ReqoreInput>
</StyledTimeField>
</ReqoreControlGroup>
)}
</ReqorePanel>
</Calendar>
),
[value, !isMonthDropdownOpen && !isYearDropdownOpen, focusedValue, time]
)}
>
{(segment) => <StyledDateSegment segment={segment} />}
</ReqorePopover>
Expand Down
18 changes: 18 additions & 0 deletions src/helpers/dates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export const months = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
];
export const getPreviousYears = (min: number) => {
const currentYear = new Date().getFullYear();
return new Array(currentYear - min + 1).fill(null).map((_, index) => currentYear - index);
};
4 changes: 2 additions & 2 deletions src/hooks/usePopover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ const usePopover = ({
const { addPopover, removePopover, updatePopover, popovers, isPopoverOpen } =
useContext(PopoverContext);
const tooltips = useReqoreProperty('tooltips');
const { current }: MutableRefObject<string> = useRef(shortid.generate());
const current: string = useMemo(() => shortid.generate(), []);
let { current: timeout }: MutableRefObject<any> = useRef(0);

const startEvent = startEvents[handler];
Expand Down Expand Up @@ -173,7 +173,7 @@ const usePopover = ({
if (openOnMount && targetElement) {
_addPopover();
}
}, [targetElement?.outerHTML]);
}, [!!targetElement]);

useEffect(() => {
if (targetElement && content) {
Expand Down
Loading

0 comments on commit 5f11d49

Please sign in to comment.