Skip to content

Commit ab315d3

Browse files
authored
Merge pull request #149 from icflorescu/next
Next
2 parents 2f52a45 + 695a225 commit ab315d3

File tree

8 files changed

+156
-8
lines changed

8 files changed

+156
-8
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
The following is a list of notable changes to the Mantine ContextMenu component.
44
Minor versions that are not listed in the changelog are minor bug fixes and small internal improvements or refactorings.
55

6+
## 7.6.1 (2024-02-28)
7+
8+
- Implement `iconRight` property (see [#147](https://github.com/icflorescu/mantine-contextmenu/pull/147) by [@JTson8](https://github.com/JTson8))
9+
610
## 7.6.0 (2024-02-28)
711

812
- Update dev dependencies to ensure compatibility with Mantine 7.6.0

app/examples/action-icons/ActionIconsExample.tsx

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use client';
22

3-
import { IconCopy, IconDownload } from '@tabler/icons-react';
3+
import { notifications } from '@mantine/notifications';
4+
import { IconCopy, IconDownload, IconExclamationCircle, IconTrash } from '@tabler/icons-react';
45
import { useContextMenu } from '__PACKAGE__';
56
import { Picture } from '~/components/Picture';
67
import { copyImageToClipboard, downloadImage, unsplashImages } from '~/lib/images';
@@ -11,6 +12,14 @@ export function ActionIconsExample() {
1112
// example-skip
1213
const image = unsplashImages[4];
1314
const { src } = image.file;
15+
16+
const handleDelete = () => {
17+
notifications.show({
18+
color: 'red',
19+
title: 'Can’t do that',
20+
message: 'You know you can’t delete an image from the Internet, right?',
21+
});
22+
};
1423
// example-resume
1524
return (
1625
<Picture
@@ -23,9 +32,15 @@ export function ActionIconsExample() {
2332
},
2433
{
2534
key: 'download',
26-
icon: <IconDownload size={16} />,
35+
iconRight: <IconDownload size={16} />,
2736
onClick: () => downloadImage(src),
2837
},
38+
{
39+
key: 'delete',
40+
icon: <IconTrash size={16} />,
41+
iconRight: <IconExclamationCircle size={16} />,
42+
onClick: () => handleDelete,
43+
},
2944
])}
3045
/>
3146
);

