Skip to content

Commit 20229b0

Browse files
committed
[Layout foundations] Refactor Banner to use Box
1 parent 98c0ee2 commit 20229b0

File tree

2 files changed

+92
-47
lines changed

2 files changed

+92
-47
lines changed

polaris-react/src/components/Banner/Banner.tsx

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {BannerContext} from '../../utilities/banner-context';
1818
import {useUniqueId} from '../../utilities/unique-id';
1919
import {useI18n} from '../../utilities/i18n';
2020
import type {Action, DisableableAction, LoadableAction} from '../../types';
21+
import {Box} from '../Box';
2122
import {Button} from '../Button';
2223
import {Heading} from '../Heading';
2324
import {ButtonGroup} from '../ButtonGroup';
@@ -84,38 +85,39 @@ export const Banner = forwardRef<BannerHandles, BannerProps>(function Banner(
8485
if (title) {
8586
headingID = `${id}Heading`;
8687
headingMarkup = (
87-
<div className={styles.Heading} id={headingID}>
88+
<Box className={styles.Heading} id={headingID}>
8889
<Heading element="p">{title}</Heading>
89-
</div>
90+
</Box>
9091
);
9192
}
9293

9394
const spinnerMarkup = action?.loading ? (
94-
<button
95+
<Box
96+
as="button"
9597
disabled
96-
aria-busy
98+
ariaBusy
9799
className={classNames(styles.Button, styles.loading)}
98100
>
99-
<span className={styles.Spinner}>
101+
<Box as="span" className={styles.Spinner}>
100102
<Spinner
101103
size="small"
102104
accessibilityLabel={i18n.translate(
103105
'Polaris.Button.spinnerAccessibilityLabel',
104106
)}
105107
/>
106-
</span>
108+
</Box>
107109
{action.content}
108-
</button>
110+
</Box>
109111
) : null;
110112

111113
const primaryActionMarkup = action ? (
112-
<div className={styles.PrimaryAction}>
114+
<Box className={styles.PrimaryAction}>
113115
{action.loading
114116
? spinnerMarkup
115117
: unstyledButtonFrom(action, {
116118
className: styles.Button,
117119
})}
118-
</div>
120+
</Box>
119121
) : null;
120122

121123
const secondaryActionMarkup = secondaryAction ? (
@@ -124,12 +126,12 @@ export const Banner = forwardRef<BannerHandles, BannerProps>(function Banner(
124126

125127
const actionMarkup =
126128
action || secondaryAction ? (
127-
<div className={styles.Actions}>
129+
<Box className={styles.Actions}>
128130
<ButtonGroup>
129131
{primaryActionMarkup}
130132
{secondaryActionMarkup}
131133
</ButtonGroup>
132-
</div>
134+
</Box>
133135
) : null;
134136

135137
let contentMarkup: React.ReactNode = null;
@@ -138,50 +140,49 @@ export const Banner = forwardRef<BannerHandles, BannerProps>(function Banner(
138140
if (children || actionMarkup) {
139141
contentID = `${id}Content`;
140142
contentMarkup = (
141-
<div className={styles.Content} id={contentID}>
143+
<Box className={styles.Content} id={contentID}>
142144
{children}
143145
{actionMarkup}
144-
</div>
146+
</Box>
145147
);
146148
}
147149

148150
const dismissButton = onDismiss && (
149-
<div className={styles.Dismiss}>
151+
<Box className={styles.Dismiss}>
150152
<Button
151153
plain
152154
icon={CancelSmallMinor}
153155
onClick={onDismiss}
154156
accessibilityLabel="Dismiss notification"
155157
/>
156-
</div>
158+
</Box>
157159
);
158160

159161
return (
160162
<BannerContext.Provider value>
161-
<div
163+
<Box
162164
className={className}
163-
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
164165
tabIndex={0}
165166
ref={wrapperRef}
166-
role={ariaRoleType}
167-
aria-live={stopAnnouncements ? 'off' : 'polite'}
167+
ariaRoleType={ariaRoleType}
168+
ariaLive={stopAnnouncements ? 'off' : 'polite'}
169+
ariaLabelledBy={headingID}
170+
ariaDescribedBy={contentID}
168171
onMouseUp={handleMouseUp}
169172
onKeyUp={handleKeyUp}
170173
onBlur={handleBlur}
171-
aria-labelledby={headingID}
172-
aria-describedby={contentID}
173174
>
174175
{dismissButton}
175176

176-
<div className={styles.Ribbon}>
177+
<Box className={styles.Ribbon}>
177178
<Icon source={iconName} color={iconColor} />
178-
</div>
179+
</Box>
179180

180-
<div className={styles.ContentWrapper}>
181+
<Box className={styles.ContentWrapper}>
181182
{headingMarkup}
182183
{contentMarkup}
183-
</div>
184-
</div>
184+
</Box>
185+
</Box>
185186
</BannerContext.Provider>
186187
);
187188
});
@@ -194,7 +195,9 @@ function SecondaryActionFrom({action}: {action: Action}) {
194195
url={action.url}
195196
external={action.external}
196197
>
197-
<span className={styles.Text}>{action.content}</span>
198+
<Box as="span" className={styles.Text}>
199+
{action.content}
200+
</Box>
198201
</UnstyledLink>
199202
);
200203
}
@@ -204,7 +207,9 @@ function SecondaryActionFrom({action}: {action: Action}) {
204207
className={styles.SecondaryAction}
205208
onClick={action.onAction}
206209
>
207-
<span className={styles.Text}>{action.content}</span>
210+
<Box as="span" className={styles.Text}>
211+
{action.content}
212+
</Box>
208213
</UnstyledButton>
209214
);
210215
}

polaris-react/src/components/Box/Box.tsx

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import styles from './Box.scss';
77

88
type Element = 'div' | 'span' | 'button';
99

10+
// TODO: Bring logic to extract token values into `polaris-tokens`
1011
type ColorsTokenGroup = typeof colors;
1112
type ColorsTokenName = keyof ColorsTokenGroup;
1213
type BackgroundColorTokenScale = Extract<
@@ -22,18 +23,15 @@ type BackgroundColorTokenScale = Extract<
2223
type DepthTokenGroup = typeof depth;
2324
type DepthTokenName = keyof DepthTokenGroup;
2425
type ShadowsTokenName = Exclude<DepthTokenName, `shadows-${string}`>;
25-
2626
type DepthTokenScale = ShadowsTokenName extends `shadow-${infer Scale}`
2727
? Scale
2828
: never;
2929

3030
type ShapeTokenGroup = typeof shape;
3131
type ShapeTokenName = keyof ShapeTokenGroup;
32-
3332
type BorderShapeTokenScale = ShapeTokenName extends `border-${infer Scale}`
3433
? Scale
3534
: never;
36-
3735
type BorderTokenScale = Exclude<
3836
BorderShapeTokenScale,
3937
`radius-${string}` | `width-${string}`
@@ -62,8 +60,6 @@ interface BorderRadius {
6260

6361
type SpacingTokenGroup = typeof spacing;
6462
type SpacingTokenName = keyof SpacingTokenGroup;
65-
66-
// TODO: Bring this logic into tokens
6763
type SpacingTokenScale = SpacingTokenName extends `space-${infer Scale}`
6864
? Scale
6965
: never;
@@ -76,34 +72,48 @@ interface Spacing {
7672
}
7773

7874
export interface BoxProps {
75+
/** Used to indicate the element is being modified */
76+
ariaBusy?: boolean;
77+
/** Used to identify the ID of the element that describes Box */
78+
ariaDescribedBy?: string;
79+
/** Used to identify the Id of element used as aria-labelledby */
80+
ariaLabelledBy?: string;
81+
/** Used to indicate the element will be updated */
82+
ariaLive?: string;
83+
/** Used to describe the semantic element type */
84+
ariaRoleType?: string;
7985
/** HTML Element type */
8086
as?: Element;
81-
/** Background color of the Box */
87+
/** Background color */
8288
background?: BackgroundColorTokenScale;
83-
/** Border styling of the Box */
89+
/** Border styling */
8490
border?: BorderTokenScale;
85-
/** Bottom border styling of the Box */
91+
/** Bottom border styling */
8692
borderBottom?: BorderTokenScale;
87-
/** Left border styling of the Box */
93+
/** Left border styling */
8894
borderLeft?: BorderTokenScale;
89-
/** Right border styling of the Box */
95+
/** Right border styling */
9096
borderRight?: BorderTokenScale;
91-
/** Top border styling of the Box */
97+
/** Top border styling */
9298
borderTop?: BorderTokenScale;
93-
/** Border radius of the Box */
99+
/** Border radius styling */
94100
borderRadius?: BorderRadiusTokenScale;
95-
/** Bottom left border radius of the Box */
101+
/** Bottom left border radius styling */
96102
borderRadiusBottomLeft?: BorderRadiusTokenScale;
97-
/** Bottom right border radius of the Box */
103+
/** Bottom right border radius styling */
98104
borderRadiusBottomRight?: BorderRadiusTokenScale;
99-
/** Top left border radius of the Box */
105+
/** Top left border radius styling */
100106
borderRadiusTopLeft?: BorderRadiusTokenScale;
101-
/** Top right border radius of the Box */
107+
/** Top right border radius styling */
102108
borderRadiusTopRight?: BorderRadiusTokenScale;
103109
/** Inner content of the Box */
104110
children: ReactNode;
105-
/** Custom styling for the Box */
111+
/** A custom class name to apply styles to the Box */
106112
className?: string;
113+
/** Set disabled state on the Box */
114+
disabled?: boolean;
115+
/** A unique identifier */
116+
id?: string;
107117
/** Spacing outside of the Box */
108118
margin?: SpacingTokenScale;
109119
/** Bottom spacing outside of the Box */
@@ -124,15 +134,28 @@ export interface BoxProps {
124134
paddingRight?: SpacingTokenScale;
125135
/** Top spacing inside of the Box */
126136
paddingTop?: SpacingTokenScale;
127-
/** Shadow on the Box */
137+
/** Shadow styling */
128138
shadow?: DepthTokenScale;
139+
/** Used to indicate the element is focusable in sequential order */
140+
tabIndex?: number;
141+
/** Callback triggered when focus is removed */
142+
onBlur?(event: React.FocusEvent<HTMLElement>): void;
129143
/** Callback triggered on click */
130144
onClick?(event: React.MouseEvent<HTMLElement>): void;
145+
/** Callback triggered on key up */
146+
onKeyUp?(event: React.KeyboardEvent<HTMLElement>): void;
147+
/** Callback triggered on mouse up */
148+
onMouseUp?(event: React.MouseEvent<HTMLElement>): void;
131149
}
132150

133151
export const Box = forwardRef<HTMLElement, BoxProps>(
134152
(
135153
{
154+
ariaBusy,
155+
ariaDescribedBy,
156+
ariaLabelledBy,
157+
ariaLive,
158+
ariaRoleType,
136159
as = 'div',
137160
background,
138161
border,
@@ -147,6 +170,8 @@ export const Box = forwardRef<HTMLElement, BoxProps>(
147170
borderRadiusTopRight,
148171
className,
149172
children,
173+
disabled = false,
174+
id,
150175
margin,
151176
marginBottom,
152177
marginLeft,
@@ -158,7 +183,11 @@ export const Box = forwardRef<HTMLElement, BoxProps>(
158183
paddingRight,
159184
paddingTop,
160185
shadow,
186+
tabIndex,
187+
onBlur,
161188
onClick,
189+
onKeyUp,
190+
onMouseUp,
162191
},
163192
ref,
164193
) => {
@@ -265,9 +294,20 @@ export const Box = forwardRef<HTMLElement, BoxProps>(
265294
as,
266295
{
267296
className: boxClassName,
268-
style: sanitizeCustomProperties(style),
297+
'aria-busy': ariaBusy,
298+
'aria-describedby': ariaDescribedBy,
299+
'aria-labelledby': ariaLabelledBy,
300+
'aria-live': ariaLive,
301+
role: ariaRoleType,
302+
disabled,
303+
id,
269304
ref,
305+
style: sanitizeCustomProperties(style),
306+
tabIndex,
307+
...(onBlur ? {onBlur} : undefined),
270308
...(onClick ? {onClick} : undefined),
309+
...(onKeyUp ? {onKeyUp} : undefined),
310+
...(onMouseUp ? {onMouseUp} : undefined),
271311
},
272312
children,
273313
);

0 commit comments

Comments
 (0)