@rpg-engine/long-bow 0.1.68 → 0.1.71

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 (47) hide show
  1. package/dist/components/Abstractions/SlotsContainer.d.ts +11 -0
  2. package/dist/components/DraggableContainer.d.ts +3 -2
  3. package/dist/components/Equipment/EquipmentSet.d.ts +13 -0
  4. package/dist/components/Item/Inventory/ItemSlot.d.ts +10 -2
  5. package/dist/components/Item/Inventory/itemContainerHelper.d.ts +6 -2
  6. package/dist/components/Item/SpriteFromAtlas.d.ts +2 -0
  7. package/dist/components/Multitab/Tab.d.ts +9 -0
  8. package/dist/components/Multitab/TabBody.d.ts +7 -0
  9. package/dist/components/Multitab/TabsContainer.d.ts +17 -0
  10. package/dist/components/SimpleProgressBar.d.ts +3 -4
  11. package/dist/components/SkillProgressBar.d.ts +6 -4
  12. package/dist/components/SkillsContainer.d.ts +7 -0
  13. package/dist/components/store/UI.store.d.ts +34 -0
  14. package/dist/constants/uiColors.d.ts +7 -0
  15. package/dist/index.d.ts +1 -0
  16. package/dist/long-bow.cjs.development.js +5258 -419
  17. package/dist/long-bow.cjs.development.js.map +1 -1
  18. package/dist/long-bow.cjs.production.min.js +1 -1
  19. package/dist/long-bow.cjs.production.min.js.map +1 -1
  20. package/dist/long-bow.esm.js +5260 -420
  21. package/dist/long-bow.esm.js.map +1 -1
  22. package/dist/mocks/equipmentSet.mocks.d.ts +3 -0
  23. package/dist/mocks/skills.mocks.d.ts +115 -0
  24. package/package.json +5 -3
  25. package/src/components/Abstractions/SlotsContainer.tsx +42 -0
  26. package/src/components/DraggableContainer.tsx +65 -38
  27. package/src/components/Equipment/EquipmentSet.tsx +179 -0
  28. package/src/components/I_Book.png +0 -0
  29. package/src/components/Item/Inventory/ItemContainer.tsx +70 -178
  30. package/src/components/Item/Inventory/ItemSlot.tsx +92 -24
  31. package/src/components/Item/Inventory/itemContainerHelper.ts +48 -11
  32. package/src/components/Item/SpriteFromAtlas.tsx +18 -1
  33. package/src/components/ListMenu.tsx +3 -3
  34. package/src/components/Multitab/Tab.tsx +57 -0
  35. package/src/components/Multitab/TabBody.tsx +13 -0
  36. package/src/components/Multitab/TabsContainer.tsx +97 -0
  37. package/src/components/SimpleProgressBar.tsx +14 -10
  38. package/src/components/SkillProgressBar.tsx +74 -20
  39. package/src/components/SkillsContainer.tsx +235 -0
  40. package/src/components/store/UI.store.ts +192 -0
  41. package/src/constants/uiColors.ts +7 -0
  42. package/src/index.tsx +1 -0
  43. package/src/mocks/atlas/items/items.json +4677 -189
  44. package/src/mocks/atlas/items/items.png +0 -0
  45. package/src/mocks/equipmentSet.mocks.ts +347 -0
  46. package/src/mocks/itemContainer.mocks.ts +33 -33
  47. package/src/mocks/skills.mocks.ts +116 -0
@@ -1,19 +1,13 @@
1
- import {
2
- IItem,
3
- IItemContainer,
4
- IPayloadProps,
5
- ItemSocketEvents,
6
- } from '@rpg-engine/shared';
7
- import React, { useEffect, useRef, useState } from 'react';
1
+ import { IItem, IItemContainer, ItemSocketEvents } from '@rpg-engine/shared';
2
+ import { observer } from 'mobx-react';
3
+ import React, { useState } from 'react';
8
4
  import styled from 'styled-components';
9
- import { useOutsideClick } from '../../../hooks/useOutsideAlerter';
10
5
  import { IPosition } from '../../../types/eventTypes';
11
- import { DraggableContainer } from '../../DraggableContainer';
6
+ import { SlotsContainer } from '../../Abstractions/SlotsContainer';
12
7
  import { ListMenu } from '../../ListMenu';
13
- import { RPGUIContainerTypes } from '../../RPGUIContainer';
8
+ import { uiStore } from '../../store/UI.store';
14
9
  import { ItemCard } from '../Cards/ItemCard';
