@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.
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpg-engine/long-bow",
3
- "version": "0.3.38",
3
+ "version": "0.3.40",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -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 { ITradeResponseItem, getItemTextureKeyPath } from '@rpg-engine/shared';
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
- ></SelectArrow>
97
+ />
79
98
  <QuantityDisplay>
80
99
  <TextOverlay>
81
100
  <Item>{selectedQty}</Item>
82
101
  </TextOverlay>
83
102
  </QuantityDisplay>
84
- <SelectArrow
103
+ <StyledArrow
85
104
  size={32}
86
105
  className="arrow-selector"
87
106
  direction="right"
88
107
  onClick={onRightClick}
89
108
  onTouchStart={onRightClick}
90
- ></SelectArrow>
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: 20%;
192
+ flex: 40%;
163
193
  `;
164
194
 
165
195
  const QuantityDisplay = styled.div`
@@ -80,7 +80,7 @@ export const TradingMenu: React.FC<ITrandingMenu> = ({
80
80
  onCloseButton={() => {
81
81
  if (onClose) onClose();
82
82
  }}
83
- width="500px"
83
+ width="600px"
84
84
  cancelDrag=".equipment-container-body .arrow-selector"
85
85
  >
86
86
  <>
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
+ };