Skip to content

Commit

Permalink
fix popover inside modal when usePortal is true
Browse files Browse the repository at this point in the history
  • Loading branch information
aboveyunhai committed Jan 22, 2024
1 parent 966dd73 commit ca5b4c5
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 101 deletions.
251 changes: 154 additions & 97 deletions example/index.tsx
@@ -1,5 +1,5 @@
import 'react-app-polyfill/ie11';
import React, { useState } from 'react';
import React, { useRef, useState } from 'react';
import ReactDOM from 'react-dom';
import {
Box,
Expand All @@ -12,6 +12,13 @@ import {
Heading,
HStack,
Link,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
StackDivider,
Switch,
Tab,
Expand All @@ -22,6 +29,7 @@ import {
Text,
ThemeConfig,
useColorMode,
useDisclosure,
VStack,
} from '@chakra-ui/react';
import {
Expand Down Expand Up @@ -51,6 +59,8 @@ const App = () => {
const [firstDayOfWeek, setFirstDayOfWeek] = useState<FirstDayOfWeek>(1);
const [isSingleChecked, setSingleCheck] = useState(true);
const [isRangeChecked, setRangeCheck] = useState(true);
const { isOpen, onOpen, onClose } = useDisclosure();
const modalRef = useRef(null);

return (
<VStack
Expand Down Expand Up @@ -137,102 +147,148 @@ const App = () => {
<TabPanels height={'20rem'}>
<TabPanel>
<Panel>
<Section title="Single:">
<Flex alignItems={'center'} gap={2}>
<Box marginRight={'1rem'}>closeOnSelect:</Box>
<Switch
isChecked={isSingleChecked}
onChange={(e) => setSingleCheck(e.currentTarget.checked)}
/>
<Button
size={'sm'}
onClick={() => {
setDate(undefined);
}}
>
Set Empty (undefined)
</Button>
</Flex>
{/* chakra ui add prefix for the trigger for some reasons? */}
<Flex style={{ gap: '1rem' }} alignItems="center">
<label htmlFor={`popover-trigger-default`}>Default:</label>
<SingleDatepicker
id="default"
date={date}
disabledDates={
new Set([
startOfDay(subDays(demoDate, 6)).getTime(),
startOfDay(subDays(demoDate, 4)).getTime(),
startOfDay(subDays(demoDate, 2)).getTime(),
])
}
propsConfigs={{}}
minDate={subDays(demoDate, 8)}
maxDate={addDays(demoDate, 8)}
onDateChange={setDate}
closeOnSelect={isSingleChecked}
/>
</Flex>
<Flex style={{ gap: '1rem' }} alignItems="center">
<label htmlFor={`popover-trigger-input`}>Input:</label>
<SingleDatepicker
id="input"
triggerVariant="input"
date={date}
disabledDates={
new Set([
startOfDay(subDays(demoDate, 6)).getTime(),
startOfDay(subDays(demoDate, 4)).getTime(),
startOfDay(subDays(demoDate, 2)).getTime(),
])
}
minDate={subDays(demoDate, 8)}
maxDate={addDays(demoDate, 8)}
onDateChange={setDate}
closeOnSelect={isSingleChecked}
/>
</Flex>
</Section>
<Section title="Range:">
<Flex alignItems={'center'} gap={2}>
<Box marginRight={'1rem'}>closeOnSelect:</Box>
<Switch
isChecked={isRangeChecked}
onChange={(e) => setRangeCheck(e.currentTarget.checked)}
/>
<Button
size={'sm'}
onClick={() => {
setSelectedDates([]);
}}
>
Set Empty (Empty Array: "[]")
</Button>
</Flex>
<Flex style={{ gap: '1rem' }} alignItems="center">
<label htmlFor={`popover-trigger-default-range`}>
Default:
</label>
<RangeDatepicker
id="default-range"
selectedDates={selectedDates}
onDateChange={setSelectedDates}
closeOnSelect={isRangeChecked}
/>
</Flex>
<Flex style={{ gap: '1rem' }} alignItems="center">
<label htmlFor={`popover-trigger-input-range`}>
Input:
</label>
<RangeDatepicker
id="input-range"
triggerVariant="input"
selectedDates={selectedDates}
onDateChange={setSelectedDates}
closeOnSelect={isRangeChecked}
/>
</Flex>
</Section>
<Flex flexDir={'column'} gap={3} pb="5rem">
<Section title="Single:">
<Flex alignItems={'center'} gap={2}>
<Box marginRight={'1rem'}>closeOnSelect:</Box>
<Switch
isChecked={isSingleChecked}
onChange={(e) => setSingleCheck(e.currentTarget.checked)}
/>
<Button
size={'sm'}
onClick={() => {
setDate(undefined);
}}
>
Set Empty (undefined)
</Button>
</Flex>
{/* chakra ui add prefix for the trigger for some reasons? */}
<Flex gap="1rem" alignItems="center">
<label htmlFor={`popover-trigger-default`}>Default:</label>
<SingleDatepicker
id="default"
date={date}
disabledDates={
new Set([
startOfDay(subDays(demoDate, 6)).getTime(),
startOfDay(subDays(demoDate, 4)).getTime(),
startOfDay(subDays(demoDate, 2)).getTime(),
])
}
propsConfigs={{}}
minDate={subDays(demoDate, 8)}
maxDate={addDays(demoDate, 8)}
onDateChange={setDate}
closeOnSelect={isSingleChecked}
/>
</Flex>
<Flex gap="1rem" alignItems="center">
<label htmlFor={`popover-trigger-input`}>Input:</label>
<SingleDatepicker
id="input"
triggerVariant="input"
date={date}
disabledDates={
new Set([
startOfDay(subDays(demoDate, 6)).getTime(),
startOfDay(subDays(demoDate, 4)).getTime(),
startOfDay(subDays(demoDate, 2)).getTime(),
])
}
minDate={subDays(demoDate, 8)}
maxDate={addDays(demoDate, 8)}
onDateChange={setDate}
closeOnSelect={isSingleChecked}
/>
</Flex>
</Section>
<Section title="Range:">
<Flex alignItems={'center'} gap={2}>
<Box marginRight={'1rem'}>closeOnSelect:</Box>
<Switch
isChecked={isRangeChecked}
onChange={(e) => setRangeCheck(e.currentTarget.checked)}
/>
<Button
size={'sm'}
onClick={() => {
setSelectedDates([]);
}}
>
Set Empty (Empty Array: "[]")
</Button>
</Flex>
<Flex gap="1rem" alignItems="center">
<label htmlFor={`popover-trigger-default-range`}>
Default:
</label>
<RangeDatepicker
id="default-range"
selectedDates={selectedDates}
onDateChange={setSelectedDates}
closeOnSelect={isRangeChecked}
/>
</Flex>
<Flex gap="1rem" alignItems="center">
<label htmlFor={`popover-trigger-input-range`}>
Input:
</label>
<RangeDatepicker
id="input-range"
triggerVariant="input"
selectedDates={selectedDates}
onDateChange={setSelectedDates}
closeOnSelect={isRangeChecked}
/>
</Flex>
</Section>
<Section title="Inside Modal:">
<Button onClick={onOpen}>Open Modal</Button>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent ref={modalRef}>
<ModalHeader>Modal Title</ModalHeader>
<ModalCloseButton />
<ModalBody>
<Flex flexDir={'column'} gap={2}>
<div>Default:</div>
<SingleDatepicker
date={date}
onDateChange={setDate}
/>
<RangeDatepicker
selectedDates={selectedDates}
onDateChange={setSelectedDates}
/>
<div>
if <code>{`usePortal={true}`} </code> <br />
please add <code> {`portalRef={modalRef}`}</code>
</div>
<SingleDatepicker
date={date}
onDateChange={setDate}
portalRef={modalRef}
/>
<RangeDatepicker
selectedDates={selectedDates}
onDateChange={setSelectedDates}
usePortal={true}
portalRef={modalRef}
/>
</Flex>
</ModalBody>
<ModalFooter>
<Button colorScheme="blue" mr={3} onClick={onClose}>
Close
</Button>
<Button variant="ghost">Secondary Action</Button>
</ModalFooter>
</ModalContent>
</Modal>
</Section>
</Flex>
</Panel>
</TabPanel>
<TabPanel>
Expand Down Expand Up @@ -498,6 +554,7 @@ const RangeCalendarDemo = () => {
const Section: React.FC<React.PropsWithChildren<{ title?: string }>> = ({
title,
children,
sectionProps,
}) => (
<VStack spacing={3} alignItems="flex-start" padding={'0.25rem'}>
<Heading size="md">{title}</Heading>
Expand Down
10 changes: 7 additions & 3 deletions src/range.tsx
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useRef, useState } from 'react';

Check warning on line 1 in src/range.tsx

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 16.x and ubuntu-latest

'useRef' is defined but never used

Check warning on line 1 in src/range.tsx

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 16.x and windows-latest

'useRef' is defined but never used

Check warning on line 1 in src/range.tsx

View workflow job for this annotation

GitHub Actions / Build, lint, and test on Node 16.x and macOS-latest

'useRef' is defined but never used
import { Props as DayzedHookProps } from 'dayzed';
import { Month_Names_Short, Weekday_Names_Short } from './utils/calanderUtils';
import {
Expand Down Expand Up @@ -96,6 +96,7 @@ interface RangeProps extends DatepickerProps {
id?: string;
name?: string;
usePortal?: boolean;
portalRef?: React.MutableRefObject<null>;
}

export type RangeDatepickerProps = RangeProps & VariantProps;
Expand All @@ -122,6 +123,7 @@ export const RangeDatepicker: React.FC<RangeDatepickerProps> = (props) => {
id,
name,
usePortal,
portalRef,
defaultIsOpen,
closeOnSelect,
selectedDates,
Expand Down Expand Up @@ -231,7 +233,7 @@ export const RangeDatepicker: React.FC<RangeDatepickerProps> = (props) => {
}
}}
autoComplete="off"
width={'15rem'}
width={'16rem'}
isDisabled={disabled}
name={name}
value={intVal}
Expand All @@ -258,7 +260,9 @@ export const RangeDatepicker: React.FC<RangeDatepickerProps> = (props) => {
</Flex>
) : null}
{children ? children(selectedDates) : null}
<PopoverContentWrapper>
<PopoverContentWrapper
{...(usePortal ? { containerRef: portalRef } : {})}
>
<PopoverContent
width="100%"
{...propsConfigs?.popoverCompProps?.popoverContentProps}
Expand Down
6 changes: 5 additions & 1 deletion src/single.tsx
Expand Up @@ -41,6 +41,7 @@ interface SingleProps extends DatepickerProps {
id?: string;
name?: string;
usePortal?: boolean;
portalRef?: React.MutableRefObject<null>;
}

export type VariantProps =
Expand Down Expand Up @@ -88,6 +89,7 @@ export const SingleDatepicker: React.FC<SingleDatepickerProps> = (props) => {
maxDate,
configs,
usePortal,
portalRef,
disabledDates,
defaultIsOpen,
triggerVariant,
Expand Down Expand Up @@ -223,7 +225,9 @@ export const SingleDatepicker: React.FC<SingleDatepickerProps> = (props) => {
</Flex>
) : null}
{children ? children(selectedDate) : null}
<PopoverContentWrapper>
<PopoverContentWrapper
{...(usePortal ? { containerRef: portalRef } : {})}
>
<PopoverContent
width="100%"
{...propsConfigs?.popoverCompProps?.popoverContentProps}
Expand Down

0 comments on commit ca5b4c5

Please sign in to comment.