@rpg-engine/long-bow 0.2.90 → 0.2.92

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 (38) hide show
  1. package/dist/components/Abstractions/SlotsContainer.d.ts +1 -0
  2. package/dist/components/DraggableContainer.d.ts +1 -0
  3. package/dist/components/Equipment/EquipmentSet.d.ts +6 -0
  4. package/dist/components/Input.d.ts +1 -0
  5. package/dist/components/Item/Inventory/ItemContainer.d.ts +10 -0
  6. package/dist/components/Item/Inventory/ItemQuantitySelector.d.ts +7 -0
  7. package/dist/components/Item/Inventory/ItemSlot.d.ts +7 -0
  8. package/dist/components/RangeSlider.d.ts +1 -0
  9. package/dist/index.d.ts +4 -5
  10. package/dist/long-bow.cjs.development.js +523 -220
  11. package/dist/long-bow.cjs.development.js.map +1 -1
  12. package/dist/long-bow.cjs.production.min.js +1 -1
  13. package/dist/long-bow.cjs.production.min.js.map +1 -1
  14. package/dist/long-bow.esm.js +524 -220
  15. package/dist/long-bow.esm.js.map +1 -1
  16. package/dist/stories/ItemQuantitySelector.stories.d.ts +5 -0
  17. package/package.json +1 -1
  18. package/src/components/Abstractions/SlotsContainer.tsx +3 -0
  19. package/src/components/CraftBook/CraftBook.tsx +82 -92
  20. package/src/components/CraftBook/MockItems.ts +23 -20
  21. package/src/components/DraggableContainer.tsx +3 -0
  22. package/src/components/Equipment/EquipmentSet.tsx +40 -0
  23. package/src/components/Input.tsx +6 -2
  24. package/src/components/Item/Inventory/ItemContainer.tsx +98 -6
  25. package/src/components/Item/Inventory/ItemQuantitySelector.tsx +142 -0
  26. package/src/components/Item/Inventory/ItemSlot.tsx +171 -24
  27. package/src/components/RangeSlider.tsx +37 -14
  28. package/src/index.tsx +4 -5
  29. package/src/mocks/itemContainer.mocks.ts +1 -1
  30. package/src/stories/EquipmentSet.stories.tsx +10 -0
  31. package/src/stories/ItemContainer.stories.tsx +83 -15
  32. package/src/stories/ItemQuantitySelector.stories.tsx +26 -0
  33. package/src/stories/RangeSlider.stories.tsx +10 -9
  34. package/src/.DS_Store +0 -0
  35. package/src/components/NPCDialog/.DS_Store +0 -0
  36. package/src/components/NPCDialog/img/.DS_Store +0 -0
  37. package/src/mocks/.DS_Store +0 -0
  38. package/src/mocks/atlas/.DS_Store +0 -0
@@ -0,0 +1,5 @@
1
+ import { Meta } from '@storybook/react';
2
+ import { IItemQuantitySelectorProps } from '../components/Item/Inventory/ItemQuantitySelector';
3
+ declare const meta: Meta;
4
+ export default meta;
5
+ export declare const Default: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, IItemQuantitySelectorProps>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpg-engine/long-bow",
3
- "version": "0.2.90",
3
+ "version": "0.2.92",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -9,6 +9,7 @@ interface IProps {
9
9
  onClose?: () => void;
10
10
  onPositionChange?: (position: IPosition) => void;
11
11
  onOutsideClick?: () => void;
12
+ initialPosition?: IPosition;
12
13
  }
13
14
 
