Skip to content

Commit

Permalink
Add documentation page for Popover component
Browse files Browse the repository at this point in the history
  • Loading branch information
acelaya committed Nov 22, 2024
1 parent 505c800 commit ff8094c
Show file tree
Hide file tree
Showing 7 changed files with 278 additions and 16 deletions.
2 changes: 1 addition & 1 deletion src/components/feedback/Popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ export type PopoverProps = {
classes?: string | string[];
variant?: 'panel' | 'custom'; // TODO 'tooltip'

/** Whether the popover is currently open or not. Defaults to false */
/** Whether the popover is currently open or not */
open: boolean;
/** The element relative to which the popover should be positioned */
anchorElementRef: RefObject<HTMLElement | undefined>;
Expand Down
176 changes: 176 additions & 0 deletions src/pattern-library/components/patterns/feedback/PopoverPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import { Link } from '../../../../components/navigation';
import Library from '../../Library';

export default function PopoverPage() {
return (
<Library.Page
title="Popover"
intro={
<>
<p>
<code>Popover</code> is a floating component that can be shown
next/relative to another anchor element.
</p>
</>
}
>
<Library.Section
title="Popover"
intro={
<>
<p>
By default, <code>Popover</code> will be displayed under the
anchor element, unless there is not enough space below.
</p>
<p>
It will always be at least as big as the anchor element, but it
can grow to fit its content if needed. However, it will never grow
or be displayed outside of the viewport.
</p>
<p>
In browsers that support it, <code>Popover</code> uses the{' '}
<Link
target="_blank"
href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/popover"
>
<code>popover</code>
</Link>{' '}
attribute and gets toggled via{' '}
<Link
target="_blank"
href="https://developer.mozilla.org/en-US/docs/Web/API/Popover_API"
>
popover API
</Link>
. Otherwise, it is rendered as an absolute-positioned element, so
it is recommended to wrap it and its anchor element in a
relative-positioned container.
</p>
</>
}
>
<Library.Pattern>
<Library.Usage symbolName="Popover" />
<Library.Example>
<Library.Demo
title="Basic Popover"
exampleFile="popover-basic"
withSource
/>
</Library.Example>
</Library.Pattern>

<Library.Pattern title="Popover component API">
<Library.Example title="align">
<Library.Info>
<Library.InfoItem label="description">
Determines to what side of the anchor element should the popover
be aligned.
</Library.InfoItem>
<Library.InfoItem label="type">
<code>{"'left' | 'right'"}</code>
</Library.InfoItem>
<Library.InfoItem label="default">
<code>{"'left'"}</code>
</Library.InfoItem>
</Library.Info>
<Library.Demo
title="Right-aligned Popover"
exampleFile="popover-right"
withSource
/>
</Library.Example>
<Library.Example title="anchorElementRef">
<Library.Info>
<Library.InfoItem label="description">
A reference to the element to which the popover should anchor,
which will be used to calculate the popover size and
positioning.
</Library.InfoItem>
<Library.InfoItem label="type">
<code>{'RefObject<HTMLElement | undefined>'}</code>
</Library.InfoItem>
</Library.Info>
</Library.Example>
<Library.Example title="asNativePopover">
<Library.Info>
<Library.InfoItem label="description">
Determines if the{' '}
<Link
target="_blank"
href="https://developer.mozilla.org/en-US/docs/Web/API/Popover_API"
>
popover API
</Link>{' '}
should be used. It{"'"}s mainly used as a test seam, but can
help explicitly disabling this behavior if needed.
</Library.InfoItem>
<Library.InfoItem label="type">
<code>boolean</code>
</Library.InfoItem>
<Library.InfoItem label="default">
<code>true</code> if the browser supports <code>[popover]</code>
. Otherwise it is <code>false</code>
</Library.InfoItem>
</Library.Info>
</Library.Example>
<Library.Example title="classes">
<Library.Info>
<Library.InfoItem label="description">
Additional CSS classes to pass to the popover.
</Library.InfoItem>
<Library.InfoItem label="type">
<code>string | string[]</code>
</Library.InfoItem>
<Library.InfoItem label="default">
<code>undefined</code>
</Library.InfoItem>
</Library.Info>
</Library.Example>
<Library.Example title="open">
<Library.Info>
<Library.InfoItem label="description">
Whether the <code>Popover</code> is currently open or not.
</Library.InfoItem>
<Library.InfoItem label="type">
<code>boolean</code>
</Library.InfoItem>
</Library.Info>
</Library.Example>
<Library.Example title="restoreFocusOnClose">
<Library.Info>
<Library.InfoItem label="description">
Determines if focus should be restored when the{' '}
<code>Popover</code> is closed.
</Library.InfoItem>
<Library.InfoItem label="type">
<code>boolean</code>
</Library.InfoItem>
<Library.InfoItem label="default">
<code>false</code>
</Library.InfoItem>
</Library.Info>
</Library.Example>
<Library.Example title="variant">
<Library.Info>
<Library.InfoItem label="description">
Set the <code>Popover</code> theming.
</Library.InfoItem>
<Library.InfoItem label="type">
<code>{"'panel' | 'custom'"}</code>
</Library.InfoItem>
<Library.InfoItem label="default">
<code>{"'panel'"}</code>
</Library.InfoItem>
</Library.Info>
<Library.Demo
title="Custom Popover"
exampleFile="popover-custom"
withSource
/>
</Library.Example>
</Library.Pattern>
</Library.Section>
</Library.Page>
);
}
18 changes: 3 additions & 15 deletions src/pattern-library/components/patterns/input/SelectPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,21 +126,9 @@ export default function SelectPage() {
{"'"} UI can be customized and values can be objects.
</p>
<p>
In browsers that support it, the listbox uses the{' '}
<Link
target="_blank"
href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/popover"
>
<code>popover</code>
</Link>{' '}
attribute and gets toggled via{' '}
<Link
target="_blank"
href="https://developer.mozilla.org/en-US/docs/Web/API/Popover_API"
>
popover API
</Link>
. Otherwise, it is rendered as an absolute-positioned element.
A <Library.Link href="/feedback-popover">Popover</Library.Link>{' '}
component is used to wrap the listbox and ensure it is always
correctly positioned.
</p>

<Library.Example title="Composing and styling Selects">
Expand Down
27 changes: 27 additions & 0 deletions src/pattern-library/examples/popover-basic.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useRef, useState } from 'preact/hooks';

import { Popover } from '../../components/feedback';
import { Button } from '../../components/input';
import { useClickAway } from '../../hooks/use-click-away';

export default function App() {
const [open, setOpen] = useState(false);
const buttonRef = useRef<HTMLButtonElement | null>(null);

useClickAway(buttonRef, () => setOpen(false));

return (
<div className="flex justify-center">
<Button
variant="primary"
elementRef={buttonRef}
onClick={() => setOpen(prev => !prev)}
>
{open ? 'Close' : 'Open'} Popover
</Button>
<Popover open={open} anchorElementRef={buttonRef} classes="p-2">
The content of the popover goes here
</Popover>
</div>
);
}
32 changes: 32 additions & 0 deletions src/pattern-library/examples/popover-custom.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useRef, useState } from 'preact/hooks';

