@linagora/twake-mui 9.12.0 → 9.13.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,10 @@
1
+ # @linagora/twake-mui [9.13.0](https://github.com/linagora/twake-ui/compare/@linagora/twake-mui@9.12.0...@linagora/twake-mui@9.13.0) (2026-09-29)
2
+
3
+
4
+ ### Features
5
+
6
+ * **twake-mui:** Migrate Empty from cozy-ui ([159c7e2](https://github.com/linagora/twake-ui/commit/159c7e2656c03989fed1c4ea6870dcf8889dd468))
7
+
1
8
  # @linagora/twake-mui [9.12.0](https://github.com/linagora/twake-ui/compare/@linagora/twake-mui@9.11.2...@linagora/twake-mui@9.12.0) (2026-09-29)
2
9
 
3
10
 
@@ -0,0 +1,7 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Empty } from './index';
3
+ declare const meta: Meta<typeof Empty>;
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,52 @@
1
+ import { Icon, TwakeWorkplace } from '@linagora/twake-icons';
2
+ import { Box, Button, Stack } from '@mui/material';
3
+ import React from 'react';
4
+ import { Empty } from './index';
5
+ const iconSizes = ['normal', 'medium', 'large'];
6
+ const image = 'https://i.pravatar.cc/150?img=11';
7
+ const longTitle = 'This is a very very long title, just to see and verify how it works with it';
8
+ const longText = 'Ada Lovelace was an English mathematician and writer, chiefly known for her work on the Analytical Engine. She was the first to recognise that the machine had applications beyond pure calculation, and published the first algorithm intended to be carried out by such a machine.';
9
+ const meta = {
10
+ title: 'Empty',
11
+ component: Empty,
12
+ tags: ['autodocs'],
13
+ argTypes: {
14
+ iconSize: { control: 'select', options: iconSizes },
15
+ title: { control: 'text' },
16
+ text: { control: 'text' },
17
+ centered: { control: 'boolean' }
18
+ }
19
+ };
20
+ export default meta;
21
+ export const Default = {
22
+ args: {
23
+ icon: TwakeWorkplace,
24
+ iconSize: 'normal',
25
+ title: 'This list is empty',
26
+ text: 'Try adding some content to this list',
27
+ centered: false
28
+ }
29
+ };
30
+ const Section = ({ title, children }) => (React.createElement("section", null,
31
+ React.createElement("h3", { style: { marginBottom: '12px' } }, title),
32
+ children));
33
+ // Visual Regression - Combined view for Argos testing
34
+ export const Screenshot = {
35
+ tags: ['argos'],
36
+ render: () => (React.createElement(Stack, { spacing: 4 },
37
+ React.createElement(Section, { title: "Icon sizes" }, iconSizes.map(iconSize => (React.createElement(Empty, { key: iconSize, icon: TwakeWorkplace, iconSize: iconSize, title: "This list is empty", text: "Try adding some content to this list" })))),
38
+ React.createElement(Section, { title: "Long title and text" },
39
+ React.createElement(Empty, { icon: TwakeWorkplace, title: longTitle, text: longText })),
40
+ React.createElement(Section, { title: "With content" },
41
+ React.createElement(Empty, { icon: TwakeWorkplace, title: "This list is empty", text: "Try adding some content to this list" },
42
+ React.createElement(Button, { variant: "contained", sx: { mt: 2 } }, "Try refreshing"))),
43
+ React.createElement(Section, { title: "Centered" },
44
+ React.createElement(Box, { sx: { display: 'flex', height: 500, transform: 'scale(1)' } },
45
+ React.createElement(Empty, { icon: TwakeWorkplace, title: "This list is empty", text: "Try adding some content to this list", centered: true }))),
46
+ React.createElement(Section, { title: "Custom images" },
47
+ React.createElement(Empty, { icon: TwakeWorkplace, title: "With functional SVG", text: "Try adding some content to this list" }),
48
+ React.createElement(Empty, { icon: React.createElement("img", { src: image, alt: "" }), title: "With IMG", text: "Try adding some content to this list" }),
49
+ React.createElement(Empty, { icon: React.createElement("svg", { width: "100", height: "100" },
50
+ React.createElement("circle", { cx: "50", cy: "50", r: "40", stroke: "var(--twake-palette-primary-main)", strokeWidth: "4", fill: "var(--twake-palette-background-paper)" })), title: "With SVG", text: "Try adding some content to this list" }),
51
+ React.createElement(Empty, { icon: React.createElement(Icon, { icon: TwakeWorkplace }), title: "With Icon component", text: "Try adding some content to this list" }))))
52
+ };
@@ -0,0 +1,24 @@
1
+ import { IconProps } from '@linagora/twake-icons';
2
+ import { SxProps, TypographyProps } from '@mui/material';
3
+ import { Theme } from '@mui/material/styles';
4
+ import React from 'react';
5
+ export type EmptyIconSize = 'normal' | 'medium' | 'large';
6
+ export interface EmptyComponentsProps {
7
+ icon?: Partial<IconProps>;
8
+ title?: TypographyProps;
9
+ text?: TypographyProps;
10
+ childrenContainer?: React.ComponentPropsWithoutRef<'div'>;
11
+ }
12
+ export interface EmptyProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'title'> {
13
+ icon?: IconProps['icon'];
14
+ iconSize?: EmptyIconSize;
15
+ title?: React.ReactNode;
16
+ text?: React.ReactNode;
17
+ /** Below the `lg` breakpoint, pins the block to the centre of the viewport */
18
+ centered?: boolean;
19
+ componentsProps?: EmptyComponentsProps;
20
+ sx?: SxProps<Theme>;
21
+ }
22
+ export declare const EmptySubTitle: React.FC<TypographyProps>;
23
+ export declare const Empty: React.FC<EmptyProps>;
24
+ export default Empty;
@@ -0,0 +1,65 @@
1
+ import { Icon } from '@linagora/twake-icons';
2
+ import { Typography } from '@mui/material';
3
+ import { styled } from '@mui/material/styles';
4
+ import cx from 'classnames';
5
+ import React from 'react';
6
+ const ICON_CLASS_NAME = 'Empty-icon';
7
+ const iconHeights = {
8
+ normal: { desktop: 128, mobile: 96 },
9
+ medium: { desktop: 160, mobile: 128 },
10
+ large: { desktop: 192, mobile: 160 }
11
+ };
12
+ const EmptyRoot = styled('div', {
13
+ shouldForwardProp: prop => prop !== 'iconSize' && prop !== 'centered'
14
+ })(({ theme, iconSize, centered }) => ({
15
+ display: 'flex',
16
+ flexDirection: 'column',
17
+ justifyContent: 'center',
18
+ flex: '1 0 auto',
19
+ alignSelf: 'center',
20
+ margin: '0 auto',
21
+ boxSizing: 'content-box',
22
+ padding: theme.spacing(4),
23
+ textAlign: 'center',
24
+ width: `calc(100% - ${theme.spacing(8)})`,
25
+ maxWidth: 512,
26
+ [`& .${ICON_CLASS_NAME}`]: {
27
+ display: 'block',
28
+ margin: '0 auto 16px',
29
+ height: iconHeights[iconSize].desktop,
30
+ [theme.breakpoints.down('lg')]: {
31
+ marginBottom: 8,
32
+ height: iconHeights[iconSize].mobile
33
+ }
34
+ },
35
+ ...(centered && {
36
+ [theme.breakpoints.down('lg')]: {
37
+ position: 'fixed',
38
+ top: '50%',
39
+ left: '50%',
40
+ transform: 'translate(-50%, -50%)'
41
+ }
42
+ })
43
+ }));
44
+ const EmptyContent = styled('div')(({ theme }) => ({
45
+ maxWidth: 1008,
46
+ color: theme.vars.palette.text.secondary,
47
+ lineHeight: 1.5
48
+ }));
49
+ export const EmptySubTitle = props => (React.createElement(Typography, { variant: "body1", color: "textSecondary", ...props }));
50
+ const renderIcon = (icon, iconProps) => {
51
+ if (React.isValidElement(icon)) {
52
+ return React.cloneElement(icon, {
53
+ className: cx(ICON_CLASS_NAME, icon.props.className),
54
+ size: icon.props.size ?? (icon.type === Icon ? '100%' : undefined),
55
+ ...iconProps
56
+ });
57
+ }
58
+ return (React.createElement(Icon, { className: ICON_CLASS_NAME, icon: icon, size: "100%", ...iconProps }));
59
+ };
60
+ export const Empty = ({ icon, iconSize = 'normal', title, text, centered = false, componentsProps, children, ...props }) => (React.createElement(EmptyRoot, { iconSize: iconSize, centered: centered, ...props },
61
+ icon && renderIcon(icon, componentsProps?.icon),
62
+ title && (React.createElement(Typography, { gutterBottom: true, variant: "h3", color: "textPrimary", ...componentsProps?.title }, title)),
63
+ text && (React.createElement(EmptySubTitle, { gutterBottom: true, ...componentsProps?.text }, text)),
64
+ React.createElement(EmptyContent, { ...componentsProps?.childrenContainer }, children)));
65
+ export default Empty;
package/dist/index.d.ts CHANGED
@@ -13,6 +13,7 @@ export { Dialog, default as DialogDefault } from './components/Dialog';
13
13
  export { ContactPopover, default as ContactPopoverDefault } from './components/ContactPopover';
14
14
  export { default as DropdownButton } from './components/DropdownButton';
15
15
  export { default as DropdownText } from './components/DropdownText';
16
+ export { Empty, EmptySubTitle } from './components/Empty';
16
17
  export { default as ListItem } from './components/ListItem';
17
18
  export { default as ListItemButton } from './components/ListItemButton';
18
19
  export { default as ListItemText } from './components/ListItemText';
@@ -49,6 +50,7 @@ export type { ContactPopoverCalendarActionProps } from './components/ContactPopo
49
50
  export type { ContactPopoverEmailActionProps } from './components/ContactPopover/ContactPopoverEmailAction';
50
51
  export type { ChipProps } from './components/Chip';
51
52
  export type { DialogProps, DialogSize } from './components/Dialog';
53
+ export type { EmptyProps, EmptyIconSize, EmptyComponentsProps } from './components/Empty';
52
54
  export type { DropdownButtonProps } from './components/DropdownButton';
53
55
  export type { DropdownTextProps, DropdownTextVariant } from './components/DropdownText';
54
56
  export type { ListItemProps, ListItemGutters, ListItemSize } from './components/ListItem';
package/dist/index.js CHANGED
@@ -16,6 +16,7 @@ export { Dialog, default as DialogDefault } from './components/Dialog';
16
16
  export { ContactPopover, default as ContactPopoverDefault } from './components/ContactPopover';
17
17
  export { default as DropdownButton } from './components/DropdownButton';
18
18
  export { default as DropdownText } from './components/DropdownText';
19
+ export { Empty, EmptySubTitle } from './components/Empty';
19
20
  export { default as ListItem } from './components/ListItem';
20
21
  export { default as ListItemButton } from './components/ListItemButton';
21
22
  export { default as ListItemText } from './components/ListItemText';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@linagora/twake-mui",
3
3
  "type": "module",
4
- "version": "9.12.0",
4
+ "version": "9.13.0",
5
5
  "description": "MUI v9 theme system for Twake applications",
6
6
  "author": "Twake",
7
7
  "license": "MIT",