@rpg-engine/long-bow 0.1.82 → 0.1.85

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 (89) hide show
  1. package/dist/components/Button.d.ts +1 -0
  2. package/dist/components/Equipment/EquipmentSet.d.ts +3 -1
  3. package/dist/components/Item/Cards/ItemTooltip.d.ts +6 -0
  4. package/dist/components/Item/Inventory/ItemContainer.d.ts +3 -5
  5. package/dist/components/Item/Inventory/ItemContainerTypes.d.ts +4 -0
  6. package/dist/components/Item/Inventory/ItemSlot.d.ts +4 -7
  7. package/dist/components/PropertySelect/PropertySelect.d.ts +12 -0
  8. package/dist/components/QuestInfo/QuestInfo.d.ts +14 -0
  9. package/dist/components/RelativeListMenu.d.ts +13 -0
  10. package/dist/components/shared/SpriteIcon.d.ts +2 -0
  11. package/dist/index.d.ts +1 -0
  12. package/dist/long-bow.cjs.development.js +407 -813
  13. package/dist/long-bow.cjs.development.js.map +1 -1
  14. package/dist/long-bow.cjs.production.min.js +1 -1
  15. package/dist/long-bow.cjs.production.min.js.map +1 -1
  16. package/dist/long-bow.esm.js +402 -811
  17. package/dist/long-bow.esm.js.map +1 -1
  18. package/dist/stories/Button.stories.d.ts +5 -0
  19. package/dist/stories/Chat.stories.d.ts +5 -0
  20. package/dist/stories/CheckButton.stories.d.ts +5 -0
  21. package/dist/stories/DraggableContainer.stories.d.ts +5 -0
  22. package/dist/stories/Dropdown.stories.d.ts +5 -0
  23. package/dist/stories/EquipmentSet.stories.d.ts +5 -0
  24. package/dist/stories/ItemContainer.stories.d.ts +5 -0
  25. package/dist/stories/ListMenu.stories.d.ts +5 -0
  26. package/dist/stories/Multitab.stories.d.ts +6 -0
  27. package/dist/stories/NPCDialog.stories.d.ts +7 -0
  28. package/dist/stories/ProgressBar.stories.d.ts +8 -0
  29. package/dist/stories/PropertySelect.stories.d.ts +5 -0
  30. package/dist/stories/QuestInfo.stories.d.ts +5 -0
  31. package/dist/stories/RPGUIContainers.stories.d.ts +5 -0
  32. package/dist/stories/RadioButton.stories.d.ts +5 -0
  33. package/dist/stories/RangeSlider.stories.d.ts +5 -0
  34. package/dist/stories/ScrollList.stories.d.ts +5 -0
  35. package/dist/stories/SimpleProgressBar.stories.d.ts +5 -0
  36. package/dist/stories/SkillProgressBar.stories.d.ts +5 -0
  37. package/dist/stories/SkillsContainer.stories.d.ts +5 -0
  38. package/dist/stories/Text.stories.d.ts +7 -0
  39. package/package.json +2 -2
  40. package/src/components/Button.tsx +3 -2
  41. package/src/components/Equipment/EquipmentSet.tsx +97 -142
  42. package/src/components/Item/Cards/ItemTooltip.tsx +32 -0
  43. package/src/components/Item/Inventory/ItemContainer.tsx +47 -95
  44. package/src/components/Item/Inventory/ItemContainerTypes.ts +4 -0
  45. package/src/components/Item/Inventory/ItemSlot.tsx +145 -104
  46. package/src/components/NPCDialog/QuestionDialog/QuestionDialog.tsx +0 -3
  47. package/src/components/PropertySelect/PropertySelect.tsx +101 -0
  48. package/src/components/PropertySelect/img/ui-arrows/arrow01-left-clicked.png +0 -0
  49. package/src/components/PropertySelect/img/ui-arrows/arrow01-left.png +0 -0
  50. package/src/components/PropertySelect/img/ui-arrows/arrow01-right-clicked.png +0 -0
  51. package/src/components/PropertySelect/img/ui-arrows/arrow01-right.png +0 -0
  52. package/src/components/PropertySelect/img/ui-arrows/arrow02-left-clicked.png +0 -0
  53. package/src/components/PropertySelect/img/ui-arrows/arrow02-left.png +0 -0
  54. package/src/components/PropertySelect/img/ui-arrows/arrow02-right-clicked.png +0 -0
  55. package/src/components/PropertySelect/img/ui-arrows/arrow02-right.png +0 -0
  56. package/src/components/QuestInfo/QuestInfo.tsx +143 -0
  57. package/src/components/QuestInfo/img/default.png +0 -0
  58. package/src/components/RelativeListMenu.tsx +83 -0
  59. package/src/components/SkillsContainer.tsx +15 -1
  60. package/src/components/shared/SpriteIcon.tsx +4 -2
  61. package/src/index.tsx +1 -0
  62. package/src/mocks/atlas/icons/icons.json +494 -62
  63. package/src/mocks/atlas/icons/icons.png +0 -0
  64. package/src/mocks/itemContainer.mocks.ts +1 -1
  65. package/src/stories/Button.stories.tsx +36 -0
  66. package/src/stories/Chat.stories.tsx +170 -0
  67. package/src/stories/CheckButton.stories.tsx +48 -0
  68. package/src/stories/DraggableContainer.stories.tsx +28 -0
  69. package/src/stories/Dropdown.stories.tsx +46 -0
  70. package/src/stories/EquipmentSet.stories.tsx +50 -0
  71. package/src/stories/ItemContainer.stories.tsx +50 -0
  72. package/src/stories/ListMenu.stories.tsx +56 -0
  73. package/src/stories/Multitab.stories.tsx +51 -0
  74. package/src/stories/NPCDialog.stories.tsx +130 -0
  75. package/src/stories/ProgressBar.stories.tsx +23 -0
  76. package/src/stories/PropertySelect.stories.tsx +41 -0
  77. package/src/stories/QuestInfo.stories.tsx +76 -0
  78. package/src/stories/RPGUIContainers.stories.tsx +42 -0
  79. package/src/stories/RadioButton.stories.tsx +49 -0
  80. package/src/stories/RangeSlider.stories.tsx +60 -0
  81. package/src/stories/ScrollList.stories.tsx +85 -0
  82. package/src/stories/SimpleProgressBar.stories.tsx +22 -0
  83. package/src/stories/SkillProgressBar.stories.tsx +30 -0
  84. package/src/stories/SkillsContainer.stories.tsx +31 -0
  85. package/src/stories/Text.stories.tsx +42 -0
  86. package/dist/components/Item/Cards/ItemCard.d.ts +0 -9
  87. package/dist/components/store/UI.store.d.ts +0 -34
  88. package/src/components/Item/Cards/ItemCard.tsx +0 -36
  89. package/src/components/store/UI.store.ts +0 -192
