@rpg-engine/long-bow 0.8.106 → 0.8.108

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.8.106",
3
+ "version": "0.8.108",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -1,10 +1,10 @@
1
- import React from 'react';
1
+ import React, { memo, useCallback } from 'react';
2
2
  import styled from 'styled-components';
3
3
  import { Chat, IStyles } from '../Chat/Chat';
4
4
  import { SearchCharacter } from './SearchCharacter';
5
5
  import { ChatMessage, PrivateChatCharacter } from './types';
6
6
 
7
- interface ChatContentProps {
7
+ interface IChatContentProps {
8
8
  isPrivate: boolean;
9
9
  isTrade: boolean;
10
10
  isGlobal: boolean;
@@ -28,76 +28,93 @@ interface ChatContentProps {
28
28
  onSendGuildChatMessage: (message: string) => void;
29
29
  }
30
30
 
31
- export const ChatContent: React.FC<ChatContentProps> = ({
32
- isPrivate,
33
- isTrade,
34
- isGlobal,
35
- searchCharacterUI,
36
- chatMessages,
37
- onSendLocalChatMessage,
38
- onSendGlobalChatMessage,
39
- onSendPrivateChatMessage,
40
- onSendTradeMessage,
41
- onCloseButton,
42
- styles,
43
- onFocus,
44
- onBlur,
45
- isExpanded,
46
- autoCloseOnSend,
47
- onChangeCharacterName,
48
- privateChatCharacters,
49
- hideSearchCharacterUI,
50
- onCharacterClick,
51
- isGuild,
52
- onSendGuildChatMessage,
53
- }) => {
54
- const handleSendMessage = (message: string) => {
55
- if (autoCloseOnSend) {
56
- onCloseButton();
57
- }
31
+ export const ChatContent: React.FC<IChatContentProps> = memo(
32
+ ({
33
+ isPrivate,
34
+ isTrade,
35
+ isGlobal,
36
+ searchCharacterUI,
37
+ chatMessages,
38
+ onSendLocalChatMessage,
39
+ onSendGlobalChatMessage,
40
+ onSendPrivateChatMessage,
41
+ onSendTradeMessage,
42
+ onCloseButton,
43
+ styles,
44
+ onFocus,
45
+ onBlur,
46
+ isExpanded,
47
+ autoCloseOnSend,
48
+ onChangeCharacterName,
49
+ privateChatCharacters,
50
+ hideSearchCharacterUI,
51
+ onCharacterClick,
52
+ isGuild,
53
+ onSendGuildChatMessage,
54
+ }) => {
55
+ const handleSendMessage = useCallback(
56
+ (message: string) => {
57
+ if (autoCloseOnSend) {
58
+ onCloseButton();
59
+ }
60
+
61
+ if (isPrivate) {
62
+ onSendPrivateChatMessage(message);
63
+ } else if (isTrade) {
64
+ onSendTradeMessage(message);
65
+ } else if (isGuild) {
66
+ onSendGuildChatMessage(message);
67
+ } else if (isGlobal) {
68
+ onSendGlobalChatMessage(message);
69
+ } else {
70
+ onSendLocalChatMessage(message);
71
+ }
72
+ },
73
+ [
74
+ autoCloseOnSend,
75
+ isPrivate,
76
+ isTrade,
77
+ isGuild,
78
+ isGlobal,
79
+ onCloseButton,
80
+ onSendPrivateChatMessage,
81
+ onSendTradeMessage,
82
+ onSendGuildChatMessage,
83
+ onSendGlobalChatMessage,
84
+ onSendLocalChatMessage,
85
+ ]
86
+ );
58
87
 
59
- if (isPrivate) {
60
- onSendPrivateChatMessage(message);
61
- } else if (isTrade) {
62
- onSendTradeMessage(message);
63
- } else if (isGuild) {
64
- onSendGuildChatMessage(message);
65
- } else if (isGlobal) {
66
- onSendGlobalChatMessage(message);
67
- } else {
68
- onSendLocalChatMessage(message);
88
+ if (isPrivate && searchCharacterUI) {
89
+ return (
90
+ <SearchCharacter
91
+ onFocus={onFocus}
92
+ onBlur={onBlur}
93
+ onChangeCharacterName={onChangeCharacterName}
94
+ styles={styles}
95
+ recentCharacters={privateChatCharacters}
96
+ hideSearchCharacterUI={hideSearchCharacterUI}
97
+ onCharacterClick={onCharacterClick}
98
+ />
99
+ );
69
100
  }
70
- };
71
101
 
72
- if (isPrivate && searchCharacterUI) {
73
102
  return (
74
- <SearchCharacter
75
- onFocus={onFocus}
76
- onBlur={onBlur}
77
- onChangeCharacterName={onChangeCharacterName}
78
- styles={styles}
79
- recentCharacters={privateChatCharacters}
80
- hideSearchCharacterUI={hideSearchCharacterUI}
81
- onCharacterClick={onCharacterClick}
82
- />
103
+ <ChatWrapper>
104
+ <Chat
105
+ chatMessages={chatMessages}
106
+ onSendChatMessage={handleSendMessage}
107
+ sendMessage={true}
108
+ onCloseButton={onCloseButton}
109
+ styles={styles}
110
+ onFocus={onFocus}
111
+ onBlur={onBlur}
112
+ isExpanded={isExpanded}
113
+ />
114
+ </ChatWrapper>
83
115
  );
84
116
  }
85
-
86
- return (
87
- <ChatWrapper>
88
- <Chat
89
- chatMessages={chatMessages}
90
- onSendChatMessage={handleSendMessage}
91
- sendMessage={true}
92
- onCloseButton={onCloseButton}
93
- styles={styles}
94
- onFocus={onFocus}
95
- onBlur={onBlur}
96
- isExpanded={isExpanded}
97
- />
98
- </ChatWrapper>
99
- );
100
- };
117
+ );
101
118
 
102
119
  const ChatWrapper = styled.div`
103
120
  flex-grow: 1;
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { memo, useCallback } from 'react';
2
2
  import { RxCross2, RxMagnifyingGlass } from 'react-icons/rx';
3
3
  import styled from 'styled-components';
4
4
  import { uiColors } from '../../constants/uiColors';
@@ -17,30 +17,39 @@ interface IRecentChatsProps {
17
17
  onPreviousChatCharacterClick: (character: PrivateChatCharacter) => void;
18
18
  onRemoveRecentChatCharacter?: (character: PrivateChatCharacter) => void;
19
19
  isPrivate: boolean;
20
- hideSearchCharacterUI: () => void; // Add this line
20
+ hideSearchCharacterUI: () => void;
21
21
  }
22
22
 
23
- export const RecentChats: React.FC<IRecentChatsProps> = ({
24
- showRecentChats,
25
- toggleRecentChats,
26
- hasUnseenMessages,
27
- showSearchCharacterUI,
28
- recentChatCharacters,
29
- recentSelectedChatCharacterId,
30
- unseenMessageCharacterIds,
31
- onPreviousChatCharacterClick,
32
- onRemoveRecentChatCharacter,
33
- isPrivate,
34
- hideSearchCharacterUI, // Add this line
35
- }) => {
36
- const handlePreviousChatCharacterClick = (
37
- character: PrivateChatCharacter
38
- ) => {
39
- onPreviousChatCharacterClick(character);
40
- hideSearchCharacterUI(); // Call hideSearchCharacterUI here
41
- };
42
-
43
- return (
23
+ export const RecentChats: React.FC<IRecentChatsProps> = memo(
24
+ ({
25
+ showRecentChats,
26
+ toggleRecentChats,
27
+ hasUnseenMessages,
28
+ showSearchCharacterUI,
29
+ recentChatCharacters,
30
+ recentSelectedChatCharacterId,
31
+ unseenMessageCharacterIds,
32
+ onPreviousChatCharacterClick,
33
+ onRemoveRecentChatCharacter,
34
+ isPrivate,
35
+ hideSearchCharacterUI,
36
+ }) => {
37
+ const handlePreviousChatCharacterClick = useCallback(
38
+ (character: PrivateChatCharacter) => {
39
+ onPreviousChatCharacterClick(character);
40
+ hideSearchCharacterUI();
41
+ },
42
+ [onPreviousChatCharacterClick, hideSearchCharacterUI]
43
+ );
44
+
45
+ const handleRemoveCharacter = useCallback(
46
+ (character: PrivateChatCharacter) => {
47
+ onRemoveRecentChatCharacter?.(character);
48
+ },
49
+ [onRemoveRecentChatCharacter]
50
+ );
51
+
52
+ return (
44
53
  <RecentChatTabContainer isOpen={showRecentChats} isPrivate={isPrivate}>
45
54
  <RecentChatTopBar>
46
55
  <BurgerIconContainer
@@ -75,7 +84,7 @@ export const RecentChats: React.FC<IRecentChatsProps> = ({
75
84
  </ListElement>
76
85
  <CloseButton
77
86
  className="close-button"
78
- onPointerDown={() => onRemoveRecentChatCharacter?.(character)}
87
+ onPointerDown={() => handleRemoveCharacter(character)}
79
88
  >
80
89
  <RxCross2 size={16} />
81
90
  </CloseButton>
@@ -84,7 +93,8 @@ export const RecentChats: React.FC<IRecentChatsProps> = ({
84
93
  </RecentChatLogContainer>
85
94
  </RecentChatTabContainer>
86
95
  );
87
- };
96
+ }
97
+ );
88
98
 
89
99
  const RecentChatTabContainer = styled.div<{
90
100
  isPrivate: boolean;
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useRef, useState } from 'react';
1
+ import React, { memo, useCallback, useEffect, useRef, useState } from 'react';
2
2
  import { RxMagnifyingGlass } from 'react-icons/rx';
3
3
  import styled from 'styled-components';
4
4
  import { uiColors } from '../../constants/uiColors';
@@ -18,101 +18,115 @@ interface ISearchCharacterProps {
18
18
  hideSearchCharacterUI: () => void;
19
19
  }
20
20
 
21
- export const SearchCharacter = ({
22
- onChangeCharacterName,
23
- onBlur,
24
- onFocus,
25
- recentCharacters,
26
- hideSearchCharacterUI,
27
- onCharacterClick,
28
- styles = {
29
- textColor: '#c65102',
30
- buttonColor: '#005b96',
31
- buttonBackgroundColor: 'rgba(0,0,0,.2)',
32
- width: '80%',
33
- height: 'auto',
34
- },
35
- }: ISearchCharacterProps) => {
36
- const [characterName, setCharacterName] = useState('');
37
- const searchCharacterRef = useRef<HTMLInputElement>(null);
38
-
39
- useEffect(() => {
40
- const timer = setTimeout(() => {
41
- if (searchCharacterRef.current) {
42
- searchCharacterRef.current.focus();
43
- }
44
- }, 100);
45
-
46
- return () => clearTimeout(timer);
47
- }, []);
48
-
49
- const handleSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
50
- event.preventDefault();
51
- if (!characterName || characterName.trim() === '') return;
52
- onChangeCharacterName(characterName);
53
- };
54
-
55
- const handleCharacterClick = (character: PrivateChatCharacter) => {
56
- if (!onCharacterClick) return;
57
- setCharacterName('');
58
- onCharacterClick(character);
59
- hideSearchCharacterUI();
60
- };
61
-
62
- return (
63
- <SearchContainer>
64
- <Form onSubmit={handleSubmit}>
65
- <Column flex={70}>
66
- <TextField
67
- value={characterName}
68
- ref={searchCharacterRef}
69
- id="characterName"
70
- name="characterName"
71
- onChange={e => {
72
- setCharacterName(e.target.value);
73
- onChangeCharacterName(e.target.value);
74
- }}
75
- placeholder="Search for a character..."
76
- height={20}
77
- type="text"
78
- autoComplete="off"
79
- onFocus={onFocus}
80
- onBlur={onBlur}
81
- onPointerDown={onFocus}
82
- />
83
- </Column>
84
- <Column justifyContent="flex-end">
85
- <SearchButton
86
- type="submit"
87
- buttonColor={styles?.buttonColor || '#005b96'}
88
- buttonBackgroundColor={
89
- styles?.buttonBackgroundColor || 'rgba(0,0,0,.5)'
90
- }
91
- id="chat-send-button"
92
- style={{ borderRadius: '20%' }}
93
- >
94
- <RxMagnifyingGlass size={15} />
95
- </SearchButton>
96
- </Column>
97
- </Form>
98
-
99
- {recentCharacters && recentCharacters.length > 0 && (
100
- <ListContainer>
101
- {recentCharacters.map(character => (
102
- <ListElement
103
- onPointerDown={() => handleCharacterClick(character)}
104
- key={character._id}
21
+ export const SearchCharacter: React.FC<ISearchCharacterProps> = memo(
22
+ ({
23
+ onChangeCharacterName,
24
+ onBlur,
25
+ onFocus,
26
+ recentCharacters,
27
+ hideSearchCharacterUI,
28
+ onCharacterClick,
29
+ styles = {
30
+ textColor: '#c65102',
31
+ buttonColor: '#005b96',
32
+ buttonBackgroundColor: 'rgba(0,0,0,.2)',
33
+ width: '80%',
34
+ height: 'auto',
35
+ },
36
+ }) => {
37
+ const [characterName, setCharacterName] = useState('');
38
+ const searchCharacterRef = useRef<HTMLInputElement>(null);
39
+
40
+ useEffect(() => {
41
+ const timer = setTimeout(() => {
42
+ if (searchCharacterRef.current) {
43
+ searchCharacterRef.current.focus();
44
+ }
45
+ }, 100);
46
+
47
+ return () => clearTimeout(timer);
48
+ }, []);
49
+
50
+ const handleSubmit = useCallback(
51
+ (event: React.SyntheticEvent<HTMLFormElement>) => {
52
+ event.preventDefault();
53
+ if (!characterName || characterName.trim() === '') return;
54
+ onChangeCharacterName(characterName);
55
+ },
56
+ [characterName, onChangeCharacterName]
57
+ );
58
+
59
+ const handleCharacterClick = useCallback(
60
+ (character: PrivateChatCharacter) => {
61
+ if (!onCharacterClick) return;
62
+ setCharacterName('');
63
+ onCharacterClick(character);
64
+ hideSearchCharacterUI();
65
+ },
66
+ [onCharacterClick, hideSearchCharacterUI]
67
+ );
68
+
69
+ const handleInputChange = useCallback(
70
+ (e: React.ChangeEvent<HTMLInputElement>) => {
71
+ const value = e.target.value;
72
+ setCharacterName(value);
73
+ onChangeCharacterName(value);
74
+ },
75
+ [onChangeCharacterName]
76
+ );
77
+
78
+ return (
79
+ <SearchContainer>
80
+ <Form onSubmit={handleSubmit}>
81
+ <Column flex={70}>
82
+ <TextField
83
+ value={characterName}
84
+ ref={searchCharacterRef}
85
+ id="characterName"
86
+ name="characterName"
87
+ onChange={handleInputChange}
88
+ placeholder="Search for a character..."
89
+ height={20}
90
+ type="text"
91
+ autoComplete="off"
92
+ onFocus={onFocus}
93
+ onBlur={onBlur}
94
+ onPointerDown={onFocus}
95
+ />
96
+ </Column>
97
+ <Column justifyContent="flex-end">
98
+ <SearchButton
99
+ type="submit"
100
+ buttonColor={styles?.buttonColor || '#005b96'}
101
+ buttonBackgroundColor={
102
+ styles?.buttonBackgroundColor || 'rgba(0,0,0,.5)'
103
+ }
104
+ id="chat-send-button"
105
+ style={{ borderRadius: '20%' }}
105
106
  >
106
- <Ellipsis maxWidth="150px" maxLines={1}>
107
- {character.name}
108
- </Ellipsis>
109
- </ListElement>
110
- ))}
111
- </ListContainer>
112
- )}
113
- </SearchContainer>
114
- );
115
- };
107
+ <RxMagnifyingGlass size={15} />
108
+ </SearchButton>
109
+ </Column>
110
+ </Form>
111
+
112
+ {recentCharacters && recentCharacters.length > 0 && (
113
+ <ListContainer>
114
+ {recentCharacters.map(character => (
115
+ <ListElement
116
+ onPointerDown={() => handleCharacterClick(character)}
117
+ key={character._id}
118
+ >
119
+ <Ellipsis maxWidth="150px" maxLines={1}>
120
+ {character.name}
121
+ </Ellipsis>
122
+ </ListElement>
123
+ ))}
124
+ </ListContainer>
125
+ )}
126
+ </SearchContainer>
127
+ );
128
+ }
129
+ );
116
130
 
117
131
  interface IButtonProps {
118
132
  buttonColor: string;
@@ -131,6 +131,29 @@ export const generateContextMenu = (
131
131
  );
132
132
  break;
133
133
  }
134
+
135
+ // Add "Use" for consumable items in nested containers
136
+ if (item.type === ItemType.Consumable && item.isUsable) {
137
+ const hasUseAction = contextActionMenu.some(action => action.id === ItemSocketEvents.Use);
138
+ if (!hasUseAction) {
139
+ contextActionMenu.unshift({
140
+ id: ItemSocketEvents.Use,
141
+ text: ItemSocketEventsDisplayLabels[ItemSocketEvents.Use],
142
+ });
143
+ }
144
+ }
145
+
146
+ // Add "Use with..." for items that have hasUseWith property
147
+ const contextActionMenuDontHaveUseWith = !contextActionMenu.find(action =>
148
+ action.text.toLowerCase().includes('use with')
149
+ );
150
+
151
+ if (item.hasUseWith && contextActionMenuDontHaveUseWith) {
152
+ contextActionMenu.push({
153
+ id: ItemSocketEvents.UseWith,
154
+ text: ItemSocketEvents.UseWith,
155
+ });
156
+ }
134
157
  }
135
158
  if (itemContainerType === ItemContainerType.MapContainer) {
136
159
  switch (item.type) {
@@ -47,7 +47,7 @@ export const ProgressBar: React.FC<IBarProps> = ({
47
47
  >
48
48
  {displayText && (
49
49
  <TextOverlay>
50
- <ProgressBarText>
50
+ <ProgressBarText translate="no">
51
51
  {displayValue}/{displayMax}
52
52
  </ProgressBarText>
53
53
  </TextOverlay>
@@ -1,4 +1,4 @@
1
- import { useEffect, useState } from 'react';
1
+ import { useCallback, useEffect, useMemo, useState } from 'react';
2
2
  import { PrivateChatCharacter } from '../components/ChatRevamp/types';
3
3
 
4
4
  interface IUseChat {
@@ -27,27 +27,39 @@ export const useChat = ({
27
27
  }
28
28
  }, [isPrivate]);
29
29
 
30
- const toggleExpand = () => setIsExpanded(prev => !prev);
30
+ const toggleExpand = useCallback(() => setIsExpanded(prev => !prev), []);
31
31
 
32
- const toggleRecentChats = () => setShowRecentChats(prev => !prev);
32
+ const toggleRecentChats = useCallback(
33
+ () => setShowRecentChats(prev => !prev),
34
+ []
35
+ );
33
36
 
34
- const handleTabChange = (tabId: string) => {
35
- if (tabId === 'private') {
36
- setIsExpanded(true);
37
- }
38
- onChangeTab(tabId);
39
- };
37
+ const handleTabChange = useCallback(
38
+ (tabId: string) => {
39
+ if (tabId === 'private') {
40
+ setIsExpanded(true);
41
+ }
42
+ onChangeTab(tabId);
43
+ },
44
+ [onChangeTab]
45
+ );
40
46
 
41
- const handlePreviousChatCharacterClick = (
42
- character: PrivateChatCharacter
43
- ) => {
44
- if (onPreviousChatCharacterClick) {
45
- onPreviousChatCharacterClick(character);
46
- }
47
- if (hideSearchCharacterUI) {
48
- hideSearchCharacterUI();
49
- }
50
- };
47
+ const handlePreviousChatCharacterClick = useCallback(
48
+ (character: PrivateChatCharacter) => {
49
+ if (onPreviousChatCharacterClick) {
50
+ onPreviousChatCharacterClick(character);
51
+ }
52
+ if (hideSearchCharacterUI) {
53
+ hideSearchCharacterUI();
54
+ }
55
+ },
56
+ [onPreviousChatCharacterClick, hideSearchCharacterUI]
57
+ );
58
+
59
+ const hasUnseenMessages = useMemo(
60
+ () => unseenMessageCharacterIds && unseenMessageCharacterIds.length > 0,
61
+ [unseenMessageCharacterIds]
62
+ );
51
63
 
52
64
  return {
53
65
  showRecentChats,
@@ -56,7 +68,6 @@ export const useChat = ({
56
68
  toggleRecentChats,
57
69
  handleTabChange,
58
70
  handlePreviousChatCharacterClick,
59
- hasUnseenMessages:
60
- unseenMessageCharacterIds && unseenMessageCharacterIds?.length > 0,
71
+ hasUnseenMessages,
61
72
  };
62
73
  };