@rpg-engine/long-bow 0.3.38 → 0.3.40
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/dist/components/CircularController/CircularController.d.ts +10 -0
- package/dist/components/Spellbook/QuickSpells.d.ts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/long-bow.cjs.development.js +160 -62
- package/dist/long-bow.cjs.development.js.map +1 -1
- package/dist/long-bow.cjs.production.min.js +1 -1
- package/dist/long-bow.cjs.production.min.js.map +1 -1
- package/dist/long-bow.esm.js +159 -63
- package/dist/long-bow.esm.js.map +1 -1
- package/dist/stories/CircullarController.stories.d.ts +5 -0
- package/package.json +1 -1
- package/src/components/CircularController/CircularController.tsx +162 -0
- package/src/components/Spellbook/QuickSpells.tsx +5 -1
- package/src/components/TradingMenu/TradingItemRow.tsx +35 -5
- package/src/components/TradingMenu/TradingMenu.tsx +1 -1
- package/src/index.tsx +1 -0
- package/src/stories/CircullarController.stories.tsx +33 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Meta } from '@storybook/react';
|
|
2
|
+
import { CircularControllerProps } from '../components/CircularController/CircularController';
|
|
3
|
+
declare const meta: Meta;
|
|
4
|
+
export default meta;
|
|
5
|
+
export declare const Default: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, CircularControllerProps>;
|
package/package.json
CHANGED
|
@@ -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
|
+
`;
|
|
@@ -57,7 +57,7 @@ export const QuickSpells: React.FC<QuickSpellsProps> = ({
|
|
|
57
57
|
);
|
|
58
58
|
};
|
|
59
59
|
|
|
60
|
-
const SpellShortcut = styled.button`
|
|
60
|
+
export const SpellShortcut = styled.button`
|
|
61
61
|
width: 3rem;
|
|
62
62
|
height: 3rem;
|
|
63
63
|
background-color: ${uiColors.lightGray};
|
|
@@ -71,6 +71,10 @@ const SpellShortcut = styled.button`
|
|
|
71
71
|
justify-content: center;
|
|
72
72
|
position: relative;
|
|
73
73
|
|
|
74
|
+
span {
|
|
75
|
+
pointer-events: none;
|
|
76
|
+
}
|
|
77
|
+
|
|
74
78
|
.mana {
|
|
75
79
|
position: absolute;
|
|
76
80
|
top: -5px;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getItemTextureKeyPath, ITradeResponseItem } from '@rpg-engine/shared';
|
|
2
2
|
import capitalize from 'lodash/capitalize';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import styled from 'styled-components';
|
|
@@ -37,6 +37,18 @@ export const TradingItemRow: React.FC<ITradeComponentProps> = ({
|
|
|
37
37
|
onQuantityChange(traderItem, newQuantity);
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
|
+
const onLeftOutClick = () => {
|
|
41
|
+
if (selectedQty >= 10) {
|
|
42
|
+
const newQuantity = selectedQty - 10;
|
|
43
|
+
onQuantityChange(traderItem, newQuantity);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const onRightOutClick = () => {
|
|
47
|
+
if (selectedQty < (traderItem.qty ?? 999)) {
|
|
48
|
+
const newQuantity = selectedQty + 10;
|
|
49
|
+
onQuantityChange(traderItem, newQuantity);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
40
52
|
|
|
41
53
|
return (
|
|
42
54
|
<ItemWrapper>
|
|
@@ -70,29 +82,47 @@ export const TradingItemRow: React.FC<ITradeComponentProps> = ({
|
|
|
70
82
|
|
|
71
83
|
<QuantityContainer>
|
|
72
84
|
<SelectArrow
|
|
85
|
+
size={32}
|
|
86
|
+
className="arrow-selector"
|
|
87
|
+
direction="left"
|
|
88
|
+
onClick={onLeftOutClick}
|
|
89
|
+
onTouchStart={onLeftOutClick}
|
|
90
|
+
/>
|
|
91
|
+
<StyledArrow
|
|
73
92
|
size={32}
|
|
74
93
|
className="arrow-selector"
|
|
75
94
|
direction="left"
|
|
76
95
|
onClick={onLeftClick}
|
|
77
96
|
onTouchStart={onLeftClick}
|
|
78
|
-
|
|
97
|
+
/>
|
|
79
98
|
<QuantityDisplay>
|
|
80
99
|
<TextOverlay>
|
|
81
100
|
<Item>{selectedQty}</Item>
|
|
82
101
|
</TextOverlay>
|
|
83
102
|
</QuantityDisplay>
|
|
84
|
-
<
|
|
103
|
+
<StyledArrow
|
|
85
104
|
size={32}
|
|
86
105
|
className="arrow-selector"
|
|
87
106
|
direction="right"
|
|
88
107
|
onClick={onRightClick}
|
|
89
108
|
onTouchStart={onRightClick}
|
|
90
|
-
|
|
109
|
+
/>
|
|
110
|
+
<SelectArrow
|
|
111
|
+
size={32}
|
|
112
|
+
className="arrow-selector"
|
|
113
|
+
direction="right"
|
|
114
|
+
onClick={onRightOutClick}
|
|
115
|
+
onTouchStart={onRightOutClick}
|
|
116
|
+
/>
|
|
91
117
|
</QuantityContainer>
|
|
92
118
|
</ItemWrapper>
|
|
93
119
|
);
|
|
94
120
|
};
|
|
95
121
|
|
|
122
|
+
const StyledArrow = styled(SelectArrow)`
|
|
123
|
+
margin: 40px;
|
|
124
|
+
`;
|
|
125
|
+
|
|
96
126
|
const ItemWrapper = styled.div`
|
|
97
127
|
width: 100%;
|
|
98
128
|
margin: auto;
|
|
@@ -159,7 +189,7 @@ const QuantityContainer = styled.div<IContainerProps>`
|
|
|
159
189
|
justify-content: center;
|
|
160
190
|
align-items: center;
|
|
161
191
|
|
|
162
|
-
flex:
|
|
192
|
+
flex: 40%;
|
|
163
193
|
`;
|
|
164
194
|
|
|
165
195
|
const QuantityDisplay = styled.div`
|
package/src/index.tsx
CHANGED
|
@@ -3,6 +3,7 @@ export * from './components/Character/CharacterSelection';
|
|
|
3
3
|
export * from './components/Chat/Chat';
|
|
4
4
|
export * from './components/Chatdeprecated/ChatDeprecated';
|
|
5
5
|
export * from './components/CheckButton';
|
|
6
|
+
export * from './components/CircularController/CircularController';
|
|
6
7
|
export * from './components/CraftBook/CraftBook';
|
|
7
8
|
export * from './components/DraggableContainer';
|
|
8
9
|
export * from './components/Dropdown';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Meta, Story } from '@storybook/react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { RPGUIRoot } from '..';
|
|
4
|
+
import {
|
|
5
|
+
CircularController,
|
|
6
|
+
CircularControllerProps,
|
|
7
|
+
} from '../components/CircularController/CircularController';
|
|
8
|
+
import { SPELL_SHORTCUTS_STORAGE_KEY } from '../components/Spellbook/constants';
|
|
9
|
+
|
|
10
|
+
const meta: Meta = {
|
|
11
|
+
title: 'Circular Controller',
|
|
12
|
+
component: CircularController,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default meta;
|
|
16
|
+
|
|
17
|
+
const Template: Story<CircularControllerProps> = args => (
|
|
18
|
+
<RPGUIRoot>
|
|
19
|
+
<CircularController {...args} />
|
|
20
|
+
</RPGUIRoot>
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
export const Default = Template.bind({});
|
|
24
|
+
|
|
25
|
+
Default.args = {
|
|
26
|
+
spells: JSON.parse(
|
|
27
|
+
localStorage.getItem(SPELL_SHORTCUTS_STORAGE_KEY) as string
|
|
28
|
+
),
|
|
29
|
+
onSpellClick: key => console.log(key),
|
|
30
|
+
onActionClick: () => console.log('action'),
|
|
31
|
+
onCancelClick: () => console.log('cancel attack'),
|
|
32
|
+
mana: 100,
|
|
33
|
+
};
|