Skip to content

Commit 952a988

Browse files
authored
Add labelPlacement prop to IconButton and ToggleButton components (#1442)
1 parent 11a71dc commit 952a988

9 files changed

Lines changed: 109 additions & 6 deletions

File tree

.changeset/humble-gifts-appear.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@stratakit/mui": patch
3+
---
4+
5+
Added a new `labelPlacement` prop to `IconButton` and `ToggleButton` components to control the placement of a tooltip that is shown when the `label` prop is specified.

apps/test-app/app/mui.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ import DividerVertical from "examples/mui/Divider.vertical.tsx";
6666
import DrawerDefault from "examples/mui/Drawer.default.tsx";
6767
import FabDefault from "examples/mui/Fab.default.tsx";
6868
import IconButtonColors_ from "examples/mui/IconButton._colors.tsx";
69+
import IconButtonPlacements_ from "examples/mui/IconButton._placements.tsx";
6970
import IconButtonDefault from "examples/mui/IconButton.default.tsx";
7071
import IconButtonSizes from "examples/mui/IconButton.sizes.tsx";
7172
import LinearProgressColors_ from "examples/mui/LinearProgress._colors.tsx";
@@ -116,6 +117,7 @@ import TextFieldIcon from "examples/mui/TextField.icon.tsx";
116117
import TextFieldMultiline from "examples/mui/TextField.multiline.tsx";
117118
import TextFieldSizes from "examples/mui/TextField.sizes.tsx";
118119
import ToggleButtonDisabled_ from "examples/mui/ToggleButton._disabled.tsx";
120+
import ToggleButtonPlacements_ from "examples/mui/ToggleButton._placements.tsx";
119121
import ToggleButtonDefault from "examples/mui/ToggleButton.default.tsx";
120122
import ToggleButtonSizes from "examples/mui/ToggleButton.sizes.tsx";
121123
import ToggleButtonStandalone from "examples/mui/ToggleButton.standalone.tsx";
@@ -274,6 +276,11 @@ const components: Record<string, React.ReactNode> = {
274276
<IconButtonColors_ />
275277
</Stack>
276278
)}
279+
{!isProduction && (
280+
<Stack spacing={1} direction="row">
281+
<IconButtonPlacements_ />
282+
</Stack>
283+
)}
277284
</>
278285
),
279286
LinearProgress: (
@@ -390,6 +397,11 @@ const components: Record<string, React.ReactNode> = {
390397
<ToggleButtonSizes />
391398
<ToggleButtonDisabled_ />
392399
<ToggleButtonText />
400+
{!isProduction && (
401+
<Stack spacing={1} direction="row">
402+
<ToggleButtonPlacements_ />
403+
</Stack>
404+
)}
393405
</>
394406
),
395407
Tooltip: (

apps/website/src/content/docs/components/mui/IconButton.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Make sure the **IconButton** is suitable for your use case. There may be other,
2525
- The `"default"`, `"info"`, `"success"`, `"warning"`, `"inherit"` colors have been removed. The default color is now `"secondary"`.
2626
- The `size` options (`"small"`, `"medium"`, `"large"`) have all been decreased in height.
2727
- A `label` prop has been added. When specified, it is used as the **IconButton’s** accessible name and is also shown in a tooltip on hover and focus.
28+
- A `labelPlacement` prop has been added to control the placement of a tooltip that is shown when the `label` prop is specified.
2829

2930
## Examples
3031

apps/website/src/content/docs/components/mui/ToggleButton.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ links:
1111
## StrataKit MUI modifications
1212

1313
- A `label` prop has been added. When specified, it is used as the **ToggleButton’s** accessible name and is also shown in a tooltip on hover and focus.
14+
- A `labelPlacement` prop has been added to control the placement of a tooltip that is shown when the `label` prop is specified.
1415
- **ToggleButtons** are styled to match the visual appearance of the [**IconButton**](/components/iconbutton) component. Borders are displayed only when the buttons are wrapped in a `ToggleButtonGroup`. [Standalone](#standalone) **ToggleButtons** do not have borders.
1516
- **ToggleButtons** can now be rendered as regular [**Buttons**](/components/button) to [display text](#text).
1617

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3+
* See LICENSE.md in the project root for license terms and full copyright notice.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import IconButton from "@mui/material/IconButton";
7+
import { Icon } from "@stratakit/mui";
8+
9+
import svgPlaceholder from "@stratakit/icons/placeholder.svg";
10+
11+
type IconButtonProps = React.ComponentProps<typeof IconButton>;
12+
const placements = [
13+
"top",
14+
"right",
15+
"bottom",
16+
"left",
17+
] as const satisfies IconButtonProps["labelPlacement"][];
18+
19+
export default () => {
20+
return placements.map((placement) => (
21+
<IconButton
22+
key={placement}
23+
label={`${placement.charAt(0).toUpperCase()}${placement.slice(1)}`}
24+
labelPlacement={placement}
25+
>
26+
<Icon href={svgPlaceholder} />
27+
</IconButton>
28+
));
29+
};
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
3+
* See LICENSE.md in the project root for license terms and full copyright notice.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import * as React from "react";
7+
import ToggleButton from "@mui/material/ToggleButton";
8+
import { Icon } from "@stratakit/mui";
9+
10+
import svgPlaceholder from "@stratakit/icons/placeholder.svg";
11+
12+
type ToggleButtonProps = React.ComponentProps<typeof ToggleButton>;
13+
const placements = [
14+
"top",
15+
"right",
16+
"bottom",
17+
"left",
18+
] as const satisfies ToggleButtonProps["labelPlacement"][];
19+
20+
export default () => {
21+
const [selected, setSelected] = React.useState<string[]>([]);
22+
return placements.map((placement) => (
23+
<ToggleButton
24+
key={placement}
25+
value={placement}
26+
label={`${placement.charAt(0).toUpperCase()}${placement.slice(1)}`}
27+
labelPlacement={placement}
28+
selected={selected.includes(placement)}
29+
onChange={() =>
30+
setSelected((prev) =>
31+
prev.includes(placement)
32+
? prev.filter((p) => p !== placement)
33+
: [...prev, placement],
34+
)
35+
}
36+
>
37+
<Icon href={svgPlaceholder} />
38+
</ToggleButton>
39+
));
40+
};

packages/mui/src/types.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import type {
1616
TextFieldProps,
1717
TextFieldVariants,
1818
} from "@mui/material/TextField";
19+
import type { TooltipProps } from "@mui/material/Tooltip";
1920
import type { TypographyProps } from "@mui/material/Typography";
2021
import type * as React from "react";
2122

@@ -224,6 +225,13 @@ declare module "@mui/material/IconButton" {
224225
* If not specified, the accessible name and tooltip must be wired up manually.
225226
*/
226227
label?: string;
228+
229+
/**
230+
* Placement of the tooltip that is shown when the `label` prop is specified.
231+
*
232+
* @default 'top'
233+
*/
234+
labelPlacement?: TooltipProps["placement"];
227235
}
228236
}
229237

@@ -336,6 +344,13 @@ declare module "@mui/material/ToggleButton" {
336344
* Should only be provided when the toggle button does not have visible text content that can serve as an accessible name.
337345
*/
338346
label?: IconButtonProps["label"];
347+
348+
/**
349+
* Placement of the tooltip that is shown when the `label` prop is specified.
350+
*
351+
* @default 'top'
352+
*/
353+
labelPlacement?: TooltipProps["placement"];
339354
}
340355
}
341356

packages/mui/src/~components/MuiIconButton.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ import type { BaseProps } from "@stratakit/foundations/secret-internals";
1414

1515
interface MuiIconButtonProps
1616
extends BaseProps<"button">,
17-
Pick<IconButtonOwnProps, "label"> {}
17+
Pick<IconButtonOwnProps, "label" | "labelPlacement"> {}
1818

1919
const MuiIconButton = forwardRef<"button", MuiIconButtonProps>(
2020
(props, forwardedRef) => {
21-
const { label, ...rest } = props;
21+
const { label, labelPlacement, ...rest } = props;
2222

2323
if (label) {
2424
return (
25-
<Tooltip title={label} describeChild={false}>
25+
<Tooltip title={label} describeChild={false} placement={labelPlacement}>
2626
<MuiButtonBase {...rest} ref={forwardedRef} />
2727
</Tooltip>
2828
);

packages/mui/src/~components/MuiToggleButton.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ import type { BaseProps } from "@stratakit/foundations/secret-internals";
1515

1616
interface MuiToggleButtonProps
1717
extends BaseProps<"button">,
18-
Pick<ToggleButtonOwnProps, "label"> {}
18+
Pick<ToggleButtonOwnProps, "label" | "labelPlacement"> {}
1919

2020
const MuiToggleButton = forwardRef<"button", MuiToggleButtonProps>(
2121
(props, forwardedRef) => {
22-
const { label, ...rest } = props;
22+
const { label, labelPlacement, ...rest } = props;
2323

2424
const classList = props.className?.split(" ") ?? [];
2525
const size = (() => {
@@ -31,7 +31,7 @@ const MuiToggleButton = forwardRef<"button", MuiToggleButtonProps>(
3131

3232
if (label) {
3333
return (
34-
<Tooltip title={label} describeChild={false}>
34+
<Tooltip title={label} describeChild={false} placement={labelPlacement}>
3535
<MuiButtonBase
3636
{...rest}
3737
render={props.render ?? <IconButton size={size} />}

0 commit comments

Comments
 (0)