Skip to content

Commit a9dd006

Browse files
authored
Contextual help style props (#3542)
Support custom class on contextual help and upgrade to CSF3
1 parent afb946c commit a9dd006

File tree

3 files changed

+115
-57
lines changed

3 files changed

+115
-57
lines changed

packages/@react-spectrum/contextualhelp/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"dependencies": {
3434
"@babel/runtime": "^7.6.2",
3535
"@react-aria/i18n": "^3.6.0",
36+
"@react-aria/utils": "^3.13.3",
3637
"@react-spectrum/button": "^3.9.1",
3738
"@react-spectrum/dialog": "^3.5.1",
3839
"@react-spectrum/utils": "^3.7.3",

packages/@react-spectrum/contextualhelp/src/ContextualHelp.tsx

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,16 @@
1111
*/
1212

1313
import {ActionButton} from '@react-spectrum/button';
14+
import {classNames, SlotProvider} from '@react-spectrum/utils';
1415
import {Dialog, DialogTrigger} from '@react-spectrum/dialog';
1516
import {FocusableRef} from '@react-types/shared';
1617
import HelpOutline from '@spectrum-icons/workflow/HelpOutline';
1718
import helpStyles from './contextualhelp.css';
1819
import InfoOutline from '@spectrum-icons/workflow/InfoOutline';
1920
// @ts-ignore
2021
import intlMessages from '../intl/*.json';
22+
import {mergeProps, useLabels} from '@react-aria/utils';
2123
import React from 'react';
22-
import {SlotProvider} from '@react-spectrum/utils';
2324
import {SpectrumContextualHelpProps} from '@react-types/contextualhelp';
2425
import {useLocalizedStringFormatter} from '@react-aria/i18n';
2526

@@ -40,23 +41,19 @@ function ContextualHelp(props: SpectrumContextualHelpProps, ref: FocusableRef<HT
4041
footer: {UNSAFE_className: helpStyles['react-spectrum-ContextualHelp-footer']}
4142
};
4243

43-
let ariaLabel = otherProps['aria-label'];
44-
if (!ariaLabel && !otherProps['aria-labelledby']) {
45-
ariaLabel = stringFormatter.format(variant);
46-
}
44+
let labelProps = useLabels(otherProps, stringFormatter.format(variant));
4745

4846
return (
4947
<DialogTrigger {...otherProps} type="popover" placement={placement} hideArrow>
5048
<ActionButton
51-
{...otherProps}
49+
{...mergeProps(otherProps, labelProps)}
5250
ref={ref}
53-
UNSAFE_className={helpStyles['react-spectrum-ContextualHelp-button']}
54-
isQuiet
55-
aria-label={ariaLabel}>
51+
UNSAFE_className={classNames(helpStyles, 'react-spectrum-ContextualHelp-button', otherProps.UNSAFE_className)}
52+
isQuiet>
5653
{icon}
5754
</ActionButton>
5855
<SlotProvider slots={slots}>
59-
<Dialog UNSAFE_className={helpStyles['react-spectrum-ContextualHelp-dialog']}>
56+
<Dialog UNSAFE_className={classNames(helpStyles, 'react-spectrum-ContextualHelp-dialog')}>
6057
{children}
6158
</Dialog>
6259
</SlotProvider>

packages/@react-spectrum/contextualhelp/stories/ContextualHelp.stories.tsx

Lines changed: 107 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -10,58 +10,118 @@
1010
* governing permissions and limitations under the License.
1111
*/
1212

13-
import {action} from '@storybook/addon-actions';
1413
import {Button, Content, Flex, Footer, Heading, Link, Text} from '@adobe/react-spectrum';
14+
import {ComponentMeta, ComponentStoryObj} from '@storybook/react';
1515
import {ContextualHelp} from '../src';
1616
import React from 'react';
17-
import {storiesOf} from '@storybook/react';
1817

19-
storiesOf('ContextualHelp', module)
20-
.add(
21-
'default',
22-
() => render({heading: 'Help title', description: helpText()})
23-
)
24-
.add(
25-
'type: info',
26-
() => render({heading: 'Help title', description: helpText(), variant: 'info'})
27-
)
28-
.add(
29-
'with link',
30-
() => render({heading: 'Help title', description: helpText(), link: <Link>Learn more</Link>})
31-
)
32-
.add(
33-
'with button',
34-
() => (<Flex alignItems="center">
35-
<Button variant="primary" isDisabled>Create</Button>
36-
<ContextualHelp marginStart="size-100">
37-
<Heading>Help title</Heading>
38-
<Content>{helpText()}</Content>
39-
</ContextualHelp>
40-
</Flex>)
41-
)
42-
.add(
43-
'trigger events',
44-
() => render({heading: 'Help title', description: helpText(), onOpenChange: action('open change')})
45-
)
46-
.add(
47-
'placement: bottom',
48-
() => render({heading: 'Help title', description: helpText(), placement: 'bottom'})
49-
)
50-
.add(
51-
'placement: bottom start',
52-
() => render({heading: 'Help title', description: helpText(), placement: 'bottom start'})
53-
);
18+
export default {
19+
title: 'ContextualHelp',
20+
component: ContextualHelp,
21+
argTypes: {
22+
onOpenChange: {
23+
action: 'openChange',
24+
table: {disable: true}
25+
},
26+
placement: {
27+
control: 'select',
28+
defaultValue: 'bottom',
29+
options: [
30+
'bottom', 'bottom left', 'bottom right', 'bottom start', 'bottom end',
31+
'top', 'top left', 'top right', 'top start', 'top end',
32+
'left', 'left top', 'left bottom',
33+
'start', 'start top', 'start bottom',
34+
'right', 'right top', 'right bottom',
35+
'end', 'end top', 'end bottom'
36+
]
37+
},
38+
variant: {
39+
control: 'select',
40+
defaultValue: 'help',
41+
options: ['help', 'info']
42+
},
43+
offset: {
44+
control: 'number',
45+
defaultValue: 0,
46+
min: -500,
47+
max: 500
48+
},
49+
crossOffset: {
50+
control: 'number',
51+
defaultValue: 0,
52+
min: -500,
53+
max: 500
54+
},
55+
containerPadding: {
56+
control: 'number',
57+
defaultValue: 0,
58+
min: -500,
59+
max: 500
60+
},
61+
shouldFlip: {
62+
control: 'boolean',
63+
defaultValue: true
64+
},
65+
children: {
66+
table: {disable: true}
67+
}
68+
}
69+
} as ComponentMeta<typeof ContextualHelp>;
70+
71+
export type ContextualHelpStory = ComponentStoryObj<typeof ContextualHelp>;
5472

5573
const helpText = () => <Text>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin sit amet tristique risus. In sit amet suscipit lorem.</Text>;
5674

57-
function render(props: any = {}) {
58-
let {heading, description, link, ...otherProps} = props;
75+
export const Default: ContextualHelpStory = {
76+
args: {
77+
children: (
78+
<>
79+
<Heading>Help title</Heading>
80+
<Content>{helpText()}</Content>
81+
</>
82+
)
83+
}
84+
};
85+
86+
export const WithLink: ContextualHelpStory = {
87+
args: {
88+
children: (
89+
<>
90+
<Heading>Help title</Heading>
91+
<Content>{helpText()}</Content>
92+
<Footer><Link>Learn more</Link></Footer>
93+
</>
94+
)
95+
},
96+
name: 'with link'
97+
};
98+
99+
export const WithButton: ContextualHelpStory = {
100+
args: {
101+
marginStart: 'size-100'
102+
},
103+
render: (args) => (
104+
<Flex alignItems="center">
105+
<Button variant="primary" isDisabled>Create</Button>
106+
<ContextualHelp {...args} UNSAFE_className="foo">
107+
<Heading>Help title</Heading>
108+
<Content>{helpText()}</Content>
109+
</ContextualHelp>
110+
</Flex>
111+
),
112+
name: 'with button',
113+
parameters: {description: {data: 'Custom classname foo is on the contextual help button.'}}
114+
};
59115

60-
return (
61-
<ContextualHelp {...otherProps}>
62-
{heading && <Heading>{heading}</Heading>}
63-
{description && <Content>{description}</Content>}
64-
{link && <Footer>{link}</Footer>}
65-
</ContextualHelp>
66-
);
67-
}
116+
export const AriaLabelledyBy: ContextualHelpStory = {
117+
render: (args) => (
118+
<Flex alignItems="center">
119+
<div id="foo">I label the contextual help button</div>
120+
<ContextualHelp {...args} aria-labelledby="foo">
121+
<Heading>Help title</Heading>
122+
<Content>{helpText()}</Content>
123+
</ContextualHelp>
124+
</Flex>
125+
),
126+
name: 'aria-labelledyby'
127+
};

0 commit comments

Comments
 (0)