@rpg-engine/long-bow 0.3.44 → 0.3.46

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 (103) hide show
  1. package/dist/components/Abstractions/SlotsContainer.d.ts +1 -0
  2. package/dist/components/Button.d.ts +3 -2
  3. package/dist/components/Chat/Chat.d.ts +12 -2
  4. package/dist/components/Chatdeprecated/ChatDeprecated.d.ts +13 -0
  5. package/dist/components/CheckButton.d.ts +1 -2
  6. package/dist/components/CircularController/CircularController.d.ts +10 -0
  7. package/dist/components/CraftBook/CraftBook.d.ts +15 -0
  8. package/dist/components/CraftBook/MockItems.d.ts +2 -0
  9. package/dist/components/DraggableContainer.d.ts +1 -0
  10. package/dist/components/DropdownSelectorContainer.d.ts +13 -0
  11. package/dist/components/Equipment/EquipmentSet.d.ts +8 -0
  12. package/dist/components/Input.d.ts +1 -0
  13. package/dist/components/Item/Inventory/ItemContainer.d.ts +12 -0
  14. package/dist/components/Item/Inventory/ItemQuantitySelector.d.ts +7 -0
  15. package/dist/components/Item/Inventory/ItemSlot.d.ts +9 -0
  16. package/dist/components/NPCDialog/NPCDialogText.d.ts +4 -2
  17. package/dist/components/RadioInput/RadioButton.d.ts +8 -0
  18. package/dist/components/RadioInput/RadioInput.d.ts +13 -0
  19. package/dist/components/RadioInput/instruments.d.ts +4 -0
  20. package/dist/components/RangeSlider.d.ts +1 -0
  21. package/dist/components/Spellbook/QuickSpells.d.ts +10 -0
  22. package/dist/components/Spellbook/Spell.d.ts +11 -0
  23. package/dist/components/Spellbook/Spellbook.d.ts +15 -0
  24. package/dist/components/Spellbook/SpellbookShortcuts.d.ts +10 -0
  25. package/dist/components/Spellbook/constants.d.ts +3 -0
  26. package/dist/components/Spellbook/mockSpells.d.ts +2 -0
  27. package/dist/components/itemSelector/ItemSelector.d.ts +14 -0
  28. package/dist/constants/uiDevices.d.ts +1 -0
  29. package/dist/index.d.ts +8 -0
  30. package/dist/long-bow.cjs.development.js +7464 -515
  31. package/dist/long-bow.cjs.development.js.map +1 -1
  32. package/dist/long-bow.cjs.production.min.js +1 -1
  33. package/dist/long-bow.cjs.production.min.js.map +1 -1
  34. package/dist/long-bow.esm.js +7458 -518
  35. package/dist/long-bow.esm.js.map +1 -1
  36. package/dist/mocks/equipmentSet.mocks.d.ts +15 -2
  37. package/dist/mocks/skills.mocks.d.ts +2 -121
  38. package/dist/stories/ChatDeprecated.stories.d.ts +5 -0
  39. package/dist/stories/CircullarController.stories.d.ts +5 -0
  40. package/dist/stories/CraftBook.stories.d.ts +4 -0
  41. package/dist/stories/DropdownSelectorContainer.stories.d.ts +5 -0
  42. package/dist/stories/ItemQuantitySelector.stories.d.ts +5 -0
  43. package/dist/stories/ItemSelector.stories.d.ts +4 -0
  44. package/dist/stories/QuickSpells.stories.d.ts +5 -0
  45. package/dist/stories/RadioInput.stories.d.ts +5 -0
  46. package/dist/stories/Spellbook.stories.d.ts +5 -0
  47. package/package.json +5 -2
  48. package/src/components/Abstractions/SlotsContainer.tsx +3 -0
  49. package/src/components/Button.tsx +18 -8
  50. package/src/components/Chat/Chat.tsx +105 -105
  51. package/src/components/Chatdeprecated/ChatDeprecated.tsx +200 -0
  52. package/src/components/CheckButton.tsx +1 -1
  53. package/src/components/CircularController/CircularController.tsx +162 -0
  54. package/src/components/CraftBook/CraftBook.tsx +230 -0
  55. package/src/components/CraftBook/MockItems.ts +46 -0
  56. package/src/components/DraggableContainer.tsx +4 -1
  57. package/src/components/Dropdown.tsx +7 -1
  58. package/src/components/DropdownSelectorContainer.tsx +42 -0
  59. package/src/components/Equipment/EquipmentSet.tsx +46 -0
  60. package/src/components/Input.tsx +6 -2
  61. package/src/components/Item/Inventory/ItemContainer.tsx +104 -6
  62. package/src/components/Item/Inventory/ItemQuantitySelector.tsx +142 -0
  63. package/src/components/Item/Inventory/ItemSlot.tsx +234 -34
  64. package/src/components/NPCDialog/NPCDialog.tsx +4 -28
  65. package/src/components/NPCDialog/NPCDialogText.tsx +75 -15
  66. package/src/components/NPCDialog/img/press-button.gif +0 -0
  67. package/src/components/RadioInput/RadioButton.tsx +98 -0
  68. package/src/components/RadioInput/RadioInput.tsx +99 -0
  69. package/src/components/RadioInput/instruments.ts +16 -0
  70. package/src/components/RangeSlider.tsx +37 -14
  71. package/src/components/SkillsContainer.tsx +1 -1
  72. package/src/components/Spellbook/QuickSpells.tsx +120 -0
  73. package/src/components/Spellbook/Spell.tsx +201 -0
  74. package/src/components/Spellbook/Spellbook.tsx +144 -0
  75. package/src/components/Spellbook/SpellbookShortcuts.tsx +77 -0
  76. package/src/components/Spellbook/constants.ts +12 -0
  77. package/src/components/Spellbook/mockSpells.ts +60 -0
  78. package/src/components/TimeWidget/TimeWidget.tsx +1 -0
  79. package/src/components/TradingMenu/TradingItemRow.tsx +43 -6
  80. package/src/components/TradingMenu/TradingMenu.tsx +1 -1
  81. package/src/components/itemSelector/ItemSelector.tsx +136 -0
  82. package/src/components/shared/SpriteFromAtlas.tsx +4 -1
  83. package/src/constants/uiDevices.ts +5 -0
  84. package/src/hooks/useOutsideAlerter.ts +2 -2
  85. package/src/index.tsx +8 -0
  86. package/src/mocks/atlas/items/items.json +6086 -314
  87. package/src/mocks/atlas/items/items.png +0 -0
  88. package/src/mocks/equipmentSet.mocks.ts +49 -4
  89. package/src/mocks/itemContainer.mocks.ts +54 -6
  90. package/src/mocks/skills.mocks.ts +8 -2
  91. package/src/stories/Chat.stories.tsx +20 -3
  92. package/src/stories/ChatDeprecated.stories.tsx +170 -0
  93. package/src/stories/CircullarController.stories.tsx +33 -0
  94. package/src/stories/CraftBook.stories.tsx +40 -0
  95. package/src/stories/DropdownSelectorContainer.stories.tsx +41 -0
  96. package/src/stories/EquipmentSet.stories.tsx +10 -0
  97. package/src/stories/ItemContainer.stories.tsx +84 -15
  98. package/src/stories/ItemQuantitySelector.stories.tsx +26 -0
  99. package/src/stories/ItemSelector.stories.tsx +77 -0
  100. package/src/stories/QuickSpells.stories.tsx +38 -0
  101. package/src/stories/RadioInput.stories.tsx +35 -0
  102. package/src/stories/RangeSlider.stories.tsx +10 -9
  103. package/src/stories/Spellbook.stories.tsx +107 -0
