@superdispatch/ui-lab 0.50.3 → 0.50.5
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/.babelrc.js +5 -0
- package/package.json +38 -13
- package/pkg/README.md +10 -0
- package/{dist-node → pkg/dist-node}/index.js +52 -40
- package/pkg/dist-node/index.js.map +1 -0
- package/{dist-src → pkg/dist-src}/email-autocomplate/EmailAutocomplete.js +3 -3
- package/{dist-src → pkg/dist-src}/file-drop-zone/FileDropZone.js +2 -2
- package/{dist-src → pkg/dist-src}/flag-list/FlagListItem.js +11 -19
- package/{dist-src → pkg/dist-src}/index.js +1 -0
- package/{dist-src → pkg/dist-src}/navbar/Navbar.js +13 -4
- package/{dist-src → pkg/dist-src}/navbar/NavbarAccordion.js +18 -9
- package/{dist-src → pkg/dist-src}/navbar/NavbarList.js +1 -1
- package/{dist-src → pkg/dist-src}/sidebar/SidebarBackButton.js +1 -1
- package/{dist-src → pkg/dist-src}/sidebar/SidebarMenuItem.js +1 -1
- package/{dist-src → pkg/dist-src}/sidebar/SidebarMenuItemAvatar.js +1 -1
- package/{dist-types → pkg/dist-types}/index.d.ts +8 -2
- package/{dist-web → pkg/dist-web}/index.js +52 -42
- package/pkg/dist-web/index.js.map +1 -0
- package/pkg/package.json +41 -0
- package/playroom.ts +24 -0
- package/src/alert/Alert.stories.tsx +162 -0
- package/src/alert/Alert.tsx +135 -0
- package/src/banner/Banner.stories.tsx +64 -0
- package/src/banner/Banner.tsx +120 -0
- package/src/box/Box.stories.tsx +20 -0
- package/src/box/Box.tsx +257 -0
- package/src/button/Button.stories.tsx +739 -0
- package/src/button/Button.tsx +498 -0
- package/src/button-area/ButtonArea.stories.tsx +65 -0
- package/src/button-area/ButtonArea.tsx +90 -0
- package/src/chat/Chat.stories.tsx +130 -0
- package/src/chat/Chat.tsx +57 -0
- package/src/chat/ChatMessage.tsx +45 -0
- package/src/chat/README.MD +7 -0
- package/src/chat/__tests__/Chat.spec.tsx +29 -0
- package/src/chat/__tests__/ChatMessage.spec.tsx +39 -0
- package/src/container/Container.tsx +48 -0
- package/src/description-item/DescriptionItem.stories.tsx +163 -0
- package/src/description-item/DescriptionItem.tsx +104 -0
- package/src/description-line-item/DescriptionLineItem.stories.tsx +23 -0
- package/src/description-line-item/DescriptionLineItem.tsx +29 -0
- package/src/email-autocomplate/CloseIcon.tsx +20 -0
- package/src/email-autocomplate/EmailAutocomplete.stories.tsx +47 -0
- package/src/email-autocomplate/EmailAutocomplete.tsx +138 -0
- package/src/file-drop-zone/FileDropZone.stories.tsx +44 -0
- package/src/file-drop-zone/FileDropZone.tsx +170 -0
- package/src/file-list-item/FileListItem.stories.tsx +37 -0
- package/src/file-list-item/FileListItem.tsx +148 -0
- package/src/file-list-item/__tests__/FileListItem.spec.tsx +339 -0
- package/src/flag-list/FlagList.stories.tsx +72 -0
- package/src/flag-list/FlagList.tsx +54 -0
- package/src/flag-list/FlagListItem.tsx +126 -0
- package/src/index.spec.ts +53 -0
- package/src/index.ts +36 -0
- package/src/linked-text/LinkeText.stories.tsx +42 -0
- package/src/linked-text/LinkedText.tsx +47 -0
- package/src/multiline-text/MultilineText.stories.tsx +30 -0
- package/src/multiline-text/MultilineText.ts +16 -0
- package/src/navbar/Navbar.stories.tsx +137 -0
- package/src/navbar/Navbar.tsx +132 -0
- package/src/navbar/NavbarAccordion.tsx +195 -0
- package/src/navbar/NavbarAvatar.tsx +51 -0
- package/src/navbar/NavbarBottomBar.tsx +135 -0
- package/src/navbar/NavbarContext.tsx +22 -0
- package/src/navbar/NavbarItem.tsx +125 -0
- package/src/navbar/NavbarList.tsx +247 -0
- package/src/navbar/NavbarMenu.tsx +102 -0
- package/src/passwordStepper/PasswordStrength.stories.tsx +95 -0
- package/src/passwordStepper/PasswordStrength.tsx +107 -0
- package/src/passwordStepper/PasswordUtils.tsx +42 -0
- package/src/passwordStepper/PasswordValidationComponents.tsx +95 -0
- package/src/sidebar/Sidebar.stories.tsx +376 -0
- package/src/sidebar/Sidebar.tsx +75 -0
- package/src/sidebar/SidebarBackButton.tsx +33 -0
- package/src/sidebar/SidebarContainer.tsx +114 -0
- package/src/sidebar/SidebarContent.tsx +119 -0
- package/src/sidebar/SidebarDivider.tsx +15 -0
- package/src/sidebar/SidebarMenuItem.tsx +196 -0
- package/src/sidebar/SidebarMenuItemAction.tsx +27 -0
- package/src/sidebar/SidebarMenuItemAvatar.tsx +59 -0
- package/src/sidebar/SidebarMenuItemContext.tsx +33 -0
- package/src/sidebar/SidebarSubheader.tsx +38 -0
- package/src/styled.d.ts +12 -0
- package/src/text-box/TextBox.stories.tsx +114 -0
- package/src/text-box/TextBox.tsx +238 -0
- package/src/utils/RuleNormalizer.ts +24 -0
- package/src/utils/mergeStyles.ts +28 -0
- package/tsconfig.json +19 -0
- package/LICENSE +0 -21
- package/dist-node/index.js.map +0 -1
- package/dist-web/index.js.map +0 -1
- /package/{dist-src → pkg/dist-src}/alert/Alert.js +0 -0
- /package/{dist-src → pkg/dist-src}/banner/Banner.js +0 -0
- /package/{dist-src → pkg/dist-src}/box/Box.js +0 -0
- /package/{dist-src → pkg/dist-src}/button/Button.js +0 -0
- /package/{dist-src → pkg/dist-src}/button-area/ButtonArea.js +0 -0
- /package/{dist-src → pkg/dist-src}/chat/Chat.js +0 -0
- /package/{dist-src → pkg/dist-src}/chat/ChatMessage.js +0 -0
- /package/{dist-src → pkg/dist-src}/container/Container.js +0 -0
- /package/{dist-src → pkg/dist-src}/description-item/DescriptionItem.js +0 -0
- /package/{dist-src → pkg/dist-src}/description-line-item/DescriptionLineItem.js +0 -0
- /package/{dist-src → pkg/dist-src}/email-autocomplate/CloseIcon.js +0 -0
- /package/{dist-src → pkg/dist-src}/file-list-item/FileListItem.js +0 -0
- /package/{dist-src → pkg/dist-src}/flag-list/FlagList.js +0 -0
- /package/{dist-src → pkg/dist-src}/linked-text/LinkedText.js +0 -0
- /package/{dist-src → pkg/dist-src}/multiline-text/MultilineText.js +0 -0
- /package/{dist-src → pkg/dist-src}/navbar/NavbarAvatar.js +0 -0
- /package/{dist-src → pkg/dist-src}/navbar/NavbarBottomBar.js +0 -0
- /package/{dist-src → pkg/dist-src}/navbar/NavbarContext.js +0 -0
- /package/{dist-src → pkg/dist-src}/navbar/NavbarItem.js +0 -0
- /package/{dist-src → pkg/dist-src}/navbar/NavbarMenu.js +0 -0
- /package/{dist-src → pkg/dist-src}/passwordStepper/PasswordStrength.js +0 -0
- /package/{dist-src → pkg/dist-src}/passwordStepper/PasswordUtils.js +0 -0
- /package/{dist-src → pkg/dist-src}/passwordStepper/PasswordValidationComponents.js +0 -0
- /package/{dist-src → pkg/dist-src}/sidebar/Sidebar.js +0 -0
- /package/{dist-src → pkg/dist-src}/sidebar/SidebarContainer.js +0 -0
- /package/{dist-src → pkg/dist-src}/sidebar/SidebarContent.js +0 -0
- /package/{dist-src → pkg/dist-src}/sidebar/SidebarDivider.js +0 -0
- /package/{dist-src → pkg/dist-src}/sidebar/SidebarMenuItemAction.js +0 -0
- /package/{dist-src → pkg/dist-src}/sidebar/SidebarMenuItemContext.js +0 -0
- /package/{dist-src → pkg/dist-src}/sidebar/SidebarSubheader.js +0 -0
- /package/{dist-src → pkg/dist-src}/text-box/TextBox.js +0 -0
- /package/{dist-src → pkg/dist-src}/utils/RuleNormalizer.js +0 -0
- /package/{dist-src → pkg/dist-src}/utils/mergeStyles.js +0 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { AppBar, Toolbar } from '@material-ui/core';
|
|
2
|
+
import { Column, Columns, Stack, SuperDispatchTheme } from '@superdispatch/ui';
|
|
3
|
+
import {
|
|
4
|
+
MouseEvent,
|
|
5
|
+
ReactElement,
|
|
6
|
+
ReactNode,
|
|
7
|
+
useLayoutEffect,
|
|
8
|
+
useRef,
|
|
9
|
+
} from 'react';
|
|
10
|
+
import styled, { css } from 'styled-components';
|
|
11
|
+
import { Box } from '../box/Box';
|
|
12
|
+
import { TextBox } from '../text-box/TextBox';
|
|
13
|
+
import { SidebarBackButton } from './SidebarBackButton';
|
|
14
|
+
import { useSidebarContext } from './SidebarContainer';
|
|
15
|
+
|
|
16
|
+
const SidebarAppBar = styled(AppBar)(
|
|
17
|
+
({ theme }: { theme: SuperDispatchTheme }) => {
|
|
18
|
+
return css`
|
|
19
|
+
${theme.breakpoints.up('sm')} {
|
|
20
|
+
&& {
|
|
21
|
+
border-left: transparent;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
`;
|
|
25
|
+
},
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const ToolbarContent = styled.div`
|
|
29
|
+
flex: 1;
|
|
30
|
+
padding: 16px;
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
export interface SidebarContentProps {
|
|
34
|
+
dense?: boolean;
|
|
35
|
+
title: ReactNode;
|
|
36
|
+
children: ReactNode;
|
|
37
|
+
action?: ReactNode;
|
|
38
|
+
openOnMount?: boolean;
|
|
39
|
+
closeOnUnmount?: boolean;
|
|
40
|
+
onBack?: (event: MouseEvent<HTMLButtonElement>) => void;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function SidebarContent({
|
|
44
|
+
dense,
|
|
45
|
+
action,
|
|
46
|
+
title,
|
|
47
|
+
children,
|
|
48
|
+
onBack,
|
|
49
|
+
openOnMount,
|
|
50
|
+
closeOnUnmount,
|
|
51
|
+
}: SidebarContentProps): ReactElement {
|
|
52
|
+
const isOpenedOnMount = useRef<boolean>(false);
|
|
53
|
+
const isClosedOnMount = useRef<boolean>(false);
|
|
54
|
+
|
|
55
|
+
const { openSidebarContent, openSidebar } = useSidebarContext();
|
|
56
|
+
|
|
57
|
+
useLayoutEffect(() => {
|
|
58
|
+
if (openOnMount) {
|
|
59
|
+
if (isOpenedOnMount.current) {
|
|
60
|
+
// eslint-disable-next-line no-console
|
|
61
|
+
console.warn(
|
|
62
|
+
'[SidebarContent]: "openOnMount" should not change during lifecycle of the component.',
|
|
63
|
+
);
|
|
64
|
+
} else {
|
|
65
|
+
isOpenedOnMount.current = true;
|
|
66
|
+
openSidebarContent();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}, [openOnMount, openSidebarContent]);
|
|
70
|
+
|
|
71
|
+
useLayoutEffect(() => {
|
|
72
|
+
return () => {
|
|
73
|
+
if (closeOnUnmount) {
|
|
74
|
+
if (isClosedOnMount.current) {
|
|
75
|
+
// eslint-disable-next-line no-console
|
|
76
|
+
console.warn(
|
|
77
|
+
'[SidebarContent]: "closeOnUnmount" should not change during lifecycle of the component.',
|
|
78
|
+
);
|
|
79
|
+
} else {
|
|
80
|
+
isClosedOnMount.current = true;
|
|
81
|
+
openSidebar();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}, [openSidebar, closeOnUnmount]);
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<Stack space="none">
|
|
89
|
+
<SidebarAppBar>
|
|
90
|
+
<Toolbar disableGutters={true}>
|
|
91
|
+
<ToolbarContent>
|
|
92
|
+
<Columns align={['top', 'center']} space="small">
|
|
93
|
+
<Column width="content">
|
|
94
|
+
<SidebarBackButton onClick={onBack} />
|
|
95
|
+
</Column>
|
|
96
|
+
|
|
97
|
+
<Column>
|
|
98
|
+
<Columns
|
|
99
|
+
space="small"
|
|
100
|
+
collapseBelow="tablet"
|
|
101
|
+
reverse={[true, false]}
|
|
102
|
+
align={['bottom', 'center']}
|
|
103
|
+
>
|
|
104
|
+
<Column>
|
|
105
|
+
<TextBox variant="heading-2">{title}</TextBox>
|
|
106
|
+
</Column>
|
|
107
|
+
|
|
108
|
+
{action && <Column width="content">{action}</Column>}
|
|
109
|
+
</Columns>
|
|
110
|
+
</Column>
|
|
111
|
+
</Columns>
|
|
112
|
+
</ToolbarContent>
|
|
113
|
+
</Toolbar>
|
|
114
|
+
</SidebarAppBar>
|
|
115
|
+
|
|
116
|
+
<Box padding={dense ? 'none' : ['small', 'medium']}>{children}</Box>
|
|
117
|
+
</Stack>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Divider } from '@material-ui/core';
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
|
|
5
|
+
const SidebarDividerRoot = styled.div`
|
|
6
|
+
padding: 20px 24px;
|
|
7
|
+
`;
|
|
8
|
+
|
|
9
|
+
export const SidebarDivider = forwardRef<HTMLDivElement>((_, ref) => {
|
|
10
|
+
return (
|
|
11
|
+
<SidebarDividerRoot ref={ref}>
|
|
12
|
+
<Divider />
|
|
13
|
+
</SidebarDividerRoot>
|
|
14
|
+
);
|
|
15
|
+
});
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { alpha, ButtonBase } from '@material-ui/core';
|
|
2
|
+
import { OpenInNew } from '@material-ui/icons';
|
|
3
|
+
import {
|
|
4
|
+
Color,
|
|
5
|
+
ColorDynamic,
|
|
6
|
+
Column,
|
|
7
|
+
Columns,
|
|
8
|
+
Inline,
|
|
9
|
+
mergeRefs,
|
|
10
|
+
} from '@superdispatch/ui';
|
|
11
|
+
import {
|
|
12
|
+
forwardRef,
|
|
13
|
+
MouseEvent,
|
|
14
|
+
ReactNode,
|
|
15
|
+
useLayoutEffect,
|
|
16
|
+
useRef,
|
|
17
|
+
useState,
|
|
18
|
+
} from 'react';
|
|
19
|
+
import styled, { css } from 'styled-components';
|
|
20
|
+
import { TextBox } from '../text-box/TextBox';
|
|
21
|
+
import { useSidebarContext } from './SidebarContainer';
|
|
22
|
+
import { SidebarMenuItemContextProvider } from './SidebarMenuItemContext';
|
|
23
|
+
|
|
24
|
+
interface SidebarMenuItemRootProps {
|
|
25
|
+
hasAvatar: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const SidebarMenuItemRoot = styled.div<SidebarMenuItemRootProps>(
|
|
29
|
+
({ hasAvatar, theme }) => {
|
|
30
|
+
const height = hasAvatar ? 48 : 40;
|
|
31
|
+
const mode = theme.palette.type;
|
|
32
|
+
const color =
|
|
33
|
+
mode === 'dark' ? alpha(Color.White, 0.08) : ColorDynamic.Silver200;
|
|
34
|
+
return css`
|
|
35
|
+
position: relative;
|
|
36
|
+
|
|
37
|
+
& > .MuiButtonBase-root {
|
|
38
|
+
width: 100%;
|
|
39
|
+
display: flex;
|
|
40
|
+
justify-content: flex-start;
|
|
41
|
+
|
|
42
|
+
padding-left: 24px;
|
|
43
|
+
padding-right: 24px;
|
|
44
|
+
height: ${height}px;
|
|
45
|
+
max-height: ${height}px;
|
|
46
|
+
|
|
47
|
+
&[aria-current='true'] {
|
|
48
|
+
background-color: ${color};
|
|
49
|
+
box-shadow: inset 4px 0 0 ${ColorDynamic.Blue300};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
&:hover {
|
|
53
|
+
background-color: ${color};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
`;
|
|
57
|
+
},
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const SidebarMenuItemBadge = styled.div`
|
|
61
|
+
font-size: 12px;
|
|
62
|
+
font-weight: 500;
|
|
63
|
+
line-height: 16px;
|
|
64
|
+
padding-left: 4px;
|
|
65
|
+
padding-right: 4px;
|
|
66
|
+
border-radius: 100px;
|
|
67
|
+
|
|
68
|
+
color: ${ColorDynamic.Dark500};
|
|
69
|
+
background-color: ${ColorDynamic.Silver400};
|
|
70
|
+
`;
|
|
71
|
+
|
|
72
|
+
export interface SidebarMenuItemProps {
|
|
73
|
+
selected?: boolean;
|
|
74
|
+
external?: boolean;
|
|
75
|
+
disabled?: boolean;
|
|
76
|
+
onClick?: (event: MouseEvent<HTMLButtonElement>) => void;
|
|
77
|
+
|
|
78
|
+
badge?: null | number;
|
|
79
|
+
action?: ReactNode;
|
|
80
|
+
avatar?: ReactNode;
|
|
81
|
+
children?: ReactNode;
|
|
82
|
+
openContentOnClick?: boolean;
|
|
83
|
+
secondaryActions?: ReactNode;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export const SidebarMenuItem = forwardRef<HTMLDivElement, SidebarMenuItemProps>(
|
|
87
|
+
(
|
|
88
|
+
{
|
|
89
|
+
action,
|
|
90
|
+
avatar,
|
|
91
|
+
onClick,
|
|
92
|
+
external,
|
|
93
|
+
children,
|
|
94
|
+
disabled,
|
|
95
|
+
selected,
|
|
96
|
+
secondaryActions,
|
|
97
|
+
badge: badgeProp,
|
|
98
|
+
openContentOnClick,
|
|
99
|
+
},
|
|
100
|
+
ref,
|
|
101
|
+
) => {
|
|
102
|
+
const [hovered, setHovered] = useState(false);
|
|
103
|
+
const rootRef = useRef<HTMLDivElement>(null);
|
|
104
|
+
const { openSidebarContent } = useSidebarContext();
|
|
105
|
+
const { matches: isHoverSupported } = matchMedia('(hover: hover)');
|
|
106
|
+
|
|
107
|
+
useLayoutEffect(() => {
|
|
108
|
+
const rootNode = rootRef.current;
|
|
109
|
+
|
|
110
|
+
if (rootNode) {
|
|
111
|
+
if (isHoverSupported) {
|
|
112
|
+
rootNode.addEventListener('mouseenter', () => {
|
|
113
|
+
setHovered(true);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
rootNode.addEventListener('mouseleave', () => {
|
|
117
|
+
setHovered(false);
|
|
118
|
+
});
|
|
119
|
+
} else {
|
|
120
|
+
setHovered(true);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}, [isHoverSupported]);
|
|
124
|
+
|
|
125
|
+
const badge =
|
|
126
|
+
!badgeProp || !Number.isFinite(badgeProp)
|
|
127
|
+
? null
|
|
128
|
+
: badgeProp > 999
|
|
129
|
+
? '999+'
|
|
130
|
+
: badgeProp;
|
|
131
|
+
|
|
132
|
+
return (
|
|
133
|
+
<SidebarMenuItemRoot ref={mergeRefs(ref, rootRef)} hasAvatar={!!avatar}>
|
|
134
|
+
<ButtonBase
|
|
135
|
+
disabled={disabled}
|
|
136
|
+
aria-current={selected}
|
|
137
|
+
onClick={(event) => {
|
|
138
|
+
onClick?.(event);
|
|
139
|
+
if (!event.isDefaultPrevented() && openContentOnClick) {
|
|
140
|
+
openSidebarContent();
|
|
141
|
+
}
|
|
142
|
+
}}
|
|
143
|
+
>
|
|
144
|
+
<Columns align="center" space="xsmall">
|
|
145
|
+
<Column>
|
|
146
|
+
<Columns align="center" space="xsmall">
|
|
147
|
+
<Column width="fluid">
|
|
148
|
+
<Columns align="center" space="xsmall">
|
|
149
|
+
{!!avatar && (
|
|
150
|
+
<SidebarMenuItemContextProvider
|
|
151
|
+
hovered={hovered}
|
|
152
|
+
disabled={disabled}
|
|
153
|
+
>
|
|
154
|
+
<Column width="content">{avatar}</Column>
|
|
155
|
+
</SidebarMenuItemContextProvider>
|
|
156
|
+
)}
|
|
157
|
+
|
|
158
|
+
<Column width="adaptive">
|
|
159
|
+
<TextBox
|
|
160
|
+
variant={selected ? 'body-semibold' : 'body'}
|
|
161
|
+
noWrap={true}
|
|
162
|
+
>
|
|
163
|
+
{children}
|
|
164
|
+
</TextBox>
|
|
165
|
+
</Column>
|
|
166
|
+
|
|
167
|
+
{external && (
|
|
168
|
+
<Column width="content">
|
|
169
|
+
<OpenInNew color="action" fontSize="small" />
|
|
170
|
+
</Column>
|
|
171
|
+
)}
|
|
172
|
+
</Columns>
|
|
173
|
+
</Column>
|
|
174
|
+
</Columns>
|
|
175
|
+
</Column>
|
|
176
|
+
|
|
177
|
+
{(!!action || !!secondaryActions) && (
|
|
178
|
+
<Column width="content">
|
|
179
|
+
<Inline>
|
|
180
|
+
{(selected || hovered) && secondaryActions}
|
|
181
|
+
{action}
|
|
182
|
+
</Inline>
|
|
183
|
+
</Column>
|
|
184
|
+
)}
|
|
185
|
+
|
|
186
|
+
{!!badge && (
|
|
187
|
+
<Column width="content">
|
|
188
|
+
<SidebarMenuItemBadge>{badge}</SidebarMenuItemBadge>
|
|
189
|
+
</Column>
|
|
190
|
+
)}
|
|
191
|
+
</Columns>
|
|
192
|
+
</ButtonBase>
|
|
193
|
+
</SidebarMenuItemRoot>
|
|
194
|
+
);
|
|
195
|
+
},
|
|
196
|
+
);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { IconButton, Tooltip, TooltipProps } from '@material-ui/core';
|
|
2
|
+
import { forwardRef, ReactElement } from 'react';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
|
|
5
|
+
const SidebarMenuItemActionRoot = styled(IconButton)`
|
|
6
|
+
& .MuiSvgIcon-root {
|
|
7
|
+
font-size: 16px;
|
|
8
|
+
}
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
export interface SidebarMenuItemActionProps
|
|
12
|
+
extends Pick<TooltipProps, 'title' | 'placement'> {
|
|
13
|
+
children: ReactElement;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const SidebarMenuItemAction = forwardRef<
|
|
17
|
+
HTMLButtonElement,
|
|
18
|
+
SidebarMenuItemActionProps
|
|
19
|
+
>(({ title, placement, children }, ref) => {
|
|
20
|
+
return (
|
|
21
|
+
<Tooltip title={title} placement={placement}>
|
|
22
|
+
<SidebarMenuItemActionRoot ref={ref} size="small" edge="end">
|
|
23
|
+
{children}
|
|
24
|
+
</SidebarMenuItemActionRoot>
|
|
25
|
+
</Tooltip>
|
|
26
|
+
);
|
|
27
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Avatar, Checkbox } from '@material-ui/core';
|
|
2
|
+
import { forwardRef, SyntheticEvent, useMemo } from 'react';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
import { useSidebarMenuItemContext } from './SidebarMenuItemContext';
|
|
5
|
+
|
|
6
|
+
function stopPropagation(event: SyntheticEvent): void {
|
|
7
|
+
event.stopPropagation();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const SidebarMenuItemAvatarCheckbox = styled.div`
|
|
11
|
+
margin: -5px;
|
|
12
|
+
`;
|
|
13
|
+
|
|
14
|
+
export interface SidebarMenuItemAvatarProps {
|
|
15
|
+
children: string;
|
|
16
|
+
|
|
17
|
+
value?: boolean;
|
|
18
|
+
onChange?: (checked: boolean) => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const SidebarMenuItemAvatar = forwardRef<
|
|
22
|
+
HTMLDivElement,
|
|
23
|
+
SidebarMenuItemAvatarProps
|
|
24
|
+
>(({ children, value, onChange }, ref) => {
|
|
25
|
+
const { hovered, disabled } = useSidebarMenuItemContext();
|
|
26
|
+
|
|
27
|
+
const initials = useMemo(() => {
|
|
28
|
+
const matches = children.match(/\b\w/g) || [];
|
|
29
|
+
|
|
30
|
+
const first = matches.shift() || '';
|
|
31
|
+
const last = matches.pop() || '';
|
|
32
|
+
|
|
33
|
+
return (first + last).toUpperCase();
|
|
34
|
+
}, [children]);
|
|
35
|
+
|
|
36
|
+
if (value === true || (hovered && value != null)) {
|
|
37
|
+
return (
|
|
38
|
+
<SidebarMenuItemAvatarCheckbox>
|
|
39
|
+
<Checkbox
|
|
40
|
+
color="primary"
|
|
41
|
+
checked={value}
|
|
42
|
+
disabled={disabled}
|
|
43
|
+
onClick={stopPropagation}
|
|
44
|
+
onMouseDown={stopPropagation}
|
|
45
|
+
onTouchStart={stopPropagation}
|
|
46
|
+
onChange={(_, checked) => {
|
|
47
|
+
onChange?.(checked);
|
|
48
|
+
}}
|
|
49
|
+
/>
|
|
50
|
+
</SidebarMenuItemAvatarCheckbox>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<Avatar ref={ref} aria-hidden={true}>
|
|
56
|
+
{initials}
|
|
57
|
+
</Avatar>
|
|
58
|
+
);
|
|
59
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
ReactElement,
|
|
4
|
+
ReactNode,
|
|
5
|
+
useContext,
|
|
6
|
+
useMemo,
|
|
7
|
+
} from 'react';
|
|
8
|
+
|
|
9
|
+
export interface SidebarMenuItemContext {
|
|
10
|
+
hovered?: boolean;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const context = createContext<SidebarMenuItemContext>({});
|
|
15
|
+
|
|
16
|
+
export function useSidebarMenuItemContext(): SidebarMenuItemContext {
|
|
17
|
+
return useContext(context);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface SidebarMenuItemContextProviderProps
|
|
21
|
+
extends SidebarMenuItemContext {
|
|
22
|
+
children?: ReactNode;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function SidebarMenuItemContextProvider({
|
|
26
|
+
children,
|
|
27
|
+
hovered = false,
|
|
28
|
+
disabled = false,
|
|
29
|
+
}: SidebarMenuItemContextProviderProps): ReactElement {
|
|
30
|
+
const ctx = useMemo(() => ({ hovered, disabled }), [hovered, disabled]);
|
|
31
|
+
|
|
32
|
+
return <context.Provider value={ctx}>{children}</context.Provider>;
|
|
33
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Column, Columns } from '@superdispatch/ui';
|
|
2
|
+
import { forwardRef, ReactNode } from 'react';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
import { TextBox } from '../text-box/TextBox';
|
|
5
|
+
|
|
6
|
+
const SidebarSubheaderRoot = styled.div`
|
|
7
|
+
display: flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
|
|
10
|
+
height: 40px;
|
|
11
|
+
max-height: 40px;
|
|
12
|
+
padding-left: 24px;
|
|
13
|
+
padding-right: 24px;
|
|
14
|
+
`;
|
|
15
|
+
|
|
16
|
+
export interface SidebarSubheaderProps {
|
|
17
|
+
id?: string;
|
|
18
|
+
action?: ReactNode;
|
|
19
|
+
children?: ReactNode;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const SidebarSubheader = forwardRef<
|
|
23
|
+
HTMLDivElement,
|
|
24
|
+
SidebarSubheaderProps
|
|
25
|
+
>(({ id, action, children }, ref) => {
|
|
26
|
+
return (
|
|
27
|
+
<SidebarSubheaderRoot ref={ref}>
|
|
28
|
+
<Columns space="xsmall" align="center">
|
|
29
|
+
<Column>
|
|
30
|
+
<TextBox id={id} variant="heading-6" color="secondary" noWrap={true}>
|
|
31
|
+
{children}
|
|
32
|
+
</TextBox>
|
|
33
|
+
</Column>
|
|
34
|
+
{!!action && <Column width="content">{action}</Column>}
|
|
35
|
+
</Columns>
|
|
36
|
+
</SidebarSubheaderRoot>
|
|
37
|
+
);
|
|
38
|
+
});
|
package/src/styled.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { SuperDispatchTheme } from '@superdispatch/ui';
|
|
2
|
+
import 'styled-components';
|
|
3
|
+
|
|
4
|
+
declare module 'styled-components' {
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
6
|
+
export interface DefaultTheme extends SuperDispatchTheme {}
|
|
7
|
+
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
9
|
+
export interface StyledConfig<O extends object = {}> {
|
|
10
|
+
displayName?: string;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Meta } from '@storybook/react';
|
|
2
|
+
import { Column, Columns, Inline, Stack } from '@superdispatch/ui';
|
|
3
|
+
import { Box } from '../box/Box';
|
|
4
|
+
import { TextBox } from './TextBox';
|
|
5
|
+
|
|
6
|
+
export default { title: 'Lab/TextBox', component: TextBox } as Meta;
|
|
7
|
+
|
|
8
|
+
export const basic = () => (
|
|
9
|
+
<TextBox>
|
|
10
|
+
Hello{' '}
|
|
11
|
+
<span role="img" aria-label="waving hand">
|
|
12
|
+
👋
|
|
13
|
+
</span>
|
|
14
|
+
</TextBox>
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
export const alignment = () => (
|
|
18
|
+
<Columns space="xsmall">
|
|
19
|
+
<Column>
|
|
20
|
+
<Box backgroundColor="Silver400" padding="xsmall" borderRadius="small">
|
|
21
|
+
<TextBox align="right">Align Right</TextBox>
|
|
22
|
+
</Box>
|
|
23
|
+
</Column>
|
|
24
|
+
|
|
25
|
+
<Column>
|
|
26
|
+
<Box backgroundColor="Silver400" padding="xsmall" borderRadius="small">
|
|
27
|
+
<TextBox align="center">Align Center</TextBox>
|
|
28
|
+
</Box>
|
|
29
|
+
</Column>
|
|
30
|
+
|
|
31
|
+
<Column>
|
|
32
|
+
<Box backgroundColor="Silver400" padding="xsmall" borderRadius="small">
|
|
33
|
+
<TextBox align="left">Align Left</TextBox>
|
|
34
|
+
</Box>
|
|
35
|
+
</Column>
|
|
36
|
+
</Columns>
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
export const responsiveAlignment = () => (
|
|
40
|
+
<Box backgroundColor="Silver400" padding="xsmall" borderRadius="small">
|
|
41
|
+
<TextBox align={['center', 'right']}>Text</TextBox>
|
|
42
|
+
</Box>
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
export const colors = () => (
|
|
46
|
+
<Box backgroundColor="Silver400" borderRadius="small" padding="xsmall">
|
|
47
|
+
<Inline>
|
|
48
|
+
<TextBox color="primary">Primary</TextBox>
|
|
49
|
+
<TextBox color="secondary">Secondary</TextBox>
|
|
50
|
+
<TextBox color="disabled">Disabled</TextBox>
|
|
51
|
+
<TextBox color="white">White</TextBox>
|
|
52
|
+
<TextBox color="blue">Blue</TextBox>
|
|
53
|
+
<TextBox color="green">Green</TextBox>
|
|
54
|
+
<TextBox color="purple">Purple</TextBox>
|
|
55
|
+
<TextBox color="red">Red</TextBox>
|
|
56
|
+
<TextBox color="teal">Teal</TextBox>
|
|
57
|
+
<TextBox color="yellow">Yellow</TextBox>
|
|
58
|
+
</Inline>
|
|
59
|
+
</Box>
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
export const variants = () => (
|
|
63
|
+
<Stack>
|
|
64
|
+
<TextBox variant="heading-1">h1. Heading</TextBox>
|
|
65
|
+
<TextBox variant="heading-2">h2. Heading</TextBox>
|
|
66
|
+
<TextBox variant="heading-3">h3. Heading</TextBox>
|
|
67
|
+
<TextBox variant="heading-4">h4. Heading</TextBox>
|
|
68
|
+
<TextBox variant="heading-5">h5. Heading</TextBox>
|
|
69
|
+
<TextBox variant="heading-6">h6. Heading</TextBox>
|
|
70
|
+
<TextBox variant="body">
|
|
71
|
+
body. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quos
|
|
72
|
+
blanditiis tenetur unde suscipit, quam beatae rerum inventore consectetur,
|
|
73
|
+
neque doloribus, cupiditate numquam dignissimos laborum fugiat deleniti?
|
|
74
|
+
</TextBox>
|
|
75
|
+
<TextBox variant="body-block">
|
|
76
|
+
body-block. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quos
|
|
77
|
+
blanditiis tenetur unde suscipit, quam beatae rerum inventore consectetur,
|
|
78
|
+
neque doloribus, cupiditate numquam dignissimos laborum fugiat deleniti?
|
|
79
|
+
</TextBox>
|
|
80
|
+
<TextBox variant="body-semibold">
|
|
81
|
+
body-semibold. Lorem ipsum dolor sit amet, consectetur adipisicing elit.
|
|
82
|
+
Quos blanditiis tenetur unde suscipit, quam beatae rerum inventore
|
|
83
|
+
consectetur, neque doloribus, cupiditate numquam dignissimos laborum
|
|
84
|
+
fugiat deleniti?
|
|
85
|
+
</TextBox>
|
|
86
|
+
<TextBox variant="caption">
|
|
87
|
+
caption. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quos
|
|
88
|
+
blanditiis tenetur unde suscipit, quam beatae rerum inventore consectetur,
|
|
89
|
+
neque doloribus, cupiditate numquam dignissimos laborum fugiat deleniti?
|
|
90
|
+
</TextBox>
|
|
91
|
+
<TextBox variant="hint">
|
|
92
|
+
hint. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quos
|
|
93
|
+
blanditiis tenetur unde suscipit, quam beatae rerum inventore consectetur,
|
|
94
|
+
neque doloribus, cupiditate numquam dignissimos laborum fugiat deleniti?
|
|
95
|
+
</TextBox>
|
|
96
|
+
</Stack>
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
export const noWrap = () => (
|
|
100
|
+
<Box width="128px">
|
|
101
|
+
<TextBox noWrap={true}>
|
|
102
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
|
|
103
|
+
</TextBox>
|
|
104
|
+
</Box>
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
export const wrapOverflow = () => (
|
|
108
|
+
<Box width="128px">
|
|
109
|
+
<TextBox wrapOverflow={true}>
|
|
110
|
+
Most words are short and don‘t need to break. But
|
|
111
|
+
Antidisestablishmentarianism is long.
|
|
112
|
+
</TextBox>
|
|
113
|
+
</Box>
|
|
114
|
+
);
|