app/examples/action-icons/page.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Code } from '@mantine/core';
12
import type { Route } from 'next';
23
import { CodeBlock } from '~/components/CodeBlock';
34
import { PageNavigation } from '~/components/PageNavigation';
@@ -17,7 +18,10 @@ export default async function ActionIconsExamplePage() {
1718
return (
1819
<>
1920
<PageTitle of={PATH} />
20-
<Txt>You can provide action icons to the context menu items, like so:</Txt>
21+
<Txt>
22+
You can provide action icons to the context menu items by setting the <Code>icon</Code> and{' '}
23+
<Code>iconRight</Code> properties, like so:
24+
</Txt>
2125
<CodeBlock code={code} />
2226
<Txt>Right-click on the image to trigger the context menu:</Txt>
2327
<ActionIconsExample />

app/examples/submenus/SubmenuExamples.tsx

+104-1
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,35 @@
11
'use client';
22

3-
import { IconCopy, IconDownload, IconUser } from '@tabler/icons-react';
3+
import {
4+
IconArrowRight,
5+
IconChevronRight,
6+
IconCopy,
7+
IconDownload,
8+
IconFlipHorizontal,
9+
IconFlipVertical,
10+
IconUser,
11+
IconView360,
12+
} from '@tabler/icons-react';
413
import { useContextMenu } from '__PACKAGE__';
14+
import { useState } from 'react';
515
import { Picture } from '~/components/Picture';
616
import { copyImageToClipboard, downloadImage, unsplashImages } from '~/lib/images';
717

818
export function SubmenuExample() {
919
// example-start submenu
1020
const { showContextMenu } = useContextMenu();
21+
22+
const [flipVertical, setFlipVertical] = useState(false);
23+
const [flipHorizontal, setFlipHorizontal] = useState(false);
1124
// example-skip
1225
const image = unsplashImages[1];
1326
const { src } = image.file;
1427
// example-resume
1528
return (
1629
<Picture
1730
image={image}
31+
flipVertical={flipVertical}
32+
flipHorizontal={flipHorizontal}
1833
onContextMenu={showContextMenu([
1934
{
2035
icon: <IconCopy size={16} />,
@@ -40,6 +55,22 @@ export function SubmenuExample() {
4055
},
4156
],
4257
},
58+
{
59+
key: 'flip',
60+
icon: <IconView360 size={16} />,
61+
items: [
62+
{
63+
key: 'flipVertical',
64+
icon: <IconFlipVertical size={16} />,
65+
onClick: () => setFlipVertical((v) => !v),
66+
},
67+
{
68+
key: 'flipHorizontal',
69+
icon: <IconFlipHorizontal size={16} />,
70+
onClick: () => setFlipHorizontal((v) => !v),
71+
},
72+
],
73+
},
4374
])}
4475
/>
4576
);
@@ -121,3 +152,75 @@ export function NestedSubmenuExample() {
121152
);
122153
// example-end
123154
}
155+
156+
export function SubmenuExampleCustomArrowIcon() {
157+
// example-start submenu-custom-arrow-icon
158+
const { showContextMenu } = useContextMenu();
159+
160+
const [flipVertical, setFlipVertical] = useState(false);
161+
const [flipHorizontal, setFlipHorizontal] = useState(false);
162+
// example-skip
163+
const image = unsplashImages[1];
164+
const { src } = image.file;
165+
// example-resume
166+
return (
167+
<Picture
168+
image={image}
169+
flipVertical={flipVertical}
170+
flipHorizontal={flipHorizontal}
171+
onContextMenu={showContextMenu([
172+
// example-skip some items
173+
{
174+
icon: <IconCopy size={16} />,
175+
key: 'copy',
176+
onClick: () => copyImageToClipboard(src),
177+
},
178+
{
179+
icon: <IconDownload size={16} />,
180+
key: 'download',
181+
onClick: () => downloadImage(src),
182+
},
183+
// example-resume
184+
{
185+
key: 'author',
186+
icon: <IconUser size={16} />,
187+
// 👇 custom arrow icon
188+
iconRight: <IconChevronRight size={16} />,
189+
items: [
190+
// example-skip some nested items
191+
{
192+
key: 'open-in-new-tab',
193+
onClick: () => window.open(`http://unsplash.com/@${image.author.profile}`, '_blank'),
194+
},
195+
{
196+
key: 'another-item',
197+
onClick: () => console.log('another item clicked'),
198+
},
199+
// example-resume
200+
],
201+
},
202+
{
203+
key: 'flip',
204+
icon: <IconView360 size={16} />,
205+
// 👇 custom arrow icon
206+
iconRight: <IconArrowRight size={16} />,
207+
items: [
208+
// example-skip more nested items
209+
{
210+
key: 'flipVertical',
211+
icon: <IconFlipVertical size={16} />,
212+
onClick: () => setFlipVertical((v) => !v),
213+
},
214+
{
215+
key: 'flipHorizontal',
216+
icon: <IconFlipHorizontal size={16} />,
217+
onClick: () => setFlipHorizontal((v) => !v),
218+
},
219+
// example-resume
220+
],
221+
},
222+
])}
223+
/>
224+
);
225+
// example-end
226+
}

app/examples/submenus/page.tsx

+12-2
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,17 @@ import { Txt } from '~/components/Txt';
88
import { readCodeFile } from '~/lib/code';
99
import { allPromiseProps, getRouteMetadata } from '~/lib/utils';
1010
import { SubmenuDelayExample } from './SubmenuDelayExample';
11-
import { NestedSubmenuExample, SubmenuExample } from './SubmenuExamples';
11+
import { NestedSubmenuExample, SubmenuExample, SubmenuExampleCustomArrowIcon } from './SubmenuExamples';
1212

1313
const PATH: Route = '/examples/submenus';
1414

1515
export const metadata = getRouteMetadata(PATH);
1616

1717
export default async function ActionColorsExamplePage() {
1818
const code = await allPromiseProps({
19-
default: readCodeFile<Record<'submenu' | 'nested-submenu', string>>(`${PATH}/SubmenuExamples.tsx`),
19+
default: readCodeFile<Record<'submenu' | 'nested-submenu' | 'submenu-custom-arrow-icon', string>>(
20+
`${PATH}/SubmenuExamples.tsx`
21+
),
2022
submenuDelayProviderProp: readCodeFile<string>(`${PATH}/SubmenuDelayProviderPropExample.tsx`),
2123
});
2224

@@ -47,6 +49,14 @@ export default async function ActionColorsExamplePage() {
4749
<CodeBlock code={code['submenuDelayProviderProp']} />
4850
<Txt>Right-click on the image to trigger the context menu:</Txt>
4951
<SubmenuDelayExample />
52+
<PageSubtitle value="Using a custom arrow icon" />
53+
<Txt>
54+
You can customize the submenu arrow icon by setting the <Code>iconRight</Code> property like in the following
55+
example:
56+
</Txt>
57+
<CodeBlock code={code['default']['submenu-custom-arrow-icon']} />
58+
<Txt>Right-click on the image to trigger the context menu:</Txt>
59+
<SubmenuExampleCustomArrowIcon />
5060
<Txt>Head over to the next example to discover other features.</Txt>
5161
<PageNavigation of={PATH} />
5262
</>

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mantine-contextmenu",
3-
"version": "7.6.0",
3+
"version": "7.6.1",
44
"description": "Craft your applications for productivity and meet your users’ expectations by enhancing your Mantine-based UIs with a desktop-grade, lightweight yet fully-featured, dark-theme aware context-menu component, built by the creator of Mantine DataTable",
55
"keywords": [
66
"ui",

package/ContextMenuItem.tsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export function ContextMenuItem({
1010
className,
1111
style,
1212
icon,
13+
iconRight,
1314
title,
1415
color,
1516
disabled,
@@ -97,7 +98,11 @@ export function ContextMenuItem({
9798
</Box>
9899
)}
99100
<div className="mantine-contextmenu-item-button-title">{title}</div>
100-
{items && (
101+
{ iconRight ? (
102+
<Box fz={0} ml="xs" mt={-2}>
103+
{iconRight}
104+
</Box>
105+
) : items && (
101106
<Box fz={10} mt={-2} ml="xs">
102107
103108
</Box>

package/types.ts

+7
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ export type ContextMenuItemOptions = {
105105
*/
106106
icon?: React.ReactNode;
107107

108+
/**
109+
* Optional context menu item icon for the right side of the title.
110+
* If provided this will overwrite the submenu's ▶ icon
111+
*/
112+
iconRight?: React.ReactNode;
113+
108114
/**
109115
* Optional context menu item title.
110116
* If not provided, one will be generated automatically by "humanizing" the key.
@@ -143,6 +149,7 @@ export type ContextMenuItemOptions = {
143149
))
144150
| {
145151
icon?: never;
152+
iconRight?: never;
146153
title?: never;
147154
color?: never;
148155
disabled?: never;

0 commit comments

Comments
 (0)