@rpg-engine/long-bow 0.3.80 → 0.3.81

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.3.80",
3
+ "version": "0.3.81",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import styled from 'styled-components';
4
+
5
+ const modalRoot = document.getElementById('modal-root')!;
6
+
7
+ interface ModalPortalProps {
8
+ children: React.ReactNode;
9
+ }
10
+
11
+ const ModalPortal: React.FC<ModalPortalProps> = ({ children }) => {
12
+ return ReactDOM.createPortal(
13
+ <Container className="rpgui-content">{children}</Container>,
14
+ modalRoot
15
+ );
16
+ };
17
+
18
+ const Container = styled.div`
19
+ position: static !important;
20
+ `;
21
+
22
+ export default ModalPortal;
@@ -137,7 +137,7 @@ export const ItemInfo: React.FC<IItemInfoProps> = ({
137
137
 
138
138
  {item.maxStackSize && item.maxStackSize !== 1 && (
139
139
  <StackInfo>
140
- x{item.stackQty ?? 1}({item.maxStackSize})
140
+ x{Math.round((item.stackQty ?? 1) * 100) / 100}({item.maxStackSize})
141
141
  </StackInfo>
142
142
  )}
143
143
 
@@ -1,6 +1,7 @@
1
1
  import { IEquipmentSet, IItem } from '@rpg-engine/shared';
2
2
  import React, { useEffect, useRef } from 'react';
3
3
  import styled from 'styled-components';
4
+ import ModalPortal from '../../Abstractions/ModalPortal';
4
5
  import { ItemInfoDisplay } from './ItemInfoDisplay';
5
6
 
6
7
  export interface IItemTooltipProps {
@@ -22,7 +23,6 @@ export const ItemTooltip: React.FC<IItemTooltipProps> = ({
22
23
 
23
24
  useEffect(() => {
24
25
  const { current } = ref;
25
- let initialOffset: DOMRect;
26
26
 
27
27
  if (current) {
28
28
  const handleMouseMove = (event: MouseEvent) => {
@@ -30,9 +30,6 @@ export const ItemTooltip: React.FC<IItemTooltipProps> = ({
30
30
 
31
31
  // Adjust the position of the tooltip based on the mouse position
32
32
  const rect = current.getBoundingClientRect();
33
- if (!initialOffset) {
34
- initialOffset = rect;
35
- }
36
33
 
37
34
  const tooltipWidth = rect.width;
38
35
  const tooltipHeight = rect.height;
@@ -40,14 +37,12 @@ export const ItemTooltip: React.FC<IItemTooltipProps> = ({
40
37
  clientX + tooltipWidth + offset > window.innerWidth;
41
38
  const isOffScreenBottom =
42
39
  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;
40
+ const x = isOffScreenRight
41
+ ? clientX - tooltipWidth - offset
42
+ : clientX + offset;
43
+ const y = isOffScreenBottom
44
+ ? clientY - tooltipHeight - offset
45
+ : clientY + offset;
51
46
 
52
47
  current.style.transform = `translate(${x}px, ${y}px)`;
53
48
  current.style.opacity = '1';
@@ -64,22 +59,25 @@ export const ItemTooltip: React.FC<IItemTooltipProps> = ({
64
59
  }, []);
65
60
 
66
61
  return (
67
- <Container ref={ref}>
68
- <ItemInfoDisplay
69
- item={item}
70
- atlasIMG={atlasIMG}
71
- atlasJSON={atlasJSON}
72
- equipmentSet={equipmentSet}
73
- />
74
- </Container>
62
+ <ModalPortal>
63
+ <Container ref={ref}>
64
+ <ItemInfoDisplay
65
+ item={item}
66
+ atlasIMG={atlasIMG}
67
+ atlasJSON={atlasJSON}
68
+ equipmentSet={equipmentSet}
69
+ />
70
+ </Container>
71
+ </ModalPortal>
75
72
  );
76
73
  };
77
74
 
78
75
  const Container = styled.div`
79
- position: fixed;
80
- z-index: 50;
76
+ position: absolute;
77
+ z-index: 100;
81
78
  pointer-events: none;
82
79
  left: 0;
83
80
  top: 0;
84
81
  opacity: 0;
82
+ transition: opacity 0.08s;
85
83
  `;
@@ -1,6 +1,7 @@
1
1
  import { IEquipmentSet, IItem } from '@rpg-engine/shared';
2
- import React, { useEffect, useRef } from 'react';
2
+ import React, { useRef } from 'react';
3
3
  import styled from 'styled-components';
4
+ import ModalPortal from '../../Abstractions/ModalPortal';
4
5
  import { ItemInfoDisplay } from './ItemInfoDisplay';
5
6
 
6
7
  interface IListMenuOption {
@@ -31,72 +32,86 @@ export const MobileItemTooltip: React.FC<MobileItemTooltipProps> = ({
31
32
  }) => {
32
33
  const ref = useRef<HTMLDivElement>(null);
33
34
 
34
- useEffect(() => {
35
- const { current } = ref;
36
-
37
- if (current) {
38
- // Adjust the position to be on whole window
39
- const rect = current.getBoundingClientRect();
40
-
41
- const x = (-rect.x * 100) / (scale * 100);
42
- const y = (-rect.y * 100) / (scale * 100);
43
-
44
- current.style.transform = `translate(${x}px, ${y}px)`;
45
- current.style.opacity = '0.92';
46
- }
47
-
48
- return;
49
- }, []);
35
+ const handleFadeOut = () => {
36
+ ref.current?.classList.add('fadeOut');
37
+ };
50
38
 
51
39
  return (
52
- <Container
53
- ref={ref}
54
- onTouchEnd={() => {
55
- setTimeout(() => {
56
- closeTooltip();
57
- }, 10);
58
- }}
59
- scale={scale}
60
- >
61
- <ItemInfoDisplay
62
- item={item}
63
- atlasIMG={atlasIMG}
64
- atlasJSON={atlasJSON}
65
- equipmentSet={equipmentSet}
66
- isMobile
67
- />
68
- <OptionsContainer>
69
- {options?.map(option => (
70
- <Option
71
- key={option.id}
72
- onTouchEnd={() => {
73
- setTimeout(() => {
74
- onSelected?.(option.id);
75
- closeTooltip();
76
- }, 10);
77
- }}
78
- >
79
- {option.text}
80
- </Option>
81
- ))}
82
- </OptionsContainer>
83
- </Container>
40
+ <ModalPortal>
41
+ <Container
42
+ ref={ref}
43
+ onTouchEnd={() => {
44
+ handleFadeOut();
45
+ setTimeout(() => {
46
+ closeTooltip();
47
+ }, 100);
48
+ }}
49
+ scale={scale}
50
+ >
51
+ <ItemInfoDisplay
52
+ item={item}
53
+ atlasIMG={atlasIMG}
54
+ atlasJSON={atlasJSON}
55
+ equipmentSet={equipmentSet}
56
+ isMobile
57
+ />
58
+ <OptionsContainer>
59
+ {options?.map(option => (
60
+ <Option
61
+ key={option.id}
62
+ onTouchEnd={() => {
63
+ handleFadeOut();
64
+ setTimeout(() => {
65
+ onSelected?.(option.id);
66
+ closeTooltip();
67
+ }, 100);
68
+ }}
69
+ >
70
+ {option.text}
71
+ </Option>
72
+ ))}
73
+ </OptionsContainer>
74
+ </Container>
75
+ </ModalPortal>
84
76
  );
85
77
  };
86
78
 
87
79
  const Container = styled.div<{ scale: number }>`
88
- position: fixed;
89
- z-index: 50;
80
+ position: absolute;
81
+ z-index: 100;
90
82
  left: 0;
91
83
  top: 0;
92
- opacity: 0;
93
- width: ${({ scale }) => `calc(100vw * 100 / ${scale * 100})`};
94
- height: ${({ scale }) => `calc(100vh * 100 / ${scale * 100})`};
84
+ width: 100vw;
85
+ height: 100vh;
95
86
  background-color: rgba(0 0 0 / 0.5);
96
87
  display: flex;
97
88
  justify-content: center;
98
89
  align-items: center;
99
90
  gap: 0.5rem;
91
+ transition: opacity 0.08s;
92
+ animation: fadeIn 0.1s forwards;
93
+
94
+ @keyframes fadeIn {
95
+ 0% {
96
+ opacity: 0;
97
+ }
98
+ 100% {
99
+ opacity: 0.92;
100
+ }
101
+ }
102
+
103
+ @keyframes fadeOut {
104
+ 0% {
105
+ opacity: 0.92;
106
+ }
107
+ 100% {
108
+ opacity: 0;
109
+ }
110
+ }
111
+
112
+ &.fadeOut {
113
+ animation: fadeOut 0.1s forwards;
114
+ }
100
115
 
101
116
  @media (max-width: 580px) {
102
117
  flex-direction: column;
@@ -122,7 +137,7 @@ const Option = styled.button`
122
137
  border: none;
123
138
  border-radius: 3px;
124
139
  width: 8rem;
125
- transition: background-color 0.2s;
140
+ transition: background-color 0.1s;
126
141
 
127
142
  &:hover {
128
143
  background-color: #555;
@@ -12,6 +12,7 @@ import { SlotsContainer } from '../../Abstractions/SlotsContainer';
12
12
  import { ItemQuantitySelector } from './ItemQuantitySelector';
13
13
 
14
14
  import { IPosition } from '../../../types/eventTypes';
15
+ import ModalPortal from '../../Abstractions/ModalPortal';
15
16
  import { ShortcutsSetter } from '../../Shortcuts/ShortcutsSetter';
16
17
  import { ItemSlot } from './ItemSlot';
17
18
 
@@ -169,27 +170,29 @@ export const ItemContainer: React.FC<IItemContainerProps> = ({
169
170
  </ItemsContainer>
170
171
  </SlotsContainer>
171
172
  {quantitySelect.isOpen && (
172
- <QuantitySelectorContainer>
173
- <ItemQuantitySelector
174
- quantity={quantitySelect.maxQuantity}
175
- onConfirm={quantity => {
176
- quantitySelect.callback(quantity);
177
- setQuantitySelect({
178
- isOpen: false,
179
- maxQuantity: 1,
180
- callback: () => {},
181
- });
182
- }}
183
- onClose={() => {
184
- quantitySelect.callback(-1);
185
- setQuantitySelect({
186
- isOpen: false,
187
- maxQuantity: 1,
188
- callback: () => {},
189
- });
190
- }}
191
- />
192
- </QuantitySelectorContainer>
173
+ <ModalPortal>
174
+ <QuantitySelectorContainer>
175
+ <ItemQuantitySelector
176
+ quantity={quantitySelect.maxQuantity}
177
+ onConfirm={quantity => {
178
+ quantitySelect.callback(quantity);
179
+ setQuantitySelect({
180
+ isOpen: false,
181
+ maxQuantity: 1,
182
+ callback: () => {},
183
+ });
184
+ }}
185
+ onClose={() => {
186
+ quantitySelect.callback(-1);
187
+ setQuantitySelect({
188
+ isOpen: false,
189
+ maxQuantity: 1,
190
+ callback: () => {},
191
+ });
192
+ }}
193
+ />
194
+ </QuantitySelectorContainer>
195
+ </ModalPortal>
193
196
  )}
194
197
  </>
195
198
  );
@@ -146,7 +146,9 @@ export const ItemSlot: React.FC<IProps> = observer(
146
146
  return (
147
147
  <ItemQtyContainer key={`qty-${itemId}`}>
148
148
  <Ellipsis maxLines={1} maxWidth="48px">
149
- <ItemQty className={qtyClassName}> {stackQty} </ItemQty>
149
+ <ItemQty className={qtyClassName}>
150
+ {Math.round(stackQty * 100) / 100}{' '}
151
+ </ItemQty>
150
152
  </Ellipsis>
151
153
  </ItemQtyContainer>
152
154
  );
@@ -470,7 +470,7 @@ export const items: IItem[] = [
470
470
  isEquipable: true,
471
471
  isStackable: true,
472
472
  maxStackSize: 100,
473
- stackQty: 203.23,
473
+ stackQty: 203.200000000000008,
474
474
  isUsable: false,
475
475
  isStorable: true,
476
476
  isTwoHanded: false,