@@ -1,14 +1,18 @@
1
1
  import { IItem, IItemContainer, ItemSlotType } from '@rpg-engine/shared';
2
- import React from 'react';
2
+
3
+ import { observer } from 'mobx-react-lite';
4
+ import React, { useEffect, useState } from 'react';
3
5
  import styled from 'styled-components';
4
6
  import atlasJSON from '../../../mocks/atlas/items/items.json';
5
7
  import atlasIMG from '../../../mocks/atlas/items/items.png';
8
+ import { RelativeListMenu } from '../../RelativeListMenu';
6
9
  import { SpriteFromAtlas } from '../../shared/SpriteFromAtlas';
7
-
8
- export enum SlotContainerType {
9
- INVENTORY = 'Inventory',
10
- EQUIPMENT_SET = 'EquipmentSet',
11
- }
10
+ import { ItemTooltip } from '../Cards/ItemTooltip';
11
+ import {
12
+ handleEquipmentContextMenuList,
13
+ IContextMenuItem,
14
+ } from './itemContainerHelper';
15
+ import { SlotContainerType } from './ItemContainerTypes';
12
16
 
13
17
  const EquipmentSlotSpriteByType: any = {
14
18
  Neck: 'accessories/corruption-necklace.png',
@@ -29,6 +33,7 @@ interface IProps {
29
33
  itemContainer?: IItemContainer | null;
30
34
  slotContainerType: SlotContainerType | null;
31
35
  slotSpriteMask?: ItemSlotType | null;
36
+ onSelected: (payload: any) => void;
32
37
  onMouseOver: (
33
38
  event: any,
34
39
  slotIndex: number,
@@ -36,108 +41,143 @@ interface IProps {
36
41
  x: number,
37
42
  y: number
38
43
  ) => void;
39
- onMouseOut: () => void;
40
- onClick: (
41
- item: IItem,
42
- posX: number,
43
- posY: number,
44
- slotContainerType: SlotContainerType | null
45
- ) => void;
46
- onCancelContextMenu: () => void;
44
+ onMouseOut?: () => void;
45
+ onClick: (item: IItem, slotContainerType: SlotContainerType | null) => void;
47
46
  }
48
47
 
49
- export const ItemSlot: React.FC<IProps> = ({
50
- slotIndex,
51
- item,
52
- slotContainerType,
53
- slotSpriteMask,
54
- onMouseOver,
55
- onMouseOut,
56
- onClick,
57
- onCancelContextMenu,
58
- }) => {
59
- const getLeftPositionValue = (quantity: number) => {
60
- if (quantity > 0 && quantity < 10) return '2.5rem';
61
- else if (quantity > 9 && quantity < 100) return '2.0rem';
62
- else if (quantity > 99) return '1rem';
63
- return '2.5rem';
64
- };
65
-
66
- const renderItem = (itemToRender: IItem | null) => {
67
- const element = [];
68
- if (itemToRender?.texturePath) {
69
- element.push(
70
- <SpriteFromAtlas
71
- atlasIMG={atlasIMG}
72
- atlasJSON={atlasJSON}
73
- spriteKey={itemToRender.texturePath}
74
- imgScale={3}
75
- />
76
- );
77
- }
78
- if (itemToRender?.isStackable && itemToRender?.stackQty) {
79
- element.push(
80
- <ItemQty left={getLeftPositionValue(itemToRender.stackQty)}>
81
- {' '}
82
- {itemToRender.stackQty}{' '}
83
- </ItemQty>
84
- );
85
- }
86
- return element;
87
- };
88
-
89
- const renderEquipment = (itemToRender: IItem | null) => {
90
- if (
91
- itemToRender?.texturePath &&
92
- itemToRender.allowedEquipSlotType?.includes(slotSpriteMask!)
93
- ) {
94
- return (
95
- <SpriteFromAtlas
96
- atlasIMG={atlasIMG}
97
- atlasJSON={atlasJSON}
98
- spriteKey={itemToRender.texturePath}
99
- imgScale={3}
100
- />
101
- );
102
- } else {
103
- return (
104
- <SpriteFromAtlas
105
- atlasIMG={atlasIMG}
106
- atlasJSON={atlasJSON}
107
- spriteKey={EquipmentSlotSpriteByType[slotSpriteMask!]}
108
- imgScale={3}
109
- grayScale={true}
110
- opacity={0.4}
111
- />
112
- );
113
- }
114
- };
115
-
116
- const onRenderSlot = (itemToRender: IItem | null) => {
117
- if (slotContainerType === SlotContainerType.EQUIPMENT_SET)
118
- return renderEquipment(itemToRender);
119
- return renderItem(itemToRender);
120
- };
121
-
122
- return (
123
- <Container
124
- className="rpgui-icon empty-slot"
125
- onMouseOver={event =>
126
- onMouseOver(event, slotIndex, item, event.clientX, event.clientY)
48
+ export const ItemSlot: React.FC<IProps> = observer(
49
+ ({
50
+ slotIndex,
51
+ item,
52
+ slotContainerType,
53
+ slotSpriteMask,
54
+ onMouseOver,
55
+ onMouseOut,
56
+ onClick,
57
+ onSelected,
58
+ }) => {
59
+ const [isTooltipVisible, setTooltipVisible] = useState(false);
60
+
61
+ const [isContextMenuVisible, setIsContextMenuVisible] = useState(false);
62
+
63
+ const [contextActions, setContextActions] = useState<IContextMenuItem[]>(
64
+ []
65
+ );
66
+
67
+ useEffect(() => {
68
+ if (item) {
69
+ setContextActions(handleEquipmentContextMenuList(item.type));
70
+ }
71
+ }, [item]);
72
+
73
+ const getLeftPositionValue = (quantity: number) => {
74
+ if (quantity > 0 && quantity < 10) return '2.5rem';
75
+ else if (quantity > 9 && quantity < 100) return '2.0rem';
76
+ else if (quantity > 99) return '1rem';
77
+ return '2.5rem';
78
+ };
79
+
80
+ const renderItem = (itemToRender: IItem | null) => {
81
+ const element = [];
82
+ if (itemToRender?.texturePath) {
83
+ element.push(
84
+ <SpriteFromAtlas
85
+ key={itemToRender._id}
86
+ atlasIMG={atlasIMG}
87
+ atlasJSON={atlasJSON}
88
+ spriteKey={itemToRender.texturePath}
89
+ imgScale={3}
90
+ />
91
+ );
92
+ }
93
+ if (itemToRender?.isStackable && itemToRender?.stackQty) {
94
+ element.push(
95
+ <ItemQty
96
+ left={getLeftPositionValue(itemToRender.stackQty)}
97
+ key={`qty-${itemToRender._id}`}
98
+ >
99
+ {' '}
100
+ {itemToRender.stackQty}{' '}
101
+ </ItemQty>
102
+ );
127
103
  }
128
- onMouseOut={() => onMouseOut()}
129
- onClick={e => {
130
- if (item) {
131
- onClick(item, e.clientX, e.clientY, slotContainerType);
132
- } else {
133
- onCancelContextMenu();
104
+ return element;
105
+ };
106
+
107
+ const renderEquipment = (itemToRender: IItem | null) => {
108
+ if (
109
+ itemToRender?.texturePath &&
110
+ itemToRender.allowedEquipSlotType?.includes(slotSpriteMask!)
111
+ ) {
112
+ return (
113
+ <SpriteFromAtlas
114
+ key={itemToRender._id}
115
+ atlasIMG={atlasIMG}
116
+ atlasJSON={atlasJSON}
117
+ spriteKey={itemToRender.texturePath}
118
+ imgScale={3}
119
+ />
120
+ );
121
+ } else {
122
+ return (
123
+ <SpriteFromAtlas
124
+ atlasIMG={atlasIMG}
125
+ atlasJSON={atlasJSON}
126
+ spriteKey={EquipmentSlotSpriteByType[slotSpriteMask!]}
127
+ imgScale={3}
128
+ grayScale={true}
129
+ opacity={0.4}
130
+ />
131
+ );
132
+ }
133
+ };
134
+
135
+ const onRenderSlot = (itemToRender: IItem | null) => {
136
+ if (slotContainerType === SlotContainerType.EQUIPMENT_SET)
137
+ return renderEquipment(itemToRender);
138
+ return renderItem(itemToRender);
139
+ };
140
+
141
+ return (
142
+ <Container
143
+ className="rpgui-icon empty-slot"
144
+ onMouseOver={event =>
145
+ onMouseOver(event, slotIndex, item, event.clientX, event.clientY)
134
146
  }
135
- }}
136
- >
137
- {onRenderSlot(item)}
138
- </Container>
139
- );
140
- };
147
+ onMouseOut={() => {
148
+ if (onMouseOut) onMouseOut();
149
+ }}
150
+ onMouseEnter={() => setTooltipVisible(true)}
151
+ onMouseLeave={() => setTooltipVisible(false)}
152
+ onClick={() => {
153
+ setTooltipVisible(false);
154
+
155
+ if (item) {
156
+ setIsContextMenuVisible(!isContextMenuVisible);
157
+ onClick(item, slotContainerType);
158
+ }
159
+ }}
160
+ >
161
+ {isContextMenuVisible && contextActions && (
162
+ <RelativeListMenu
163
+ options={contextActions}
164
+ onSelected={(optionId: string) => {
165
+ setIsContextMenuVisible(false);
166
+ onSelected(optionId);
167
+ }}
168
+ onOutsideClick={() => {
169
+ setIsContextMenuVisible(false);
170
+ }}
171
+ />
172
+ )}
173
+
174
+ {isTooltipVisible && item && <ItemTooltip label={item.name} />}
175
+
176
+ {onRenderSlot(item)}
177
+ </Container>
178
+ );
179
+ }
180
+ );
141
181
 
142
182
  const Container = styled.div`
143
183
  margin: 0.1rem;
@@ -146,6 +186,7 @@ const Container = styled.div`
146
186
  top: 1.5rem;
147
187
  left: 1.5rem;
148
188
  }
189
+ position: relative;
149
190
  `;
150
191
 
151
192
  interface IItemQtyProps {
@@ -191,9 +191,7 @@ export const QuestionDialog: React.FC<IProps> = ({
191
191
 
192
192
  const Container = styled.div`
193
193
  display: flex;
194
-
195
194
  word-break: break-all;
196
-
197
195
  box-sizing: border-box;
198
196
  justify-content: flex-start;
199
197
  align-items: flex-start;
@@ -233,7 +231,6 @@ const AnswerRow = styled.div`
233
231
  align-items: center;
234
232
  margin-bottom: 0.5rem;
235
233
  height: 22px;
236
-
237
234
  p {
238
235
  line-height: unset;
239
236
  margin-top: 0;
@@ -0,0 +1,101 @@
1
+ import React, { useState } from 'react';
2
+ import styled from 'styled-components';
3
+ import LeftArrowClickIcon from './img/ui-arrows/arrow01-left-clicked.png';
4
+ import LeftArrowIcon from './img/ui-arrows/arrow01-left.png';
5
+ import RightArrowClickIcon from './img/ui-arrows/arrow01-right-clicked.png';
6
+ import RightArrowIcon from './img/ui-arrows/arrow01-right.png';
7
+
8
+ export interface IPropertySelectProps {
9
+ availableProperties: Array<IPropertiesProps>;
10
+ selectedProperty: object;
11
+ children?: React.ReactNode;
12
+ }
13
+
14
+ export interface IPropertiesProps {
15
+ id: string;
16
+ name: string;
17
+ }
18
+
19
+ export const PropertySelect: React.FC<IPropertySelectProps> = ({
20
+ availableProperties,
21
+ }) => {
22
+ const [currentIndex, setCurrentIndex] = useState(0);
23
+ const propertiesLength = availableProperties.length - 1;
24
+
25
+ const onLeftClick = () => {
26
+ if (currentIndex === 0) setCurrentIndex(propertiesLength);
27
+ else setCurrentIndex(index => index - 1);
28
+ };
29
+ const onRightClick = () => {
30
+ if (currentIndex === propertiesLength) setCurrentIndex(0);
31
+ else setCurrentIndex(index => index + 1);
32
+ };
33
+ return (
34
+ <Container>
35
+ <TextOverlay>
36
+ <Item>{availableProperties[currentIndex].name}</Item>
37
+ </TextOverlay>
38
+ <div className="rpgui-progress-track"></div>
39
+ <LeftArrow onClick={onLeftClick}></LeftArrow>
40
+ <RightArrow onClick={onRightClick}></RightArrow>
41
+ </Container>
42
+ );
43
+ };
44
+
45
+ const Item = styled.span`
46
+ font-size: 1rem;
47
+ color: white;
48
+ text-align: center;
49
+ z-index: 1;
50
+ position: absolute;
51
+ left: 50%;
52
+ transform: translateX(-50%);
53
+ top: 12px;
54
+ `;
55
+
56
+ const TextOverlay = styled.div`
57
+ width: 100%;
58
+ position: relative;
59
+ `;
60
+
61
+ interface IContainerProps {
62
+ percentageWidth?: number;
63
+ minWidth?: number;
64
+ style?: Record<string, any>;
65
+ }
66
+
67
+ const Container = styled.div<IContainerProps>`
68
+ position: relative;
69
+ display: flex;
70
+ flex-direction: column;
71
+ justify-content: start;
72
+ align-items: flex-start;
73
+ min-width: 100px;
74
+ width: 40%;
75
+ `;
76
+
77
+ const LeftArrow = styled.div`
78
+ background-image: url(${LeftArrowIcon});
79
+ background-size: 100% 100%;
80
+ left: 0;
81
+ position: absolute;
82
+ width: 40px;
83
+ height: 42px;
84
+ :active {
85
+ background-image: url(${LeftArrowClickIcon});
86
+ }
87
+ `;
88
+
89
+ const RightArrow = styled.div`
90
+ background-image: url(${RightArrowIcon});
91
+ right: 0;
92
+ position: absolute;
93
+ width: 40px;
94
+ background-size: 100% 100%;
95
+ height: 42px;
96
+ :active {
97
+ background-image: url(${RightArrowClickIcon});
98
+ }
99
+ `;
100
+
101
+ export default PropertySelect;
@@ -0,0 +1,143 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+ import { Button, ButtonTypes } from '../Button';
4
+ import { DraggableContainer } from '../DraggableContainer';
5
+ import { RPGUIContainerTypes } from '../RPGUIContainer';
6
+ import { Column } from '../shared/Column';
7
+
8
+ import thumbnailDefault from './img/default.png';
9
+
10
+ export interface IQuestInfoProps {
11
+ title: string;
12
+ children: React.ReactNode;
13
+ onClose?: () => void;
14
+ button?: Array<IQuestButtonProps>;
15
+ thumbnail?: string;
16
+ }
17
+
18
+ export interface IQuestButtonProps {
19
+ disabled: boolean;
20
+ title: string;
21
+ onClick: () => void;
22
+ }
23
+
24
+ export const QuestInfo: React.FC<IQuestInfoProps> = ({
25
+ title,
26
+ onClose,
27
+ button,
28
+ thumbnail,
29
+ children,
30
+ }) => {
31
+ return (
32
+ <QuestDraggableContainer
33
+ type={RPGUIContainerTypes.Framed}
34
+ onCloseButton={() => {
35
+ if (onClose) onClose();
36
+ }}
37
+ width="730px"
38
+ cancelDrag=".equipment-container-body"
39
+ >
40
+ {title && (
41
+ <TitleContainer className="drag-handler">
42
+ <Title>
43
+ <Thumbnail src={thumbnail || thumbnailDefault} />
44
+ {title}
45
+ </Title>
46
+ <QuestSplitDiv>
47
+ <hr className="golden" />
48
+ </QuestSplitDiv>
49
+ </TitleContainer>
50
+ )}
51
+ <Content>{children}</Content>
52
+ <QuestColumn className="dark-background" justifyContent="flex-end">
53
+ {button &&
54
+ button.map((item, index) => (
55
+ <Button
56
+ key={index}
57
+ onClick={item.onClick}
58
+ disabled={item.disabled}
59
+ buttonType={ButtonTypes.RPGUIButton}
60
+ id={`button-${index}`}
61
+ >
62
+ {item.title}
63
+ </Button>
64
+ ))}
65
+ </QuestColumn>
66
+ </QuestDraggableContainer>
67
+ );
68
+ };
69
+
70
+ const QuestDraggableContainer = styled(DraggableContainer)`
71
+ border: 1px solid black;
72
+ width: 600px;
73
+ height: 500px;
74
+ overflow-y: scroll;
75
+ padding: 0 0 0 0 !important;
76
+ .DraggableContainer__TitleContainer-sc-184mpyl-2 {
77
+ height: auto;
78
+ }
79
+ .container-close {
80
+ position: sticky;
81
+ margin-left: auto;
82
+ top: 10px;
83
+ padding-right: 5px;
84
+ }
85
+ img {
86
+ display: inline-block;
87
+ vertical-align: middle;
88
+ line-height: normal;
89
+ }
90
+ `;
91
+
92
+ const Content = styled.div`
93
+ padding: 18px;
94
+ h1 {
95
+ text-align: left;
96
+ margin: 14px 0px;
97
+ }
98
+ `;
99
+
100
+ const QuestSplitDiv = styled.div`
101
+ width: 100%;
102
+ font-size: 11px;
103
+ margin-bottom: 10px;
104
+ hr {
105
+ margin: 0px;
106
+ padding: 0px;
107
+ }
108
+ p {
109
+ margin-bottom: 0px;
110
+ }
111
+ `;
112
+
113
+ const QuestColumn = styled(Column)`
114
+ background: #4e4a4e;
115
+ padding-top: 5px;
116
+ position: sticky;
117
+ bottom: 0;
118
+ `;
119
+
120
+ const TitleContainer = styled.div`
121
+ background: #4e4a4e;
122
+ position: sticky;
123
+ top: 0;
124
+ width: 100%;
125
+ display: flex;
126
+ flex-wrap: wrap;
127
+ justify-content: flex-start;
128
+ align-items: center;
129
+ `;
130
+
131
+ const Title = styled.h1`
132
+ color: white;
133
+ z-index: 22;
134
+ font-size: 0.6rem;
135
+ `;
136
+
137
+ const Thumbnail = styled.img`
138
+ color: white;
139
+ z-index: 22;
140
+ font-size: 10px;
141
+ width: 64px;
142
+ margin-right: 0.5rem;
143
+ `;
@@ -0,0 +1,83 @@
1
+ import React, { useEffect, useRef } from 'react';
2
+ import styled from 'styled-components';
3
+ import { useOutsideClick } from '../hooks/useOutsideAlerter';
4
+
5
+ interface IListMenuOption {
6
+ id: string;
7
+ text: string;
8
+ }
9
+
10
+ export interface IRelativeMenuProps {
11
+ options: IListMenuOption[];
12
+ onSelected: (selectedOptionId: string) => void;
13
+ fontSize?: number;
14
+ onOutsideClick?: () => void;
15
+ }
16
+
17
+ export const RelativeListMenu: React.FC<IRelativeMenuProps> = ({
18
+ options,
19
+ onSelected,
20
+ onOutsideClick,
21
+ fontSize = 0.8,
22
+ }) => {
23
+ const ref = useRef(null);
24
+
25
+ useOutsideClick(ref, 'relative-context-menu');
26
+
27
+ useEffect(() => {
28
+ document.addEventListener('clickOutside', event => {
29
+ const e = event as CustomEvent;
30
+
31
+ if (e.detail.id === 'relative-context-menu') {
32
+ if (onOutsideClick) {
33
+ onOutsideClick();
34
+ }
35
+ }
36
+ });
37
+
38
+ return () => {
39
+ document.removeEventListener('clickOutside', _e => {});
40
+ };
41
+ }, []);
42
+
43
+ return (
44
+ <Container fontSize={fontSize} ref={ref}>
45
+ <ul className="rpgui-list-imp" style={{ overflow: 'hidden' }}>
46
+ {options.map((params, index) => (
47
+ <ListElement
48
+ key={params?.id || index}
49
+ onClick={() => {
50
+ onSelected(params?.id);
51
+ }}
52
+ >
53
+ {params?.text || 'No text'}
54
+ </ListElement>
55
+ ))}
56
+ </ul>
57
+ </Container>
58
+ );
59
+ };
60
+
61
+ interface IContainerProps {
62
+ fontSize?: number;
63
+ }
64
+
65
+ const Container = styled.div<IContainerProps>`
66
+ position: absolute;
67
+ top: 1rem;
68
+ left: 4rem;
69
+
70
+ display: flex;
71
+ flex-direction: column;
72
+ width: 100%;
73
+ justify-content: start;
74
+ align-items: flex-start;
75
+
76
+ li {
77
+ font-size: ${props => props.fontSize}em;
78
+ }
79
+ `;
80
+
81
+ const ListElement = styled.li`
82
+ margin-right: 0.5rem;
83
+ `;
@@ -15,7 +15,12 @@ export const SkillsContainer: React.FC<ISkillContainerProps> = ({
15
15
  skill,
16
16
  }) => {
17
17
  return (
18
- <SkillsDraggableContainer title="Skills" onCloseButton={onCloseButton}>
18
+ <SkillsDraggableContainer title="Skills">
19
+ {onCloseButton && (
20
+ <CloseButton onClick={onCloseButton} onTouchStart={onCloseButton}>
21
+ X
22
+ </CloseButton>
23
+ )}
19
24
  <SkillSplitDiv>
20
25
  <p>Combat Skills</p>
21
26
  <hr className="golden" />
@@ -233,3 +238,12 @@ const SkillSplitDiv = styled.div`
233
238
  margin-bottom: 0px;
234
239
  }
235
240
  `;
241
+
242
+ const CloseButton = styled.div`
243
+ position: absolute;
244
+ top: 2px;
245
+ right: 2px;
246
+ color: white;
247
+ z-index: 22;
248
+ font-size: 0.7rem;
249
+ `;