@@ -0,0 +1,200 @@
1
+ import { IChatMessage } from '@rpg-engine/shared';
2
+ import dayjs from 'dayjs';
3
+ import React, { useEffect, useState } from 'react';
4
+ import { ErrorBoundary } from 'react-error-boundary';
5
+ import styled from 'styled-components';
6
+ import { uiColors } from '../../constants/uiColors';
7
+ import { uiFonts } from '../../constants/uiFonts';
8
+ import { Button, ButtonTypes } from '../Button';
9
+ import { Input } from '../Input';
10
+ import { RPGUIContainer, RPGUIContainerTypes } from '../RPGUIContainer';
11
+ import { Column } from '../shared/Column';
12
+
13
+ interface IEmitter {
14
+ _id: string;
15
+ name: string;
16
+ }
17
+ export interface IChatDeprecatedProps {
18
+ chatMessages: IChatMessage[];
19
+ onSendChatMessage: (message: string) => void;
20
+ onCloseButton: () => void;
21
+ onFocus?: () => void;
22
+ onBlur?: () => void;
23
+ opacity?: number;
24
+ width?: string;
25
+ height?: string;
26
+ }
27
+
28
+ export const ChatDeprecated: React.FC<IChatDeprecatedProps> = ({
29
+ chatMessages,
30
+ onSendChatMessage,
31
+ opacity = 1,
32
+ width = '100%',
33
+ height = '250px',
34
+ onCloseButton,
35
+ onFocus,
36
+ onBlur,
37
+ }) => {
38
+ const [message, setMessage] = useState('');
39
+
40
+ useEffect(() => {
41
+ scrollChatToBottom();
42
+ }, []);
43
+
44
+ useEffect(() => {
45
+ scrollChatToBottom();
46
+ }, [chatMessages]);
47
+
48
+ const scrollChatToBottom = () => {
49
+ const scrollingElement = document.querySelector('.chat-body');
50
+ if (scrollingElement) {
51
+ scrollingElement.scrollTop = scrollingElement.scrollHeight;
52
+ }
53
+ };
54
+
55
+ const handleSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
56
+ event.preventDefault();
57
+ onSendChatMessage(message);
58
+ setMessage('');
59
+ };
60
+ const getInputValue = (value: string) => {
61
+ setMessage(value);
62
+ };
63
+
64
+ const onRenderMessageLines = (
65
+ emitter: IEmitter,
66
+ createdAt: string | undefined,
67
+ message: string
68
+ ) => {
69
+ return `${dayjs(createdAt || new Date()).format('HH:mm')} ${
70
+ emitter?.name ? `${emitter.name}: ` : 'Unknown: '
71
+ } ${message}`;
72
+ };
73
+
74
+ const onRenderChatMessages = (chatMessages: IChatMessage[]) => {
75
+ return chatMessages?.length ? (
76
+ chatMessages?.map(({ _id, createdAt, emitter, message }, index) => (
77
+ <MessageText key={`${_id}_${index}`}>
78
+ {onRenderMessageLines(emitter, createdAt as string, message)}
79
+ </MessageText>
80
+ ))
81
+ ) : (
82
+ <MessageText>No messages available.</MessageText>
83
+ );
84
+ };
85
+
86
+ return (
87
+ <Container>
88
+ <CustomContainer
89
+ type={RPGUIContainerTypes.FramedGrey}
90
+ width={width}
91
+ height={height}
92
+ className="chat-container"
93
+ opacity={opacity}
94
+ >
95
+ <ErrorBoundary fallback={<p>Oops! Your chat has crashed.</p>}>
96
+ {onCloseButton && (
97
+ <CloseButton onClick={onCloseButton} onTouchStart={onCloseButton}>
98
+ X
99
+ </CloseButton>
100
+ )}
101
+ <RPGUIContainer
102
+ type={RPGUIContainerTypes.FramedGrey}
103
+ width={'100%'}
104
+ height={'80%'}
105
+ className="chat-body dark-background"
106
+ >
107
+ {onRenderChatMessages(chatMessages)}
108
+ </RPGUIContainer>
109
+
110
+ <Form onSubmit={handleSubmit}>
111
+ <Column flex={70}>
112
+ <CustomInput
113
+ value={message}
114
+ id="inputMessage"
115
+ onChange={e => getInputValue(e.target.value)}
116
+ height={20}
117
+ className="chat-input dark-background"
118
+ type="text"
119
+ autoComplete="off"
120
+ onFocus={onFocus}
121
+ onBlur={onBlur}
122
+ />
123
+ </Column>
124
+ <Column justifyContent="flex-end">
125
+ <Button
126
+ buttonType={ButtonTypes.RPGUIButton}
127
+ id="chat-send-button"
128
+ >
129
+ Send
130
+ </Button>
131
+ </Column>
132
+ </Form>
133
+ </ErrorBoundary>
134
+ </CustomContainer>
135
+ </Container>
136
+ );
137
+ };
138
+
139
+ const Container = styled.div`
140
+ position: relative;
141
+ `;
142
+
143
+ const CloseButton = styled.div`
144
+ position: absolute;
145
+ top: 2px;
146
+ right: 0px;
147
+ color: white;
148
+ z-index: 22;
149
+ font-size: 0.7rem;
150
+ `;
151
+
152
+ const CustomInput = styled(Input)`
153
+ height: 30px;
154
+ width: 100%;
155
+
156
+ .rpgui-content .input {
157
+ min-height: 39px;
158
+ }
159
+ `;
160
+
161
+ interface ICustomContainerProps {
162
+ opacity: number;
163
+ }
164
+
165
+ const CustomContainer = styled(RPGUIContainer)`
166
+ display: block;
167
+
168
+ opacity: ${(props: ICustomContainerProps) => props.opacity};
169
+
170
+ &:hover {
171
+ opacity: 1;
172
+ }
173
+
174
+ .dark-background {
175
+ background-color: ${uiColors.darkGray} !important;
176
+ }
177
+
178
+ .chat-body {
179
+ &.rpgui-container.framed-grey {
180
+ background: unset;
181
+ }
182
+ max-height: 170px;
183
+ overflow-y: auto;
184
+ }
185
+ `;
186
+
187
+ const Form = styled.form`
188
+ display: flex;
189
+ width: 100%;
190
+ justify-content: center;
191
+ align-items: center;
192
+ `;
193
+
194
+ const MessageText = styled.p`
195
+ display: block !important;
196
+ width: 100%;
197
+ font-size: ${uiFonts.size.xsmall} !important;
198
+ overflow-y: auto;
199
+ margin: 0;
200
+ `;
@@ -10,7 +10,7 @@ export interface ICheckProps {
10
10
  onChange: (selectedValues: IChecklistSelectedValues) => void;
11
11
  }
