@rpg-engine/long-bow 0.3.69 → 0.3.71

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.
Files changed (158) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +181 -181
  3. package/dist/components/CraftBook/CraftBook.d.ts +2 -1
  4. package/dist/components/Item/Cards/ItemInfo.d.ts +10 -0
  5. package/dist/components/Item/Cards/ItemInfoDisplay.d.ts +9 -0
  6. package/dist/components/Item/Cards/ItemInfoWrapper.d.ts +11 -0
  7. package/dist/components/Item/Cards/ItemTooltip.d.ts +7 -4
  8. package/dist/components/Item/Inventory/ItemContainer.d.ts +2 -1
  9. package/dist/components/Item/Inventory/ItemSlot.d.ts +4 -1
  10. package/dist/components/TradingMenu/TradingItemRow.d.ts +2 -1
  11. package/dist/components/TradingMenu/TradingMenu.d.ts +4 -3
  12. package/dist/components/shared/SpriteFromAtlas.d.ts +1 -0
  13. package/dist/long-bow.cjs.development.js +1220 -949
  14. package/dist/long-bow.cjs.development.js.map +1 -1
  15. package/dist/long-bow.cjs.production.min.js +1 -1
  16. package/dist/long-bow.cjs.production.min.js.map +1 -1
  17. package/dist/long-bow.esm.js +1222 -953
  18. package/dist/long-bow.esm.js.map +1 -1
  19. package/dist/stories/ItemInfoDisplay.stories.d.ts +8 -0
  20. package/dist/stories/TradingMenu.stories.d.ts +2 -2
  21. package/package.json +100 -100
  22. package/src/components/Abstractions/SlotsContainer.tsx +45 -45
  23. package/src/components/Arrow/SelectArrow.tsx +69 -69
  24. package/src/components/Arrow/img/arrow01-left-clicked.png +0 -0
  25. package/src/components/Arrow/img/arrow01-left.png +0 -0
  26. package/src/components/Arrow/img/arrow01-right-clicked.png +0 -0
  27. package/src/components/Arrow/img/arrow01-right.png +0 -0
  28. package/src/components/Arrow/img/arrow02-left-clicked.png +0 -0
  29. package/src/components/Arrow/img/arrow02-left.png +0 -0
  30. package/src/components/Arrow/img/arrow02-right-clicked.png +0 -0
  31. package/src/components/Arrow/img/arrow02-right.png +0 -0
  32. package/src/components/Button.tsx +40 -40
  33. package/src/components/Character/CharacterSelection.tsx +96 -96
  34. package/src/components/CharacterStatus/CharacterStatus.tsx +120 -120
  35. package/src/components/Chat/Chat.tsx +195 -195
  36. package/src/components/Chatdeprecated/ChatDeprecated.tsx +198 -198
  37. package/src/components/CheckButton.tsx +65 -65
  38. package/src/components/CircularController/CircularController.tsx +248 -248
  39. package/src/components/CraftBook/CraftBook.tsx +237 -227
  40. package/src/components/CraftBook/MockItems.ts +41 -46
  41. package/src/components/DraggableContainer.tsx +153 -153
  42. package/src/components/Dropdown.tsx +90 -90
  43. package/src/components/DropdownSelectorContainer.tsx +42 -42
  44. package/src/components/Equipment/EquipmentSet.tsx +190 -190
  45. package/src/components/HistoryDialog.tsx +104 -104
  46. package/src/components/Input.tsx +15 -15
  47. package/src/components/Item/Cards/ItemInfo.tsx +248 -0
  48. package/src/components/Item/Cards/ItemInfoDisplay.tsx +120 -0
  49. package/src/components/Item/Cards/ItemInfoWrapper.tsx +39 -0
  50. package/src/components/Item/Cards/ItemTooltip.tsx +85 -33
  51. package/src/components/Item/Inventory/ErrorBoundary.tsx +42 -42
  52. package/src/components/Item/Inventory/ItemContainer.tsx +214 -210
  53. package/src/components/Item/Inventory/ItemContainerTypes.ts +6 -6
  54. package/src/components/Item/Inventory/ItemQuantitySelector.tsx +138 -138
  55. package/src/components/Item/Inventory/ItemSlot.tsx +512 -501
  56. package/src/components/Item/Inventory/itemContainerHelper.ts +156 -156
  57. package/src/components/ListMenu.tsx +63 -63
  58. package/src/components/Multitab/Tab.tsx +66 -66
  59. package/src/components/Multitab/TabBody.tsx +13 -13
  60. package/src/components/Multitab/TabsContainer.tsx +97 -97
  61. package/src/components/NPCDialog/NPCDialog.tsx +121 -121
  62. package/src/components/NPCDialog/NPCDialogText.tsx +113 -113
  63. package/src/components/NPCDialog/NPCMultiDialog.tsx +159 -159
  64. package/src/components/NPCDialog/QuestionDialog/QuestionDialog.tsx +237 -237
  65. package/src/components/ProgressBar.tsx +92 -92
  66. package/src/components/PropertySelect/PropertySelect.tsx +106 -106
  67. package/src/components/QuestInfo/QuestInfo.tsx +230 -230
  68. package/src/components/QuestList.tsx +129 -129
  69. package/src/components/RPGUIContainer.tsx +47 -47
  70. package/src/components/RPGUIForceRenderStart.tsx +45 -45
  71. package/src/components/RPGUIRoot.tsx +14 -14
  72. package/src/components/RadioButton.tsx +53 -53
  73. package/src/components/RadioInput/RadioButton.tsx +96 -96
  74. package/src/components/RadioInput/RadioInput.tsx +102 -102
  75. package/src/components/RadioInput/instruments.ts +15 -15
  76. package/src/components/RangeSlider.tsx +78 -78
  77. package/src/components/RelativeListMenu.tsx +83 -83
  78. package/src/components/ScrollList.tsx +79 -79
  79. package/src/components/Shortcuts/Shortcuts.tsx +151 -151
  80. package/src/components/Shortcuts/ShortcutsSetter.tsx +132 -132
  81. package/src/components/Shortcuts/SingleShortcut.ts +62 -62
  82. package/src/components/SimpleProgressBar.tsx +62 -62
  83. package/src/components/SkillProgressBar.tsx +133 -133
  84. package/src/components/SkillsContainer.tsx +198 -198
  85. package/src/components/Spellbook/Spell.tsx +201 -201
  86. package/src/components/Spellbook/Spellbook.tsx +150 -150
  87. package/src/components/Spellbook/constants.ts +8 -8
  88. package/src/components/Spellbook/mockSpells.ts +60 -60
  89. package/src/components/StaticBook/StaticBook.tsx +103 -103
  90. package/src/components/TextArea.tsx +11 -11
  91. package/src/components/TimeWidget/DayNightPeriod/DayNightPeriod.tsx +35 -35
  92. package/src/components/TimeWidget/TimeWidget.tsx +63 -63
  93. package/src/components/TradingMenu/TradingItemRow.tsx +195 -181
  94. package/src/components/TradingMenu/TradingMenu.tsx +211 -203
  95. package/src/components/TradingMenu/items.mock.ts +48 -96
  96. package/src/components/Truncate.tsx +25 -25
  97. package/src/components/itemSelector/ItemSelector.tsx +136 -136
  98. package/src/components/shared/Column.tsx +16 -16
  99. package/src/components/shared/Ellipsis.tsx +65 -65
  100. package/src/components/shared/SpriteFromAtlas.tsx +104 -102
  101. package/src/components/typography/DynamicText.tsx +49 -49
  102. package/src/constants/uiColors.ts +20 -20
  103. package/src/constants/uiDevices.ts +3 -3
  104. package/src/constants/uiFonts.ts +12 -12
  105. package/src/hooks/useEventListener.ts +21 -21
  106. package/src/hooks/useOutsideAlerter.ts +25 -25
  107. package/src/index.tsx +40 -40
  108. package/src/libs/StringHelpers.ts +3 -3
  109. package/src/mocks/atlas/entities/entities.json +20215 -20215
  110. package/src/mocks/atlas/icons/icons.json +735 -735
  111. package/src/mocks/atlas/items/items.json +12086 -12086
  112. package/src/mocks/equipmentSet.mocks.ts +391 -393
  113. package/src/mocks/itemContainer.mocks.ts +563 -562
  114. package/src/mocks/skills.mocks.ts +128 -128
  115. package/src/stories/Arrow.stories.tsx +26 -26
  116. package/src/stories/Button.stories.tsx +36 -36
  117. package/src/stories/CharacterSelection.stories.tsx +45 -45
  118. package/src/stories/CharacterStatus.stories.tsx +29 -29
  119. package/src/stories/Chat.stories.tsx +187 -187
  120. package/src/stories/ChatDeprecated.stories.tsx +170 -170
  121. package/src/stories/CheckButton.stories.tsx +48 -48
  122. package/src/stories/CircullarController.stories.tsx +37 -37
  123. package/src/stories/CraftBook.stories.tsx +42 -40
  124. package/src/stories/DayNightPeriod.stories.tsx +27 -27
  125. package/src/stories/DraggableContainer.stories.tsx +28 -28
  126. package/src/stories/Dropdown.stories.tsx +46 -46
  127. package/src/stories/DropdownSelectorContainer.stories.tsx +41 -41
  128. package/src/stories/EquipmentSet.stories.tsx +65 -65
  129. package/src/stories/HistoryDialog.stories.tsx +61 -61
  130. package/src/stories/ItemContainer.stories.tsx +200 -198
  131. package/src/stories/ItemInfoDisplay.stories.tsx +33 -0
  132. package/src/stories/ItemQuantitySelector.stories.tsx +26 -26
  133. package/src/stories/ItemSelector.stories.tsx +77 -77
  134. package/src/stories/ItemTradingComponent.stories.tsx +35 -35
  135. package/src/stories/ListMenu.stories.tsx +56 -56
  136. package/src/stories/Multitab.stories.tsx +51 -51
  137. package/src/stories/NPCDialog.stories.tsx +130 -130
  138. package/src/stories/NPCMultiDialog.stories.tsx +71 -71
  139. package/src/stories/ProgressBar.stories.tsx +23 -23
  140. package/src/stories/PropertySelect.stories.tsx +40 -40
  141. package/src/stories/QuestInfo.stories.tsx +107 -107
  142. package/src/stories/QuestList.stories.tsx +82 -82
  143. package/src/stories/RPGUIContainers.stories.tsx +42 -42
  144. package/src/stories/RadioButton.stories.tsx +49 -49
  145. package/src/stories/RadioInput.stories.tsx +34 -34
  146. package/src/stories/RangeSlider.stories.tsx +64 -64
  147. package/src/stories/ScrollList.stories.tsx +85 -85
  148. package/src/stories/Shortcuts.stories.tsx +39 -39
  149. package/src/stories/SimpleProgressBar.stories.tsx +22 -22
  150. package/src/stories/SkillProgressBar.stories.tsx +34 -34
  151. package/src/stories/SkillsContainer.stories.tsx +35 -35
  152. package/src/stories/Spellbook.stories.tsx +104 -104
  153. package/src/stories/StaticBook.stories.tsx +32 -32
  154. package/src/stories/Text.stories.tsx +42 -42
  155. package/src/stories/TimeWidget.stories.tsx +27 -27
  156. package/src/stories/TradingMenu.stories.tsx +47 -45
  157. package/src/types/eventTypes.ts +4 -4
  158. package/src/types/index.d.ts +2 -2