14
15
  export const SlotsContainer: React.FC<IProps> = ({
@@ -17,6 +18,7 @@ export const SlotsContainer: React.FC<IProps> = ({
17
18
  onClose,
18
19
  onPositionChange,
19
20
  onOutsideClick,
21
+ initialPosition,
20
22
  }) => {
21
23
  return (
22
24
  <DraggableContainer
@@ -35,6 +37,7 @@ export const SlotsContainer: React.FC<IProps> = ({
35
37
  }
36
38
  }}
37
39
  onOutsideClick={onOutsideClick}
40
+ initialPosition={initialPosition}
38
41
  >
39
42
  {children}
40
43
  </DraggableContainer>
@@ -5,7 +5,6 @@ import { Button, ButtonTypes } from '../Button';
5
5
  import { DraggableContainer } from '../DraggableContainer';
6
6
  import { Dropdown, IOptionsProps } from '../Dropdown';
7
7
  import { RPGUIContainerTypes } from '../RPGUIContainer';
8
- import { RPGUIForceRenderStart } from '../RPGUIForceRenderStart';
9
8
  import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
10
9
 
11
10
  export interface IItemCraftSelectorProps {
@@ -71,101 +70,92 @@ export const CraftBook: React.FC<IItemCraftSelectorProps> = ({
71
70
  return name;
72
71
  };
73
72
 
74
- const handleClick = () => {
75
- let element = document.querySelector(
76
- `input[name='test']:checked`
77
- ) as HTMLInputElement;
78
- const elementValue = element.value;
79
- setCraftItem(elementValue);
73
+ const handleClick = (value: string) => {
74
+ setCraftItem(value);
80
75
  };
81
76
 
82
77
  return (
83
- <RPGUIForceRenderStart
84
- elementDOMId="radioInput"
85
- elementRenderedDOMKey="rpgui-radio"
86
- RPGUICreateFunction="radio"
78
+ <DraggableContainer
79
+ type={RPGUIContainerTypes.Framed}
80
+ width="500px"
81
+ cancelDrag=".equipment-container-body .arrow-selector"
82
+ onCloseButton={() => {
83
+ if (onClose) {
84
+ onClose();
85
+ }
86
+ }}
87
87
  >
88
- <DraggableContainer
89
- type={RPGUIContainerTypes.Framed}
90
- width="500px"
91
- cancelDrag=".equipment-container-body .arrow-selector"
92
- onCloseButton={() => {
93
- if (onClose) {
94
- onClose();
95
- }
96
- }}
97
- >
98
- <div style={{ width: '100%' }}>
99
- <Title>{'Craftbook'}</Title>
100
- <Subtitle>{'Select an item to craft'}</Subtitle>
101
- <hr className="golden" />
102
- </div>
103
- <Dropdown
104
- options={getDropdownOptions()}
105
- onChange={value => onSelect(value)}
106
- />
107
- <RadioInputScroller>
108
- {craftablesItems?.map((option, index) => (
109
- <RadioOptionsWrapper key={index}>
110
- <SpriteAtlasWrapper>
111
- <SpriteFromAtlas
112
- atlasIMG={atlasIMG}
113
- atlasJSON={atlasJSON}
114
- spriteKey={option.texturePath}
115
- imgScale={3}
116
- grayScale={!option.canCraft}
117
- />
118
- </SpriteAtlasWrapper>
119
- <div>
120
- <input
121
- className="rpgui-radio"
122
- type="radio"
123
- value={option.name}
124
- name="test"
125
- disabled={!option.canCraft}
126
- id="radioInput"
127
- />
128
- <label
129
- onClick={handleClick}
130
- style={{ display: 'flex', alignItems: 'center' }}
131
- onMouseEnter={() => setIsShown({ show: true, index: index })}
132
- onMouseLeave={() => setIsShown({ show: false, index: index })}
133
- >
134
- {modifyString(option.name)}
135
- </label>
136
-
137
- {isShown &&
138
- isShown.index === index &&
139
- option.ingredients.map((option, index) => (
140
- <Recipes key={index}>
141
- <SpriteFromAtlas
142
- atlasIMG={atlasIMG}
143
- atlasJSON={atlasJSON}
144
- spriteKey={option.texturePath}
145
- imgScale={1}
146
- />
147
- <StyledItem>
148
- {modifyString(option.key)} ({option.qty}x)
149
- </StyledItem>
150
- </Recipes>
151
- ))}
152
- </div>
153
- </RadioOptionsWrapper>
154
- ))}
155
- </RadioInputScroller>
156
- <ButtonWrapper>
157
- <Button buttonType={ButtonTypes.RPGUIButton} onClick={onClose}>
158
- Cancel
159
- </Button>
160
- <Button
161
- buttonType={ButtonTypes.RPGUIButton}
162
- onClick={() => onCraftItem(craftItem)}
163
- >
164
- Craft
165
- </Button>
166
- </ButtonWrapper>
167
- </DraggableContainer>
168
- </RPGUIForceRenderStart>
88
+ <div style={{ width: '100%' }}>
89
+ <Title>{'Craftbook'}</Title>
90
+ <Subtitle>{'Select an item to craft'}</Subtitle>
91
+ <hr className="golden" />
92
+ </div>
93
+ <Dropdown
94
+ options={getDropdownOptions()}
95
+ onChange={value => onSelect(value)}
96
+ />
97
+ <RadioInputScroller>
98
+ {craftablesItems?.map((option, index) => (
99
+ <RadioOptionsWrapper key={index}>
100
+ <SpriteAtlasWrapper>
101
+ <SpriteFromAtlas
102
+ atlasIMG={atlasIMG}
103
+ atlasJSON={atlasJSON}
104
+ spriteKey={option.texturePath}
105
+ imgScale={3}
106
+ grayScale={!option.canCraft}
107
+ />
108
+ </SpriteAtlasWrapper>
109
+ <div>
110
+ <input
111
+ className="rpgui-radio"
112
+ type="radio"
113
+ value={option.name}
114
+ name="test"
115
+ disabled={!option.canCraft}
116
+ checked={craftItem === option.key}
117
+ onChange={() => handleClick(option.key)}
118
+ />
119
+ <label
120
+ onClick={() => handleClick(option.key)}
121
+ style={{ display: 'flex', alignItems: 'center' }}
122
+ onMouseEnter={() => setIsShown({ show: true, index: index })}
123
+ onMouseLeave={() => setIsShown({ show: false, index: index })}
124
+ >
125
+ {modifyString(option.name)}
126
+ </label>
127
+
128
+ {isShown &&
129
+ isShown.index === index &&
130
+ option.ingredients.map((option, index) => (
131
+ <Recipes key={index}>
132
+ <SpriteFromAtlas
133
+ atlasIMG={atlasIMG}
134
+ atlasJSON={atlasJSON}
135
+ spriteKey={option.texturePath}
136
+ imgScale={1}
137
+ />
138
+ <StyledItem>
139
+ {modifyString(option.key)} ({option.qty}x)
140
+ </StyledItem>
141
+ </Recipes>
142
+ ))}
143
+ </div>
144
+ </RadioOptionsWrapper>
145
+ ))}
146
+ </RadioInputScroller>
147
+ <ButtonWrapper>
148
+ <Button buttonType={ButtonTypes.RPGUIButton} onClick={onClose}>
149
+ Cancel
150
+ </Button>
151
+ <Button
152
+ buttonType={ButtonTypes.RPGUIButton}
153
+ onClick={() => onCraftItem(craftItem)}
154
+ >
155
+ Craft
156
+ </Button>
157
+ </ButtonWrapper>
158
+ </DraggableContainer>
169
159
  );
170
160
  };
171
161
 
@@ -6,38 +6,41 @@ export const craftableItems: ICraftableItem[] = [
6
6
  name: 'Bandana',
7
7
  canCraft: true,
8
8
  texturePath: 'accessories/bandana.png',
9
- ingredients: [ {
10
- key: "leather",
11
- name: "leather",
12
- qty: 10,
13
- texturePath: "crafting-resources/leather.png",
14
- }
9
+ ingredients: [
10
+ {
11
+ key: 'leather',
12
+ name: 'leather',
13
+ qty: 10,
14
+ texturePath: 'crafting-resources/leather.png',
15
+ },
15
16
  ],
16
17
  },
17
18
  {
18
- key: 'bandana',
19
+ key: 'bandana1',
19
20
  name: 'Bandana',
20
21
  canCraft: true,
21
22
  texturePath: 'accessories/bandana.png',
22
- ingredients: [ {
23
- key: "leather",
24
- name: "leather",
25
- qty: 10,
26
- texturePath: "crafting-resources/leather.png",
27
- }
23
+ ingredients: [
24
+ {
25
+ key: 'leather',
26
+ name: 'leather',
27
+ qty: 10,
28
+ texturePath: 'crafting-resources/leather.png',
29
+ },
28
30
  ],
29
31
  },
30
32
  {
31
- key: 'bandana',
33
+ key: 'bandana2',
32
34
  name: 'Bandana',
33
35
  canCraft: true,
34
36
  texturePath: 'accessories/bandana.png',
35
- ingredients: [ {
36
- key: "leather",
37
- name: "leather",
38
- qty: 10,
39
- texturePath: "crafting-resources/leather.png",
40
- }
37
+ ingredients: [
38
+ {
39
+ key: 'leather',
40
+ name: 'leather',
41
+ qty: 10,
42
+ texturePath: 'crafting-resources/leather.png',
43
+ },
41
44
  ],
42
45
  },
43
46
  ];
@@ -19,6 +19,7 @@ export interface IDraggableContainerProps {
19
19
  cancelDrag?: string;
20
20
  onPositionChange?: (position: IPosition) => void;
21
21
  onOutsideClick?: () => void;
22
+ initialPosition?: IPosition;
22
23
  }
23
24
 
24
25
  export const DraggableContainer: React.FC<IDraggableContainerProps> = ({
@@ -34,6 +35,7 @@ export const DraggableContainer: React.FC<IDraggableContainerProps> = ({
34
35
  cancelDrag,
35
36
  onPositionChange,
36
37
  onOutsideClick,
38
+ initialPosition = { x: 0, y: 0 },
37
39
  }) => {
38
40
  const draggableRef = useRef(null);
39
41
 
@@ -66,6 +68,7 @@ export const DraggableContainer: React.FC<IDraggableContainerProps> = ({
66
68
  });
67
69
  }
68
70
  }}
71
+ defaultPosition={initialPosition}
69
72
  >
70
73
  <Container
71
74
  ref={draggableRef}
@@ -8,6 +8,7 @@ import {
8
8
  } from '@rpg-engine/shared';
9
9
  import React from 'react';
10
10
  import styled from 'styled-components';
11
+ import { IPosition } from '../../types/eventTypes';
11
12
  import { DraggableContainer } from '../DraggableContainer';
12
13
  import { ItemSlot } from '../Item/Inventory/ItemSlot';
13
14
  import { RPGUIContainerTypes } from '../RPGUIContainer';
@@ -20,6 +21,19 @@ export interface IEquipmentSetProps {
20
21
  item: IItem,
21
22
  itemContainerType: ItemContainerType | null
22
23
  ) => void;
24
+ onItemDragStart?: (
25
+ item: IItem,
26
+ slotIndex: number,
27
+ itemContainerType: ItemContainerType | null
28
+ ) => void;
29
+ onItemDragEnd?: (quantity?: number) => void;
30
+ onItemPlaceDrop?: (
31
+ item: IItem | null,
32
+ slotIndex: number,
33
+ itemContainerType: ItemContainerType | null
34
+ ) => void;
35
+ onItemOutsideDrop?: (item: IItem, position: IPosition) => void;
36
+ checkIfItemCanBeMoved: () => boolean;
23
37
  onMouseOver?: (e: any, slotIndex: number, item: IItem | null) => void;
24
38
  onSelected?: (optionId: string) => void;
25
39
  initialPosition?: { x: number; y: number };
@@ -36,6 +50,11 @@ export const EquipmentSet: React.FC<IEquipmentSetProps> = ({
36
50
  onItemClick,
37
51
  atlasIMG,
38
52
  atlasJSON,
53
+ onItemDragEnd,
54
+ onItemDragStart,
55
+ onItemPlaceDrop,
56
+ onItemOutsideDrop,
57
+ checkIfItemCanBeMoved,
39
58
  }) => {
40
59
  const {
41
60
  neck,
@@ -102,6 +121,25 @@ export const EquipmentSet: React.FC<IEquipmentSetProps> = ({
102
121
  onSelected={(optionId: string) => {
103
122
  if (onSelected) onSelected(optionId);
104
123
  }}
124
+ onDragStart={(item, slotIndex, itemContainerType) => {
125
+ if (!item) {
126
+ return;
127
+ }
128
+
129
+ if (onItemDragStart)
130
+ onItemDragStart(item, slotIndex, itemContainerType);
131
+ }}
132
+ onDragEnd={quantity => {
133
+ if (onItemDragEnd) onItemDragEnd(quantity);
134
+ }}
135
+ checkIfItemCanBeMoved={checkIfItemCanBeMoved}
136
+ onPlaceDrop={(item, slotIndex, itemContainerType) => {
137
+ if (onItemPlaceDrop)
138
+ onItemPlaceDrop(item, slotIndex, itemContainerType);
139
+ }}
140
+ onOutsideDrop={(item, position) => {
141
+ if (onItemOutsideDrop) onItemOutsideDrop(item, position);
142
+ }}
105
143
  atlasIMG={atlasIMG}
106
144
  atlasJSON={atlasJSON}
107
145
  />
@@ -134,6 +172,7 @@ const EquipmentSetContainer = styled.div`
134
172
  justify-content: center;
135
173
  flex-wrap: wrap;
136
174
  flex-direction: row;
175
+ touch-action: none;
137
176
  `;
138
177
 
139
178
  const EquipmentColumn = styled.div`
@@ -141,4 +180,5 @@ const EquipmentColumn = styled.div`
141
180
  justify-content: center;
142
181
  flex-wrap: wrap;
143
182
  flex-direction: column;
183
+ touch-action: none;
144
184
  `;
@@ -4,8 +4,12 @@ export interface IInputProps
4
4
  extends React.DetailedHTMLProps<
5
5
  React.InputHTMLAttributes<HTMLInputElement>,
6
6
  HTMLInputElement
7
- > {}
7
+ > {
8
+ innerRef?: React.Ref<HTMLInputElement>;
9
+ }
8
10
 
9
11
  export const Input: React.FC<IInputProps> = ({ ...props }) => {
10
- return <input {...props} />;
12
+ const { innerRef, ...rest } = props;
13
+
14
+ return <input {...rest} ref={props.innerRef} />;
11
15
  };
@@ -1,8 +1,10 @@
1
1
  import { IItem, IItemContainer, ItemContainerType } from '@rpg-engine/shared';
2
- import React from 'react';
2
+ import React, { useState } from 'react';
3
3
  import styled from 'styled-components';
4
4
  import { SlotsContainer } from '../../Abstractions/SlotsContainer';
5
+ import { ItemQuantitySelector } from './ItemQuantitySelector';
5
6
 
7
+ import { IPosition } from '../../../types/eventTypes';
6
8
  import { ItemSlot } from './ItemSlot';
7
9
 
8
10
  export interface IItemContainerProps {
@@ -13,12 +15,26 @@ export interface IItemContainerProps {
13
15
  ItemType: IItem['type'],
14
16
  itemContainerType: ItemContainerType | null
15
17
  ) => void;
18
+ onItemDragStart?: (
19
+ item: IItem,
20
+ slotIndex: number,
21
+ itemContainerType: ItemContainerType | null
22
+ ) => void;
23
+ onItemDragEnd?: (quantity?: number) => void;
24
+ onOutsideDrop?: (item: IItem, position: IPosition) => void;
25
+ onItemPlaceDrop?: (
26
+ item: IItem | null,
27
+ slotIndex: number,
28
+ itemContainerType: ItemContainerType | null
29
+ ) => void;
30
+ checkIfItemCanBeMoved: () => boolean;
16
31
  onMouseOver?: (e: any, slotIndex: number, item: IItem | null) => void;
17
32
  onSelected?: (optionId: string, item: IItem) => void;
18
33
  type: ItemContainerType;
19
34
  atlasJSON: any;
20
35
  atlasIMG: any;
21
36
  disableContextMenu?: boolean;
37
+ initialPosition?: { x: number; y: number };
22
38
  }
23
39
 
24
40
  export const ItemContainer: React.FC<IItemContainerProps> = ({
@@ -31,7 +47,19 @@ export const ItemContainer: React.FC<IItemContainerProps> = ({
31
47
  atlasJSON,
32
48
  atlasIMG,
33
49
  disableContextMenu = false,
50
+ onItemDragEnd,
51
+ onItemDragStart,
52
+ onItemPlaceDrop,
53
+ onOutsideDrop,
54
+ checkIfItemCanBeMoved,
55
+ initialPosition,
34
56
  }) => {
57
+ const [quantitySelect, setQuantitySelect] = useState({
58
+ isOpen: false,
59
+ maxQuantity: 1,
60
+ callback: (_quantity: number) => {},
61
+ });
62
+
35
63
  const onRenderSlots = () => {
36
64
  const slots = [];
37
65
 
@@ -52,6 +80,28 @@ export const ItemContainer: React.FC<IItemContainerProps> = ({
52
80
  onSelected={(optionId: string, item: IItem) => {
53
81
  if (onSelected) onSelected(optionId, item);
54
82
  }}
83
+ onDragStart={(item, slotIndex, itemContainerType) => {
84
+ if (onItemDragStart)
85
+ onItemDragStart(item, slotIndex, itemContainerType);
86
+ }}
87
+ onDragEnd={quantity => {
88
+ if (onItemDragEnd) onItemDragEnd(quantity);
89
+ }}
90
+ checkIfItemCanBeMoved={checkIfItemCanBeMoved}
91
+ openQuantitySelector={(maxQuantity, callback) => {
92
+ setQuantitySelect({
93
+ isOpen: true,
94
+ maxQuantity,
95
+ callback,
96
+ });
97
+ }}
98
+ onPlaceDrop={(item, slotIndex, itemContainerType) => {
99
+ if (onItemPlaceDrop)
100
+ onItemPlaceDrop(item, slotIndex, itemContainerType);
101
+ }}
102
+ onOutsideDrop={(item, position) => {
103
+ if (onOutsideDrop) onOutsideDrop(item, position);
104
+ }}
55
105
  atlasIMG={atlasIMG}
56
106
  atlasJSON={atlasJSON}
57
107
  />
@@ -61,11 +111,40 @@ export const ItemContainer: React.FC<IItemContainerProps> = ({
61
111
  };
62
112
 
63
113
  return (
64
- <SlotsContainer title={itemContainer.name || 'Container'} onClose={onClose}>
65
- <ItemsContainer className="item-container-body">
66
- {onRenderSlots()}
67
- </ItemsContainer>
68
- </SlotsContainer>
114
+ <>
115
+ <SlotsContainer
116
+ title={itemContainer.name || 'Container'}
117
+ onClose={onClose}
118
+ initialPosition={initialPosition}
119
+ >
120
+ <ItemsContainer className="item-container-body">
121
+ {onRenderSlots()}
122
+ </ItemsContainer>
123
+ </SlotsContainer>
124
+ {quantitySelect.isOpen && (
125
+ <QuantitySelectorContainer>
126
+ <ItemQuantitySelector
127
+ quantity={quantitySelect.maxQuantity}
128
+ onConfirm={quantity => {
129
+ quantitySelect.callback(quantity);
130
+ setQuantitySelect({
131
+ isOpen: false,
132
+ maxQuantity: 1,
133
+ callback: () => {},
134
+ });
135
+ }}
136
+ onClose={() => {
137
+ quantitySelect.callback(-1);
138
+ setQuantitySelect({
139
+ isOpen: false,
140
+ maxQuantity: 1,
141
+ callback: () => {},
142
+ });
143
+ }}
144
+ />
145
+ </QuantitySelectorContainer>
146
+ )}
147
+ </>
69
148
  );
70
149
  };
71
150
 
@@ -75,3 +154,16 @@ const ItemsContainer = styled.div`
75
154
  justify-content: center;
76
155
  flex-wrap: wrap;
77
156
  `;
157
+
158
+ const QuantitySelectorContainer = styled.div`
159
+ position: absolute;
160
+ top: 0;
161
+ left: 0;
162
+ width: 100vw;
163
+ height: 100vh;
164
+ z-index: 100;
165
+ display: flex;
166
+ justify-content: center;
167
+ align-items: center;
168
+ background-color: rgba(0, 0, 0, 0.5);
169
+ `;