-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2bfe2b2
commit 53b6e67
Showing
24 changed files
with
2,030 additions
and
129 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { PLACEMENTS } from '../ModalArrow/ModalArrow.constants'; | ||
import { COLORS } from '../ModalContainer/ModalContainer.constants'; | ||
import { BOUNDARIES } from '../Popover/Popover.constants'; | ||
|
||
export const DEFAULTS = { | ||
BOUNDARY: BOUNDARIES.PARENT, | ||
COLOR: COLORS.PRIMARY, | ||
OFFSET_DISTANCE: 5, | ||
OFFSET_SKIDDING: 0, | ||
PLACEMENT: PLACEMENTS.AUTO as string, | ||
STRATEGY: 'absolute' as const, | ||
VARIANT: 'small', | ||
} as const; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { commonStyles } from '../../storybook/helper.stories.argtypes'; | ||
import { popoverArgTypes } from '../Popover/Popover.stories.args'; | ||
|
||
const toggletipArgTypes = { | ||
placement: { | ||
description: `Placement of the Toggletip relative to the trigger component`, | ||
...popoverArgTypes['placement'], | ||
}, | ||
offsetSkidding: { | ||
description: `The offset skidding (in px) along the reference.`, | ||
...popoverArgTypes['offsetSkidding'], | ||
}, | ||
offsetDistance: { | ||
description: `The offset distance (in px) from the reference.`, | ||
...popoverArgTypes['offsetDistance'], | ||
}, | ||
variant: { | ||
description: `Variant of the Toggletip - can be either small or medium`, | ||
...popoverArgTypes['variant'], | ||
}, | ||
children: { | ||
description: 'Provides the child nodes for this element.', | ||
...popoverArgTypes['children'], | ||
}, | ||
color: { | ||
description: 'What color to render this `<Toggletip />` as.', | ||
...popoverArgTypes['color'], | ||
}, | ||
boundary: { | ||
description: 'The overflow boundary of the toggletip element.', | ||
...popoverArgTypes['boundary'], | ||
}, | ||
}; | ||
|
||
export { toggletipArgTypes }; | ||
|
||
export default { | ||
...commonStyles, | ||
...toggletipArgTypes, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
The `<Toggletip />` component allows adding a Toggletip to whatever provided as `triggerComponent`. It | ||
will show the Tooltip after a click event. It utilise live area to notify Screen Reader or other assistive technology. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
import React from 'react'; | ||
import { MultiTemplate, Template } from '../../storybook/helper.stories.templates'; | ||
import { DocumentationPage } from '../../storybook/helper.stories.docs'; | ||
import StyleDocs from '../../storybook/docs.stories.style.mdx'; | ||
import Documentation from './Toggletip.stories.docs.mdx'; | ||
import Toggletip, { ToggletipProps } from './'; | ||
import Text from '../Text'; | ||
import ButtonPill from '../ButtonPill'; | ||
import ButtonSimple from '../ButtonSimple'; | ||
import { COLORS } from '../ModalContainer/ModalContainer.constants'; | ||
import argTypes from './Toggletip.stories.args'; | ||
import { PLACEMENTS } from '../ModalArrow/ModalArrow.constants'; | ||
import Icon from '../Icon'; | ||
import Flex from '../Flex'; | ||
import Popover from '../Popover'; | ||
import ButtonCircle from '../ButtonCircle'; | ||
|
||
export default { | ||
title: 'Momentum UI/Toggletip', | ||
component: Toggletip, | ||
parameters: { | ||
expanded: true, | ||
docs: { | ||
page: DocumentationPage(Documentation, StyleDocs), | ||
}, | ||
}, | ||
}; | ||
|
||
const Example = Template<ToggletipProps>(Toggletip).bind({}); | ||
|
||
Example.argTypes = { ...argTypes }; | ||
|
||
Example.args = { | ||
placement: PLACEMENTS.AUTO, | ||
variant: 'small', | ||
color: COLORS.PRIMARY, | ||
delay: [0, 0], | ||
children: <p>Toggletip</p>, | ||
triggerComponent: ( | ||
<ButtonCircle | ||
ghost | ||
size={64} | ||
aria-label="About toggletip" | ||
style={{ margin: '10rem auto', display: 'flex' }} | ||
> | ||
<Icon name="info-badge" weight="filled" scale={32} /> | ||
</ButtonCircle> | ||
), | ||
}; | ||
|
||
const Common = MultiTemplate<ToggletipProps>(Toggletip).bind({}); | ||
|
||
Common.argTypes = { ...argTypes }; | ||
|
||
Common.args = {}; | ||
Common.parameters = { | ||
variants: [ | ||
{ | ||
children: <p>Label toggletip TERTIARY color, variant medium</p>, | ||
triggerComponent: ( | ||
<ButtonSimple style={{ margin: '10rem auto', display: 'flex' }}>Click me!</ButtonSimple> | ||
), | ||
placement: PLACEMENTS.RIGHT, | ||
variant: 'medium', | ||
color: COLORS.TERTIARY, | ||
}, | ||
{ | ||
children: <p>Toggletip, PRIMARY color, variant small</p>, | ||
triggerComponent: ( | ||
<ButtonSimple style={{ margin: '10rem auto', display: 'flex' }}>Click me!</ButtonSimple> | ||
), | ||
placement: PLACEMENTS.BOTTOM_START, | ||
variant: 'small', | ||
color: COLORS.PRIMARY, | ||
}, | ||
{ | ||
children: <p>Toggletip, SECONDARY color, variant medium, showDelay 500ms</p>, | ||
triggerComponent: ( | ||
<ButtonSimple> | ||
Click me! <br /> Open with delay | ||
</ButtonSimple> | ||
), | ||
placement: PLACEMENTS.LEFT_START, | ||
delay: [500], | ||
variant: 'medium', | ||
color: COLORS.SECONDARY, | ||
}, | ||
], | ||
}; | ||
|
||
const Offset = Template<ToggletipProps>(Toggletip).bind({}); | ||
|
||
Offset.argTypes = { ...argTypes }; | ||
|
||
Offset.args = { | ||
placement: PLACEMENTS.RIGHT, | ||
variant: 'small', | ||
color: COLORS.TERTIARY, | ||
delay: [0, 0], | ||
offsetDistance: -150, | ||
triggerComponent: ( | ||
<ButtonPill style={{ margin: '10rem auto', display: 'flex', width: '30rem' }}> | ||
Click me! | ||
</ButtonPill> | ||
), | ||
children: ( | ||
<Flex style={{ width: '10rem', height: '10rem' }} justifyContent="center" alignItems="center"> | ||
<Text type="display">🏖</Text> | ||
</Flex> | ||
), | ||
}; | ||
|
||
const MultiplePopovers = Template<ToggletipProps>((args: ToggletipProps) => { | ||
const triggerComponent = ( | ||
<Toggletip | ||
placement={PLACEMENTS.BOTTOM} | ||
triggerComponent={ | ||
<ButtonSimple style={{ margin: '10rem auto', display: 'flex' }}>Click me!</ButtonSimple> | ||
} | ||
> | ||
Description toggletip on click | ||
</Toggletip> | ||
); | ||
return <Popover {...args} triggerComponent={triggerComponent} />; | ||
}).bind({}); | ||
|
||
MultiplePopovers.argTypes = { ...argTypes }; | ||
|
||
MultiplePopovers.args = { | ||
placement: PLACEMENTS.TOP, | ||
children: 'Popover content on click', | ||
}; | ||
|
||
export { Example, Common, Offset, MultiplePopovers }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import React, { ForwardedRef, forwardRef, useCallback, useEffect, useRef } from 'react'; | ||
import Popover, { PopoverInstance } from '../Popover'; | ||
import { Props } from './Toggletip.types'; | ||
import { DEFAULTS } from './Toggletip.constants'; | ||
import { BoundaryType, PlacementType } from '../Popover/Popover.types'; | ||
|
||
/** | ||
* Toggletip component | ||
* | ||
* Shows a non-interactable popover component with inside a live aria. | ||
* | ||
* @see [WCAG - Tooltip pattern]{@link https://www.w3.org/WAI/ARIA/apg/patterns/tooltip/} | ||
* | ||
* Toggletip content must be rendered in a live aria because Screen reader can not pick up changes | ||
* on the active element. This is why the | ||
* - we can not use the aria-describedby and | ||
* - the "status" div have to be rendered upfront | ||
* | ||
* @see [Tooltips & Toggletips]{@link https://inclusive-components.design/tooltips-toggletips/} | ||
*/ | ||
const Toggletip = forwardRef( | ||
( | ||
{ | ||
boundary = DEFAULTS.BOUNDARY as BoundaryType, | ||
color = DEFAULTS.COLOR, | ||
offsetDistance = DEFAULTS.OFFSET_DISTANCE, | ||
offsetSkidding = DEFAULTS.OFFSET_SKIDDING, | ||
placement = DEFAULTS.PLACEMENT as PlacementType, | ||
strategy = DEFAULTS.STRATEGY, | ||
variant = DEFAULTS.VARIANT, | ||
triggerComponent, | ||
children, | ||
...otherProps | ||
}: Props, | ||
ref: ForwardedRef<HTMLElement> | ||
) => { | ||
const tippyRef = useRef<PopoverInstance>(null); | ||
const liveAriaRef = useRef<HTMLDivElement>(null); | ||
const triggerComponentRef = useRef<HTMLElement>(null); | ||
|
||
// Update aria props manually, because "The `aria` attribute is reserved for future use in React." | ||
// see https://atomiks.github.io/tippyjs/v6/all-props/#aria | ||
const setInstance = useCallback((popoverInstance: PopoverInstance | undefined) => { | ||
popoverInstance?.setProps?.({ aria: { expanded: false, content: null } }); | ||
tippyRef.current = popoverInstance; | ||
otherProps?.setInstance?.(popoverInstance); | ||
}, []); | ||
|
||
// Hide popover on when the trigger component loose focus | ||
// User must re-open the toggletip otherwise SR will not announce the content when user | ||
// focus on the trigger component because of the live area | ||
const hidePopoverOnBlur = useCallback(() => { | ||
tippyRef.current?.hide(); | ||
}, [tippyRef.current]); | ||
|
||
useEffect(() => { | ||
const triggerRef = triggerComponentRef.current; | ||
if (triggerRef) { | ||
triggerRef.addEventListener('blur', hidePopoverOnBlur); | ||
return () => triggerRef.removeEventListener('blur', hidePopoverOnBlur); | ||
} | ||
}, [triggerComponentRef.current]); | ||
|
||
return ( | ||
<> | ||
<Popover | ||
ref={ref} | ||
appendTo={() => liveAriaRef.current} | ||
trigger="click" | ||
triggerComponent={React.cloneElement(triggerComponent, { ref: triggerComponentRef })} | ||
showArrow | ||
interactive={false} | ||
addBackdrop={false} | ||
role="generic" | ||
boundary={boundary} | ||
color={color} | ||
offsetDistance={offsetDistance} | ||
offsetSkidding={offsetSkidding} | ||
placement={placement} | ||
strategy={strategy} | ||
variant={variant} | ||
{...otherProps} | ||
setInstance={setInstance} | ||
> | ||
{children} | ||
</Popover> | ||
<div role="status" ref={liveAriaRef} /> | ||
</> | ||
); | ||
} | ||
); | ||
|
||
Toggletip.displayName = 'Toggletip'; | ||
|
||
export default Toggletip; |
Oops, something went wrong.