12
12
 
13
- interface IChecklistSelectedValues {
13
+ export interface IChecklistSelectedValues {
14
14
  [label: string]: boolean;
15
15
  }
16
16
 
@@ -0,0 +1,162 @@
1
+ import { IRawSpell } from '@rpg-engine/shared';
2
+ import React from 'react';
3
+ import styled from 'styled-components';
4
+ import { uiColors } from '../../constants/uiColors';
5
+ import { SpellShortcut } from '../Spellbook/QuickSpells';
6
+
7
+ export type CircularControllerProps = {
8
+ onActionClick: () => void;
9
+ onCancelClick: () => void;
10
+ onSpellClick: (spellKey: string) => void;
11
+ mana: number;
12
+ spells: IRawSpell[];
13
+ };
14
+
15
+ export const CircularController: React.FC<CircularControllerProps> = ({
16
+ onActionClick,
17
+ onCancelClick,
18
+ onSpellClick,
19
+ mana,
20
+ spells,
21
+ }) => {
22
+ const onTouchStart = (e: React.TouchEvent<HTMLButtonElement>) => {
23
+ const target = e.target as HTMLButtonElement;
24
+ target?.classList.add('active');
25
+ };
26
+
27
+ const onTouchEnd = (
28
+ action: () => void,
29
+ e: React.TouchEvent<HTMLButtonElement>
30
+ ) => {
31
+ const target = e.target as HTMLButtonElement;
32
+ setTimeout(() => {
33
+ target?.classList.remove('active');
34
+ }, 100);
35
+ action();
36
+ };
37
+
38
+ return (
39
+ <ButtonsContainer>
40
+ <SpellsContainer>
41
+ {Array.from({ length: 4 }).map((_, i) => {
42
+ const variant = i === 0 ? 'top' : i === 3 ? 'bottom' : '';
43
+ const spell = spells[i];
44
+
45
+ const onSpellClickBinded = spell
46
+ ? onSpellClick.bind(null, spell.key)
47
+ : () => {};
48
+
49
+ return (
50
+ <StyledShortcut
51
+ key={i}
52
+ disabled={mana < spell?.manaCost}
53
+ onTouchStart={onTouchStart}
54
+ onTouchEnd={onTouchEnd.bind(null, onSpellClickBinded)}
55
+ className={variant}
56
+ >
57
+ <span className="mana">{spell?.key && spell?.manaCost}</span>
58
+ <span className="magicWords">
59
+ {spell?.magicWords.split(' ').map(word => word[0])}
60
+ </span>
61
+ </StyledShortcut>
62
+ );
63
+ })}
64
+ </SpellsContainer>
65
+ <Button
66
+ onTouchStart={onTouchStart}
67
+ onTouchEnd={onTouchEnd.bind(null, onActionClick)}
68
+ >
69
+ <div className="rpgui-icon sword" />
70
+ </Button>
71
+
72
+ <CancelButton
73
+ onTouchStart={onTouchStart}
74
+ onTouchEnd={onTouchEnd.bind(null, onCancelClick)}
75
+ >
76
+ <span>X</span>
77
+ </CancelButton>
78
+ </ButtonsContainer>
79
+ );
80
+ };
81
+
82
+ const Button = styled.button`
83
+ width: 4.3rem;
84
+ height: 4.3rem;
85
+ background-color: ${uiColors.lightGray};
86
+ border: 2px solid ${uiColors.darkGray};
87
+ border-radius: 50%;
88
+ text-transform: uppercase;
89
+ font-size: 0.7rem;
90
+ font-weight: bold;
91
+ display: flex;
92
+ align-items: center;
93
+ justify-content: center;
94
+ position: relative;
95
+ transition: background-color 0.1s;
96
+
97
+ &.active {
98
+ background-color: ${uiColors.gray};
99
+ }
100
+
101
+ .sword {
102
+ transform: rotate(-45deg);
103
+ height: 2.5rem;
104
+ width: 1.9rem;
105
+ pointer-events: none;
106
+ }
107
+ `;
108
+
109
+ const CancelButton = styled(Button)`
110
+ width: 3rem;
111
+ height: 3rem;
112
+ font-size: 0.8rem;
113
+
114
+ span {
115
+ margin-top: 4px;
116
+ margin-left: 2px;
117
+ pointer-events: none;
118
+ }
119
+ `;
120
+
121
+ const ButtonsContainer = styled.div`
122
+ display: flex;
123
+ align-items: center;
124
+ justify-content: center;
125
+ gap: 0.5rem;
126
+ `;
127
+
128
+ const SpellsContainer = styled.div`
129
+ display: flex;
130
+ align-items: center;
131
+ justify-content: center;
132
+ gap: 0.4rem;
133
+ flex-direction: column;
134
+
135
+ .top {
136
+ transform: translate(93%, 25%);
137
+ }
138
+
139
+ .bottom {
140
+ transform: translate(93%, -25%);
141
+ }
142
+ `;
143
+
144
+ const StyledShortcut = styled(SpellShortcut)`
145
+ width: 2.5rem;
146
+ height: 2.5rem;
147
+ transition: background-color 0.1s;
148
+
149
+ .mana {
150
+ font-size: 0.5rem;
151
+ }
152
+
153
+ &:hover,
154
+ &:focus,
155
+ &:active {
156
+ background-color: ${uiColors.lightGray};
157
+ }
158
+
159
+ &.active {
160
+ background-color: ${uiColors.gray};
161
+ }
162
+ `;
@@ -0,0 +1,230 @@
1
+ import { ICraftableItem, ItemSubType } from '@rpg-engine/shared';
2
+ import React, { useState } from 'react';
3
+ import styled from 'styled-components';
4
+ import { Button, ButtonTypes } from '../Button';
5
+ import { DraggableContainer } from '../DraggableContainer';
6
+ import { Dropdown, IOptionsProps } from '../Dropdown';
7
+ import { RPGUIContainerTypes } from '../RPGUIContainer';
8
+ import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
9
+
10
+ export interface IItemCraftSelectorProps {
11
+ atlasJSON: any;
12
+ atlasIMG: any;
13
+ onClose: () => void;
14
+ onSelect: (value: string) => void;
15
+ onCraftItem: (value: string | undefined) => void;
16
+ craftablesItems: ICraftableItem[];
17
+ }
18
+
19
+ export interface ShowMessage {
20
+ show: boolean;
21
+ index: number;
22
+ }
23
+
24
+ export const CraftBook: React.FC<IItemCraftSelectorProps> = ({
25
+ atlasIMG,
26
+ atlasJSON,
27
+ onClose,
28
+ onSelect,
29
+ onCraftItem,
30
+ craftablesItems,
31
+ }) => {
32
+ let optionsId: number = 0;
33
+ const [isShown, setIsShown] = useState<ShowMessage>({
34
+ show: false,
35
+ index: 200,
36
+ });
37
+ const [craftItem, setCraftItem] = useState<string>();
38
+
39
+ const getDropdownOptions = () => {
40
+ const options: IOptionsProps[] = [];
41
+
42
+ Object.keys(ItemSubType).forEach(key => {
43
+ if (key === 'CraftingResource' || key === 'DeadBody') {
44
+ return; // we can't craft crafting resouces...
45
+ }
46
+
47
+ options.push({
48
+ id: optionsId,
49
+ value: key,
50
+ option: key,
51
+ });
52
+ optionsId += 1;
53
+ });
54
+
55
+ return options;
56
+ };
57
+
58
+ const modifyString = (str: string) => {
59
+ // Split the string by "/" and "."
60
+ let parts = str.split('/');
61
+ let fileName = parts[parts.length - 1];
62
+ parts = fileName.split('.');
63
+ let name = parts[0];
64
+
65
+ // Replace all occurrences of "-" with " "
66
+ name = name.replace(/-/g, ' ');
67
+
68
+ // Uppercase the first word
69
+ let words = name.split(' ');
70
+ let firstWord = words[0].slice(0, 1).toUpperCase() + words[0].slice(1);
71
+ let modifiedWords = [firstWord].concat(words.slice(1));
72
+ name = modifiedWords.join(' ');
73
+
74
+ return name;
75
+ };
76
+
77
+ const handleClick = (value: string) => {
78
+ setCraftItem(value);
79
+ };
80
+
81
+ return (
82
+ <DraggableContainer
83
+ type={RPGUIContainerTypes.Framed}
84
+ width="500px"
85
+ cancelDrag=".equipment-container-body .arrow-selector .rpgui-dropdown-imp"
86
+ onCloseButton={() => {
87
+ if (onClose) {
88
+ onClose();
89
+ }
90
+ }}
91
+ >
92
+ <div style={{ width: '100%' }}>
93
+ <Title>{'Craftbook'}</Title>
94
+ <Subtitle>{'Select an item to craft'}</Subtitle>
95
+ <hr className="golden" />
96
+ </div>
97
+ <Dropdown
98
+ options={getDropdownOptions()}
99
+ onChange={value => onSelect(value)}
100
+ />
101
+ <RadioInputScroller>
102
+ {craftablesItems?.map((option, index) => (
103
+ <RadioOptionsWrapper key={index}>
104
+ <SpriteAtlasWrapper>
105
+ <SpriteFromAtlas
106
+ atlasIMG={atlasIMG}
107
+ atlasJSON={atlasJSON}
108
+ spriteKey={option.texturePath}
109
+ imgScale={3}
110
+ grayScale={!option.canCraft}
111
+ />
112
+ </SpriteAtlasWrapper>
113
+ <div>
114
+ <input
115
+ className="rpgui-radio"
116
+ type="radio"
117
+ value={option.name}
118
+ name="test"
119
+ disabled={!option.canCraft}
120
+ checked={craftItem === option.key}
121
+ onChange={() => handleClick(option.key)}
122
+ />
123
+ <label
124
+ onClick={() => {
125
+ handleClick(option.key);
126
+ }}
127
+ onTouchStart={() => {
128
+ setIsShown({ show: true, index: index });
129
+ }}
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
158
+ buttonType={ButtonTypes.RPGUIButton}
159
+ onClick={onClose}
160
+ onTouchStart={onClose}
161
+ >
162
+ Cancel
163
+ </Button>
164
+ <Button
165
+ buttonType={ButtonTypes.RPGUIButton}
166
+ onClick={() => onCraftItem(craftItem)}
167
+ onTouchStart={() => onCraftItem(craftItem)}
168
+ >
169
+ Craft
170
+ </Button>
171
+ </ButtonWrapper>
172
+ </DraggableContainer>
173
+ );
174
+ };
175
+
176
+ const StyledItem = styled.div`
177
+ margin-left: 10px;
178
+ `;
179
+
180
+ const Recipes = styled.div`
181
+ font-size: 0.6rem;
182
+ color: yellow !important;
183
+ margin-bottom: 3px;
184
+ display: flex;
185
+ align-items: center;
186
+
187
+ .sprite-from-atlas-img {
188
+ top: 0px;
189
+ left: 0px;
190
+ }
191
+ `;
192
+
193
+ const Title = styled.h1`
194
+ font-size: 0.6rem;
195
+ color: yellow !important;
196
+ `;
197
+ const Subtitle = styled.h1`
198
+ font-size: 0.4rem;
199
+ color: yellow !important;
200
+ `;
201
+
202
+ const RadioInputScroller = styled.div`
203
+ padding-left: 15px;
204
+ padding-top: 10px;
205
+ width: 100%;
206
+ margin-top: 1rem;
207
+ align-items: center;
208
+ margin-left: 20px;
209
+ align-items: flex-start;
210
+ overflow-y: scroll;
211
+ height: 360px;
212
+ -webkit-overflow-scrolling: touch;
213
+ `;
214
+
215
+ const SpriteAtlasWrapper = styled.div`
216
+ margin-right: 40px;
217
+ `;
218
+
219
+ const RadioOptionsWrapper = styled.div`
220
+ display: flex;
221
+ align-items: stretch;
222
+ margin-bottom: 40px;
223
+ `;
224
+
225
+ const ButtonWrapper = styled.div`
226
+ display: flex;
227
+ justify-content: space-around;
228
+ padding-top: 20px;
229
+ width: 100%;
230
+ `;
@@ -0,0 +1,46 @@
1
+ import { ICraftableItem } from '@rpg-engine/shared';
2
+
3
+ export const craftableItems: ICraftableItem[] = [
4
+ {
5
+ key: 'bandana',
6
+ name: 'Bandana',
7
+ canCraft: true,
8
+ texturePath: 'accessories/bandana.png',
9
+ ingredients: [
10
+ {
11
+ key: 'leather',
12
+ name: 'leather',
13
+ qty: 10,
14
+ texturePath: 'crafting-resources/leather.png',
15
+ },
16
+ ],
17
+ },
18
+ {
19
+ key: 'bandana1',
20
+ name: 'Bandana',
21
+ canCraft: true,
22
+ texturePath: 'accessories/bandana.png',
23
+ ingredients: [
24
+ {
25
+ key: 'leather',
26
+ name: 'leather',
27
+ qty: 10,
28
+ texturePath: 'crafting-resources/leather.png',
29
+ },
30
+ ],
31
+ },
32
+ {
33
+ key: 'bandana2',
34
+ name: 'Bandana',
35
+ canCraft: true,
36
+ texturePath: 'accessories/bandana.png',
37
+ ingredients: [
38
+ {
39
+ key: 'leather',
40
+ name: 'leather',
41
+ qty: 10,
42
+ texturePath: 'crafting-resources/leather.png',
43
+ },
44
+ ],
45
+ },
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}
@@ -120,7 +123,7 @@ const CloseButton = styled.div`
120
123
  right: 0px;
121
124
  color: white;
122
125
  z-index: 22;
123
- font-size: 0.8rem;
126
+ font-size: 1.1rem;
124
127
  `;
125
128
 
126
129
  const TitleContainer = styled.div`
@@ -28,7 +28,7 @@ export const Dropdown: React.FC<IDropdownProps> = ({
28
28
  useEffect(() => {
29
29
  const firstOption = options[0];
30
30
 
31
- if (firstOption) {
31
+ if (firstOption && !selectedValue) {
32
32
  setSelectedValue(firstOption.value);
33
33
  setSelectedOption(firstOption.option);
34
34
  }
@@ -46,6 +46,7 @@ export const Dropdown: React.FC<IDropdownProps> = ({
46
46
  id={`dropdown-${dropdownId}`}
47
47
  className="rpgui-dropdown-imp rpgui-dropdown-imp-header"
48
48
  onClick={() => setOpened(prev => !prev)}
49
+ onTouchStart={() => setOpened(prev => !prev)}
49
50
  >
50
51
  <label>▼</label> {selectedOption}
51
52
  </DropdownSelect>
@@ -60,6 +61,11 @@ export const Dropdown: React.FC<IDropdownProps> = ({
60
61
  setSelectedOption(option.option);
61
62
  setOpened(false);
62
63
  }}
64
+ onTouchStart={() => {
65
+ setSelectedValue(option.value);
66
+ setSelectedOption(option.option);
67
+ setOpened(false);
68
+ }}
63
69
  >
64
70
  {option.option}
65
71
  </li>