Skip to content

Commit

Permalink
feat(popover): add i18nDismissLabel prop (#2227)
Browse files Browse the repository at this point in the history
  • Loading branch information
shleewhite committed Feb 22, 2022
1 parent a70ce82 commit 4aefbe7
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 33 deletions.
6 changes: 6 additions & 0 deletions .changeset/nervous-clouds-suffer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@twilio-paste/popover': patch
'@twilio-paste/core': patch
---

[Popover] add i18nDismissLabel prop to support i18n
32 changes: 32 additions & 0 deletions packages/paste-core/components/popover/__tests__/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -219,4 +219,36 @@ describe('Popover', () => {
expect(popoverButton).toHaveStyleRule('background-color', 'rgb(6,3,58)');
});
});

describe('i18n', () => {
it('should have default dismiss button text', () => {
render(
<Theme.Provider theme="default">
<PopoverContainer baseId="test-id" visible>
<PopoverButton variant="primary">Open popover</PopoverButton>
<Popover aria-label="Popover">Foo</Popover>
</PopoverContainer>
</Theme.Provider>
);

const dismissButton = screen.getByRole('button', {name: 'Close popover'});
expect(dismissButton).toBeDefined();
});

it('should use i18nKeyboardControls for dismiss button text', () => {
render(
<Theme.Provider theme="default">
<PopoverContainer baseId="test-id" visible>
<PopoverButton variant="primary">Abrir popover</PopoverButton>
<Popover aria-label="Popover" i18nDismissLabel="Cerrar popover">
Foo
</Popover>
</PopoverContainer>
</Theme.Provider>
);

const dismissButton = screen.getByRole('button', {name: 'Cerrar popover'});
expect(dismissButton).toBeDefined();
});
});
});
66 changes: 33 additions & 33 deletions packages/paste-core/components/popover/src/Popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {Button} from '@twilio-paste/button';
import {CloseIcon} from '@twilio-paste/icons/esm/CloseIcon';
import {StyledBase} from '@twilio-paste/theme';
import {NonModalDialogPrimitive} from '@twilio-paste/non-modal-dialog-primitive';
import {ScreenReaderOnly} from '@twilio-paste/screen-reader-only';
import {PopoverArrow} from './PopoverArrow';
import {PopoverContext} from './PopoverContext';

Expand Down Expand Up @@ -33,47 +34,46 @@ StyledPopover.displayName = 'StyledPopover';
export interface PopoverProps extends Pick<BoxProps, 'element'> {
'aria-label': string;
children: React.ReactNode;
i18nDismissLabel?: string;
}

const Popover = React.forwardRef<HTMLDivElement, PopoverProps>(({children, element = 'POPOVER', ...props}, ref) => {
const popover = React.useContext(PopoverContext);
return (
<NonModalDialogPrimitive {...(popover as any)} {...props} as={StyledPopover} ref={ref} preventBodyScroll={false}>
{/* import Paste Theme Based Styles due to portal positioning. */}
<StyledBase>
<PopoverArrow {...(popover as any)} />
<Box element={element} paddingX="space80" paddingY="space70">
<Box position="absolute" right={8} top={8}>
<Button
element={`${element}_CLOSE_BUTTON`}
variant="secondary_icon"
size="reset"
// @ts-ignore
// Property 'hide' does not exist on type 'Partial<PopoverState>'
// But reakit docs suggest using it
// https://reakit.io/docs/popover/#initial-focus
onClick={popover.hide}
>
<CloseIcon
element={`${element}_CLOSE_ICON`}
decorative={false}
color="colorTextWeak"
size="sizeIcon10"
title="Close popover"
/>
</Button>
const Popover = React.forwardRef<HTMLDivElement, PopoverProps>(
({children, element = 'POPOVER', i18nDismissLabel = 'Close popover', ...props}, ref) => {
const popover = React.useContext(PopoverContext);
return (
<NonModalDialogPrimitive {...(popover as any)} {...props} as={StyledPopover} ref={ref} preventBodyScroll={false}>
{/* import Paste Theme Based Styles due to portal positioning. */}
<StyledBase>
<PopoverArrow {...(popover as any)} />
<Box element={element} paddingX="space80" paddingY="space70">
<Box position="absolute" right={8} top={8}>
<Button
element={`${element}_CLOSE_BUTTON`}
variant="secondary_icon"
size="reset"
// @ts-ignore
// Property 'hide' does not exist on type 'Partial<PopoverState>'
// But reakit docs suggest using it
// https://reakit.io/docs/popover/#initial-focus
onClick={popover.hide}
>
<CloseIcon element={`${element}_CLOSE_ICON`} decorative color="colorTextWeak" size="sizeIcon10" />
<ScreenReaderOnly>{i18nDismissLabel}</ScreenReaderOnly>
</Button>
</Box>
{children}
</Box>
{children}
</Box>
</StyledBase>
</NonModalDialogPrimitive>
);
});
</StyledBase>
</NonModalDialogPrimitive>
);
}
);

