@rpg-engine/long-bow 0.7.18 → 0.7.21

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpg-engine/long-bow",
3
- "version": "0.7.18",
3
+ "version": "0.7.21",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -1,5 +1,5 @@
1
1
  import dayjs from 'dayjs';
2
- import React, { useEffect, useState } from 'react';
2
+ import React, { useEffect, useRef, useState } from 'react';
3
3
  import { ErrorBoundary } from 'react-error-boundary';
4
4
  import { FaTimes } from 'react-icons/fa';
5
5
  import styled from 'styled-components';
@@ -28,6 +28,7 @@ export interface IChatProps {
28
28
  opacity?: number;
29
29
  sendMessage: boolean;
30
30
  styles?: IStyles;
31
+ isExpanded: boolean;
31
32
  }
32
33
 
33
34
  export const Chat: React.FC<IChatProps> = ({
@@ -43,12 +44,17 @@ export const Chat: React.FC<IChatProps> = ({
43
44
  width: '100%',
44
45
  height: '100%',
45
46
  },
47
+ isExpanded,
46
48
  }) => {
47
49
  const [message, setMessage] = useState('');
50
+ const inputRef = useRef<HTMLInputElement>(null);
48
51
 
49
52
  useEffect(() => {
50
- scrollChatToBottom();
51
- }, [chatMessages]);
53
+ if (isExpanded) {
54
+ scrollChatToBottom();
55
+ }
56
+ inputRef.current?.focus();
57
+ }, [chatMessages, isExpanded]);
52
58
 
