@rpg-engine/long-bow 0.1.70 → 0.1.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 (29) hide show
  1. package/dist/components/Abstractions/SlotsContainer.d.ts +11 -0
  2. package/dist/components/DraggableContainer.d.ts +1 -0
  3. package/dist/components/Equipment/EquipmentSet.d.ts +13 -0
  4. package/dist/components/Item/Inventory/ItemSlot.d.ts +10 -2
  5. package/dist/components/Item/Inventory/itemContainerHelper.d.ts +6 -2
  6. package/dist/components/store/UI.store.d.ts +34 -0
  7. package/dist/index.d.ts +1 -0
  8. package/dist/long-bow.cjs.development.js +1700 -365
  9. package/dist/long-bow.cjs.development.js.map +1 -1
  10. package/dist/long-bow.cjs.production.min.js +1 -1
  11. package/dist/long-bow.cjs.production.min.js.map +1 -1
  12. package/dist/long-bow.esm.js +1703 -367
  13. package/dist/long-bow.esm.js.map +1 -1
  14. package/dist/mocks/equipmentSet.mocks.d.ts +3 -0
  15. package/package.json +4 -2
  16. package/src/components/Abstractions/SlotsContainer.tsx +42 -0
  17. package/src/components/DraggableContainer.tsx +62 -37
  18. package/src/components/Equipment/EquipmentSet.tsx +179 -0
  19. package/src/components/Item/Inventory/ItemContainer.tsx +70 -178
  20. package/src/components/Item/Inventory/ItemSlot.tsx +92 -24
  21. package/src/components/Item/Inventory/itemContainerHelper.ts +48 -11
  22. package/src/components/Item/SpriteFromAtlas.tsx +8 -1
  23. package/src/components/ListMenu.tsx +3 -3
  24. package/src/components/store/UI.store.ts +192 -0
  25. package/src/index.tsx +1 -0
  26. package/src/mocks/atlas/items/items.json +1209 -181
  27. package/src/mocks/atlas/items/items.png +0 -0
  28. package/src/mocks/equipmentSet.mocks.ts +347 -0
  29. package/src/mocks/itemContainer.mocks.ts +33 -33
@@ -1,6 +1,7 @@
1
- import React from 'react';
1
+ import React, { useEffect, useRef } from 'react';
2
2
  import Draggable, { DraggableData } from 'react-draggable';
3
3
  import styled from 'styled-components';
4
+ import { useOutsideClick } from '../hooks/useOutsideAlerter';
4
5
  import { IPosition } from '../types/eventTypes';
5
6
  import { RPGUIContainerTypes } from './RPGUIContainer';
6
7
 
@@ -16,6 +17,7 @@ export interface IDraggableContainerProps {
16
17
  onCloseButton?: () => void;
17
18
  cancelDrag?: string;
18
19
  onPositionChange?: (position: IPosition) => void;
20
+ onOutsideClick?: () => void;
19
21
  }
20
22
 