Popover.propTypes = {
'aria-label': PropTypes.string.isRequired,
children: PropTypes.node.isRequired,
element: PropTypes.string,
i18nDismissLabel: PropTypes.string,
};

Popover.displayName = 'Popover';
Expand Down
18 changes: 18 additions & 0 deletions packages/paste-core/components/popover/stories/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,21 @@ export const Customization: React.FC = () => {
</CustomizationProvider>
);
};

export const I18n = (): React.ReactNode => {
return (
<Box height="300px">
<PopoverContainer baseId="test-id" visible>
<PopoverButton variant="primary">Abrir popover</PopoverButton>
<Popover aria-label="Popover" i18nDismissLabel="Cerrar popover">
<Text as="span">
&quot;Vivir en las fronteras y en los márgenes, mantener intacta la identidad múltiple y la integridad, es
como tratar de nadar en un nuevo elemento, un elemento &apos;extranjero&apos;&quot; — Gloria E. Anzaldúa
</Text>
</Popover>
</PopoverContainer>
</Box>
);
};

I18n.storyName = 'i18n Prop';
20 changes: 20 additions & 0 deletions packages/paste-website/src/component-examples/PopoverExamples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,23 @@ render(
<PopoverExample />
)
`.trim();

export const i18nExample = `
const I18nExample = () => {
return (
<PopoverContainer baseId="popover-example">
<PopoverButton variant="primary">Abrir popover</PopoverButton>
<Popover aria-label="Popover" i18nDismissLabel="Cerrar popover">
<Text as="span">
"Vivir en las fronteras y en los márgenes, mantener intacta la identidad múltiple y la integridad, es
como tratar de nadar en un nuevo elemento, un elemento 'extranjero'" — Gloria E. Anzaldúa
</Text>
</Popover>
</PopoverContainer>
);
};
render(
<I18nExample />
)
`.trim();
21 changes: 21 additions & 0 deletions packages/paste-website/src/pages/components/popover/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
badgeExample,
buttonVariantsExample,
setWidthExample,
i18nExample,
} from '../../../component-examples/PopoverExamples';

export const pageQuery = graphql`
Expand Down Expand Up @@ -250,6 +251,22 @@ For full details on how to use the state hook, and what props to provide it, fol
{StateHookPopoverExample}
</LivePreview>

### Internationalization

To internationalize the popover, simply pass different text as children to the popover's contents and the `aria-label` prop. The only exception is the dismiss button–to change the dismiss button’s text, use the `i18nDismissLabel` prop.

<LivePreview
scope={{
Popover,
PopoverContainer,
PopoverButton,
Text,
}}
noInline
>
{i18nExample}
</LivePreview>

## Anatomy

### PopoverButton
Expand Down Expand Up @@ -450,6 +467,10 @@ Sets the placement of popover in relation to the `PopoverButton`. Available opti

Required label for this Popover component. Titles the entire popover context for screen readers.

##### `i18nDismissLabel: string`

Label for the dismiss button in the popover. The default value is 'Close popover'.

<ChangelogRevealer>
<Changelog />
</ChangelogRevealer>
Expand Down

0 comments on commit 4aefbe7

Please sign in to comment.