Skip to content

Commit

Permalink
[@mantine/core] ActionIcon: Add gradient variant support (#2133)
Browse files Browse the repository at this point in the history
* [@mantine/core] ActionIcon: Add support for gradient variant.

* [@mantine/core] ActionIcon: Add missing keys in storybook demo.
  • Loading branch information
zhulien-ivanov committed Aug 16, 2022
1 parent 02bdf0d commit 72555ad
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 63 deletions.
82 changes: 81 additions & 1 deletion src/mantine-core/src/ActionIcon/ActionIcon.story.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import React from 'react';
import { MANTINE_COLORS, useMantineTheme } from '@mantine/styles';
import React, { CSSProperties } from 'react';
import { ActionIcon } from './ActionIcon';
import { Center } from '../Center';
import { ACTION_ICON_VARIANTS } from './ActionIcon.styles';

export default { title: 'ActionIcon' };

Expand Down Expand Up @@ -33,3 +36,80 @@ export function ColorsIndex() {
</div>
);
}

export function Colors() {
const theme = useMantineTheme();

const sharedStyles: CSSProperties = {
padding: '10px 20px',
border: `1px solid ${
theme.colorScheme === 'light' ? theme.colors.gray[1] : theme.colors.dark[6]
}`,
};

return (
<div
style={{
padding: '40px',
}}
>
<table
style={{
borderCollapse: 'collapse',
}}
>
<thead>
<tr>
<th
style={{
...sharedStyles,
}}
>
color
</th>

{ACTION_ICON_VARIANTS.map((variant) => (
<th
key={variant}
style={{
...sharedStyles,
}}
>
{variant}
</th>
))}
</tr>
</thead>
<tbody>
{MANTINE_COLORS.map((color) => (
<tr key={color}>
<td
style={{
color: theme.colors[color][theme.fn.primaryShade()],
...sharedStyles,
}}
>
{color}
</td>

{ACTION_ICON_VARIANTS.map((variant) => (
<td
key={variant}
style={{
...sharedStyles,
}}
>
<Center>
<ActionIcon variant={variant} color={color}>
#
</ActionIcon>
</Center>
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
);
}
150 changes: 89 additions & 61 deletions src/mantine-core/src/ActionIcon/ActionIcon.styles.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
import { createStyles, MantineNumberSize, MantineColor, MantineTheme } from '@mantine/styles';
import {
createStyles,
MantineNumberSize,
MantineColor,
MantineTheme,
MantineGradient,
} from '@mantine/styles';

export type ActionIconVariant =
| 'subtle'
| 'filled'
| 'outline'
| 'light'
| 'default'
| 'transparent';
export const ACTION_ICON_VARIANTS = [
'subtle',
'filled',
'outline',
'light',
'default',
'transparent',
'gradient',
] as const;

export type ActionIconVariant = typeof ACTION_ICON_VARIANTS[number];

export interface ActionIconStylesParams {
color: MantineColor;
size: MantineNumberSize;
radius: MantineNumberSize;
variant: ActionIconVariant;
gradient: MantineGradient;
}

export const sizes = {
Expand All @@ -27,9 +38,10 @@ interface GetVariantStyles {
variant: ActionIconVariant;
theme: MantineTheme;
color: MantineColor;
gradient: MantineGradient;
}

function getVariantStyles({ variant, theme, color }: GetVariantStyles) {
function getVariantStyles({ variant, theme, color, gradient }: GetVariantStyles) {
if (variant === 'transparent') {
return {
border: '1px solid transparent',
Expand All @@ -38,67 +50,83 @@ function getVariantStyles({ variant, theme, color }: GetVariantStyles) {
};
}

const colors = theme.fn.variant({ color, variant });
const colors = theme.fn.variant({ color, variant, gradient });

if (variant === 'gradient') {
return {
border: 0,
backgroundImage: colors.background,
color: colors.color,

'&:hover': theme.fn.hover({
backgroundSize: '200%',
}),
};
}

return {
border: `1px solid ${colors.border}`,
backgroundColor: colors.background,
color: colors.color,
border: `1px solid ${colors.border}`,
...theme.fn.hover({ backgroundColor: colors.hover }),
...theme.fn.hover({
backgroundColor: colors.hover,
}),
};
}

export default createStyles((theme, { color, size, radius, variant }: ActionIconStylesParams) => ({
root: {
...getVariantStyles({ variant, theme, color }),
position: 'relative',
height: theme.fn.size({ size, sizes }),
minHeight: theme.fn.size({ size, sizes }),
width: theme.fn.size({ size, sizes }),
minWidth: theme.fn.size({ size, sizes }),
borderRadius: theme.fn.radius(radius),
padding: 0,
lineHeight: 1,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',

'&:active': theme.activeStyles,

'&[data-disabled]': {
color: theme.colors.gray[theme.colorScheme === 'dark' ? 6 : 4],
cursor: 'not-allowed',
backgroundColor:
variant === 'transparent'
? undefined
: theme.fn.themeColor('gray', theme.colorScheme === 'dark' ? 8 : 1),
borderColor:
variant === 'transparent'
? undefined
: theme.fn.themeColor('gray', theme.colorScheme === 'dark' ? 8 : 1),

'&:active': {
transform: 'none',
},
},
export default createStyles(
(theme, { color, size, radius, variant, gradient }: ActionIconStylesParams) => ({
root: {
...getVariantStyles({ variant, theme, color, gradient }),
position: 'relative',
height: theme.fn.size({ size, sizes }),
minHeight: theme.fn.size({ size, sizes }),
width: theme.fn.size({ size, sizes }),
minWidth: theme.fn.size({ size, sizes }),
borderRadius: theme.fn.radius(radius),
padding: 0,
lineHeight: 1,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',

'&[data-loading]': {
pointerEvents: 'none',
'&:active': theme.activeStyles,

'&::before': {
content: '""',
position: 'absolute',
top: -1,
left: -1,
right: -1,
bottom: -1,
backgroundColor:
theme.colorScheme === 'dark'
? theme.fn.rgba(theme.colors.dark[7], 0.5)
: 'rgba(255, 255, 255, .5)',
borderRadius: theme.fn.radius(radius),
'&[data-disabled]': {
color: theme.colors.gray[theme.colorScheme === 'dark' ? 6 : 4],
cursor: 'not-allowed',
backgroundColor:
variant === 'transparent'
? undefined
: theme.fn.themeColor('gray', theme.colorScheme === 'dark' ? 8 : 1),
borderColor:
variant === 'transparent'
? undefined
: theme.fn.themeColor('gray', theme.colorScheme === 'dark' ? 8 : 1),

'&:active': {
transform: 'none',
},
},

'&[data-loading]': {
pointerEvents: 'none',

'&::before': {
content: '""',
position: 'absolute',
top: -1,
left: -1,
right: -1,
bottom: -1,
backgroundColor:
theme.colorScheme === 'dark'
? theme.fn.rgba(theme.colors.dark[7], 0.5)
: 'rgba(255, 255, 255, .5)',
borderRadius: theme.fn.radius(radius),
cursor: 'not-allowed',
},
},
},
},
}));
})
);
7 changes: 6 additions & 1 deletion src/mantine-core/src/ActionIcon/ActionIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
MantineColor,
Selectors,
useComponentDefaultProps,
MantineGradient,
} from '@mantine/styles';
import { createPolymorphicComponent } from '@mantine/utils';
import { UnstyledButton } from '../UnstyledButton';
Expand All @@ -24,6 +25,9 @@ export interface ActionIconProps
/** Key of theme.colors */
color?: MantineColor;

/** Controls gradient settings in gradient variant only */
gradient?: MantineGradient;

/** Button border-radius from theme or number to set border-radius in px */
radius?: MantineNumberSize;

Expand Down Expand Up @@ -55,6 +59,7 @@ export const _ActionIcon = forwardRef<HTMLButtonElement, ActionIconProps>((props
radius,
size,
variant,
gradient,
disabled,
loaderProps,
loading,
Expand All @@ -63,7 +68,7 @@ export const _ActionIcon = forwardRef<HTMLButtonElement, ActionIconProps>((props
} = useComponentDefaultProps('ActionIcon', defaultProps, props);

const { classes, cx, theme } = useStyles(
{ size, radius, color, variant },
{ size, radius, color, variant, gradient },
{ name: 'ActionIcon', unstyled }
);
const colors = theme.fn.variant({ color, variant: 'light' });
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import { ActionIcon, Group } from '@mantine/core';
import { IconSun } from '@tabler/icons';

const code = `
import { ActionIcon, Group } from '@mantine/core';
import { Sun } from 'tabler-icons-react';
function Demo() {
return (
<>
<ActionIcon variant="gradient" gradient={{ from: 'indigo', to: 'cyan' }}><IconSun size={18} /></ActionIcon>
<ActionIcon variant="gradient" gradient={{ from: 'teal', to: 'lime', deg: 105 }}><IconSun size={18} /></ActionIcon>
<ActionIcon variant="gradient" gradient={{ from: 'teal', to: 'blue', deg: 60 }}><IconSun size={18} /></ActionIcon>
<ActionIcon variant="gradient" gradient={{ from: 'orange', to: 'red' }}><IconSun size={18} /></ActionIcon>
<ActionIcon variant="gradient" gradient={{ from: '#ed6ea0', to: '#ec8c69', deg: 35 }}><IconSun size={18} /></ActionIcon>
</>
);
}
`;

function Demo() {
return (
<Group position="center">
<ActionIcon variant="gradient" gradient={{ from: 'indigo', to: 'cyan' }}>
<IconSun size={18} />
</ActionIcon>
<ActionIcon variant="gradient" gradient={{ from: 'teal', to: 'lime', deg: 105 }}>
<IconSun size={18} />
</ActionIcon>
<ActionIcon variant="gradient" gradient={{ from: 'teal', to: 'blue', deg: 60 }}>
<IconSun size={18} />
</ActionIcon>
<ActionIcon variant="gradient" gradient={{ from: 'orange', to: 'red' }}>
<IconSun size={18} />
</ActionIcon>
<ActionIcon variant="gradient" gradient={{ from: '#ed6ea0', to: '#ec8c69', deg: 35 }}>
<IconSun size={18} />
</ActionIcon>
</Group>
);
}

export const gradient: MantineDemo = {
type: 'demo',
component: Demo,
code,
};
1 change: 1 addition & 0 deletions src/mantine-demos/src/demos/core/ActionIcon/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { colors } from './ActionIcon.demo.colors';
export { configurator } from './ActionIcon.demo.configurator';
export { variants } from './ActionIcon.demo.variants';
export { gradient } from './ActionIcon.demo.gradient';

0 comments on commit 72555ad

Please sign in to comment.