@@ -0,0 +1,248 @@
1
+ import { IItem } from '@rpg-engine/shared';
2
+ import React from 'react';
3
+ import styled from 'styled-components';
4
+ import { uiColors } from '../../../constants/uiColors';
5
+ import { uiFonts } from '../../../constants/uiFonts';
6
+ import { SpriteFromAtlas } from '../../shared/SpriteFromAtlas';
7
+ import { ErrorBoundary } from '../Inventory/ErrorBoundary';
8
+ import { EquipmentSlotSpriteByType, rarityColor } from '../Inventory/ItemSlot';
9
+
10
+ interface IItemInfoProps {
11
+ item: IItem;
12
+ itemToCompare?: IItem;
13
+ atlasIMG: any;
14
+ atlasJSON: any;
15
+ }
16
+
17
+ interface IItemStat {
18
+ key: keyof IItem;
19
+ label?: string;
20
+ higherIsWorse?: boolean;
21
+ }
22
+
23
+ const statisticsToDisplay: IItemStat[] = [
24
+ { key: 'attack' },
25
+ { key: 'defense' },
26
+ { key: 'maxRange', label: 'Range' },
27
+ { key: 'weight', higherIsWorse: true },
28
+ ];
29
+
30
+ export const ItemInfo: React.FC<IItemInfoProps> = ({
31
+ item,
32
+ itemToCompare,
33
+ atlasIMG,
34
+ atlasJSON,
35
+ }) => {
36
+ const renderStatistics = () => {
37
+ const statistics = [];
38
+
39
+ for (const stat of statisticsToDisplay) {
40
+ const itemStatistic = item[stat.key];
41
+
42
+ if (itemStatistic) {
43
+ const label =
44
+ stat.label || stat.key[0].toUpperCase() + stat.key.slice(1);
45
+
46
+ const isItemToCompare = !!itemToCompare;
47
+
48
+ const isOnlyInOneItem = isItemToCompare && !itemToCompare?.[stat.key];
49
+ const statDiff =
50
+ parseInt(itemStatistic.toString()) -
51
+ parseInt(itemToCompare?.[stat.key]?.toString() ?? '0');
52
+
53
+ const isDifference = isItemToCompare && statDiff !== 0;
54
+ const isBetter =
55
+ (statDiff > 0 && !stat.higherIsWorse) ||
56
+ (statDiff < 0 && stat.higherIsWorse);
57
+
58
+ statistics.push(
59
+ <Statistic key={stat.key} className={isOnlyInOneItem ? 'better' : ''}>
60
+ <div className="label">{label}:</div>
61
+ <div
62
+ className={`value ${
63
+ isDifference ? (isBetter ? 'better' : 'worse') : ''
64
+ }`}
65
+ >
66
+ {`${itemStatistic.toString()} ${
67
+ isDifference ? `(${statDiff > 0 ? '+' : ''}${statDiff})` : ''
68
+ }`}
69
+ </div>
70
+ </Statistic>
71
+ );
72
+ }
73
+ }
74
+
75
+ return statistics;
76
+ };
77
+
78
+ const renderMissingStatistic = () => {
79
+ const statistics = [];
80
+
81
+ for (const stat of statisticsToDisplay) {
82
+ const itemToCompareStatistic = itemToCompare?.[stat.key];
83
+
84
+ if (itemToCompareStatistic && !item[stat.key]) {
85
+ const label =
86
+ stat.label || stat.key[0].toUpperCase() + stat.key.slice(1);
87
+
88
+ statistics.push(
89
+ <Statistic key={stat.key} className="worse">
90
+ <div className="label">{label}:</div>
91
+ <div className="value worse">
92
+ {itemToCompareStatistic.toString()}
93
+ </div>
94
+ </Statistic>
95
+ );
96
+ }
97
+ }
98
+
99
+ return statistics;
100
+ };
101
+
102
+ const renderAvaibleSlots = () => {
103
+ if (!item.allowedEquipSlotType) return null;
104
+
105
+ return item.allowedEquipSlotType.map((slotType, index) => (
106
+ <ErrorBoundary key={index}>
107
+ <SpriteFromAtlas
108
+ atlasIMG={atlasIMG}
109
+ atlasJSON={atlasJSON}
110
+ spriteKey={EquipmentSlotSpriteByType[slotType]}
111
+ imgScale={2}
112
+ grayScale={true}
113
+ opacity={0.4}
114
+ containerStyle={{ width: '32px', height: '32px' }}
115
+ />
116
+ </ErrorBoundary>
117
+ ));
118
+ };
119
+
120
+ return (
121
+ <Container item={item}>
122
+ <Header>
123
+ <div>
124
+ <Title>{item.name}</Title>
125
+ {item.rarity !== 'Common' && (
126
+ <Rarity item={item}>{item.rarity}</Rarity>
127
+ )}
128
+ <Type>{item.subType}</Type>
129
+ </div>
130
+ <AllowedSlots>{renderAvaibleSlots()}</AllowedSlots>
131
+ </Header>
132
+
133
+ {renderStatistics()}
134
+ {item.isTwoHanded && <Statistic>Two handed</Statistic>}
135
+
136
+ <Description>{item.description}</Description>
137
+
138
+ {item.maxStackSize && item.maxStackSize !== 1 && (
139
+ <StackInfo>
140
+ x{item.stackQty ?? 1}({item.maxStackSize})
141
+ </StackInfo>
142
+ )}
143
+
144
+ {renderMissingStatistic().length > 0 && (
145
+ <MissingStatistics>
146
+ <Statistic>Equipped Diff</Statistic>
147
+ {itemToCompare && renderMissingStatistic()}
148
+ </MissingStatistics>
149
+ )}
150
+ </Container>
151
+ );
152
+ };
153
+
154
+ const Container = styled.div<{ item: IItem }>`
155
+ color: white;
156
+ background-color: #222;
157
+ border-radius: 5px;
158
+ padding: 0.5rem;
159
+ width: max-content;
160
+ font-size: ${uiFonts.size.small};
161
+ border: 3px solid ${({ item }) => rarityColor(item) ?? uiColors.lightGray};
162
+ `;
163
+
164
+ const Title = styled.div`
165
+ font-size: ${uiFonts.size.medium};
166
+ font-weight: bold;
167
+ margin-bottom: 0.5rem;
168
+ display: flex;
169
+ align-items: center;
170
+ margin: 0;
171
+ `;
172
+
173
+ const Rarity = styled.div<{ item: IItem }>`
174
+ font-size: ${uiFonts.size.small};
175
+ font-weight: normal;
176
+ margin-top: 0.2rem;
177
+ color: ${({ item }) => rarityColor(item)};
178
+ filter: brightness(1.5);
179
+ `;
180
+
181
+ const Type = styled.div`
182
+ font-size: ${uiFonts.size.small};
183
+ margin-top: 0.2rem;
184
+ color: ${uiColors.lightGray};
185
+ `;
186
+
187
+ const Statistic = styled.div`
188
+ margin-bottom: 0.4rem;
189
+
190
+ .label {
191
+ display: inline-block;
192
+ margin-right: 0.5rem;
193
+ color: inherit;
194
+ }
195
+
196
+ .value {
197
+ display: inline-block;
198
+ color: inherit;
199
+ }
200
+
201
+ &.better,
202
+ .better {
203
+ color: ${uiColors.lightGreen};
204
+ }
205
+
206
+ &.worse,
207
+ .worse {
208
+ color: ${uiColors.cardinal};
209
+ }
210
+ `;
211
+
212
+ const Description = styled.div`
213
+ margin-top: 1.5rem;
214
+ font-size: ${uiFonts.size.small};
215
+ color: ${uiColors.lightGray};
216
+ font-style: italic;
217
+ width: max-content;
218
+ max-width: 20rem;
219
+ `;
220
+
221
+ const Header = styled.div`
222
+ display: flex;
223
+ align-items: center;
224
+ justify-content: space-between;
225
+ margin-bottom: 0.5rem;
226
+ `;
227
+
228
+ const AllowedSlots = styled.div`
229
+ display: flex;
230
+ align-items: center;
231
+ justify-content: center;
232
+ flex-wrap: wrap;
233
+ gap: 0.5rem;
234
+ margin-left: 2rem;
235
+ `;
236
+
237
+ const StackInfo = styled.div`
238
+ width: 100%;
239
+ text-align: right;
240
+ font-size: ${uiFonts.size.small};
241
+ color: ${uiColors.orange};
242
+ margin-top: 1rem;
243
+ `;
244
+
245
+ const MissingStatistics = styled.div`
246
+ margin-top: 1rem;
247
+ color: ${uiColors.cardinal};
248
+ `;
@@ -0,0 +1,120 @@
1
+ import { IEquipmentSet, IItem } from '@rpg-engine/shared';
2
+ import { camelCase } from 'lodash';
3
+ import React, { useMemo } from 'react';
4
+ import styled from 'styled-components';
5
+ import { ItemInfo } from './ItemInfo';
6
+
7
+ export interface IItemInfoDisplayProps {
8
+ item: IItem;
9
+ atlasIMG: any;
10
+ atlasJSON: any;
11
+ equipmentSet?: IEquipmentSet | null;
12
+ }
13
+
14
+ type EquipmentSlotTypes =
15
+ | 'head'
16
+ | 'neck'
17
+ | 'leftHand'
18
+ | 'rightHand'
19
+ | 'ring'
20
+ | 'legs'
21
+ | 'boot'
22
+ | 'accessory'
23
+ | 'armor'
24
+ | 'inventory';
25
+
26
+ const itemSlotTypes: EquipmentSlotTypes[] = [
27
+ 'head',
28
+ 'neck',
29
+ 'leftHand',
30
+ 'rightHand',
31
+ 'ring',
32
+ 'legs',
33
+ 'boot',
34
+ 'accessory',
35
+ 'armor',
36
+ 'inventory',
37
+ ];
38
+
39
+ const getSlotType = (
40
+ itemSlotTypes: string[],
41
+ slotType: string,
42
+ subType: string
43
+ ): keyof IEquipmentSet => {
44
+ if (!itemSlotTypes.includes(slotType)) {
45
+ return subType as keyof IEquipmentSet;
46
+ }
47
+ return slotType as keyof IEquipmentSet;
48
+ };
49
+
50
+ export const ItemInfoDisplay: React.FC<IItemInfoDisplayProps> = ({
51
+ item,
52
+ atlasIMG,
53
+ atlasJSON,
54
+ equipmentSet,
55
+ }) => {
56
+ const itemToCompare = useMemo(() => {
57
+ if (equipmentSet && item.allowedEquipSlotType?.length) {
58
+ const allowedSlotTypeCamelCase = camelCase(item.allowedEquipSlotType[0]);
59
+ const itemSubTypeCamelCase = camelCase(item.subType);
60
+
61
+ const slotType = getSlotType(
62
+ itemSlotTypes,
63
+ allowedSlotTypeCamelCase,
64
+ itemSubTypeCamelCase
65
+ );
66
+
67
+ const itemFromEquipment = equipmentSet[slotType] as IItem;
68
+
69
+ if (
70
+ itemFromEquipment &&
71
+ (!item._id || itemFromEquipment._id !== item._id)
72
+ ) {
73
+ return itemFromEquipment;
74
+ }
75
+ }
76
+
77
+ return undefined;
78
+ }, [equipmentSet, item]);
79
+
80
+ return (
81
+ <Flex>
82
+ <ItemInfo
83
+ item={item}
84
+ itemToCompare={itemToCompare}
85
+ atlasIMG={atlasIMG}
86
+ atlasJSON={atlasJSON}
87
+ />
88
+
89
+ {itemToCompare && (
90
+ <CompareContainer>
91
+ <Equipped>
92
+ <span>Equipped</span>
93
+ </Equipped>
94
+ <ItemInfo
95
+ item={itemToCompare}
96
+ itemToCompare={item}
97
+ atlasIMG={atlasIMG}
98
+ atlasJSON={atlasJSON}
99
+ />
100
+ </CompareContainer>
101
+ )}
102
+ </Flex>
103
+ );
104
+ };
105
+
106
+ const Flex = styled.div`
107
+ display: flex;
108
+ gap: 0.5rem;
109
+ `;
110
+
111
+ const Equipped = styled.div`
112
+ position: absolute;
113
+ bottom: 100%;
114
+ left: 50%;
115
+ transform: translateX(-50%);
116
+ `;
117
+
118
+ const CompareContainer = styled.div`
119
+ position: relative;
120
+ `;
@@ -0,0 +1,39 @@
1
+ import { IEquipmentSet, IItem } from '@rpg-engine/shared';
2
+ import React, { useState } from 'react';
3
+ import { ItemTooltip } from './ItemTooltip';
4
+
5
+ interface IItemInfoWrapperProps {
6
+ item: IItem;
7
+ children: React.ReactNode;
8
+ atlasIMG: any;
9
+ atlasJSON: any;
10
+ equipmentSet?: IEquipmentSet | null;
11
+ }
12
+
13
+ export const ItemInfoWrapper: React.FC<IItemInfoWrapperProps> = ({
14
+ children,
15
+ atlasIMG,
16
+ atlasJSON,
17
+ item,
18
+ equipmentSet,
19
+ }) => {
20
+ const [isItemInfoVisible, setIsItemInfoVisible] = useState(false);
21
+
22
+ return (
23
+ <div
24
+ onMouseEnter={setIsItemInfoVisible.bind(null, true)}
25
+ onMouseLeave={setIsItemInfoVisible.bind(null, false)}
26
+ >
27
+ {children}
28
+
29
+ {isItemInfoVisible && (
30
+ <ItemTooltip
31
+ atlasIMG={atlasIMG}
32
+ atlasJSON={atlasJSON}
33
+ equipmentSet={equipmentSet}
34
+ item={item}
35
+ />
36
+ )}
37
+ </div>
38
+ );
39
+ };
@@ -1,33 +1,85 @@
1
- import React from 'react';
2
- import styled from 'styled-components';
3
- import { uiFonts } from '../../../constants/uiFonts';
4
-
5
- interface IProps {
6
- label: string;
7
- }
8
-
9
- export const ItemTooltip: React.FC<IProps> = ({ label }) => {
10
- return (
11
- <Container>
12
- <div>{label}</div>
13
- </Container>
14
- );
15
- };
16
-
17
- const Container = styled.div`
18
- z-index: 2;
19
- position: absolute;
20
- top: 1rem;
21
- left: 4rem;
22
-
23
- font-size: ${uiFonts.size.xxsmall};
24
- color: white;
25
- background-color: black;
26
- border-radius: 5px;
27
- padding: 0.5rem;
28
- min-width: 20px;
29
- width: 100%;
30
- text-align: center;
31
-
32
- opacity: 0.75;
33
- `;
1
+ import { IEquipmentSet, IItem } from '@rpg-engine/shared';
2
+ import React, { useEffect, useRef } from 'react';
3
+ import styled from 'styled-components';
4
+ import { ItemInfoDisplay } from './ItemInfoDisplay';
5
+
6
+ export interface IItemTooltipProps {
7
+ item: IItem;
8
+ atlasIMG: any;
9
+ atlasJSON: any;
10
+ equipmentSet?: IEquipmentSet | null;
11
+ }
12
+
13
+ const offset = 20;
14
+
15
+ export const ItemTooltip: React.FC<IItemTooltipProps> = ({
16
+ item,
17
+ atlasIMG,
18
+ atlasJSON,
19
+ equipmentSet,
20
+ }) => {
21
+ const ref = useRef<HTMLDivElement>(null);
22
+
23
+ useEffect(() => {
24
+ const { current } = ref;
25
+ let initialOffset: DOMRect;
26
+
27
+ if (current) {
28
+ const handleMouseMove = (event: MouseEvent) => {
29
+ const { clientX, clientY } = event;
30
+
31
+ // Adjust the position of the tooltip based on the mouse position
32
+ const rect = current.getBoundingClientRect();
33
+ if (!initialOffset) {
34
+ initialOffset = rect;
35
+ }
36
+
37
+ const tooltipWidth = rect.width;
38
+ const tooltipHeight = rect.height;
39
+ const isOffScreenRight =
40
+ clientX + tooltipWidth + offset > window.innerWidth;
41
+ const isOffScreenBottom =
42
+ clientY + tooltipHeight + offset > window.innerHeight;
43
+ const x =
44
+ (isOffScreenRight
45
+ ? clientX - tooltipWidth - offset
46
+ : clientX + offset) - initialOffset.x;
47
+ const y =
48
+ (isOffScreenBottom
49
+ ? clientY - tooltipHeight - offset
50
+ : clientY + offset) - initialOffset.y;
51
+
52
+ current.style.transform = `translate(${x}px, ${y}px)`;
53
+ current.style.opacity = '1';
54
+ };
55
+
56
+ window.addEventListener('mousemove', handleMouseMove);
57
+
58
+ return () => {
59
+ window.removeEventListener('mousemove', handleMouseMove);
60
+ };
61
+ }
62
+
63
+ return;
64
+ }, []);
65
+
66
+ return (
67
+ <Container ref={ref}>
68
+ <ItemInfoDisplay
69
+ item={item}
70
+ atlasIMG={atlasIMG}
71
+ atlasJSON={atlasJSON}
72
+ equipmentSet={equipmentSet}
73
+ />
74
+ </Container>
75
+ );
76
+ };
77
+
78
+ const Container = styled.div`
79
+ position: fixed;
80
+ z-index: 50;
81
+ pointer-events: none;
82
+ left: 0;
83
+ top: 0;
84
+ opacity: 0;
85
+ `;
@@ -1,42 +1,42 @@
1
- import React, { Component, ErrorInfo, ReactNode } from 'react';
2
- import atlasJSON from '../../../mocks/atlas/items/items.json';
3
- import atlasIMG from '../../../mocks/atlas/items/items.png';
4
- import { SpriteFromAtlas } from '../../shared/SpriteFromAtlas';
5
-
6
- interface Props {
7
- children?: ReactNode;
8
- }
9
-
10
- interface State {
11
- hasError: boolean;
12
- }
13
-
14
- export class ErrorBoundary extends Component<Props, State> {
15
- public state: State = {
16
- hasError: false,
17
- };
18
-
19
- public static getDerivedStateFromError(_: Error): State {
20
- // Update state so the next render will show the fallback UI.
21
- return { hasError: true };
22
- }
23
-
24
- public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
25
- console.error('Uncaught error:', error, errorInfo);
26
- }
27
-
28
- public render() {
29
- if (this.state.hasError) {
30
- return (
31
- <SpriteFromAtlas
32
- atlasIMG={atlasIMG}
33
- atlasJSON={atlasJSON}
34
- spriteKey={'others/no-image.png'}
35
- imgScale={3}
36
- />
37
- );
38
- }
39
-
40
- return this.props.children;
41
- }
42
- }
1
+ import React, { Component, ErrorInfo, ReactNode } from 'react';
2
+ import atlasJSON from '../../../mocks/atlas/items/items.json';
3
+ import atlasIMG from '../../../mocks/atlas/items/items.png';
4
+ import { SpriteFromAtlas } from '../../shared/SpriteFromAtlas';
5
+
6
+ interface Props {
7
+ children?: ReactNode;
8
+ }
9
+
10
+ interface State {
11
+ hasError: boolean;
12
+ }
13
+
14
+ export class ErrorBoundary extends Component<Props, State> {
15
+ public state: State = {
16
+ hasError: false,
17
+ };
18
+
19
+ public static getDerivedStateFromError(_: Error): State {
20
+ // Update state so the next render will show the fallback UI.
21
+ return { hasError: true };
22
+ }
23
+
24
+ public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
25
+ console.error('Uncaught error:', error, errorInfo);
26
+ }
27
+
28
+ public render() {
29
+ if (this.state.hasError) {
30
+ return (
31
+ <SpriteFromAtlas
32
+ atlasIMG={atlasIMG}
33
+ atlasJSON={atlasJSON}
34
+ spriteKey={'others/no-image.png'}
35
+ imgScale={3}
36
+ />
37
+ );
38
+ }
39
+
40
+ return this.props.children;
41
+ }
42
+ }