21
23
  export const DraggableContainer: React.FC<IDraggableContainerProps> = ({
@@ -30,45 +32,68 @@ export const DraggableContainer: React.FC<IDraggableContainerProps> = ({
30
32
  imgWidth = '20px',
31
33
  cancelDrag,
32
34
  onPositionChange,
35
+ onOutsideClick,
33
36
  }) => {
34
- return (
35
- <Draggable
36
- cancel={`.container-close,${cancelDrag}`}
37
- onDrag={(_e, data: DraggableData) => {
38
- if (onPositionChange) {
39
- onPositionChange({
40
- x: data.x,
41
- y: data.y,
42
- });
37
+ const draggableRef = useRef(null);
38
+
39
+ useOutsideClick(draggableRef, 'item-container');
40
+
41
+ useEffect(() => {
42
+ document.addEventListener('clickOutside', event => {
43
+ const e = event as CustomEvent;
44
+
45
+ if (e.detail.id === 'item-container') {
46
+ if (onOutsideClick) {
47
+ onOutsideClick();
43
48
  }
44
- }}
45
- >
46
- <Container
47
- width={width}
48
- height={height || 'auto'}
49
- className={`rpgui-container ${type} ${className}`}
49
+ }
50
+ });
51
+
52
+ return () => {
53
+ document.removeEventListener('clickOutside', _e => {});
54
+ };
55
+ }, []);
56
+
57
+ return (
58
+ <div ref={draggableRef}>
59
+ <Draggable
60
+ cancel={`.container-close,${cancelDrag}`}
61
+ onDrag={(_e, data: DraggableData) => {
62
+ if (onPositionChange) {
63
+ onPositionChange({
64
+ x: data.x,
65
+ y: data.y,
66
+ });
67
+ }
68
+ }}
50
69
  >
51
- {title && (
52
- <TitleContainer className="drag-handler">
53
- <Title>
54
- {imgSrc && <Icon src={imgSrc} width={imgWidth} />}
55
- {title}
56
- </Title>
57
- </TitleContainer>
58
- )}
59
- {onCloseButton && (
60
- <CloseButton
61
- className="container-close"
62
- onClick={onCloseButton}
63
- onTouchStart={onCloseButton}
64
- >
65
- X
66
- </CloseButton>
67
- )}
68
-
69
- {children}
70
- </Container>
71
- </Draggable>
70
+ <Container
71
+ width={width}
72
+ height={height || 'auto'}
73
+ className={`rpgui-container ${type} ${className}`}
74
+ >
75
+ {title && (
76
+ <TitleContainer className="drag-handler">
77
+ <Title>
78
+ {imgSrc && <Icon src={imgSrc} width={imgWidth} />}
79
+ {title}
80
+ </Title>
81
+ </TitleContainer>
82
+ )}
83
+ {onCloseButton && (
84
+ <CloseButton
85
+ className="container-close"
86
+ onClick={onCloseButton}
87
+ onTouchStart={onCloseButton}
88
+ >
89
+ X
90
+ </CloseButton>
91
+ )}
92
+
93
+ {children}
94
+ </Container>
95
+ </Draggable>
96
+ </div>
72
97
  );
73
98
  };
74
99
 
@@ -0,0 +1,179 @@
1
+ import {
2
+ IEquipementSet,
3
+ IItem,
4
+ IItemContainer,
5
+ ItemSlotType,
6
+ ItemSocketEvents,
7
+ } from '@rpg-engine/shared';
8
+ import { observer } from 'mobx-react';
9
+ import React, { useState } from 'react';
10
+ import styled from 'styled-components';
11
+ import { IPosition } from '../../types/eventTypes';
12
+ import { DraggableContainer } from '../DraggableContainer';
13
+ import { ItemCard } from '../Item/Cards/ItemCard';
14
+ import { ItemSlot, SlotContainerType } from '../Item/Inventory/ItemSlot';
15
+ import { ListMenu } from '../ListMenu';
16
+ import { RPGUIContainerTypes } from '../RPGUIContainer';
17
+ import { uiStore } from '../store/UI.store';
18
+
19
+ export interface IEquipmentSetProps {
20
+ equipmentSet: IEquipementSet;
21
+ onClose?: () => void;
22
+ onMouseOver?: (e: any, slotIndex: number, item: IItem | null) => void;
23
+ onActionSelected?: (payload: any) => void;
24
+ initialPosition?: { x: number; y: number };
25
+ }
26
+
27
+ export const EquipmentSet: React.FC<IEquipmentSetProps> = observer(
28
+ ({
29
+ equipmentSet,
30
+ onClose,
31
+ onMouseOver,
32
+ onActionSelected,
33
+ initialPosition = { x: 0, y: 0 },
34
+ }) => {
35
+ const {
36
+ neck,
37
+ leftHand,
38
+ ring,
39
+ head,
40
+ armor,
41
+ legs,
42
+ boot,
43
+ inventory,
44
+ rightHand,
45
+ accessory,
46
+ } = equipmentSet;
47
+
48
+ const equipmentData = [
49
+ neck,
50
+ leftHand,
51
+ ring,
52
+ head,
53
+ armor,
54
+ legs,
55
+ boot,
56
+ inventory,
57
+ rightHand,
58
+ accessory,
59
+ ];
60
+
61
+ const equipmentMaskSlots = [
62
+ ItemSlotType.Neck,
63
+ ItemSlotType.LeftHand,
64
+ ItemSlotType.Ring,
65
+ ItemSlotType.Head,
66
+ ItemSlotType.Torso,
67
+ ItemSlotType.Legs,
68
+ ItemSlotType.Feet,
69
+ ItemSlotType.Inventory,
70
+ ItemSlotType.RightHand,
71
+ ItemSlotType.Accessory,
72
+ ];
73
+
74
+ // we use this draggable position to offset the menu position, after the container is dragged (otherwise, it bugs!)
75
+ const [draggablePosition, setDraggablePosition] = useState<IPosition>(
76
+ initialPosition
77
+ );
78
+
79
+ const handleOnMouseHover = (
80
+ event: any,
81
+ slotIndex: number,
82
+ item: IItem | null,
83
+ x: number,
84
+ y: number
85
+ ) => {
86
+ uiStore.handleOnMouseHover(event, slotIndex, item, x, y, onMouseOver);
87
+ };
88
+
89
+ const onSelected = (selectedActionId: ItemSocketEvents | string): void => {
90
+ uiStore.onSelected(selectedActionId, onActionSelected);
91
+ };
92
+
93
+ const onRenderEquipmentSlotRange = (start: number, end: number) => {
94
+ const equipmentRange = equipmentData.slice(start, end);
95
+ const slotMaksRange = equipmentMaskSlots.slice(start, end);
96
+
97
+ return equipmentRange.map((data, i) => {
98
+ const item = data as IItem;
99
+ const itemContainer =
100
+ (item && (item.itemContainer as IItemContainer)) ?? null;
101
+ return (
102
+ <ItemSlot
103
+ key={i}
104
+ slotIndex={i}
105
+ item={item}
106
+ itemContainer={itemContainer}
107
+ slotContainerType={SlotContainerType.EQUIPMENT_SET}
108
+ slotSpriteMask={slotMaksRange[i]}
109
+ onMouseOver={handleOnMouseHover}
110
+ onMouseOut={() => {
111
+ uiStore.clearItemHoverDetail();
112
+ }}
113
+ onClick={uiStore.handleOnItemClick}
114
+ onCancelContextMenu={() => {
115
+ uiStore.clearContextMenu();
116
+ }}
117
+ />
118
+ );
119
+ });
120
+ };
121
+
122
+ return (
123
+ <DraggableContainer
124
+ title={'Equipments'}
125
+ type={RPGUIContainerTypes.Framed}
126
+ onCloseButton={() => {
127
+ if (onClose) onClose();
128
+ }}
129
+ width="330px"
130
+ cancelDrag=".equipment-container-body"
131
+ onPositionChange={({ x, y }) => {
132
+ setDraggablePosition({ x, y });
133
+ }}
134
+ onOutsideClick={() => {
135
+ uiStore.clearContextMenu();
136
+ uiStore.clearItemHoverDetail();
137
+ }}
138
+ >
139
+ <EquipmentSetContainer className="equipment-container-body">
140
+ <EquipmentColumn>{onRenderEquipmentSlotRange(0, 3)}</EquipmentColumn>
141
+ <EquipmentColumn>{onRenderEquipmentSlotRange(3, 7)}</EquipmentColumn>
142
+ <EquipmentColumn>{onRenderEquipmentSlotRange(7, 10)}</EquipmentColumn>
143
+ </EquipmentSetContainer>
144
+
145
+ {uiStore.contextMenu?.visible ? (
146
+ <ListMenu
147
+ x={uiStore.contextMenu.posX - draggablePosition.x}
148
+ y={uiStore.contextMenu.posY - draggablePosition.y}
149
+ options={uiStore.contextMenu.contextActions}
150
+ onSelected={onSelected}
151
+ />
152
+ ) : null}
153
+
154
+ {uiStore.onHoverDetail?.visible ? (
155
+ <ItemCard
156
+ item={uiStore.onHoverDetail.item}
157
+ x={uiStore.onHoverDetail.posX - draggablePosition.x}
158
+ y={uiStore.onHoverDetail.posY - draggablePosition.y}
159
+ />
160
+ ) : null}
161
+ </DraggableContainer>
162
+ );
163
+ }
164
+ );
165
+
166
+ const EquipmentSetContainer = styled.div`
167
+ width: inherit;
168
+ display: flex;
169
+ justify-content: center;
170
+ flex-wrap: wrap;
171
+ flex-direction: row;
172
+ `;
173
+
174
+ const EquipmentColumn = styled.div`
175
+ display: flex;
176
+ justify-content: center;
177
+ flex-wrap: wrap;
178
+ flex-direction: column;
179
+ `;
@@ -1,19 +1,13 @@
1
- import {
2
- IItem,
3
- IItemContainer,
4
- IPayloadProps,
5
- ItemSocketEvents,
6
- } from '@rpg-engine/shared';
7
- import React, { useEffect, useRef, useState } from 'react';
1
+ import { IItem, IItemContainer, ItemSocketEvents } from '@rpg-engine/shared';
2
+ import { observer } from 'mobx-react';
3
+ import React, { useState } from 'react';
8
4
  import styled from 'styled-components';
9
- import { useOutsideClick } from '../../../hooks/useOutsideAlerter';
10
5
  import { IPosition } from '../../../types/eventTypes';
11
- import { DraggableContainer } from '../../DraggableContainer';
6
+ import { SlotsContainer } from '../../Abstractions/SlotsContainer';
12
7
  import { ListMenu } from '../../ListMenu';
13
- import { RPGUIContainerTypes } from '../../RPGUIContainer';
8
+ import { uiStore } from '../../store/UI.store';
14
9
  import { ItemCard } from '../Cards/ItemCard';
15
- import { handleContextMenuList } from './itemContainerHelper';
16
- import { ItemSlot } from './ItemSlot';
10
+ import { ItemSlot, SlotContainerType } from './ItemSlot';
17
11
 
18
12
  export interface IItemContainerProps {
19
13
  itemContainer: IItemContainer;
@@ -23,195 +17,93 @@ export interface IItemContainerProps {
23
17
  initialPosition?: { x: number; y: number };
24
18
  }
25
19
 
26
- interface IContextItemProps {
27
- visible: boolean;
28
- posX: number;
29
- posY: number;
30
- slotItem: IItem | null;
31
- slotIndex?: number | null;
32
- contextActions: any;
33
- }
34
-
35
- interface IHoverDetailProps {
36
- visible: boolean;
37
- posX: number;
38
- posY: number;
39
- item: IItem | null;
40
- }
41
-
42
- export const ItemContainer: React.FC<IItemContainerProps> = ({
43
- itemContainer,
44
- onClose,
45
- onMouseOver,
46
- onActionSelected,
47
- initialPosition = { x: 0, y: 0 },
48
- }) => {
49
- // we use this draggable position to offset the menu position, after the container is dragged (otherwise, it bugs!)
50
- const [draggablePosition, setDraggablePosition] = useState<IPosition>(
51
- initialPosition
52
- );
53
-
54
- const draggableRef = useRef(null);
55
-
56
- useOutsideClick(draggableRef, 'item-container');
57
-
58
- useEffect(() => {
59
- document.addEventListener('clickOutside', event => {
60
- const e = event as CustomEvent;
61
-
62
- if (e.detail.id === 'item-container') {
63
- clearContextMenu();
64
- clearItemHoverDetail();
65
- }
66
- });
67
-
68
- return () => {
69
- document.removeEventListener('clickOutside', _e => {});
20
+ export const ItemContainer: React.FC<IItemContainerProps> = observer(
21
+ ({
22
+ itemContainer,
23
+ onClose,
24
+ onMouseOver,
25
+ onActionSelected,
26
+ initialPosition = { x: 0, y: 0 },
27
+ }) => {
28
+ // we use this draggable position to offset the menu position, after the container is dragged (otherwise, it bugs!)
29
+ const [draggablePosition, setDraggablePosition] = useState<IPosition>(
30
+ initialPosition
31
+ );
32
+
33
+ const handleOnMouseHover = (
34
+ event: any,
35
+ slotIndex: number,
36
+ item: IItem | null,
37
+ x: number,
38
+ y: number
39
+ ) => {
40
+ uiStore.handleOnMouseHover(event, slotIndex, item, x, y, onMouseOver);
70
41
  };
71
- }, []);
72
-
73
- const { x: initX, y: initY } = initialPosition;
74
42
 
75
- const [contextData, setContextData] = useState<IContextItemProps>({
76
- visible: false,
77
- posX: initX,
78
- posY: initY,
79
- contextActions: [],
80
- slotItem: null,
81
- });
82
- const [itemHoverDetail, setItemHoverDetail] = useState<IHoverDetailProps>({
83
- visible: false,
84
- posX: initX,
85
- posY: initY,
86
- item: null,
87
- });
88
-
89
- const clearContextMenu = () => {
90
- setContextData({
91
- visible: false,
92
- posX: 0,
93
- posY: 0,
94
- contextActions: [],
95
- slotItem: null,
96
- });
97
- };
43
+ const onSelected = (selectedActionId: ItemSocketEvents | string): void => {
44
+ uiStore.onSelected(selectedActionId, onActionSelected);
45
+ };
98
46
 
99
- const handleOnMouseHover = (
100
- event: any,
101
- slotIndex: number,
102
- item: IItem | null,
103
- x: number,
104
- y: number
105
- ) => {
106
- if (item) {
107
- setItemHoverDetail({
108
- ...itemHoverDetail,
109
- visible: true,
110
- item: item,
111
- posX: x - draggablePosition.x,
112
- posY: y - draggablePosition.y,
113
- });
114
- if (onMouseOver) {
115
- onMouseOver(event, slotIndex, item);
47
+ const onRenderSlots = () => {
48
+ const slots = [];
49
+
50
+ for (let i = 0; i < itemContainer.slotQty; i++) {
51
+ slots.push(
52
+ <ItemSlot
53
+ key={i}
54
+ slotIndex={i}
55
+ item={itemContainer.slots?.[i] || null}
56
+ slotContainerType={SlotContainerType.INVENTORY}
57
+ onMouseOver={handleOnMouseHover}
58
+ onClick={uiStore.handleOnItemClick}
59
+ onMouseOut={() => {
60
+ uiStore.clearItemHoverDetail();
61
+ }}
62
+ onCancelContextMenu={() => {
63
+ uiStore.clearContextMenu();
64
+ }}
65
+ />
66
+ );
116
67
  }
117
- } else {
118
- clearItemHoverDetail();
119
- }
120
- };
121
-
122
- const clearItemHoverDetail = () => {
123
- setItemHoverDetail({
124
- ...itemHoverDetail,
125
- visible: false,
126
- item: null,
127
- });
128
- };
129
-
130
- const handleOnItemClick = (item: IItem, posX: number, posY: number) => {
131
- const contextList = handleContextMenuList(item.type);
132
-
133
- setContextData({
134
- ...contextData,
135
- visible: true,
136
- posX,
137
- posY,
138
- slotItem: item,
139
- contextActions: contextList,
140
- });
141
- clearItemHoverDetail();
142
- };
143
-
144
- const onSelected = (selectedActionId: ItemSocketEvents | string): void => {
145
- let payloadData: IPayloadProps = {
146
- actionType: selectedActionId,
147
- item: contextData.slotItem,
68
+ return slots;
148
69
  };
149
- if (onActionSelected) {
150
- onActionSelected(payloadData);
151
- }
152
- clearContextMenu();
153
- };
154
-
155
- const onRenderSlots = () => {
156
- const slots = [];
157
-
158
- for (let i = 0; i < itemContainer.slotQty; i++) {
159
- slots.push(
160
- <ItemSlot
161
- key={i}
162
- slotIndex={i}
163
- item={itemContainer.slots?.[i] || null}
164
- onMouseOver={handleOnMouseHover}
165
- onClick={handleOnItemClick}
166
- onCancelContextMenu={() => {
167
- clearContextMenu();
168
- }}
169
- />
170
- );
171
- }
172
- return slots;
173
- };
174
70
 
175
- return (
176
- <div ref={draggableRef}>
177
- <DraggableContainer
71
+ return (
72
+ <SlotsContainer
178
73
  title={itemContainer.name || 'Container'}
179
- type={RPGUIContainerTypes.Framed}
180
- onCloseButton={() => {
181
- if (onClose) {
182
- onClose();
183
- }
184
- }}
185
- width="330px"
186
- cancelDrag=".item-container-body"
187
74
  onPositionChange={({ x, y }) => {
188
75
  setDraggablePosition({ x, y });
189
76
  }}
77
+ onOutsideClick={() => {
78
+ uiStore.clearContextMenu();
79
+ uiStore.clearItemHoverDetail();
80
+ }}
81
+ onClose={onClose}
190
82
  >
191
83
  <ItemsContainer className="item-container-body">
192
84
  {onRenderSlots()}
193
85
  </ItemsContainer>
194
86
 
195
- {contextData.visible ? (
87
+ {uiStore.contextMenu?.visible ? (
196
88
  <ListMenu
197
- x={contextData.posX - draggablePosition.x}
198
- y={contextData.posY - draggablePosition.y}
199
- options={contextData.contextActions}
89
+ x={uiStore.contextMenu.posX - draggablePosition.x}
90
+ y={uiStore.contextMenu.posY - draggablePosition.y}
91
+ options={uiStore.contextMenu.contextActions}
200
92
  onSelected={onSelected}
201
93
  />
202
94
  ) : null}
203
95
 
204
- {itemHoverDetail.visible ? (
96
+ {uiStore.onHoverDetail?.visible ? (
205
97
  <ItemCard
206
- item={itemHoverDetail.item}
207
- x={itemHoverDetail.posX}
208
- y={itemHoverDetail.posY}
98
+ item={uiStore.onHoverDetail.item}
99
+ x={uiStore.onHoverDetail.posX}
100
+ y={uiStore.onHoverDetail.posY}
209
101
  />
210
102
  ) : null}
211
- </DraggableContainer>
212
- </div>
213
- );
214
- };
103
+ </SlotsContainer>
104
+ );
105
+ }
106
+ );
215
107
 
216
108
  const ItemsContainer = styled.div`
217
109
  max-width: 280px;