Skip to content

Commit

Permalink
feat(react): add Dialog component
Browse files Browse the repository at this point in the history
  • Loading branch information
jonambas committed Dec 25, 2023
1 parent 6e6437d commit 786107a
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 2 deletions.
28 changes: 28 additions & 0 deletions libra/components/Dialog.libra.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
Button,
Text,
Dialog,
Stack,
DateField,
Select
} from '../../packages/react/src';

directory('Dialog', () => {
add('Default', () => {
return (
<Dialog trigger={<Button>Open</Button>}>
<Stack>
<Text looksLike="h4" element="h2">
Dialog
</Text>
<DateField id="date" />
<Select id="select">
<Select.Item value="foo">Foo</Select.Item>
<Select.Item value="bar">Bar</Select.Item>
</Select>
<Button>Button</Button>
</Stack>
</Dialog>
);
});
});
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"@changesets/cli": "2.27.1",
"@pandacss/dev": "0.20.1",
"@rollup/plugin-alias": "5.0.1",
"@sweatpants/libra": "0.0.35",
"@sweatpants/libra": "0.0.36",
"@types/react": "18.2.45",
"@types/react-dom": "18.2.18",
"framer-motion": "10.16.5",
Expand Down
128 changes: 128 additions & 0 deletions packages/react/src/dialog/Dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
'use client';

import {
ComponentPropsWithRef,
MutableRefObject,
ReactNode,
forwardRef,
useEffect,
useRef,
useState
} from 'react';
import * as RadixDialog from '@radix-ui/react-dialog';
import { motion, AnimatePresence } from 'framer-motion';
import { css } from '@styles/css';
import { Button } from '../button/Button';
import { Cross } from '../icons/icons';
import { ScreenReaderOnly } from '../screen-reader-only/ScreenReaderOnly';

export type DialogProps = ComponentPropsWithRef<'div'> &
RadixDialog.DialogProps & {
trigger?: ReactNode;
};

const overlay = css({
position: 'fixed',
zIndex: '10',
inset: 0,
background: { _lightScheme: '#00000090', _darkScheme: '#00000090' }
});

const content = css({
position: 'fixed',
zIndex: '11',
top: '50%',
left: '50%',
transform: 'scale(0.9) translate(-50%, -50%)',
transformOrigin: 'top left',
background: 'contentBg',
borderRadius: { sm: 'xl', base: '0' },
borderWidth: '1px',
borderColor: 'borders',
boxShadow: '0 0 12px 0px rgba(0,0,0,0.05)',
p: '6',
maxWidth: '30rem',
width: '100%'
});

const close = css({
position: 'absolute!',
py: '4',
right: '4',
top: '4'
});

const Dialog = forwardRef<HTMLDivElement, DialogProps>((props, userRef) => {
const { children, trigger, defaultOpen, open, onOpenChange, ...rest } = props;
const [internalOpen, setInternalOpen] = useState<boolean>(
defaultOpen ?? open ?? false
);

const ref = useRef(null) as MutableRefObject<HTMLElement | null>;

useEffect(() => {
if (typeof document !== 'undefined' && document.body) {
ref.current = document.body;
}
}, []);

const handleOpenChange = (value: boolean) => {
setInternalOpen(value);
onOpenChange?.(value);
};

const finalOpen = defaultOpen ?? open ?? internalOpen;

return (
<RadixDialog.Root
ref={userRef}
onOpenChange={handleOpenChange}
open={finalOpen}
{...rest}
>
<RadixDialog.Trigger asChild>{trigger}</RadixDialog.Trigger>
<AnimatePresence>
{finalOpen ? (
<RadixDialog.Portal forceMount>
<RadixDialog.Overlay asChild className={overlay}>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
/>
</RadixDialog.Overlay>
<RadixDialog.Content className={content} asChild>
<motion.div
transition={{ duration: 0.25, ease: 'easeInOut' }}
initial={{
opacity: 0,
transform: 'scale(0.98) translate(-50%, -50%)'
}}
animate={{
opacity: 1,
transform: 'scale(1) translate(-50%, -50%)'
}}
exit={{
opacity: 0,
transform: 'scale(0.98) translate(-50%, -50%)'
}}
>
{children}
<RadixDialog.Close asChild>
<Button className={close} kind="bare" size="md">
<ScreenReaderOnly>Close</ScreenReaderOnly>
<Cross />
</Button>
</RadixDialog.Close>
</motion.div>
</RadixDialog.Content>
</RadixDialog.Portal>
) : null}
</AnimatePresence>
</RadixDialog.Root>
);
});

Dialog.displayName = 'Dialog';

export { Dialog };
2 changes: 1 addition & 1 deletion packages/react/src/drawer/Drawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const content = css({
});

const close = css({
position: 'absolute',
position: 'absolute!',
py: '4',
right: '4',
top: '4'
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export * from './card/CardDivider';
export * from './color-scheme-provider/ColorSchemeProvider';
export * from './date-field/DateField';
export * from './date-picker/DatePicker';
export * from './dialog/Dialog';
export * from './drawer/Drawer';
export * from './icons/icons';
export * from './label/Label';
Expand Down

0 comments on commit 786107a

Please sign in to comment.