import { Popover } from '../../components/feedback';
import { Button } from '../../components/input';
import { useClickAway } from '../../hooks/use-click-away';

export default function App() {
const [open, setOpen] = useState(false);
const buttonRef = useRef<HTMLButtonElement | null>(null);

useClickAway(buttonRef, () => setOpen(false));

return (
<div className="flex justify-center">
<Button
variant="primary"
elementRef={buttonRef}
onClick={() => setOpen(prev => !prev)}
>
{open ? 'Close' : 'Open'} Popover
</Button>
<Popover
open={open}
anchorElementRef={buttonRef}
variant="custom"
classes="p-3 border-4 border-slate-7 bg-green-success text-white font-bold rounded-tr-lg rounded-bl-lg"
>
This popover has been customized
</Popover>
</div>
);
}
32 changes: 32 additions & 0 deletions src/pattern-library/examples/popover-right.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useRef, useState } from 'preact/hooks';

import { Popover } from '../../components/feedback';
import { Button } from '../../components/input';
import { useClickAway } from '../../hooks/use-click-away';

export default function App() {
const [open, setOpen] = useState(false);
const buttonRef = useRef<HTMLButtonElement | null>(null);

useClickAway(buttonRef, () => setOpen(false));

return (
<div className="flex justify-center">
<Button
variant="primary"
elementRef={buttonRef}
onClick={() => setOpen(prev => !prev)}
>
{open ? 'Close' : 'Open'} Popover
</Button>
<Popover
open={open}
align="right"
anchorElementRef={buttonRef}
classes="p-2"
>
The content of the popover goes here
</Popover>
</div>
);
}
7 changes: 7 additions & 0 deletions src/pattern-library/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import TablePage from './components/patterns/data/TablePage';
import ThumbnailPage from './components/patterns/data/ThumbnailPage';
import CalloutPage from './components/patterns/feedback/CalloutPage';
import DialogPage from './components/patterns/feedback/DialogPage';
import PopoverPage from './components/patterns/feedback/PopoverPage';
import SpinnerPage from './components/patterns/feedback/SpinnerPage';
import ToastMessagesPage from './components/patterns/feedback/ToastMessagesPage';
import UseClickAwayPage from './components/patterns/hooks/UseClickAwayPage';
Expand Down Expand Up @@ -146,6 +147,12 @@ const routes: PlaygroundRoute[] = [
component: DialogPage,
route: '/feedback-dialog',
},
{
title: 'Popover',
group: 'feedback',
component: PopoverPage,
route: '/feedback-popover',
},
{
title: 'Spinner',
group: 'feedback',
Expand Down

0 comments on commit ff8094c

Please sign in to comment.