53
59
  const scrollChatToBottom = () => {
54
60
  const scrollingElement = document.querySelector('.chat-body');
@@ -78,39 +84,41 @@ export const Chat: React.FC<IChatProps> = ({
78
84
  <ChatContainer
79
85
  width={styles.width || 'auto'}
80
86
  height={styles.height || 'auto'}
87
+ isExpanded={isExpanded}
81
88
  >
82
- <CloseButton onClick={onCloseButton}>
83
- <FaTimes />
84
- </CloseButton>
85
- <ErrorBoundary fallback={<p>Oops! Your chat has crashed.</p>}>
86
- <MessagesContainer className="chat-body">
87
- {chatMessages.map((chatMessage, index) => (
88
- <Message
89
- color={styles.textColor || uiColors.yellow}
90
- key={`${chatMessage._id}_${index}`}
91
- >
92
- {formatMessage(chatMessage)}
93
- </Message>
94
- ))}
95
- </MessagesContainer>
96
-
97
- <Form onSubmit={handleSubmit}>
98
- <TextField
99
- value={message}
100
- onChange={e => setMessage(e.target.value)}
101
- type="text"
102
- autoComplete="off"
103
- onFocus={onFocus}
104
- onBlur={onBlur}
105
- onPointerDown={onFocus}
106
- autoFocus
107
- placeholder="Type your message..."
108
- />
109
- <SendButton type="submit" disabled={!message.trim()}>
110
-
111
- </SendButton>
112
- </Form>
113
- </ErrorBoundary>
89
+ {isExpanded && (
90
+ <ErrorBoundary fallback={<p>Oops! Your chat has crashed.</p>}>
91
+ <CloseButton onClick={onCloseButton}>
92
+ <FaTimes />
93
+ </CloseButton>
94
+ <MessagesContainer className="chat-body">
95
+ {chatMessages.map((chatMessage, index) => (
96
+ <Message
97
+ color={styles.textColor || uiColors.yellow}
98
+ key={`${chatMessage._id}_${index}`}
99
+ >
100
+ {formatMessage(chatMessage)}
101
+ </Message>
102
+ ))}
103
+ </MessagesContainer>
104
+ </ErrorBoundary>
105
+ )}
106
+ <Form onSubmit={handleSubmit} isExpanded={isExpanded}>
107
+ <TextField
108
+ ref={inputRef}
109
+ value={message}
110
+ onChange={e => setMessage(e.target.value)}
111
+ type="text"
112
+ autoComplete="off"
113
+ onFocus={onFocus}
114
+ onBlur={onBlur}
115
+ onPointerDown={onFocus}
116
+ placeholder="Type your message..."
117
+ />
118
+ <SendButton type="submit" disabled={!message.trim()}>
119
+
120
+ </SendButton>
121
+ </Form>
114
122
  </ChatContainer>
115
123
  );
116
124
  };
@@ -124,9 +132,9 @@ interface IMessageProps {
124
132
  color: string;
125
133
  }
126
134
 
127
- const ChatContainer = styled.div<IContainerProps>`
135
+ const ChatContainer = styled.div<IContainerProps & { isExpanded: boolean }>`
128
136
  width: ${props => props.width};
129
- height: ${props => props.height};
137
+ height: ${props => (props.isExpanded ? props.height : 'auto')};
130
138
  background-color: rgba(30, 30, 30, 0.3);
131
139
  display: flex;
132
140
  flex-direction: column;
@@ -180,10 +188,11 @@ const Message = styled.div<IMessageProps>`
180
188
  word-break: break-word;
181
189
  `;
182
190
 
183
- const Form = styled.form`
191
+ const Form = styled.form<{ isExpanded: boolean }>`
184
192
  display: flex;
185
193
  padding: 8px;
186
194
  background-color: rgba(42, 42, 42, 0.4);
195
+ border-radius: ${props => (props.isExpanded ? '0' : '8px')};
187
196
  `;
188
197
 
189
198
  const TextField = styled.input`
@@ -4,9 +4,10 @@ import {
4
4
  IPrivateChatMessage,
5
5
  ITradeChatMessage,
6
6
  } from '@rpg-engine/shared';
7
- import React, { useState } from 'react';
7
+ import React, { useEffect, useState } from 'react';
8
+ import { IoMdContract, IoMdExpand } from 'react-icons/io';
8
9
  import { RxCross2, RxMagnifyingGlass } from 'react-icons/rx';
9
- import styled from 'styled-components';
10
+ import styled, { css } from 'styled-components';
10
11
  import { uiColors } from '../../constants/uiColors';
11
12
  import { uiFonts } from '../../constants/uiFonts';
12
13
  import { Chat, IStyles } from '../Chat/Chat';
@@ -42,6 +43,7 @@ export interface IChatRevampProps {
42
43
  searchCharacterUI: boolean;
43
44
  hideSearchCharacterUI: () => void;
44
45
  showSearchCharacterUI: () => void;
46
+ minimizedByDefault?: boolean;
45
47
  }
46
48
 
47
49
  export const ChatRevamp: React.FC<IChatRevampProps> = ({
@@ -67,14 +69,31 @@ export const ChatRevamp: React.FC<IChatRevampProps> = ({
67
69
  searchCharacterUI,
68
70
  hideSearchCharacterUI,
69
71
  showSearchCharacterUI,
72
+ minimizedByDefault = false,
70
73
  }) => {
71
74
  const [showRecentChats, setShowRecentChats] = useState(false);
75
+ const [isExpanded, setIsExpanded] = useState(!minimizedByDefault);
72
76
 
73
77
  const isPrivate = activeTab === 'private';
74
78
  const isTrade = activeTab === 'trade';
75
79
 
80
+ useEffect(() => {
81
+ if (isPrivate) {
82
+ setIsExpanded(true);
83
+ }
84
+ }, [isPrivate]);
85
+
86
+ const toggleExpand = () => setIsExpanded(prev => !prev);
87
+
76
88
  const toggleRecentChats = () => setShowRecentChats(prev => !prev);
77
89
 
90
+ const handleTabChange = (tabId: string) => {
91
+ if (tabId === 'private') {
92
+ setIsExpanded(true);
93
+ }
94
+ onChangeTab(tabId);
95
+ };
96
+
78
97
  const handlePreviousChatCharacterClick = (
79
98
  character: PrivateChatCharacter
80
99
  ) => {
@@ -88,7 +107,7 @@ export const ChatRevamp: React.FC<IChatRevampProps> = ({
88
107
  <Tab
89
108
  key={`${tab.label}_${index}`}
90
109
  active={tab.id === activeTab}
91
- onPointerDown={() => onChangeTab(tab.id)}
110
+ onPointerDown={() => handleTabChange(tab.id)}
92
111
  >
93
112
  {tab.label}
94
113
  </Tab>
@@ -170,31 +189,67 @@ export const ChatRevamp: React.FC<IChatRevampProps> = ({
170
189
  styles={styles}
171
190
  onFocus={onFocus}
172
191
  onBlur={onBlur}
192
+ isExpanded={isExpanded}
173
193
  />
174
194
  );
175
195
  };
176
196
 
177
197
  return (
178
- <>
179
- {renderTabs()}
198
+ <ChatRevampContainer>
199
+ <TopBar isExpanded={isExpanded}>
200
+ {isExpanded && renderTabs()}
201
+ <ExpandButton onClick={toggleExpand} isExpanded={isExpanded}>
202
+ {isExpanded ? <IoMdContract size={20} /> : <IoMdExpand size={20} />}
203
+ </ExpandButton>
204
+ </TopBar>
180
205
  <PrivateChatContainer
181
206
  width={styles?.width || '80%'}
182
207
  height={styles?.height || 'auto'}
208
+ isExpanded={isExpanded}
183
209
  >
184
- <RecentChatTabContainer isPrivate={isPrivate} isOpen={showRecentChats}>
185
- {renderRecentChatTopBar()}
186
- {renderRecentChatList()}
187
- </RecentChatTabContainer>
210
+ {isExpanded && (
211
+ <RecentChatTabContainer
212
+ isPrivate={isPrivate}
213
+ isOpen={showRecentChats}
214
+ >
215
+ {renderRecentChatTopBar()}
216
+ {renderRecentChatList()}
217
+ </RecentChatTabContainer>
218
+ )}
188
219
  <ChatWrapper>{renderChatContent()}</ChatWrapper>
189
220
  </PrivateChatContainer>
190
- </>
221
+ </ChatRevampContainer>
191
222
  );
192
223
  };
193
224
 
194
- const TabContainer = styled.div`
225
+ const ChatRevampContainer = styled.div`
226
+ display: flex;
227
+ flex-direction: column;
195
228
  width: 100%;
229
+ position: relative;
230
+ `;
231
+
232
+ interface ITopBarProps {
233
+ isExpanded: boolean;
234
+ }
235
+
236
+ const TopBar = styled.div<ITopBarProps>`
237
+ display: flex;
238
+ align-items: center;
239
+ justify-content: flex-start;
240
+
241
+ ${({ isExpanded }) =>
242
+ !isExpanded &&
243
+ css`
244
+ min-height: 32px; // Ensure there's always space for the expand button when its collapsed
245
+ `}
246
+ `;
247
+
248
+ const TabContainer = styled.div`
196
249
  display: flex;
197
250
  gap: 10px;
251
+ align-items: center;
252
+ flex-grow: 1;
198
253
  `;
199
254
 
200
255
  const Tab = styled.button<{ active: boolean }>`
@@ -216,14 +271,40 @@ const Tab = styled.button<{ active: boolean }>`
216
271
  color: ${props => (props.active ? 'white' : uiColors.darkGray)};
217
272
  `;
218
273
 
219
- const PrivateChatContainer = styled.div<{ width: string; height: string }>`
220
- width: ${({ width }) => width};
221
- height: ${({ height }) => height};
274
+ const ExpandButton = styled.button<{ isExpanded: boolean }>`
275
+ position: absolute;
276
+ top: 0;
277
+ right: 0;
278
+ width: 30px;
279
+ height: 30px;
280
+ background-color: ${uiColors.orange};
281
+ color: white;
282
+ border: none;
283
+ border-radius: 50%;
284
+ display: flex;
285
+ justify-content: center;
286
+ align-items: center;
287
+ cursor: pointer;
288
+ transition: all 0.3s ease;
289
+ z-index: 10;
290
+
291
+ &:hover {
292
+ background-color: ${uiColors.orange};
293
+ }
294
+ `;
222
295
 
296
+ const PrivateChatContainer = styled.div<{
297
+ width: string;
298
+ height: string;
299
+ isExpanded: boolean;
300
+ }>`
301
+ width: ${({ width }) => width};
302
+ height: ${({ height, isExpanded }) => (isExpanded ? height : 'auto')};
223
303
  padding: 10px;
224
304
  background-color: rgba(0, 0, 0, 0.2);
225
305
  display: flex;
226
306
  gap: 10px;
307
+ flex-direction: column;
227
308
  `;
228
309
 
229
310
  const RecentChatTabContainer = styled.div<{
@@ -394,4 +475,5 @@ const ChatWrapper = styled.div`
394
475
  overflow: hidden;
395
476
  display: flex;
396
477
  flex-direction: column;
478
+ position: relative;
397
479
  `;