15
- import { handleContextMenuList } from './itemContainerHelper';
16
- import { ItemSlot } from './ItemSlot';
10
+ import { ItemSlot, SlotContainerType } from './ItemSlot';
17
11
 
18
12
  export interface IItemContainerProps {
19
13
  itemContainer: IItemContainer;
@@ -23,195 +17,93 @@ export interface IItemContainerProps {
23
17
  initialPosition?: { x: number; y: number };
24
18
  }
25
19
 
26
- interface IContextItemProps {
27
- visible: boolean;
28
- posX: number;
29
- posY: number;
30
- slotItem: IItem | null;
31
- slotIndex?: number | null;
32
- contextActions: any;
33
- }
34
-
35
- interface IHoverDetailProps {
36
- visible: boolean;
37
- posX: number;
38
- posY: number;
39
- item: IItem | null;
40
- }
41
-
42
- export const ItemContainer: React.FC<IItemContainerProps> = ({
43
- itemContainer,
44
- onClose,
45
- onMouseOver,
46
- onActionSelected,
47
- initialPosition = { x: 0, y: 0 },
48
- }) => {
49
- // we use this draggable position to offset the menu position, after the container is dragged (otherwise, it bugs!)
50
- const [draggablePosition, setDraggablePosition] = useState<IPosition>(
51
- initialPosition
52
- );
53
-
54
- const draggableRef = useRef(null);
55
-
56
- useOutsideClick(draggableRef, 'item-container');
57
-
58
- useEffect(() => {
59
- document.addEventListener('clickOutside', event => {
60
- const e = event as CustomEvent;
61
-
62
- if (e.detail.id === 'item-container') {
63
- clearContextMenu();
64
- clearItemHoverDetail();
65
- }
66
- });
67
-
68
- return () => {
69
- document.removeEventListener('clickOutside', _e => {});
20
+ export const ItemContainer: React.FC<IItemContainerProps> = observer(
21
+ ({
22
+ itemContainer,
23
+ onClose,
24
+ onMouseOver,
25
+ onActionSelected,
26
+ initialPosition = { x: 0, y: 0 },
27
+ }) => {
28
+ // we use this draggable position to offset the menu position, after the container is dragged (otherwise, it bugs!)
29
+ const [draggablePosition, setDraggablePosition] = useState<IPosition>(
30
+ initialPosition
31
+ );
32
+
33
+ const handleOnMouseHover = (
34
+ event: any,
35
+ slotIndex: number,
36
+ item: IItem | null,
37
+ x: number,
38
+ y: number
39
+ ) => {
40
+ uiStore.handleOnMouseHover(event, slotIndex, item, x, y, onMouseOver);
70
41
  };
71
- }, []);
72
-
73
- const { x: initX, y: initY } = initialPosition;
74
42
 
75
- const [contextData, setContextData] = useState<IContextItemProps>({
76
- visible: false,
77
- posX: initX,
78
- posY: initY,
79
- contextActions: [],
80
- slotItem: null,
81
- });
82
- const [itemHoverDetail, setItemHoverDetail] = useState<IHoverDetailProps>({
83
- visible: false,
84
- posX: initX,
85
- posY: initY,
86
- item: null,
87
- });
88
-
89
- const clearContextMenu = () => {
90
- setContextData({
91
- visible: false,
92
- posX: 0,
93
- posY: 0,
94
- contextActions: [],
95
- slotItem: null,
96
- });
97
- };
43
+ const onSelected = (selectedActionId: ItemSocketEvents | string): void => {
44
+ uiStore.onSelected(selectedActionId, onActionSelected);
45
+ };
98
46
 
99
- const handleOnMouseHover = (
100
- event: any,
101
- slotIndex: number,
102
- item: IItem | null,
103
- x: number,
104
- y: number
105
- ) => {
106
- if (item) {
107
- setItemHoverDetail({
108
- ...itemHoverDetail,
109
- visible: true,
110
- item: item,
111
- posX: x - draggablePosition.x,
112
- posY: y - draggablePosition.y,
113
- });
114
- if (onMouseOver) {
115
- onMouseOver(event, slotIndex, item);
47
+ const onRenderSlots = () => {
48
+ const slots = [];
49
+
50
+ for (let i = 0; i < itemContainer.slotQty; i++) {
51
+ slots.push(
52
+ <ItemSlot
53
+ key={i}
54
+ slotIndex={i}
55
+ item={itemContainer.slots?.[i] || null}
56
+ slotContainerType={SlotContainerType.INVENTORY}
57
+ onMouseOver={handleOnMouseHover}
58
+ onClick={uiStore.handleOnItemClick}
59
+ onMouseOut={() => {
60
+ uiStore.clearItemHoverDetail();
61
+ }}
62
+ onCancelContextMenu={() => {
63
+ uiStore.clearContextMenu();
64
+ }}
65
+ />
66
+ );
116
67
  }
117
- } else {
118
- clearItemHoverDetail();
119
- }
120
- };
121
-
122
- const clearItemHoverDetail = () => {
123
- setItemHoverDetail({
124
- ...itemHoverDetail,
125
- visible: false,
126
- item: null,
127
- });
128
- };
129
-
130
- const handleOnItemClick = (item: IItem, posX: number, posY: number) => {
131
- const contextList = handleContextMenuList(item.type);
132
-
133
- setContextData({
134
- ...contextData,
135
- visible: true,
136
- posX,
137
- posY,
138
- slotItem: item,
139
- contextActions: contextList,
140
- });
141
- clearItemHoverDetail();
142
- };
143
-
144
- const onSelected = (selectedActionId: ItemSocketEvents | string): void => {
145
- let payloadData: IPayloadProps = {
146
- actionType: selectedActionId,
147
- item: contextData.slotItem,
68
+ return slots;
148
69
  };
149
- if (onActionSelected) {
150
- onActionSelected(payloadData);
151
- }
152
- clearContextMenu();
153
- };
154
-
155
- const onRenderSlots = () => {
156
- const slots = [];
157
-
158
- for (let i = 0; i < itemContainer.slotQty; i++) {
159
- slots.push(
160
- <ItemSlot
161
- key={i}
162
- slotIndex={i}
163
- item={itemContainer.slots?.[i] || null}
164
- onMouseOver={handleOnMouseHover}
165
- onClick={handleOnItemClick}
166
- onCancelContextMenu={() => {
167
- clearContextMenu();
168
- }}
169
- />
170
- );
171
- }
172
- return slots;
173
- };
174
70
 
175
- return (
176
- <div ref={draggableRef}>
177
- <DraggableContainer
71
+ return (
72
+ <SlotsContainer
178
73
  title={itemContainer.name || 'Container'}
179
- type={RPGUIContainerTypes.Framed}
180
- onCloseButton={() => {
181
- if (onClose) {
182
- onClose();
183
- }
184
- }}
185
- width="330px"
186
- cancelDrag=".item-container-body"
187
74
  onPositionChange={({ x, y }) => {
188
75
  setDraggablePosition({ x, y });
189
76
  }}
77
+ onOutsideClick={() => {
78
+ uiStore.clearContextMenu();
79
+ uiStore.clearItemHoverDetail();
80
+ }}
81
+ onClose={onClose}
190
82
  >
191
83
  <ItemsContainer className="item-container-body">
192
84
  {onRenderSlots()}
193
85
  </ItemsContainer>
194
86
 
195
- {contextData.visible ? (
87
+ {uiStore.contextMenu?.visible ? (
196
88
  <ListMenu
197
- x={contextData.posX - draggablePosition.x}
198
- y={contextData.posY - draggablePosition.y}
199
- options={contextData.contextActions}
89
+ x={uiStore.contextMenu.posX - draggablePosition.x}
90
+ y={uiStore.contextMenu.posY - draggablePosition.y}
91
+ options={uiStore.contextMenu.contextActions}
200
92
  onSelected={onSelected}
201
93
  />
202
94
  ) : null}
203
95
 
204
- {itemHoverDetail.visible ? (
96
+ {uiStore.onHoverDetail?.visible ? (
205
97
  <ItemCard
206
- item={itemHoverDetail.item}
207
- x={itemHoverDetail.posX}
208
- y={itemHoverDetail.posY}
98
+ item={uiStore.onHoverDetail.item}
99
+ x={uiStore.onHoverDetail.posX}
100
+ y={uiStore.onHoverDetail.posY}
209
101
  />
210
102
  ) : null}
211
- </DraggableContainer>
212
- </div>
213
- );
214
- };
103
+ </SlotsContainer>
104
+ );
105
+ }
106
+ );
215
107
 
216
108
  const ItemsContainer = styled.div`
217
109
  max-width: 280px;
@@ -1,12 +1,34 @@
1
- import { IItem } from '@rpg-engine/shared';
1
+ import { IItem, IItemContainer, ItemSlotType } from '@rpg-engine/shared';
2
2
  import React from 'react';
3
3
  import styled from 'styled-components';
4
4
  import atlasJSON from '../../../mocks/atlas/items/items.json';
5
5
  import atlasIMG from '../../../mocks/atlas/items/items.png';
6
6
  import { SpriteFromAtlas } from '../SpriteFromAtlas';
7
+
8
+ export enum SlotContainerType {
9
+ INVENTORY = 'Inventory',
10
+ EQUIPMENT_SET = 'EquipmentSet',
11
+ }
12
+
13
+ const EquipmentSlotSpriteByType: any = {
14
+ Neck: 'accessories/corruption-necklace.png',
15
+ LeftHand: 'swords/broad-sword.png',
16
+ Ring: 'rings/iron-ring.png',
17
+ Head: 'helmets/viking-helmet.png',
18
+ Torso: 'armors/iron-armor.png',
19
+ Legs: 'crafting-resources/medicinal-leaf.png',
20
+ Feet: 'boots/iron-boots.png',
21
+ Inventory: 'containers/bag.png',
22
+ RightHand: 'shields/plate-shield.png',
23
+ Accessory: 'gloves/plate-gloves.png',
24
+ };
25
+
7
26
  interface IProps {
8
27
  slotIndex: number;
9
28
  item: IItem | null;
29
+ itemContainer?: IItemContainer | null;
30
+ slotContainerType: SlotContainerType | null;
31
+ slotSpriteMask?: ItemSlotType | null;
10
32
  onMouseOver: (
11
33
  event: any,
12
34
  slotIndex: number,
@@ -14,14 +36,23 @@ interface IProps {
14
36
  x: number,
15
37
  y: number
16
38
  ) => void;
17
- onClick: (item: IItem, posX: number, posY: number) => void;
39
+ onMouseOut: () => void;
40
+ onClick: (
41
+ item: IItem,
42
+ posX: number,
43
+ posY: number,
44
+ slotContainerType: SlotContainerType | null
45
+ ) => void;
18
46
  onCancelContextMenu: () => void;
19
47
  }
20
48
 
21
49
  export const ItemSlot: React.FC<IProps> = ({
22
50
  slotIndex,
23
51
  item,
52
+ slotContainerType,
53
+ slotSpriteMask,
24
54
  onMouseOver,
55
+ onMouseOut,
25
56
  onClick,
26
57
  onCancelContextMenu,
27
58
  }) => {
@@ -32,51 +63,88 @@ export const ItemSlot: React.FC<IProps> = ({
32
63
  return '2.5rem';
33
64
  };
34
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
+ scale={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
+ scale={3}
100
+ />
101
+ );
102
+ } else {
103
+ return (
104
+ <SpriteFromAtlas
105
+ atlasIMG={atlasIMG}
106
+ atlasJSON={atlasJSON}
107
+ spriteKey={EquipmentSlotSpriteByType[slotSpriteMask!]}
108
+ scale={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
+
35
122
  return (
36
123
  <Container
37
124
  className="rpgui-icon empty-slot"
38
125
  onMouseOver={event =>
39
126
  onMouseOver(event, slotIndex, item, event.clientX, event.clientY)
40
127
  }
128
+ onMouseOut={() => onMouseOut()}
41
129
  onClick={e => {
42
130
  if (item) {
43
- console.log(e);
44
- onClick(item, e.clientX, e.clientY);
131
+ onClick(item, e.clientX, e.clientY, slotContainerType);
45
132
  } else {
46
133
  onCancelContextMenu();
47
134
  }
48
135
  }}
49
136
  >
50
- {item && item.texturePath ? (
51
- <SpriteFromAtlas
52
- atlasIMG={atlasIMG}
53
- atlasJSON={atlasJSON}
54
- spriteKey={item.texturePath}
55
- scale={3}
56
- />
57
- ) : null}
58
- {item && item.isStackable && item?.stackQty ? (
59
- <ItemQty left={getLeftPositionValue(item.stackQty)}>
60
- {' '}
61
- {item.stackQty}{' '}
62
- </ItemQty>
63
- ) : null}
137
+ {onRenderSlot(item)}
64
138
  </Container>
65
139
  );
66
140
  };
67
141
 
68
142
  const Container = styled.div`
69
143
  margin: 0.1rem;
70
- // border: 1px red solid;
71
-
72
144
  .sprite-from-atlas-img {
73
145
  position: relative;
74
146
  top: 1.5rem;
75
147
  left: 1.5rem;
76
-
77
- &:hover {
78
- filter: sepia(100%) saturate(300%) brightness(70%) hue-rotate(180deg);
79
- }
80
148
  }
81
149
  `;
82
150
 
@@ -1,21 +1,32 @@
1
- import { ActionsByItemType, ItemType } from '@rpg-engine/shared';
1
+ import {
2
+ ActionsByItemType,
3
+ ItemSocketEventsDisplayLabels,
4
+ ItemType,
5
+ } from '@rpg-engine/shared';
2
6
 
3
- interface IContextMenuItem {
7
+ export interface IContextMenuItem {
4
8
  id: string;
5
9
  text: string;
6
10
  }
7
11
 
8
- export const handleContextMenuList = (itemType: ItemType) => {
9
- const generateContextList = (actionsByTypeList: any) => {
10
- const contextMenu: IContextMenuItem[] = actionsByTypeList.map(
11
- (action: string) => {
12
- return { id: action, text: action };
13
- }
14
- );
15
- return contextMenu;
16
- };
12
+ export enum ContainerType {
13
+ INVENTORY = 'Inventory',
14
+ EQUIPMENT_SET = 'EquipmentSet',
15
+ }
16
+
17
+ // TODO: Refactor this file
18
+ const generateContextList = (actionsByTypeList: any) => {
19
+ const contextMenu: IContextMenuItem[] = actionsByTypeList.map(
20
+ (action: string) => {
21
+ return { id: action, text: ItemSocketEventsDisplayLabels[action] };
22
+ }
23
+ );
24
+ return contextMenu;
25
+ };
17
26
 
27
+ export const handleContextMenuList = (itemType: ItemType) => {
18
28
  let contextActionMenu: IContextMenuItem[] = [];
29
+
19
30
  switch (itemType) {
20
31
  case ItemType.Weapon:
21
32
  case ItemType.Armor:
@@ -42,3 +53,29 @@ export const handleContextMenuList = (itemType: ItemType) => {
42
53
  }
43
54
  return contextActionMenu;
44
55
  };
56
+
57
+ export const handleEquipmentContextMenuList = (itemType: ItemType) => {
58
+ let contextActionMenu: IContextMenuItem[] = [];
59
+ switch (itemType) {
60
+ case ItemType.Weapon:
61
+ case ItemType.Armor:
62
+ case ItemType.Accessory:
63
+ case ItemType.Jewelry:
64
+ case ItemType.Tool:
65
+ contextActionMenu = generateContextList(
66
+ ActionsByItemType.EquipmenSetItems
67
+ );
68
+ break;
69
+ case ItemType.Container:
70
+ contextActionMenu = generateContextList(
71
+ ActionsByItemType.EquipmenSetContainer
72
+ );
73
+ break;
74
+ default:
75
+ contextActionMenu = generateContextList(
76
+ ActionsByItemType.EquipmenSetItems
77
+ );
78
+ break;
79
+ }
80
+ return contextActionMenu;
81
+ };
@@ -9,6 +9,8 @@ interface IProps {
9
9
  width?: number;
10
10
  height?: number;
11
11
  scale?: number;
12
+ grayScale?: boolean;
13
+ opacity?: number;
12
14
  }
13
15
 
14
16
  export const SpriteFromAtlas: React.FC<IProps> = ({
@@ -18,6 +20,8 @@ export const SpriteFromAtlas: React.FC<IProps> = ({
18
20
  width = GRID_WIDTH,
19
21
  height = GRID_HEIGHT,
20
22
  scale = 2,
23
+ grayScale = false,
24
+ opacity = 1,
21
25
  }) => {
22
26
  //! If an item is not showing, remember that you MUST run yarn atlas:copy everytime you add a new item to the atlas (it will sync our public folder atlas with src/atlas).
23
27
  //!Due to React's limitations, we cannot import it from the public folder directly!
@@ -25,12 +29,14 @@ export const SpriteFromAtlas: React.FC<IProps> = ({
25
29
  const spriteData = atlasJSON.frames[spriteKey];
26
30
 
27
31
  return (
28
- <Container width={width} height={height}>
32
+ <Container width={width} height={height} hasHover={grayScale}>
29
33
  <ImgSprite
30
34
  className="sprite-from-atlas-img"
31
35
  atlasIMG={atlasIMG}
32
36
  frame={spriteData.frame}
33
37
  scale={scale}
38
+ grayScale={grayScale}
39
+ opacity={opacity}
34
40
  />
35
41
  </Container>
36
42
  );
@@ -45,16 +51,25 @@ interface IImgSpriteProps {
45
51
  h: number;
46
52
  };
47
53
  scale: number;
54
+ grayScale: boolean;
55
+ opacity: number;
48
56
  }
49
57
 
50
58
  interface IContainerProps {
51
59
  width: number;
52
60
  height: number;
61
+ hasHover: boolean;
53
62
  }
54
63
 
55
64
  const Container = styled.div`
56
65
  width: ${(props: IContainerProps) => props.width}px;
57
66
  height: ${(props: IContainerProps) => props.height}px;
67
+ ${(props: IContainerProps) =>
68
+ !props.hasHover
69
+ ? `&:hover {
70
+ filter: sepia(100%) saturate(300%) brightness(70%) hue-rotate(180deg);
71
+ }`
72
+ : ``}
58
73
  `;
59
74
 
60
75
  const ImgSprite = styled.div<IImgSpriteProps>`
@@ -66,4 +81,6 @@ const ImgSprite = styled.div<IImgSpriteProps>`
66
81
  position: relative;
67
82
  top: 8px;
68
83
  left: 8px;
84
+ filter: ${props => (props.grayScale ? 'grayscale(100%)' : 'none')};
85
+ opacity: ${props => props.opacity};
69
86
  `;
@@ -26,12 +26,12 @@ export const ListMenu: React.FC<IListMenuProps> = ({
26
26
  <ul className="rpgui-list-imp" style={{ overflow: 'hidden' }}>
27
27
  {options.map(params => (
28
28
  <ListElement
29
- key={params.text}
29
+ key={params?.id}
30
30
  onClick={() => {
31
- onSelected(params.id);
31
+ onSelected(params?.id);
32
32
  }}
33
33
  >
34
- {params.text}
34
+ {params?.text || 'No text'}
35
35
  </ListElement>
36
36
  ))}
37
37
  </ul>
@@ -0,0 +1,57 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+ import { MultitabType } from './TabsContainer';
4
+
5
+ export interface ISingleTab {
6
+ active: boolean;
7
+ label: string;
8
+ onClick: () => void;
9
+ type: MultitabType;
10
+ }
11
+
12
+ export const Tab: React.FC<ISingleTab> = ({ active, label, onClick, type }) => {
13
+ return (
14
+ <CustomTab activeTab={active} onClick={onClick} className={type}>
15
+ <p>{label}</p>
16
+ </CustomTab>
17
+ );
18
+ };
19
+
20
+ interface ICustomTab {
21
+ activeTab: boolean;
22
+ }
23
+
24
+ const CustomTab = styled.div<ICustomTab>`
25
+ width: 120px;
26
+ color: white;
27
+ font-size: 0.8rem;
28
+
29
+ &.gray {
30
+ border-left: 0.25rem solid rgba(0, 0, 0, 0.25);
31
+ border-right: 0.25rem solid rgba(0, 0, 0, 0.25);
32
+ border-top: 0.25rem solid rgba(0, 0, 0, 0.25);
33
+ background: ${props => (props.activeTab ? '#4E4A4E' : '#2b292b')};
34
+ }
35
+
36
+ &.brown {
37
+ border-left: 0.25rem solid #996d55;
38
+ border-right: 0.25rem solid #996d55;
39
+ border-top: 0.25rem solid #996d55;
40
+ background: ${props => (props.activeTab ? '#BF886A' : '#B67051')};
41
+ }
42
+
43
+ margin-right: 10px;
44
+ p {
45
+ text-align: center;
46
+ font-size: 0.6rem;
47
+
48
+ opacity: ${props => (props.activeTab ? '1' : '0.5')};
49
+ }
50
+
51
+ border-radius: 5px 5px 0 0;
52
+
53
+ z-index: ${props => (props.activeTab ? 1 : -1)};
54
+
55
+ position: relative;
56
+ top: 0.3rem;
57
+ `;
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ interface IProps {
5
+ id: string;
6
+ children: React.ReactNode;
7
+ }
8
+
9
+ export const TabBody: React.FC<IProps> = ({ id, children }) => {
10
+ return <Container data-tab-id={id}>{children}</Container>;
11
+ };
12
+
13
+ const Container = styled.div``;