@rpg-engine/long-bow 0.3.96 → 0.3.98

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 (182) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +181 -181
  3. package/dist/components/CircularController/CircularController.d.ts +1 -0
  4. package/dist/components/Shortcuts/Shortcuts.d.ts +1 -0
  5. package/dist/components/Shortcuts/useShortcutCooldown.d.ts +4 -0
  6. package/dist/components/Spellbook/Spell.d.ts +5 -4
  7. package/dist/components/Spellbook/Spellbook.d.ts +3 -2
  8. package/dist/components/Spellbook/cards/MobileSpellTooltip.d.ts +15 -0
  9. package/dist/components/Spellbook/cards/SpellInfo.d.ts +7 -0
  10. package/dist/components/Spellbook/cards/SpellInfoDisplay.d.ts +7 -0
  11. package/dist/components/Spellbook/cards/SpellInfoWrapper.d.ts +9 -0
  12. package/dist/components/Spellbook/cards/SpellTooltip.d.ts +6 -0
  13. package/dist/components/Spellbook/mockSpells.d.ts +2 -2
  14. package/dist/libs/CastingTypeHelper.d.ts +1 -0
  15. package/dist/long-bow.cjs.development.js +1525 -1255
  16. package/dist/long-bow.cjs.development.js.map +1 -1
  17. package/dist/long-bow.cjs.production.min.js +1 -1
  18. package/dist/long-bow.cjs.production.min.js.map +1 -1
  19. package/dist/long-bow.esm.js +1531 -1261
  20. package/dist/long-bow.esm.js.map +1 -1
  21. package/dist/stories/SpellInfoDisplay.stories.d.ts +8 -0
  22. package/package.json +100 -100
  23. package/src/.DS_Store +0 -0
  24. package/src/components/.DS_Store +0 -0
  25. package/src/components/Abstractions/ModalPortal.tsx +22 -22
  26. package/src/components/Abstractions/SlotsContainer.tsx +62 -62
  27. package/src/components/Arrow/SelectArrow.tsx +69 -69
  28. package/src/components/Arrow/img/arrow01-left-clicked.png +0 -0
  29. package/src/components/Arrow/img/arrow01-left.png +0 -0
  30. package/src/components/Arrow/img/arrow01-right-clicked.png +0 -0
  31. package/src/components/Arrow/img/arrow01-right.png +0 -0
  32. package/src/components/Arrow/img/arrow02-left-clicked.png +0 -0
  33. package/src/components/Arrow/img/arrow02-left.png +0 -0
  34. package/src/components/Arrow/img/arrow02-right-clicked.png +0 -0
  35. package/src/components/Arrow/img/arrow02-right.png +0 -0
  36. package/src/components/Button.tsx +40 -40
  37. package/src/components/Character/CharacterSelection.tsx +98 -98
  38. package/src/components/CharacterStatus/CharacterStatus.tsx +120 -120
  39. package/src/components/Chat/Chat.tsx +196 -196
  40. package/src/components/Chatdeprecated/ChatDeprecated.tsx +198 -198
  41. package/src/components/CheckButton.tsx +65 -65
  42. package/src/components/CircularController/CircularController.tsx +282 -249
  43. package/src/components/CraftBook/CraftBook.tsx +286 -286
  44. package/src/components/CraftBook/CraftingRecipe.tsx +161 -161
  45. package/src/components/CraftBook/MockItems.ts +101 -101
  46. package/src/components/DraggableContainer.tsx +180 -180
  47. package/src/components/DropdownSelectorContainer.tsx +42 -42
  48. package/src/components/Equipment/EquipmentSet.tsx +199 -199
  49. package/src/components/HistoryDialog.tsx +104 -104
  50. package/src/components/Input.tsx +15 -15
  51. package/src/components/InputRadio.tsx +41 -41
  52. package/src/components/Item/Cards/ItemInfo.tsx +298 -288
  53. package/src/components/Item/Cards/ItemInfoDisplay.tsx +135 -135
  54. package/src/components/Item/Cards/ItemInfoWrapper.tsx +62 -62
  55. package/src/components/Item/Cards/ItemTooltip.tsx +83 -83
  56. package/src/components/Item/Cards/MobileItemTooltip.tsx +149 -149
  57. package/src/components/Item/Inventory/ErrorBoundary.tsx +42 -42
  58. package/src/components/Item/Inventory/ItemContainer.tsx +231 -231
  59. package/src/components/Item/Inventory/ItemContainerTypes.ts +6 -6
  60. package/src/components/Item/Inventory/ItemQuantitySelector.tsx +138 -138
  61. package/src/components/Item/Inventory/ItemSlot.tsx +580 -580
  62. package/src/components/Item/Inventory/itemContainerHelper.ts +175 -175
  63. package/src/components/ListMenu.tsx +63 -63
  64. package/src/components/Marketplace/Marketplace.tsx +132 -132
  65. package/src/components/Marketplace/MarketplaceRows.tsx +171 -171
  66. package/src/components/Marketplace/__mocks__/index.tsx +65 -65
  67. package/src/components/Multitab/Tab.tsx +66 -66
  68. package/src/components/Multitab/TabBody.tsx +13 -13
  69. package/src/components/Multitab/TabsContainer.tsx +97 -97
  70. package/src/components/NPCDialog/.DS_Store +0 -0
  71. package/src/components/NPCDialog/NPCDialog.tsx +121 -121
  72. package/src/components/NPCDialog/NPCDialogText.tsx +113 -113
  73. package/src/components/NPCDialog/NPCMultiDialog.tsx +159 -159
  74. package/src/components/NPCDialog/QuestionDialog/QuestionDialog.tsx +237 -237
  75. package/src/components/NPCDialog/img/.DS_Store +0 -0
  76. package/src/components/ProgressBar.tsx +92 -92
  77. package/src/components/PropertySelect/PropertySelect.tsx +106 -106
  78. package/src/components/QuestInfo/QuestInfo.tsx +233 -233
  79. package/src/components/QuestList.tsx +135 -135
  80. package/src/components/RPGUIContainer.tsx +47 -47
  81. package/src/components/RPGUIForceRenderStart.tsx +45 -45
  82. package/src/components/RPGUIRoot.tsx +14 -14
  83. package/src/components/RadioButton.tsx +53 -53
  84. package/src/components/RadioInput/RadioButton.tsx +96 -96
  85. package/src/components/RadioInput/RadioInput.tsx +102 -102
  86. package/src/components/RadioInput/instruments.ts +15 -15
  87. package/src/components/RangeSlider.tsx +78 -78
  88. package/src/components/RelativeListMenu.tsx +90 -90
  89. package/src/components/ScrollList.tsx +79 -79
  90. package/src/components/Shortcuts/Shortcuts.tsx +192 -153
  91. package/src/components/Shortcuts/ShortcutsSetter.tsx +139 -139
  92. package/src/components/Shortcuts/SingleShortcut.ts +82 -62
  93. package/src/components/Shortcuts/useShortcutCooldown.ts +24 -0
  94. package/src/components/SimpleProgressBar.tsx +62 -62
  95. package/src/components/SkillProgressBar.tsx +133 -133
  96. package/src/components/SkillsContainer.tsx +206 -206
  97. package/src/components/Spellbook/Spell.tsx +236 -201
  98. package/src/components/Spellbook/Spellbook.tsx +159 -153
  99. package/src/components/Spellbook/cards/MobileSpellTooltip.tsx +137 -0
  100. package/src/components/Spellbook/cards/SpellInfo.tsx +132 -0
  101. package/src/components/Spellbook/cards/SpellInfoDisplay.tsx +31 -0
  102. package/src/components/Spellbook/cards/SpellInfoWrapper.tsx +48 -0
  103. package/src/components/Spellbook/cards/SpellTooltip.tsx +70 -0
  104. package/src/components/Spellbook/constants.ts +8 -8
  105. package/src/components/Spellbook/mockSpells.ts +85 -60
  106. package/src/components/StaticBook/StaticBook.tsx +103 -103
  107. package/src/components/TextArea.tsx +11 -11
  108. package/src/components/TimeWidget/DayNightPeriod/DayNightPeriod.tsx +35 -35
  109. package/src/components/TimeWidget/TimeWidget.tsx +65 -65
  110. package/src/components/TradingMenu/TradingItemRow.tsx +199 -199
  111. package/src/components/TradingMenu/TradingMenu.tsx +219 -219
  112. package/src/components/TradingMenu/items.mock.ts +48 -48
  113. package/src/components/Truncate.tsx +25 -25
  114. package/src/components/itemSelector/ItemSelector.tsx +136 -136
  115. package/src/components/shared/Column.tsx +16 -16
  116. package/src/components/shared/Ellipsis.tsx +68 -68
  117. package/src/components/shared/SpriteFromAtlas.tsx +104 -104
  118. package/src/components/typography/DynamicText.tsx +49 -49
  119. package/src/constants/uiColors.ts +20 -20
  120. package/src/constants/uiDevices.ts +3 -3
  121. package/src/constants/uiFonts.ts +12 -12
  122. package/src/hooks/useEventListener.ts +21 -21
  123. package/src/hooks/useOutsideAlerter.ts +25 -25
  124. package/src/index.tsx +42 -42
  125. package/src/libs/CastingTypeHelper.ts +8 -0
  126. package/src/libs/StringHelpers.ts +3 -3
  127. package/src/libs/itemCounter.ts +21 -21
  128. package/src/mocks/.DS_Store +0 -0
  129. package/src/mocks/atlas/.DS_Store +0 -0
  130. package/src/mocks/atlas/entities/entities.json +20215 -20215
  131. package/src/mocks/atlas/icons/icons.json +735 -735
  132. package/src/mocks/atlas/items/items.json +12086 -12086
  133. package/src/mocks/equipmentSet.mocks.ts +391 -391
  134. package/src/mocks/itemContainer.mocks.ts +605 -605
  135. package/src/mocks/skills.mocks.ts +128 -128
  136. package/src/stories/Arrow.stories.tsx +26 -26
  137. package/src/stories/Button.stories.tsx +36 -36
  138. package/src/stories/CharacterSelection.stories.tsx +44 -44
  139. package/src/stories/CharacterStatus.stories.tsx +29 -29
  140. package/src/stories/Chat.stories.tsx +187 -187
  141. package/src/stories/ChatDeprecated.stories.tsx +170 -170
  142. package/src/stories/CheckButton.stories.tsx +48 -48
  143. package/src/stories/CircullarController.stories.tsx +37 -37
  144. package/src/stories/CraftBook.stories.tsx +42 -42
  145. package/src/stories/DayNightPeriod.stories.tsx +27 -27
  146. package/src/stories/DraggableContainer.stories.tsx +28 -28
  147. package/src/stories/Dropdown.stories.tsx +46 -46
  148. package/src/stories/DropdownSelectorContainer.stories.tsx +41 -41
  149. package/src/stories/EquipmentSet.stories.tsx +65 -65
  150. package/src/stories/HistoryDialog.stories.tsx +61 -61
  151. package/src/stories/ItemContainer.stories.tsx +201 -201
  152. package/src/stories/ItemInfoDisplay.stories.tsx +33 -33
  153. package/src/stories/ItemQuantitySelector.stories.tsx +26 -26
  154. package/src/stories/ItemSelector.stories.tsx +77 -77
  155. package/src/stories/ItemTradingComponent.stories.tsx +35 -35
  156. package/src/stories/ListMenu.stories.tsx +56 -56
  157. package/src/stories/Marketplace.stories.tsx +42 -42
  158. package/src/stories/MarketplaceRows.stories.tsx +28 -28
  159. package/src/stories/Multitab.stories.tsx +51 -51
  160. package/src/stories/NPCDialog.stories.tsx +130 -130
  161. package/src/stories/NPCMultiDialog.stories.tsx +71 -71
  162. package/src/stories/ProgressBar.stories.tsx +23 -23
  163. package/src/stories/PropertySelect.stories.tsx +40 -40
  164. package/src/stories/QuestInfo.stories.tsx +107 -107
  165. package/src/stories/QuestList.stories.tsx +82 -82
  166. package/src/stories/RPGUIContainers.stories.tsx +42 -42
  167. package/src/stories/RadioButton.stories.tsx +49 -49
  168. package/src/stories/RadioInput.stories.tsx +34 -34
  169. package/src/stories/RangeSlider.stories.tsx +64 -64
  170. package/src/stories/ScrollList.stories.tsx +85 -85
  171. package/src/stories/Shortcuts.stories.tsx +39 -39
  172. package/src/stories/SimpleProgressBar.stories.tsx +22 -22
  173. package/src/stories/SkillProgressBar.stories.tsx +34 -34
  174. package/src/stories/SkillsContainer.stories.tsx +35 -35
  175. package/src/stories/SpellInfoDisplay.stories.tsx +27 -0
  176. package/src/stories/Spellbook.stories.tsx +104 -104
  177. package/src/stories/StaticBook.stories.tsx +32 -32
  178. package/src/stories/Text.stories.tsx +42 -42
  179. package/src/stories/TimeWidget.stories.tsx +27 -27
  180. package/src/stories/TradingMenu.stories.tsx +47 -47
  181. package/src/types/eventTypes.ts +4 -4
  182. package/src/types/index.d.ts +2 -2
