@superdispatch/ui-lab 0.50.4 → 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 +41 -21
- 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}/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 +41 -23
- 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}/flag-list/FlagListItem.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,130 @@
|
|
|
1
|
+
import { Card } from '@material-ui/core';
|
|
2
|
+
import { Meta } from '@storybook/react';
|
|
3
|
+
import { Box } from '@superdispatch/ui-lab';
|
|
4
|
+
import styled from 'styled-components';
|
|
5
|
+
import { Chat } from './Chat';
|
|
6
|
+
import { ChatMessage } from './ChatMessage';
|
|
7
|
+
|
|
8
|
+
export default { title: 'Lab/Chat', component: Chat } as Meta;
|
|
9
|
+
|
|
10
|
+
export const SingleMessage = () => (
|
|
11
|
+
<Box maxWidth="560px">
|
|
12
|
+
<Card>
|
|
13
|
+
<Chat>
|
|
14
|
+
<ChatMessage
|
|
15
|
+
variant="outgoing"
|
|
16
|
+
author="You"
|
|
17
|
+
role="dispatcher"
|
|
18
|
+
dateTime="2023-06-16T09:48:43.291212+00:00"
|
|
19
|
+
text="Hello. Just wanted to check how the messaging works :) As a reminder, pickup should be done during the morning hours 9 – 11 AM!"
|
|
20
|
+
/>
|
|
21
|
+
</Chat>
|
|
22
|
+
</Card>
|
|
23
|
+
</Box>
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
export const EmptyArrayChat = () => (
|
|
27
|
+
<Box>
|
|
28
|
+
<Card>
|
|
29
|
+
<Chat emptyText="Array is empty">{[]}</Chat>
|
|
30
|
+
</Card>
|
|
31
|
+
</Box>
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
export const EmptyNullableChat = () => (
|
|
35
|
+
<Box>
|
|
36
|
+
<Card>
|
|
37
|
+
<Chat>{null}</Chat>
|
|
38
|
+
</Card>
|
|
39
|
+
</Box>
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
export const MultipleMessages = () => (
|
|
43
|
+
<Box maxWidth="560px">
|
|
44
|
+
<Card>
|
|
45
|
+
<Chat>
|
|
46
|
+
<ChatMessage
|
|
47
|
+
variant="incoming"
|
|
48
|
+
author="Steve Trabajo"
|
|
49
|
+
role="dispatcher"
|
|
50
|
+
dateTime="2023-06-16T09:48:43.291212+00:00"
|
|
51
|
+
text="Hello, Vin! Just to confirm, load is completed."
|
|
52
|
+
/>
|
|
53
|
+
<ChatMessage
|
|
54
|
+
variant="outgoing"
|
|
55
|
+
author="Daisy Lord"
|
|
56
|
+
role="admin"
|
|
57
|
+
dateTime="2023-06-16T09:49:00.291212+00:00"
|
|
58
|
+
text="Hey, Steve. Awesome, thanks!"
|
|
59
|
+
/>
|
|
60
|
+
<ChatMessage
|
|
61
|
+
variant="outgoing"
|
|
62
|
+
author="John Wick"
|
|
63
|
+
role="admin"
|
|
64
|
+
dateTime="2023-06-16T09:51:11.291212+00:00"
|
|
65
|
+
text="Hey, Steve. Awesome, thanks!"
|
|
66
|
+
/>
|
|
67
|
+
<ChatMessage
|
|
68
|
+
variant="outgoing"
|
|
69
|
+
author="Lora Accounting"
|
|
70
|
+
role="accounting"
|
|
71
|
+
dateTime="2023-06-16T11:59:43.291212+00:00"
|
|
72
|
+
text="Can’t wait this load to be delivered to start my part :)"
|
|
73
|
+
/>
|
|
74
|
+
</Chat>
|
|
75
|
+
</Card>
|
|
76
|
+
</Box>
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
export const LoremIpsum = () => (
|
|
80
|
+
<Box maxWidth="560px">
|
|
81
|
+
<Card>
|
|
82
|
+
<Chat>
|
|
83
|
+
<ChatMessage
|
|
84
|
+
variant="incoming"
|
|
85
|
+
author="Steve Trabajo"
|
|
86
|
+
role="dispatcher"
|
|
87
|
+
dateTime="2023-06-16T06:48:43.291212+00:00"
|
|
88
|
+
text="Hello, Vin! Just to confirm, load is completed."
|
|
89
|
+
/>
|
|
90
|
+
<ChatMessage
|
|
91
|
+
variant="outgoing"
|
|
92
|
+
author="Daisy Lord"
|
|
93
|
+
role="admin"
|
|
94
|
+
dateTime="2023-06-16T09:49:43.291212+00:00"
|
|
95
|
+
text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Leo vel orci porta non pulvinar neque laoreet suspendisse interdum. Justo eget magna fermentum iaculis eu non diam. Fames ac turpis egestas maecenas. Justo laoreet sit amet cursus sit amet dictum sit. Et pharetra pharetra massa massa ultricies mi. Felis eget velit aliquet sagittis. Scelerisque in dictum non consectetur a erat nam. Amet nulla facilisi morbi tempus. Imperdiet nulla malesuada pellentesque elit eget gravida cum. A iaculis at erat pellentesque. Eget mauris pharetra et ultrices neque ornare aenean euismod. Amet purus gravida quis blandit turpis cursus in hac habitasse. Sit amet dictum sit amet justo donec. Tortor id aliquet lectus proin nibh nisl condimentum id. Condimentum mattis pellentesque id nibh tortor.
|
|
96
|
+
"
|
|
97
|
+
/>
|
|
98
|
+
<ChatMessage
|
|
99
|
+
variant="incoming"
|
|
100
|
+
author="John Wick"
|
|
101
|
+
role="admin"
|
|
102
|
+
dateTime="2023-06-16T09:53:43.291212+00:00"
|
|
103
|
+
text="Sollicitudin aliquam ultrices sagittis orci a scelerisque purus semper. Integer vitae justo eget magna fermentum iaculis. Dapibus ultrices in iaculis nunc sed augue. Eget magna fermentum iaculis eu non diam phasellus. Libero nunc consequat interdum varius sit. Eget velit aliquet sagittis id consectetur purus ut. Sed vulputate mi sit amet mauris commodo. Gravida rutrum quisque non tellus. Feugiat sed lectus vestibulum mattis ullamcorper. Vitae aliquet nec ullamcorper sit."
|
|
104
|
+
/>
|
|
105
|
+
<ChatMessage
|
|
106
|
+
variant="outgoing"
|
|
107
|
+
author="Lora Accounting"
|
|
108
|
+
role="accounting"
|
|
109
|
+
dateTime="2023-06-16T13:01:43.291212+00:00"
|
|
110
|
+
text="Dolor sit amet consectetur adipiscing. Diam sit amet nisl suscipit. Egestas sed sed risus pretium quam. Non consectetur a erat nam at lectus urna. Odio eu feugiat pretium nibh ipsum consequat. Volutpat odio facilisis mauris sit. Consectetur a erat nam at lectus urna duis convallis. Ac turpis egestas sed tempus urna et pharetra pharetra massa. Sed turpis tincidunt id aliquet risus feugiat in. Sollicitudin aliquam ultrices sagittis orci a scelerisque purus semper. Venenatis cras sed felis eget velit aliquet sagittis id consectetur. Arcu felis bibendum ut tristique et egestas. Cursus eget nunc scelerisque viverra mauris. Luctus accumsan tortor posuere ac ut consequat. Justo nec ultrices dui sapien eget mi proin sed. Egestas erat imperdiet sed euismod nisi porta. Amet venenatis urna cursus eget nunc scelerisque."
|
|
111
|
+
/>
|
|
112
|
+
</Chat>
|
|
113
|
+
</Card>
|
|
114
|
+
</Box>
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
const StyledChat = styled(Chat)`
|
|
118
|
+
min-width: 200px;
|
|
119
|
+
max-width: 200px;
|
|
120
|
+
min-height: 200px;
|
|
121
|
+
max-height: 200px;
|
|
122
|
+
`;
|
|
123
|
+
|
|
124
|
+
export const StylingTheChat = () => (
|
|
125
|
+
<Box>
|
|
126
|
+
<Card>
|
|
127
|
+
<StyledChat emptyText="200x200" />
|
|
128
|
+
</Card>
|
|
129
|
+
</Box>
|
|
130
|
+
);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Typography } from '@material-ui/core';
|
|
2
|
+
import { Stack } from '@superdispatch/ui';
|
|
3
|
+
import { Children, forwardRef } from 'react';
|
|
4
|
+
import styled from 'styled-components';
|
|
5
|
+
|
|
6
|
+
interface ChatProps {
|
|
7
|
+
className?: string;
|
|
8
|
+
children?: React.ReactNode | React.ReactNode[];
|
|
9
|
+
emptyText?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const ChatContainer = styled('div')<{
|
|
13
|
+
isEmpty: boolean;
|
|
14
|
+
}>(
|
|
15
|
+
({ isEmpty }) => `
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-direction: column-reverse;
|
|
18
|
+
overflow: auto;
|
|
19
|
+
justify-content: ${isEmpty ? 'center' : 'end'};
|
|
20
|
+
width: 100%;
|
|
21
|
+
height: 100%;
|
|
22
|
+
min-width: 300px;
|
|
23
|
+
max-width: 560px;
|
|
24
|
+
min-height: 368px;
|
|
25
|
+
max-height: 696px;
|
|
26
|
+
padding: 16px;
|
|
27
|
+
box-sizing: border-box;
|
|
28
|
+
`,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
function emptyPlaceholder(text: string): React.ReactNode {
|
|
32
|
+
return (
|
|
33
|
+
<Typography color="textSecondary" align="center">
|
|
34
|
+
{text}
|
|
35
|
+
</Typography>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const Chat = forwardRef<HTMLDivElement, ChatProps>(
|
|
40
|
+
({ children, className, emptyText = 'No new messages' }, ref) => {
|
|
41
|
+
const isEmpty = Children.toArray(children).length === 0;
|
|
42
|
+
return (
|
|
43
|
+
<ChatContainer
|
|
44
|
+
data-testid="chat-container"
|
|
45
|
+
isEmpty={isEmpty}
|
|
46
|
+
ref={ref}
|
|
47
|
+
className={className}
|
|
48
|
+
>
|
|
49
|
+
<Stack space="small">
|
|
50
|
+
{isEmpty ? emptyPlaceholder(emptyText) : children}
|
|
51
|
+
</Stack>
|
|
52
|
+
</ChatContainer>
|
|
53
|
+
);
|
|
54
|
+
},
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
Chat.displayName = 'Chat';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Typography } from '@material-ui/core';
|
|
2
|
+
import { formatDate, PrimitiveDateInput } from '@superdispatch/dates';
|
|
3
|
+
import { Inline, Stack } from '@superdispatch/ui';
|
|
4
|
+
import { DateTime } from 'luxon';
|
|
5
|
+
import { forwardRef } from 'react';
|
|
6
|
+
import { Box } from '../box/Box';
|
|
7
|
+
|
|
8
|
+
interface ChatMessageProps {
|
|
9
|
+
author: string;
|
|
10
|
+
role: string;
|
|
11
|
+
dateTime: Date | DateTime | PrimitiveDateInput;
|
|
12
|
+
text: string;
|
|
13
|
+
variant: 'incoming' | 'outgoing';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const ChatMessage = forwardRef<HTMLDivElement, ChatMessageProps>(
|
|
17
|
+
({ author, role, dateTime, text, variant }, ref) => {
|
|
18
|
+
const time = formatDate(dateTime, { variant: 'Time' });
|
|
19
|
+
return (
|
|
20
|
+
<Stack
|
|
21
|
+
space="xxsmall"
|
|
22
|
+
align={variant === 'outgoing' ? 'right' : 'left'}
|
|
23
|
+
ref={ref}
|
|
24
|
+
data-testid="chat-message"
|
|
25
|
+
>
|
|
26
|
+
<Inline verticalAlign="center">
|
|
27
|
+
<Typography color="textPrimary">{author}</Typography>
|
|
28
|
+
<Typography color="textSecondary">{role}</Typography>
|
|
29
|
+
<Typography color="textSecondary">{time}</Typography>
|
|
30
|
+
</Inline>
|
|
31
|
+
<Box
|
|
32
|
+
display="inline-block"
|
|
33
|
+
padding="xsmall"
|
|
34
|
+
marginTop="none"
|
|
35
|
+
borderRadius="medium"
|
|
36
|
+
backgroundColor={variant === 'outgoing' ? 'Blue50' : 'Silver200'}
|
|
37
|
+
>
|
|
38
|
+
<Typography color="textPrimary">{text}</Typography>
|
|
39
|
+
</Box>
|
|
40
|
+
</Stack>
|
|
41
|
+
);
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
ChatMessage.displayName = 'ChatMessage';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Chat component
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Chat component is a container component that renders a list of messages and a form to send new messages.
|
|
6
|
+
Each message displays the text of the message, the author, role, and date/time of the message.
|
|
7
|
+
It displays the author's message on the right and the receiver's message on the left
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { renderComponent } from '@superdispatch/ui-testutils';
|
|
2
|
+
import { screen } from '@testing-library/react';
|
|
3
|
+
import { Chat } from '../Chat';
|
|
4
|
+
import { ChatMessage } from '../ChatMessage';
|
|
5
|
+
|
|
6
|
+
describe('Chat', () => {
|
|
7
|
+
it('Displays placeholder message when no messages are provided', () => {
|
|
8
|
+
renderComponent(<Chat />);
|
|
9
|
+
|
|
10
|
+
expect(screen.getByText(/No new messages/i)).toBeInTheDocument();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('Renders provided messages', () => {
|
|
14
|
+
renderComponent(
|
|
15
|
+
<Chat>
|
|
16
|
+
<ChatMessage
|
|
17
|
+
variant="incoming"
|
|
18
|
+
author="Steve Trabajo"
|
|
19
|
+
role="dispatcher"
|
|
20
|
+
dateTime="2023-06-12 6:43PM"
|
|
21
|
+
text="Hello, Vin! ..."
|
|
22
|
+
/>
|
|
23
|
+
</Chat>,
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
expect(screen.getByText('Steve Trabajo')).toBeInTheDocument();
|
|
27
|
+
expect(screen.getByText('Hello, Vin! ...')).toBeInTheDocument();
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { renderComponent } from '@superdispatch/ui-testutils';
|
|
2
|
+
import { screen } from '@testing-library/react';
|
|
3
|
+
import { ChatMessage } from '../ChatMessage';
|
|
4
|
+
|
|
5
|
+
describe('ChatMessage', () => {
|
|
6
|
+
it('displays incoming message correctly', () => {
|
|
7
|
+
renderComponent(
|
|
8
|
+
<ChatMessage
|
|
9
|
+
variant="incoming"
|
|
10
|
+
author="Steve Trabajo"
|
|
11
|
+
role="dispatcher"
|
|
12
|
+
dateTime="2023-06-16T09:48:43.291212+00:00"
|
|
13
|
+
text="Hello, Vin! ..."
|
|
14
|
+
/>,
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
expect(screen.getByText('Steve Trabajo')).toBeInTheDocument();
|
|
18
|
+
expect(screen.getByText('dispatcher')).toBeInTheDocument();
|
|
19
|
+
expect(screen.getByText('4:48 AM')).toBeInTheDocument();
|
|
20
|
+
expect(screen.getByText('Hello, Vin! ...')).toBeInTheDocument();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('displays outgoing message correctly', () => {
|
|
24
|
+
renderComponent(
|
|
25
|
+
<ChatMessage
|
|
26
|
+
variant="outgoing"
|
|
27
|
+
author="Daisy Lord"
|
|
28
|
+
role="admin"
|
|
29
|
+
dateTime="2023-06-16T09:48:43.291212+00:00"
|
|
30
|
+
text="Hey Steve ..."
|
|
31
|
+
/>,
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
expect(screen.getByText('Daisy Lord')).toBeInTheDocument();
|
|
35
|
+
expect(screen.getByText('admin')).toBeInTheDocument();
|
|
36
|
+
expect(screen.getByText('4:48 AM')).toBeInTheDocument();
|
|
37
|
+
expect(screen.getByText('Hey Steve ...')).toBeInTheDocument();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { mergeRefs } from '@superdispatch/ui';
|
|
2
|
+
import { forwardRef, HTMLAttributes, useLayoutEffect, useRef } from 'react';
|
|
3
|
+
|
|
4
|
+
export type ContainerProps = HTMLAttributes<HTMLDivElement> & {
|
|
5
|
+
fullViewportHeight?: boolean;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export const Container = forwardRef<HTMLDivElement, ContainerProps>(
|
|
9
|
+
({ fullViewportHeight, ...props }, ref) => {
|
|
10
|
+
const nodeRef = useRef<HTMLDivElement | null>(null);
|
|
11
|
+
|
|
12
|
+
useLayoutEffect(() => {
|
|
13
|
+
if (!fullViewportHeight) {
|
|
14
|
+
if (nodeRef.current) {
|
|
15
|
+
nodeRef.current.style.removeProperty('height');
|
|
16
|
+
nodeRef.current.style.removeProperty('--vh');
|
|
17
|
+
}
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function updateHeight(): void {
|
|
22
|
+
if (nodeRef.current) {
|
|
23
|
+
// https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
|
|
24
|
+
nodeRef.current.style.setProperty(
|
|
25
|
+
'height',
|
|
26
|
+
'calc(var(--vh, 1vh) * 100)',
|
|
27
|
+
);
|
|
28
|
+
nodeRef.current.style.setProperty(
|
|
29
|
+
'--vh',
|
|
30
|
+
`${window.innerHeight * 0.01}px`,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
updateHeight();
|
|
36
|
+
|
|
37
|
+
window.addEventListener('resize', updateHeight);
|
|
38
|
+
|
|
39
|
+
return () => {
|
|
40
|
+
window.removeEventListener('resize', updateHeight);
|
|
41
|
+
};
|
|
42
|
+
}, [fullViewportHeight]);
|
|
43
|
+
|
|
44
|
+
return <div ref={mergeRefs(ref, nodeRef)} {...props} />;
|
|
45
|
+
},
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
Container.displayName = 'Container';
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { Link } from '@material-ui/core';
|
|
2
|
+
import CalendarTodayIcon from '@material-ui/icons/CalendarToday';
|
|
3
|
+
import DomainIcon from '@material-ui/icons/Domain';
|
|
4
|
+
import FingerprintIcon from '@material-ui/icons/Fingerprint';
|
|
5
|
+
import FlightLandIcon from '@material-ui/icons/FlightLand';
|
|
6
|
+
import FlightTakeoffIcon from '@material-ui/icons/FlightTakeoff';
|
|
7
|
+
import NotesIcon from '@material-ui/icons/Notes';
|
|
8
|
+
import PaymentIcon from '@material-ui/icons/Payment';
|
|
9
|
+
import PersonIcon from '@material-ui/icons/Person';
|
|
10
|
+
import RoomIcon from '@material-ui/icons/Room';
|
|
11
|
+
import { Meta } from '@storybook/react';
|
|
12
|
+
import { PhoneLink } from '@superdispatch/phones';
|
|
13
|
+
import { Column, Columns, Inline, Stack } from '@superdispatch/ui';
|
|
14
|
+
import { Box } from '../box/Box';
|
|
15
|
+
import { TextBox } from '../text-box/TextBox';
|
|
16
|
+
import { DescriptionItem } from './DescriptionItem';
|
|
17
|
+
|
|
18
|
+
export default {
|
|
19
|
+
title: 'Lab/DescriptionItem',
|
|
20
|
+
component: DescriptionItem,
|
|
21
|
+
} as Meta;
|
|
22
|
+
|
|
23
|
+
export const basic = () => (
|
|
24
|
+
<Box maxWidth="200px">
|
|
25
|
+
<Stack>
|
|
26
|
+
<DescriptionItem icon={<PaymentIcon />} aria-label="payment">
|
|
27
|
+
<Inline space="xxsmall">
|
|
28
|
+
<TextBox color="purple">$1,503</TextBox>
|
|
29
|
+
COD
|
|
30
|
+
<TextBox color="secondary">$49.94/mi</TextBox>
|
|
31
|
+
</Inline>
|
|
32
|
+
</DescriptionItem>
|
|
33
|
+
|
|
34
|
+
<DescriptionItem icon={<CalendarTodayIcon />} label="Posted">
|
|
35
|
+
4 hr. ago
|
|
36
|
+
</DescriptionItem>
|
|
37
|
+
|
|
38
|
+
<DescriptionItem icon={<RoomIcon />} aria-label="address">
|
|
39
|
+
167 Zosh Rd, Dallas, PA 18612
|
|
40
|
+
</DescriptionItem>
|
|
41
|
+
|
|
42
|
+
<DescriptionItem icon={<FingerprintIcon />} label="ID">
|
|
43
|
+
202CB962AC59075B964B07152D234B70
|
|
44
|
+
</DescriptionItem>
|
|
45
|
+
|
|
46
|
+
<DescriptionItem icon={<NotesIcon />} label="Notes">
|
|
47
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
|
|
48
|
+
</DescriptionItem>
|
|
49
|
+
</Stack>
|
|
50
|
+
</Box>
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
export const wrap = () => (
|
|
54
|
+
<Box maxWidth="200px">
|
|
55
|
+
<Stack>
|
|
56
|
+
<DescriptionItem icon={<RoomIcon />} wrap={true}>
|
|
57
|
+
167 Zosh Rd, Dallas, PA 18612
|
|
58
|
+
</DescriptionItem>
|
|
59
|
+
|
|
60
|
+
<DescriptionItem icon={<FingerprintIcon />} label="ID" wrap={true}>
|
|
61
|
+
202CB962AC59075B964B07152D234B70
|
|
62
|
+
</DescriptionItem>
|
|
63
|
+
|
|
64
|
+
<DescriptionItem icon={<NotesIcon />} label="Notes" wrap={true}>
|
|
65
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
|
|
66
|
+
</DescriptionItem>
|
|
67
|
+
</Stack>
|
|
68
|
+
</Box>
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
export const fallback = () => (
|
|
72
|
+
<Stack>
|
|
73
|
+
<DescriptionItem
|
|
74
|
+
icon={<CalendarTodayIcon />}
|
|
75
|
+
label="Posted on"
|
|
76
|
+
fallback="N/A"
|
|
77
|
+
>
|
|
78
|
+
{null}
|
|
79
|
+
</DescriptionItem>
|
|
80
|
+
<DescriptionItem icon={<RoomIcon />} fallback="No address available" />
|
|
81
|
+
<DescriptionItem icon={<NotesIcon />} fallback="No delivery notes">
|
|
82
|
+
{false}
|
|
83
|
+
</DescriptionItem>
|
|
84
|
+
</Stack>
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
export const inset = () => (
|
|
88
|
+
<Stack>
|
|
89
|
+
<Stack space="xxsmall">
|
|
90
|
+
<DescriptionItem icon={<PersonIcon />}>Antony Hoffman</DescriptionItem>
|
|
91
|
+
<DescriptionItem inset={true}>
|
|
92
|
+
<PhoneLink phone="+1 303 555 0105" format="national" />
|
|
93
|
+
</DescriptionItem>
|
|
94
|
+
<DescriptionItem inset={true}>
|
|
95
|
+
<Link href="mailto:dustin.russel@example.com">
|
|
96
|
+
dustin.russel@example.com
|
|
97
|
+
</Link>
|
|
98
|
+
</DescriptionItem>
|
|
99
|
+
</Stack>
|
|
100
|
+
|
|
101
|
+
<DescriptionItem icon={<RoomIcon />}>
|
|
102
|
+
167 Zosh Rd, Dallas, PA 18612
|
|
103
|
+
</DescriptionItem>
|
|
104
|
+
</Stack>
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
export const complex = () => (
|
|
108
|
+
<Box maxWidth="320px">
|
|
109
|
+
<Stack>
|
|
110
|
+
<Columns space="xsmall">
|
|
111
|
+
<Column width="adaptive">
|
|
112
|
+
<DescriptionItem icon={<DomainIcon />}>Fast Shipper</DescriptionItem>
|
|
113
|
+
</Column>
|
|
114
|
+
|
|
115
|
+
<Column width="adaptive">
|
|
116
|
+
<DescriptionItem icon={<CalendarTodayIcon />} label="Received">
|
|
117
|
+
4 hr. ago
|
|
118
|
+
</DescriptionItem>
|
|
119
|
+
</Column>
|
|
120
|
+
</Columns>
|
|
121
|
+
|
|
122
|
+
<Columns space="xsmall">
|
|
123
|
+
<Column width="adaptive">
|
|
124
|
+
<DescriptionItem icon={<FingerprintIcon />} label="Load ID">
|
|
125
|
+
02323
|
|
126
|
+
</DescriptionItem>
|
|
127
|
+
</Column>
|
|
128
|
+
|
|
129
|
+
<Column width="adaptive">
|
|
130
|
+
<DescriptionItem icon={<CalendarTodayIcon />} label="Received">
|
|
131
|
+
4 hr. ago
|
|
132
|
+
</DescriptionItem>
|
|
133
|
+
</Column>
|
|
134
|
+
</Columns>
|
|
135
|
+
|
|
136
|
+
<DescriptionItem icon={<FlightTakeoffIcon />}>
|
|
137
|
+
<Columns space="xxsmall">
|
|
138
|
+
<Column width="adaptive">
|
|
139
|
+
<TextBox noWrap={true}>Kansas City, MO 64105</TextBox>
|
|
140
|
+
</Column>
|
|
141
|
+
<Column width="adaptive">
|
|
142
|
+
<TextBox noWrap={true} color="secondary">
|
|
143
|
+
Oct 04, 2019
|
|
144
|
+
</TextBox>
|
|
145
|
+
</Column>
|
|
146
|
+
</Columns>
|
|
147
|
+
</DescriptionItem>
|
|
148
|
+
|
|
149
|
+
<DescriptionItem icon={<FlightLandIcon />}>
|
|
150
|
+
<Columns space="xxsmall">
|
|
151
|
+
<Column width="adaptive">
|
|
152
|
+
<TextBox noWrap={true}>Roeland Park, KS 66205</TextBox>
|
|
153
|
+
</Column>
|
|
154
|
+
<Column width="adaptive">
|
|
155
|
+
<TextBox noWrap={true} color="secondary">
|
|
156
|
+
Oct 04, 2019
|
|
157
|
+
</TextBox>
|
|
158
|
+
</Column>
|
|
159
|
+
</Columns>
|
|
160
|
+
</DescriptionItem>
|
|
161
|
+
</Stack>
|
|
162
|
+
</Box>
|
|
163
|
+
);
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ColorDynamic,
|
|
3
|
+
Column,
|
|
4
|
+
Columns,
|
|
5
|
+
Inline,
|
|
6
|
+
isEmptyReactNode,
|
|
7
|
+
useUID,
|
|
8
|
+
} from '@superdispatch/ui';
|
|
9
|
+
import { forwardRef, ReactNode } from 'react';
|
|
10
|
+
import styled, { css, SimpleInterpolation } from 'styled-components';
|
|
11
|
+
import { TextBox } from '../text-box/TextBox';
|
|
12
|
+
|
|
13
|
+
function descriptionItemIconMixin(
|
|
14
|
+
size: 16 | 20,
|
|
15
|
+
): readonly SimpleInterpolation[] {
|
|
16
|
+
return css`
|
|
17
|
+
width: ${size}px;
|
|
18
|
+
height: ${size + 4}px;
|
|
19
|
+
|
|
20
|
+
& > .MuiSvgIcon-root {
|
|
21
|
+
font-size: ${size}px;
|
|
22
|
+
}
|
|
23
|
+
`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const DescriptionItemIcon = styled.div(
|
|
27
|
+
({ theme }) =>
|
|
28
|
+
css`
|
|
29
|
+
display: flex;
|
|
30
|
+
align-items: center;
|
|
31
|
+
|
|
32
|
+
& > .MuiSvgIcon-root {
|
|
33
|
+
color: ${ColorDynamic.Dark100};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
${descriptionItemIconMixin(20)};
|
|
37
|
+
|
|
38
|
+
${theme.breakpoints.up('sm')} {
|
|
39
|
+
${descriptionItemIconMixin(16)};
|
|
40
|
+
}
|
|
41
|
+
`,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
export interface DescriptionItemProps {
|
|
45
|
+
id?: string;
|
|
46
|
+
'aria-label'?: string;
|
|
47
|
+
|
|
48
|
+
wrap?: boolean;
|
|
49
|
+
inset?: boolean;
|
|
50
|
+
icon?: ReactNode;
|
|
51
|
+
label?: ReactNode;
|
|
52
|
+
fallback?: ReactNode;
|
|
53
|
+
children?: ReactNode;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const DescriptionItem = forwardRef<HTMLDivElement, DescriptionItemProps>(
|
|
57
|
+
(
|
|
58
|
+
{
|
|
59
|
+
icon,
|
|
60
|
+
wrap,
|
|
61
|
+
inset,
|
|
62
|
+
label,
|
|
63
|
+
children,
|
|
64
|
+
fallback,
|
|
65
|
+
id: idProp,
|
|
66
|
+
'aria-label': ariaLabel,
|
|
67
|
+
},
|
|
68
|
+
ref,
|
|
69
|
+
) => {
|
|
70
|
+
const id = useUID(idProp);
|
|
71
|
+
const labelID = `${id}-label`;
|
|
72
|
+
const isEmptyChildren = isEmptyReactNode(children);
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<Columns id={id} ref={ref} space="xsmall" aria-label={ariaLabel}>
|
|
76
|
+
{!!(icon || inset) && (
|
|
77
|
+
<Column width="content">
|
|
78
|
+
<DescriptionItemIcon>{icon}</DescriptionItemIcon>
|
|
79
|
+
</Column>
|
|
80
|
+
)}
|
|
81
|
+
|
|
82
|
+
<Column width="adaptive">
|
|
83
|
+
<Inline space="xxsmall" noWrap={!wrap}>
|
|
84
|
+
{!!label && (
|
|
85
|
+
<TextBox as="label" id={labelID} color="secondary">
|
|
86
|
+
{label}
|
|
87
|
+
</TextBox>
|
|
88
|
+
)}
|
|
89
|
+
|
|
90
|
+
<TextBox
|
|
91
|
+
as="div"
|
|
92
|
+
noWrap={!wrap}
|
|
93
|
+
wrapOverflow={!!wrap}
|
|
94
|
+
aria-labelledby={label == null ? undefined : labelID}
|
|
95
|
+
color={isEmptyChildren && label == null ? 'secondary' : 'primary'}
|
|
96
|
+
>
|
|
97
|
+
{isEmptyChildren ? fallback : children}
|
|
98
|
+
</TextBox>
|
|
99
|
+
</Inline>
|
|
100
|
+
</Column>
|
|
101
|
+
</Columns>
|
|
102
|
+
);
|
|
103
|
+
},
|
|
104
|
+
);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Meta } from '@storybook/react';
|
|
2
|
+
import { TextBox } from '../text-box/TextBox';
|
|
3
|
+
import { DescriptionLineItem } from './DescriptionLineItem';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'Lab/DescriptionLineItem',
|
|
7
|
+
component: DescriptionLineItem,
|
|
8
|
+
} as Meta;
|
|
9
|
+
|
|
10
|
+
export const description = () => (
|
|
11
|
+
<>
|
|
12
|
+
<DescriptionLineItem title={<TextBox color="secondary">Payment</TextBox>}>
|
|
13
|
+
<TextBox align="right" color="primary" variant="heading-4">
|
|
14
|
+
$1,200
|
|
15
|
+
</TextBox>
|
|
16
|
+
</DescriptionLineItem>
|
|
17
|
+
<DescriptionLineItem title={<TextBox color="secondary">Method</TextBox>}>
|
|
18
|
+
<TextBox align="right" color="primary" variant="body">
|
|
19
|
+
Comcheck
|
|
20
|
+
</TextBox>
|
|
21
|
+
</DescriptionLineItem>
|
|
22
|
+
</>
|
|
23
|
+
);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ColorDynamic, Column, Columns } from '@superdispatch/ui';
|
|
2
|
+
import { forwardRef, ReactNode } from 'react';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
|
|
5
|
+
export const DottedLine = styled.div`
|
|
6
|
+
border-bottom: 1px dotted ${ColorDynamic.Silver400};
|
|
7
|
+
margin: 0px 8px;
|
|
8
|
+
height: 7px;
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
interface DescriptionLineItemProps {
|
|
12
|
+
title: ReactNode;
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const DescriptionLineItem = forwardRef<
|
|
17
|
+
HTMLDivElement,
|
|
18
|
+
DescriptionLineItemProps
|
|
19
|
+
>(({ title, children }, ref) => (
|
|
20
|
+
<Columns ref={ref} align="center">
|
|
21
|
+
<Column width="content">{title}</Column>
|
|
22
|
+
<Column width="fluid">
|
|
23
|
+
<DottedLine />
|
|
24
|
+
</Column>
|
|
25
|
+
<Column width="content">{children}</Column>
|
|
26
|
+
</Columns>
|
|
27
|
+
));
|
|
28
|
+
|
|
29
|
+
DescriptionLineItem.displayName = 'DescriptionLineItem';
|