@linagora/twake-mui 14.1.0 → 14.3.0

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 [14.3.0](https://github.com/linagora/twake-ui/compare/@linagora/twake-mui@14.2.0...@linagora/twake-mui@14.3.0) (2026-10-15)
2
+
3
+
4
+ ### Features
5
+
6
+ * **twake-mui:** Migrate PasswordField from cozy-ui ([5d39ddd](https://github.com/linagora/twake-ui/commit/5d39ddd8c7616e82c9f6c89cabe1a53b6b553864))
7
+
8
+ # @linagora/twake-mui [14.2.0](https://github.com/linagora/twake-ui/compare/@linagora/twake-mui@14.1.0...@linagora/twake-mui@14.2.0) (2026-10-15)
9
+
10
+
11
+ ### Features
12
+
13
+ * **twake-mui:** Migrate Filename from cozy-ui ([84f4803](https://github.com/linagora/twake-ui/commit/84f4803fedbfc211dabef69717570d75500369b4))
14
+
1
15
  # @linagora/twake-mui [14.1.0](https://github.com/linagora/twake-ui/compare/@linagora/twake-mui@14.0.0...@linagora/twake-mui@14.1.0) (2026-10-15)
2
16
 
3
17
 
@@ -0,0 +1,7 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import Filename from './index';
3
+ declare const meta: Meta<typeof Filename>;
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,95 @@
1
+ import { File, Icon } from '@linagora/twake-icons';
2
+ import { Box, Stack } from '@mui/material';
3
+ import React from 'react';
4
+ import Filename from './index';
5
+ const longName = 'Lacinia condimentum potenti id est tortor dictumst lectus tincidunt hac ultricies, curae mattis nisi neque sodales sagittis dui nulla aliquam turpis eros, finibus ac iaculis dictum et orci elit posuere ex and this is the end';
6
+ const shortName = 'Lacinia condimentum this is the end';
7
+ const path = '/some/folder/and/subfolder';
8
+ const icon = React.createElement(Icon, { icon: File, size: 32 });
9
+ const examples = [
10
+ {
11
+ title: 'Icon, extension and path',
12
+ props: { icon, filename: longName, extension: '.pdf', path }
13
+ },
14
+ {
15
+ title: 'Middle ellipsis',
16
+ props: {
17
+ icon,
18
+ filename: longName,
19
+ extension: '.pdf',
20
+ path,
21
+ midEllipsis: true
22
+ }
23
+ },
24
+ {
25
+ title: 'Without path',
26
+ props: { icon, filename: longName, extension: '.pdf' }
27
+ },
28
+ {
29
+ title: 'Without path, middle ellipsis',
30
+ props: { icon, filename: longName, extension: '.pdf', midEllipsis: true }
31
+ },
32
+ {
33
+ title: 'Body1 variant',
34
+ props: {
35
+ icon,
36
+ filename: longName,
37
+ extension: '.pdf',
38
+ path,
39
+ variant: 'body1'
40
+ }
41
+ },
42
+ {
43
+ title: 'Without icon',
44
+ props: { filename: longName, extension: '.pdf', path }
45
+ },
46
+ {
47
+ title: 'Without extension',
48
+ props: { icon, filename: longName, path }
49
+ },
50
+ {
51
+ title: 'Short name',
52
+ props: { icon, filename: shortName, extension: '.pdf', path }
53
+ },
54
+ {
55
+ title: 'Short name without path',
56
+ props: { icon, filename: shortName, extension: '.pdf' }
57
+ }
58
+ ];
59
+ const Section = ({ title, children }) => (React.createElement("section", null,
60
+ React.createElement("h3", null, title),
61
+ children));
62
+ const meta = {
63
+ title: 'Filename',
64
+ component: Filename,
65
+ tags: ['autodocs'],
66
+ argTypes: {
67
+ icon: { control: false },
68
+ filename: { control: 'text' },
69
+ extension: { control: 'text' },
70
+ midEllipsis: { control: 'boolean' },
71
+ variant: {
72
+ control: 'select',
73
+ options: ['h6', 'body1', 'body2', 'subtitle1', 'caption']
74
+ },
75
+ path: { control: 'text' }
76
+ }
77
+ };
78
+ export default meta;
79
+ export const Default = {
80
+ args: {
81
+ icon,
82
+ filename: longName,
83
+ extension: '.pdf',
84
+ midEllipsis: false,
85
+ variant: 'h6',
86
+ path
87
+ },
88
+ render: args => (React.createElement(Box, { sx: { maxWidth: 400 } },
89
+ React.createElement(Filename, { ...args })))
90
+ };
91
+ export const Screenshot = {
92
+ tags: ['argos'],
93
+ render: () => (React.createElement(Stack, { spacing: 4, sx: { maxWidth: 400 } }, examples.map(({ title, props }) => (React.createElement(Section, { key: title, title: title },
94
+ React.createElement(Filename, { ...props }))))))
95
+ };
@@ -0,0 +1,16 @@
1
+ import { TypographyProps } from '@mui/material';
2
+ import React from 'react';
3
+ export interface FilenameProps {
4
+ icon?: React.ReactNode;
5
+ /** Folder or file name */
6
+ filename?: string;
7
+ /** File extension, rendered in the secondary text color */
8
+ extension?: string;
9
+ /** Truncates the filename in its middle instead of its end */
10
+ midEllipsis?: boolean;
11
+ variant?: TypographyProps['variant'];
12
+ /** Shown on a second line, under the name */
13
+ path?: React.ReactNode;
14
+ }
15
+ declare const Filename: React.FC<FilenameProps>;
16
+ export default Filename;
@@ -0,0 +1,20 @@
1
+ import { Box, Typography } from '@mui/material';
2
+ import React from 'react';
3
+ import MidEllipsis from '../MidEllipsis';
4
+ const NameAndExtension = ({ filename, extension, midEllipsis, variant }) => (React.createElement(React.Fragment, null,
5
+ filename && (React.createElement(Typography, { variant: variant, component: "span", noWrap: true }, midEllipsis ? React.createElement(MidEllipsis, { text: filename }) : filename)),
6
+ extension && (React.createElement(Typography, { variant: variant, component: "span", color: "textSecondary" }, extension))));
7
+ const Filename = ({ icon, filename, extension, midEllipsis = false, variant = 'h6', path }) => {
8
+ const nameAndExtension = (React.createElement(NameAndExtension, { filename: filename, extension: extension, midEllipsis: midEllipsis, variant: variant }));
9
+ const iconBox = icon && (React.createElement(Box, { className: "u-flex u-pos-relative u-mr-1", sx: path ? { float: 'left', top: 4 } : undefined }, icon));
10
+ if (!path) {
11
+ return (React.createElement("div", { className: "u-flex u-flex-items-center" },
12
+ iconBox,
13
+ nameAndExtension));
14
+ }
15
+ return (React.createElement(React.Fragment, null,
16
+ iconBox,
17
+ React.createElement("div", { className: "u-flex" }, nameAndExtension),
18
+ React.createElement(Typography, { variant: "body2", component: "div", noWrap: true }, path)));
19
+ };
20
+ export default Filename;
@@ -0,0 +1,7 @@
1
+ import { TextField } from '@mui/material';
2
+ import type { Meta, StoryObj } from '@storybook/react-vite';
3
+ declare const meta: Meta<typeof TextField>;
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,43 @@
1
+ import { Stack } from '@mui/material';
2
+ import React from 'react';
3
+ import PasswordField from './index';
4
+ // TextFieldProps is a union, which Storybook cannot infer args from
5
+ const meta = {
6
+ title: 'PasswordField',
7
+ component: PasswordField,
8
+ parameters: { layout: 'centered' },
9
+ tags: ['autodocs'],
10
+ argTypes: {
11
+ label: { control: 'text' },
12
+ placeholder: { control: 'text' },
13
+ helperText: { control: 'text' },
14
+ size: { control: 'select', options: ['small', 'medium'] },
15
+ disabled: { control: 'boolean' },
16
+ error: { control: 'boolean' },
17
+ fullWidth: { control: 'boolean' }
18
+ }
19
+ };
20
+ export default meta;
21
+ export const Default = {
22
+ args: {
23
+ defaultValue: 'Cl4ude€st1Nu@ge'
24
+ }
25
+ };
26
+ const Row = ({ title, children }) => (React.createElement("section", null,
27
+ React.createElement("h3", { style: { marginBottom: '12px' } }, title),
28
+ React.createElement(Stack, { direction: "row", spacing: 2, useFlexGap: true, sx: { flexWrap: 'wrap' } }, children)));
29
+ // Visual Regression - Combined view for Argos testing
30
+ export const Screenshot = {
31
+ tags: ['argos'],
32
+ render: () => (React.createElement(Stack, { spacing: 4 },
33
+ React.createElement(Row, { title: "Default" },
34
+ React.createElement(PasswordField, { defaultValue: "Cl4ude\u20ACst1Nu@ge" }),
35
+ React.createElement(PasswordField, { label: "Password", defaultValue: "Cl4ude\u20ACst1Nu@ge" }),
36
+ React.createElement(PasswordField, { label: "Password" })),
37
+ React.createElement(Row, { title: "Sizes" },
38
+ React.createElement(PasswordField, { size: "small", defaultValue: "Cl4ude\u20ACst1Nu@ge" }),
39
+ React.createElement(PasswordField, { size: "medium", defaultValue: "Cl4ude\u20ACst1Nu@ge" })),
40
+ React.createElement(Row, { title: "States" },
41
+ React.createElement(PasswordField, { label: "Disabled", disabled: true, defaultValue: "Cl4ude\u20ACst1Nu@ge" }),
42
+ React.createElement(PasswordField, { label: "Error", error: true, helperText: "Wrong password", defaultValue: "Cl4ude\u20ACst1Nu@ge" }))))
43
+ };
@@ -0,0 +1,6 @@
1
+ import { TextFieldProps } from '@mui/material';
2
+ import React from 'react';
3
+ export type PasswordFieldProps = TextFieldProps;
4
+ /** Password field with a button to show or hide its value */
5
+ declare const PasswordField: ({ slotProps, ...props }: PasswordFieldProps) => React.ReactElement;
6
+ export default PasswordField;
@@ -0,0 +1,28 @@
1
+ import { Eye, EyeClosed, Icon } from '@linagora/twake-icons';
2
+ import { IconButton, InputAdornment, TextField } from '@mui/material';
3
+ import { mergeSlotProps } from '@mui/material/utils';
4
+ import React, { useState } from 'react';
5
+ import { useExtendI18n, useI18n } from 'twake-i18n';
6
+ import de from './locales/de.json';
7
+ import en from './locales/en.json';
8
+ import es from './locales/es.json';
9
+ import fr from './locales/fr.json';
10
+ import it from './locales/it.json';
11
+ import ru from './locales/ru.json';
12
+ import vi from './locales/vi.json';
13
+ const locales = { de, en, es, fr, it, ru, vi };
14
+ /** Password field with a button to show or hide its value */
15
+ const PasswordField = ({ slotProps, ...props }) => {
16
+ useExtendI18n(locales);
17
+ const { t } = useI18n();
18
+ const [hidden, setHidden] = useState(true);
19
+ return (React.createElement(TextField, { type: hidden ? 'password' : 'text', ...props, slotProps: {
20
+ ...slotProps,
21
+ input: mergeSlotProps(slotProps?.input, {
22
+ endAdornment: (React.createElement(InputAdornment, { position: "end" },
23
+ React.createElement(IconButton, { "aria-label": hidden ? t('PasswordField.show') : t('PasswordField.hide'), disabled: props.disabled, onClick: () => setHidden(current => !current), edge: "end" },
24
+ React.createElement(Icon, { icon: hidden ? Eye : EyeClosed }))))
25
+ })
26
+ } }));
27
+ };
28
+ export default PasswordField;
@@ -0,0 +1,6 @@
1
+ {
2
+ "PasswordField": {
3
+ "show": "Passwort anzeigen",
4
+ "hide": "Passwort verbergen"
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "PasswordField": {
3
+ "show": "Show password",
4
+ "hide": "Hide password"
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "PasswordField": {
3
+ "show": "Mostrar contraseña",
4
+ "hide": "Ocultar contraseña"
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "PasswordField": {
3
+ "show": "Afficher le mot de passe",
4
+ "hide": "Masquer le mot de passe"
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "PasswordField": {
3
+ "show": "Mostra password",
4
+ "hide": "Nascondi password"
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "PasswordField": {
3
+ "show": "Показать пароль",
4
+ "hide": "Скрыть пароль"
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "PasswordField": {
3
+ "show": "Hiển thị mật khẩu",
4
+ "hide": "Ẩn mật khẩu"
5
+ }
6
+ }
package/dist/index.d.ts CHANGED
@@ -46,6 +46,7 @@ export { default as DropdownButton } from './components/DropdownButton';
46
46
  export { default as DropdownText } from './components/DropdownText';
47
47
  export { Empty, EmptySubTitle } from './components/Empty';
48
48
  export { ExtendableFab } from './components/ExtendableFab';
49
+ export { default as Filename } from './components/Filename';
49
50
  export { default as ListItem } from './components/ListItem';
50
51
  export { default as ListItemButton } from './components/ListItemButton';
51
52
  export { default as ListItemText } from './components/ListItemText';
@@ -71,6 +72,7 @@ export { NavIcon } from './components/NavIcon';
71
72
  export { default as NavText } from './components/NavText';
72
73
  export { NavDesktopLimiter } from './components/NavDesktopLimiter';
73
74
  export { NavDesktopDropdown } from './components/NavDesktopDropdown';
75
+ export { default as PasswordField } from './components/PasswordField';
74
76
  export { nameToColor, supportedColors, getInitials } from './components/Avatar/helpers';
75
77
  export { COLORS } from './components/ColorList/helpers';
76
78
  export { default as AccordionExpandIcon } from './components/AccordionExpandIcon';
@@ -125,6 +127,7 @@ export type { EmptyProps, EmptyIconSize, EmptyComponentsProps } from './componen
125
127
  export type { DropdownButtonProps } from './components/DropdownButton';
126
128
  export type { DropdownTextProps, DropdownTextVariant } from './components/DropdownText';
127
129
  export type { ExtendableFabProps, ScrollOptions } from './components/ExtendableFab';
130
+ export type { FilenameProps } from './components/Filename';
128
131
  export type { ListItemProps, ListItemGutters, ListItemSize } from './components/ListItem';
129
132
  export type { ListItemButtonProps } from './components/ListItemButton';
130
133
  export type { ListItemTextProps } from './components/ListItemText';
@@ -147,6 +150,7 @@ export type { NavDropdownProps } from './components/NavLink/NavDropdown';
147
150
  export type { NavIconProps } from './components/NavIcon';
148
151
  export type { NavTextProps } from './components/NavText';
149
152
  export type { NavDesktopLimiterProps } from './components/NavDesktopLimiter';
153
+ export type { PasswordFieldProps } from './components/PasswordField';
150
154
  export type { NavDesktopDropdownProps } from './components/NavDesktopDropdown';
151
155
  export type { VirtualizedTableProps, VirtualizedTableColumn, VirtualizedTableRow } from './components/VirtualizedTable';
152
156
  export type { Breakpoints } from './hooks/useBreakpoints';
package/dist/index.js CHANGED
@@ -49,6 +49,7 @@ export { default as DropdownButton } from './components/DropdownButton';
49
49
  export { default as DropdownText } from './components/DropdownText';
50
50
  export { Empty, EmptySubTitle } from './components/Empty';
51
51
  export { ExtendableFab } from './components/ExtendableFab';
52
+ export { default as Filename } from './components/Filename';
52
53
  export { default as ListItem } from './components/ListItem';
53
54
  export { default as ListItemButton } from './components/ListItemButton';
54
55
  export { default as ListItemText } from './components/ListItemText';
@@ -74,6 +75,7 @@ export { NavIcon } from './components/NavIcon';
74
75
  export { default as NavText } from './components/NavText';
75
76
  export { NavDesktopLimiter } from './components/NavDesktopLimiter';
76
77
  export { NavDesktopDropdown } from './components/NavDesktopDropdown';
78
+ export { default as PasswordField } from './components/PasswordField';
77
79
  export { nameToColor, supportedColors, getInitials } from './components/Avatar/helpers';
78
80
  export { COLORS } from './components/ColorList/helpers';
79
81
  export { default as AccordionExpandIcon } from './components/AccordionExpandIcon';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@linagora/twake-mui",
3
3
  "type": "module",
4
- "version": "14.1.0",
4
+ "version": "14.3.0",
5
5
  "description": "MUI v9 theme system for Twake applications",
6
6
  "author": "Twake",
7
7
  "license": "MIT",