@linagora/twake-mui 9.8.0 → 9.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## @linagora/twake-mui [9.9.1](https://github.com/linagora/twake-ui/compare/@linagora/twake-mui@9.9.0...@linagora/twake-mui@9.9.1) (2026-09-24)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **twake-mui:** Fixed contactPopover click propagation & opening link in new pages ([b11270b](https://github.com/linagora/twake-ui/commit/b11270b060bcc749805f59059214c8a011b7b20d))
7
+
8
+ # @linagora/twake-mui [9.9.0](https://github.com/linagora/twake-ui/compare/@linagora/twake-mui@9.8.0...@linagora/twake-mui@9.9.0) (2026-09-24)
9
+
10
+
11
+ ### Features
12
+
13
+ * **twake-mui:** Migrate DropdownButton from cozy-ui ([58ef06a](https://github.com/linagora/twake-ui/commit/58ef06a9dd53659aab952824bf7ac2bc8bf2255e))
14
+
1
15
  # @linagora/twake-mui [9.8.0](https://github.com/linagora/twake-ui/compare/@linagora/twake-mui@9.7.0...@linagora/twake-mui@9.8.0) (2026-09-24)
2
16
 
3
17
 
@@ -4,6 +4,6 @@ import { IconButton, useTheme } from '@mui/material';
4
4
  import React from 'react';
5
5
  export const ContactPopoverCalendarAction = ({ url }) => {
6
6
  const theme = useTheme();
7
- return (React.createElement(IconButton, { href: url, size: "small", sx: { border: `1px solid ${theme.palette.divider}` } },
7
+ return (React.createElement(IconButton, { href: url, target: "_blank", rel: "noopener noreferrer", size: "small", sx: { border: `1px solid ${theme.palette.divider}` } },
8
8
  React.createElement(Icon, { icon: CalendarToday, size: 20, color: theme.palette.text.icon })));
9
9
  };
@@ -4,6 +4,6 @@ import { IconButton, useTheme } from '@mui/material';
4
4
  import React from 'react';
5
5
  export const ContactPopoverChatAction = ({ url }) => {
6
6
  const theme = useTheme();
7
- return (React.createElement(IconButton, { href: url, size: "small", sx: { border: `1px solid ${theme.palette.divider}` } },
7
+ return (React.createElement(IconButton, { href: url, target: "_blank", rel: "noopener noreferrer", size: "small", sx: { border: `1px solid ${theme.palette.divider}` } },
8
8
  React.createElement(Icon, { icon: Discuss, size: 20, color: theme.palette.text.icon })));
9
9
  };
@@ -4,7 +4,7 @@ import { useI18n } from 'twake-i18n';
4
4
  export const ContactPopoverEmailAction = ({ url }) => {
5
5
  const theme = useTheme();
6
6
  const { t } = useI18n();
7
- return (React.createElement(Button, { href: url, variant: "outlined", size: "small", fullWidth: true, sx: {
7
+ return (React.createElement(Button, { href: url, target: "_blank", rel: "noopener noreferrer", variant: "outlined", size: "small", fullWidth: true, sx: {
8
8
  justifyContent: 'center',
9
9
  color: theme.palette.text.primary,
10
10
  borderColor: theme.palette.divider
@@ -4,6 +4,6 @@ import { IconButton, useTheme } from '@mui/material';
4
4
  import React from 'react';
5
5
  export const ContactPopoverVideoAction = ({ url }) => {
6
6
  const theme = useTheme();
7
- return (React.createElement(IconButton, { href: url, size: "small", sx: { border: `1px solid ${theme.palette.divider}` } },
7
+ return (React.createElement(IconButton, { href: url, target: "_blank", rel: "noopener noreferrer", size: "small", sx: { border: `1px solid ${theme.palette.divider}` } },
8
8
  React.createElement(Icon, { icon: Camera, size: 20, color: theme.palette.text.icon })));
9
9
  };
@@ -119,7 +119,7 @@ export const ContactPopover = ({ name, email, children, onEmailCopy, onClose, di
119
119
  onMouseLeave: handleMouseLeave
120
120
  }
121
121
  } },
122
- React.createElement(StyledPopoverContent, null,
122
+ React.createElement(StyledPopoverContent, { onClick: event => event.stopPropagation() },
123
123
  React.createElement(CloseButton, { size: "small", onClick: handleClose },
124
124
  React.createElement(Icon, { icon: Cross, size: 16 })),
125
125
  React.createElement(AttendeeInfo, { name: name, email: email, onEmailCopy: onEmailCopy }),
@@ -0,0 +1,7 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import DropdownButton from './index';
3
+ declare const meta: Meta<typeof DropdownButton>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof meta>;
6
+ export declare const Default: Story;
7
+ export declare const Screenshot: Story;
@@ -0,0 +1,66 @@
1
+ import { Box, Grid, Stack, Typography } from '@mui/material';
2
+ import React from 'react';
3
+ import DropdownButton from './index';
4
+ const variants = [
5
+ 'h1',
6
+ 'h2',
7
+ 'h3',
8
+ 'h4',
9
+ 'h5',
10
+ 'subtitle1',
11
+ 'subtitle2',
12
+ 'body1',
13
+ 'body2',
14
+ 'caption'
15
+ ];
16
+ const meta = {
17
+ title: 'DropdownButton',
18
+ component: DropdownButton,
19
+ parameters: { layout: 'centered' },
20
+ tags: ['autodocs'],
21
+ argTypes: {
22
+ textVariant: { control: 'select', options: variants },
23
+ spaceBetween: { control: 'boolean' },
24
+ disabled: { control: 'boolean' },
25
+ fullWidth: { control: 'boolean' },
26
+ noWrap: { control: 'boolean' }
27
+ }
28
+ };
29
+ export default meta;
30
+ export const Default = {
31
+ args: {
32
+ children: 'Dropdown button'
33
+ }
34
+ };
35
+ const Container = ({ width, children }) => (React.createElement(Box, { sx: { border: '1px dashed', borderColor: 'divider', width } }, children));
36
+ // Visual Regression - Combined view for Argos testing
37
+ export const Screenshot = {
38
+ tags: ['argos'],
39
+ render: () => (React.createElement(Stack, { spacing: 4 },
40
+ React.createElement(Grid, { container: true },
41
+ React.createElement(Grid, { size: 6 },
42
+ React.createElement(Typography, null, "Default"),
43
+ variants.map(variant => (React.createElement(Box, { key: variant, sx: { mb: 2 } },
44
+ React.createElement(DropdownButton, { textVariant: variant }, variant))))),
45
+ React.createElement(Grid, { size: 6 },
46
+ React.createElement(Typography, null, "Disabled"),
47
+ variants.map(variant => (React.createElement(Box, { key: variant, sx: { mb: 2 } },
48
+ React.createElement(DropdownButton, { textVariant: variant, disabled: true }, variant)))))),
49
+ React.createElement(Container, null,
50
+ React.createElement(DropdownButton, null, "This is a long text without ellipsis without restrictive container")),
51
+ React.createElement(Container, { width: 150 },
52
+ React.createElement(DropdownButton, null, "This is a long text without ellipsis inside a restrictive container")),
53
+ React.createElement(Container, { width: 150 },
54
+ React.createElement(DropdownButton, { noWrap: true }, "This is a long text with ellipsis inside a container")),
55
+ React.createElement(Container, { width: "100%" },
56
+ React.createElement(DropdownButton, null,
57
+ "Text with",
58
+ React.createElement("br", null),
59
+ "breaking spaces",
60
+ React.createElement("br", null),
61
+ "inside content")),
62
+ React.createElement(Container, { width: "100%" },
63
+ React.createElement(DropdownButton, { fullWidth: true, spaceBetween: true }, "Space between text and icon (fullWidth needed)")),
64
+ React.createElement(Container, { width: "100%" },
65
+ React.createElement(DropdownButton, { fullWidth: true }, "Full width but no space between text and icon"))))
66
+ };
@@ -0,0 +1,11 @@
1
+ import { ButtonProps } from '@mui/material';
2
+ import React from 'react';
3
+ import { DropdownTextProps, DropdownTextVariant } from '../DropdownText';
4
+ export interface DropdownButtonProps extends ButtonProps {
5
+ textVariant?: DropdownTextVariant;
6
+ spaceBetween?: boolean;
7
+ noWrap?: boolean;
8
+ dropdownTextProps?: Partial<DropdownTextProps>;
9
+ }
10
+ declare const DropdownButton: React.ForwardRefExoticComponent<Omit<DropdownButtonProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
11
+ export default DropdownButton;
@@ -0,0 +1,20 @@
1
+ import { Button } from '@mui/material';
2
+ import { styled } from '@mui/material/styles';
3
+ import React from 'react';
4
+ import DropdownText from '../DropdownText';
5
+ const StyledButton = styled(Button)({
6
+ minHeight: 'auto',
7
+ margin: -8,
8
+ padding: 8,
9
+ textAlign: 'left',
10
+ variants: [
11
+ {
12
+ props: { fullWidth: true },
13
+ style: { width: 'calc(100% + 16px)' }
14
+ }
15
+ ]
16
+ });
17
+ const DropdownButton = React.forwardRef(({ textVariant = 'body1', spaceBetween = false, disabled = false, fullWidth = false, noWrap = false, dropdownTextProps, children, ...props }, ref) => (React.createElement(StyledButton, { ref: ref, variant: "text", color: "inherit", disabled: disabled, fullWidth: fullWidth || noWrap, ...props },
18
+ React.createElement(DropdownText, { variant: textVariant, spaceBetween: spaceBetween, disabled: disabled, noWrap: noWrap, ...dropdownTextProps }, children))));
19
+ DropdownButton.displayName = 'DropdownButton';
20
+ export default DropdownButton;
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@ export { Button, default as ButtonDefault } from './components/Button';
11
11
  export { default as Chip } from './components/Chip';
12
12
  export { Dialog, default as DialogDefault } from './components/Dialog';
13
13
  export { ContactPopover, default as ContactPopoverDefault } from './components/ContactPopover';
14
+ export { default as DropdownButton } from './components/DropdownButton';
14
15
  export { default as DropdownText } from './components/DropdownText';
15
16
  export { Tabs, default as TabsDefault } from './components/Tabs';
16
17
  export { Switch, default as SwitchDefault } from './components/Switch';
@@ -42,6 +43,7 @@ export type { ContactPopoverCalendarActionProps } from './components/ContactPopo
42
43
  export type { ContactPopoverEmailActionProps } from './components/ContactPopover/ContactPopoverEmailAction';
43
44
  export type { ChipProps } from './components/Chip';
44
45
  export type { DialogProps, DialogSize } from './components/Dialog';
46
+ export type { DropdownButtonProps } from './components/DropdownButton';
45
47
  export type { DropdownTextProps, DropdownTextVariant } from './components/DropdownText';
46
48
  export type { TabsProps } from './components/Tabs';
47
49
  export type { SwitchProps } from './components/Switch';
package/dist/index.js CHANGED
@@ -14,6 +14,7 @@ export { Button, default as ButtonDefault } from './components/Button';
14
14
  export { default as Chip } from './components/Chip';
15
15
  export { Dialog, default as DialogDefault } from './components/Dialog';
16
16
  export { ContactPopover, default as ContactPopoverDefault } from './components/ContactPopover';
17
+ export { default as DropdownButton } from './components/DropdownButton';
17
18
  export { default as DropdownText } from './components/DropdownText';
18
19
  export { Tabs, default as TabsDefault } from './components/Tabs';
19
20
  export { Switch, default as SwitchDefault } from './components/Switch';
@@ -1,6 +1,7 @@
1
- import { Attachment, Attention, Bottom, Contrast, Copy, Icon, Pen, People, Telephone } from '@linagora/twake-icons';
2
- import { Box, Button, Divider, ListItemIcon, ListItemText, Menu, MenuItem, Typography } from '@mui/material';
1
+ import { Attachment, Attention, Contrast, Copy, Icon, Pen, People, Telephone } from '@linagora/twake-icons';
2
+ import { Box, Divider, ListItemIcon, ListItemText, Menu, MenuItem, Typography } from '@mui/material';
3
3
  import React, { useState } from 'react';
4
+ import DropdownButton from '../components/DropdownButton';
4
5
  const items = [
5
6
  React.createElement(MenuItem, { key: "modify" },
6
7
  React.createElement(ListItemIcon, null,
@@ -41,7 +42,7 @@ const ExampleMenu = ({ defaultOpen = false, ...props }) => {
41
42
  const [button, setButton] = useState(null);
42
43
  const [open, setOpen] = useState(defaultOpen);
43
44
  return (React.createElement(React.Fragment, null,
44
- React.createElement(Button, { ref: setButton, variant: "text", endIcon: React.createElement(Icon, { icon: Bottom }), onClick: () => setOpen(!open) }, "Show menu"),
45
+ React.createElement(DropdownButton, { ref: setButton, onClick: () => setOpen(!open) }, "Show menu"),
45
46
  React.createElement(Menu, { anchorOrigin: { vertical: 'bottom', horizontal: 'left' }, ...props, anchorEl: button, open: open && Boolean(button), onClose: () => setOpen(false) }, items)));
46
47
  };
47
48
  const meta = {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@linagora/twake-mui",
3
3
  "type": "module",
4
- "version": "9.8.0",
4
+ "version": "9.9.1",
5
5
  "description": "MUI v9 theme system for Twake applications",
6
6
  "author": "Twake",
7
7
  "license": "MIT",