@@ -1,121 +1,121 @@
1
- import React from 'react';
2
- import styled from 'styled-components';
3
- import { RPGUIContainer, RPGUIContainerTypes } from '../RPGUIContainer';
4
- import { NPCDialogText } from './NPCDialogText';
5
- import {
6
- IQuestionDialog,
7
- IQuestionDialogAnswer,
8
- QuestionDialog,
9
- } from './QuestionDialog/QuestionDialog';
10
- import aliceDefaultThumbnail from './img/npcDialog/npcThumbnails/alice.png';
11
-
12
- export enum NPCDialogType {
13
- TextOnly = 'TextOnly',
14
- TextAndThumbnail = 'TextAndThumbnail',
15
- }
16
-
17
- export interface INPCDialogProps {
18
- text?: string;
19
- type: NPCDialogType;
20
- imagePath?: string;
21
- onClose?: () => void;
22
- isQuestionDialog?: boolean;
23
- answers?: IQuestionDialogAnswer[];
24
- questions?: IQuestionDialog[];
25
- }
26
-
27
- export const NPCDialog: React.FC<INPCDialogProps> = ({
28
- text,
29
- type,
30
- onClose,
31
- imagePath,
32
- isQuestionDialog = false,
33
- questions,
34
- answers,
35
- }) => {
36
- return (
37
- <RPGUIContainer
38
- type={RPGUIContainerTypes.FramedGold}
39
- width={isQuestionDialog ? '600px' : '80%'}
40
- height={'180px'}
41
- >
42
- {isQuestionDialog && questions && answers ? (
43
- <>
44
- <TextContainer
45
- flex={type === NPCDialogType.TextAndThumbnail ? '70%' : '100%'}
46
- >
47
- <QuestionDialog
48
- questions={questions}
49
- answers={answers}
50
- onClose={() => {
51
- if (onClose) {
52
- onClose();
53
- }
54
- }}
55
- />
56
- </TextContainer>
57
- {type === NPCDialogType.TextAndThumbnail && (
58
- <ThumbnailContainer>
59
- <NPCThumbnail src={imagePath || aliceDefaultThumbnail} />
60
- </ThumbnailContainer>
61
- )}
62
- </>
63
- ) : (
64
- <>
65
- <Container>
66
- <TextContainer
67
- flex={type === NPCDialogType.TextAndThumbnail ? '70%' : '100%'}
68
- >
69
- <NPCDialogText
70
- type={type}
71
- text={text || 'No text provided.'}
72
- onClose={() => {
73
- if (onClose) {
74
- onClose();
75
- }
76
- }}
77
- />
78
- </TextContainer>
79
- {type === NPCDialogType.TextAndThumbnail && (
80
- <ThumbnailContainer>
81
- <NPCThumbnail src={imagePath || aliceDefaultThumbnail} />
82
- </ThumbnailContainer>
83
- )}
84
- </Container>
85
- </>
86
- )}
87
- </RPGUIContainer>
88
- );
89
- };
90
-
91
- const Container = styled.div`
92
- display: flex;
93
- width: 100%;
94
- height: 100%;
95
-
96
- box-sizing: border-box;
97
- justify-content: center;
98
- align-items: flex-start;
99
- position: relative;
100
- `;
101
-
102
- interface ITextContainerProps {
103
- flex: string;
104
- }
105
-
106
- const TextContainer = styled.div<ITextContainerProps>`
107
- flex: ${({ flex }) => flex} 0 0;
108
- width: 355px;
109
- `;
110
-
111
- const ThumbnailContainer = styled.div`
112
- flex: 30% 0 0;
113
- display: flex;
114
- justify-content: flex-end;
115
- `;
116
-
117
- const NPCThumbnail = styled.img`
118
- image-rendering: pixelated;
119
- height: 128px;
120
- width: 128px;
121
- `;
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+ import { RPGUIContainer, RPGUIContainerTypes } from '../RPGUIContainer';
4
+ import { NPCDialogText } from './NPCDialogText';
5
+ import {
6
+ IQuestionDialog,
7
+ IQuestionDialogAnswer,
8
+ QuestionDialog,
9
+ } from './QuestionDialog/QuestionDialog';
10
+ import aliceDefaultThumbnail from './img/npcDialog/npcThumbnails/alice.png';
11
+
12
+ export enum NPCDialogType {
13
+ TextOnly = 'TextOnly',
14
+ TextAndThumbnail = 'TextAndThumbnail',
15
+ }
16
+
17
+ export interface INPCDialogProps {
18
+ text?: string;
19
+ type: NPCDialogType;
20
+ imagePath?: string;
21
+ onClose?: () => void;
22
+ isQuestionDialog?: boolean;
23
+ answers?: IQuestionDialogAnswer[];
24
+ questions?: IQuestionDialog[];
25
+ }
26
+
27
+ export const NPCDialog: React.FC<INPCDialogProps> = ({
28
+ text,
29
+ type,
30
+ onClose,
31
+ imagePath,
32
+ isQuestionDialog = false,
33
+ questions,
34
+ answers,
35
+ }) => {
36
+ return (
37
+ <RPGUIContainer
38
+ type={RPGUIContainerTypes.FramedGold}
39
+ width={isQuestionDialog ? '600px' : '80%'}
40
+ height={'180px'}
41
+ >
42
+ {isQuestionDialog && questions && answers ? (
43
+ <>
44
+ <TextContainer
45
+ flex={type === NPCDialogType.TextAndThumbnail ? '70%' : '100%'}
46
+ >
47
+ <QuestionDialog
48
+ questions={questions}
49
+ answers={answers}
50
+ onClose={() => {
51
+ if (onClose) {
52
+ onClose();
53
+ }
54
+ }}
55
+ />
56
+ </TextContainer>
57
+ {type === NPCDialogType.TextAndThumbnail && (
58
+ <ThumbnailContainer>
59
+ <NPCThumbnail src={imagePath || aliceDefaultThumbnail} />
60
+ </ThumbnailContainer>
61
+ )}
62
+ </>
63
+ ) : (
64
+ <>
65
+ <Container>
66
+ <TextContainer
67
+ flex={type === NPCDialogType.TextAndThumbnail ? '70%' : '100%'}
68
+ >
69
+ <NPCDialogText
70
+ type={type}
71
+ text={text || 'No text provided.'}
72
+ onClose={() => {
73
+ if (onClose) {
74
+ onClose();
75
+ }
76
+ }}
77
+ />
78
+ </TextContainer>
79
+ {type === NPCDialogType.TextAndThumbnail && (
80
+ <ThumbnailContainer>
81
+ <NPCThumbnail src={imagePath || aliceDefaultThumbnail} />
82
+ </ThumbnailContainer>
83
+ )}
84
+ </Container>
85
+ </>
86
+ )}
87
+ </RPGUIContainer>
88
+ );
89
+ };
90
+
91
+ const Container = styled.div`
92
+ display: flex;
93
+ width: 100%;
94
+ height: 100%;
95
+
96
+ box-sizing: border-box;
97
+ justify-content: center;
98
+ align-items: flex-start;
99
+ position: relative;
100
+ `;
101
+
102
+ interface ITextContainerProps {
103
+ flex: string;
104
+ }
105
+
106
+ const TextContainer = styled.div<ITextContainerProps>`
107
+ flex: ${({ flex }) => flex} 0 0;
108
+ width: 355px;
109
+ `;
110
+
111
+ const ThumbnailContainer = styled.div`
112
+ flex: 30% 0 0;
113
+ display: flex;
114
+ justify-content: flex-end;
115
+ `;
116
+
117
+ const NPCThumbnail = styled.img`
118
+ image-rendering: pixelated;
119
+ height: 128px;
120
+ width: 128px;
121
+ `;
@@ -1,113 +1,113 @@
1
- import React, { useEffect, useRef, useState } from 'react';
2
- import styled from 'styled-components';
3
- import { NPCDialogType } from '../..';
4
- import { IS_MOBILE_OR_TABLET } from '../../constants/uiDevices';
5
- import { chunkString } from '../../libs/StringHelpers';
6
- import { DynamicText } from '../typography/DynamicText';
7
- import pressButtonGif from './img/press-button.gif';
8
- import pressSpaceGif from './img/space.gif';
9
-
10
- interface IProps {
11
- text: string;
12
- onClose: () => void;
13
- onEndStep?: () => void;
14
- onStartStep?: () => void;
15
- type?: NPCDialogType;
16
- }
17
-
18
- export const NPCDialogText: React.FC<IProps> = ({
19
- text,
20
- onClose,
21
- onEndStep,
22
- onStartStep,
23
- type,
24
- }) => {
25
- const windowSize = useRef([window.innerWidth, window.innerHeight]);
26
- function maxCharacters(width: number) {
27
- // Set the font size to 16 pixels
28
- var fontSize = 11.2;
29
-
30
- // Calculate the number of characters that can fit in one line
31
- var charactersPerLine = Math.floor(width / 2 / fontSize);
32
-
33
- // Calculate the number of lines that can fit in the div
34
- var linesPerDiv = Math.floor(180 / fontSize);
35
-
36
- // Calculate the maximum number of characters that can fit in the div
37
- var maxCharacters = charactersPerLine * linesPerDiv;
38
-
39
- // Return the maximum number of characters
40
- return Math.round(maxCharacters / 5);
41
- }
42
-
43
- const textChunks = chunkString(text, maxCharacters(windowSize.current[0]));
44
-
45
- const [chunkIndex, setChunkIndex] = useState<number>(0);
46
- const onHandleSpacePress = (event: KeyboardEvent) => {
47
- if (event.code === 'Space') {
48
- goToNextStep();
49
- }
50
- };
51
-
52
- const goToNextStep = () => {
53
- const hasNextChunk = textChunks?.[chunkIndex + 1] || false;
54
-
55
- if (hasNextChunk) {
56
- setChunkIndex(prev => prev + 1);
57
- } else {
58
- // if there's no more text chunks, close the dialog
59
- onClose();
60
- }
61
- };
62
-
63
- useEffect(() => {
64
- document.addEventListener('keydown', onHandleSpacePress);
65
-
66
- return () => document.removeEventListener('keydown', onHandleSpacePress);
67
- }, [chunkIndex]);
68
-
69
- const [showGoNextIndicator, setShowGoNextIndicator] = useState<boolean>(
70
- false
71
- );
72
-
73
- return (
74
- <Container>
75
- <DynamicText
76
- text={textChunks?.[chunkIndex] || ''}
77
- onFinish={() => {
78
- setShowGoNextIndicator(true);
79
-
80
- onEndStep && onEndStep();
81
- }}
82
- onStart={() => {
83
- setShowGoNextIndicator(false);
84
-
85
- onStartStep && onStartStep();
86
- }}
87
- />
88
- {showGoNextIndicator && (
89
- <PressSpaceIndicator
90
- right={type === NPCDialogType.TextOnly ? '1rem' : '10.5rem'}
91
- src={IS_MOBILE_OR_TABLET ? pressButtonGif : pressSpaceGif}
92
- onPointerDown={() => {
93
- goToNextStep();
94
- }}
95
- />
96
- )}
97
- </Container>
98
- );
99
- };
100
-
101
- const Container = styled.div``;
102
-
103
- interface IPressSpaceIndicatorProps {
104
- right: string;
105
- }
106
-
107
- const PressSpaceIndicator = styled.img<IPressSpaceIndicatorProps>`
108
- position: absolute;
109
- right: ${({ right }) => right};
110
- bottom: 1rem;
111
- height: 20.7px;
112
- image-rendering: -webkit-optimize-contrast;
113
- `;
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import styled from 'styled-components';
3
+ import { NPCDialogType } from '../..';
4
+ import { IS_MOBILE_OR_TABLET } from '../../constants/uiDevices';
5
+ import { chunkString } from '../../libs/StringHelpers';
6
+ import { DynamicText } from '../typography/DynamicText';
7
+ import pressButtonGif from './img/press-button.gif';
8
+ import pressSpaceGif from './img/space.gif';
9
+
10
+ interface IProps {
11
+ text: string;
12
+ onClose: () => void;
13
+ onEndStep?: () => void;
14
+ onStartStep?: () => void;
15
+ type?: NPCDialogType;
16
+ }
17
+
18
+ export const NPCDialogText: React.FC<IProps> = ({
19
+ text,
20
+ onClose,
21
+ onEndStep,
22
+ onStartStep,
23
+ type,
24
+ }) => {
25
+ const windowSize = useRef([window.innerWidth, window.innerHeight]);
26
+ function maxCharacters(width: number) {
27
+ // Set the font size to 16 pixels
28
+ var fontSize = 11.2;
29
+
30
+ // Calculate the number of characters that can fit in one line
31
+ var charactersPerLine = Math.floor(width / 2 / fontSize);
32
+
33
+ // Calculate the number of lines that can fit in the div
34
+ var linesPerDiv = Math.floor(180 / fontSize);
35
+
36
+ // Calculate the maximum number of characters that can fit in the div
37
+ var maxCharacters = charactersPerLine * linesPerDiv;
38
+
39
+ // Return the maximum number of characters
40
+ return Math.round(maxCharacters / 5);
41
+ }
42
+
43
+ const textChunks = chunkString(text, maxCharacters(windowSize.current[0]));
44
+
45
+ const [chunkIndex, setChunkIndex] = useState<number>(0);
46
+ const onHandleSpacePress = (event: KeyboardEvent) => {
47
+ if (event.code === 'Space') {
48
+ goToNextStep();
49
+ }
50
+ };
51
+
52
+ const goToNextStep = () => {
53
+ const hasNextChunk = textChunks?.[chunkIndex + 1] || false;
54
+
55
+ if (hasNextChunk) {
56
+ setChunkIndex(prev => prev + 1);
57
+ } else {
58
+ // if there's no more text chunks, close the dialog
59
+ onClose();
60
+ }
61
+ };
62
+
63
+ useEffect(() => {
64
+ document.addEventListener('keydown', onHandleSpacePress);
65
+
66
+ return () => document.removeEventListener('keydown', onHandleSpacePress);
67
+ }, [chunkIndex]);
68
+
69
+ const [showGoNextIndicator, setShowGoNextIndicator] = useState<boolean>(
70
+ false
71
+ );
72
+
73
+ return (
74
+ <Container>
75
+ <DynamicText
76
+ text={textChunks?.[chunkIndex] || ''}
77
+ onFinish={() => {
78
+ setShowGoNextIndicator(true);
79
+
80
+ onEndStep && onEndStep();
81
+ }}
82
+ onStart={() => {
83
+ setShowGoNextIndicator(false);
84
+
85
+ onStartStep && onStartStep();
86
+ }}
87
+ />
88
+ {showGoNextIndicator && (
89
+ <PressSpaceIndicator
90
+ right={type === NPCDialogType.TextOnly ? '1rem' : '10.5rem'}
91
+ src={IS_MOBILE_OR_TABLET ? pressButtonGif : pressSpaceGif}
92
+ onPointerDown={() => {
93
+ goToNextStep();
94
+ }}
95
+ />
96
+ )}
97
+ </Container>
98
+ );
99
+ };
100
+
101
+ const Container = styled.div``;
102
+
103
+ interface IPressSpaceIndicatorProps {
104
+ right: string;
105
+ }
106
+
107
+ const PressSpaceIndicator = styled.img<IPressSpaceIndicatorProps>`
108
+ position: absolute;
109
+ right: ${({ right }) => right};
110
+ bottom: 1rem;
111
+ height: 20.7px;
112
+ image-rendering: -webkit-optimize-contrast;
113
+ `;