@rpg-engine/long-bow 0.1.21 → 0.1.24
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/NPCDialog/NPCDialog.d.ts +5 -1
- package/dist/NPCDialog/QuestionDialog/QuestionDialog.d.ts +17 -0
- package/dist/RPGUI/RPGUIContainer.d.ts +1 -0
- package/dist/RPGUI/RPGUIRoot.d.ts +9 -0
- package/dist/RPGUI/RPGUISlider.d.ts +13 -0
- package/dist/components/ListMenu.d.ts +10 -0
- package/dist/index.d.ts +5 -1
- package/dist/long-bow.cjs.development.js +334 -32
- 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 +331 -32
- package/dist/long-bow.esm.js.map +1 -1
- package/package.json +5 -2
- package/src/NPCDialog/NPCDialog.tsx +72 -36
- package/src/NPCDialog/NPCDialogText.tsx +0 -5
- package/src/NPCDialog/QuestionDialog/QuestionDialog.tsx +240 -0
- package/src/RPGUI/RPGUIContainer.tsx +12 -2
- package/src/RPGUI/RPGUIRoot.tsx +14 -0
- package/src/RPGUI/RPGUISlider.tsx +71 -0
- package/src/components/ListMenu.tsx +48 -0
- package/src/index.tsx +5 -1
- package/src/typography/DynamicText.tsx +1 -0
- package/dist/RPGUI/RPGUI.d.ts +0 -8
- package/src/RPGUI/RPGUI.tsx +0 -11
package/dist/long-bow.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"long-bow.esm.js","sources":["../src/RPGUI/RPGUI.tsx","../src/RPGUI/RPGUIContainer.tsx","../src/NPCDialog/img/npcDialog/npcThumbnails/alice.png","../src/NPCDialog/img/space.gif","../src/libs/StringHelpers.ts","../src/typography/DynamicText.tsx","../src/NPCDialog/NPCDialogText.tsx","../src/NPCDialog/NPCDialog.tsx"],"sourcesContent":["import React from 'react';\nimport 'rpgui/rpgui.css';\nimport 'rpgui/rpgui.js';\n\ninterface IProps {\n children: React.ReactNode;\n}\n\nexport const RPGUI: React.FC<IProps> = ({ children }) => {\n return <div className=\"rpgui-content\">{children}</div>;\n};\n","import React from 'react';\nimport styled from 'styled-components';\n\ninterface IProps {\n type: 'framed' | 'framed-golden' | 'framed-golden-2' | 'framed-grey';\n children: React.ReactNode;\n width?: string;\n}\n\nexport const RPGUIContainer: React.FC<IProps> = ({\n children,\n type,\n width = '50%',\n}) => {\n return (\n <Container width={width} className={`rpgui-container ${type}`}>\n {children}\n </Container>\n );\n};\n\ninterface IContainerProps {\n width: string;\n}\n\nconst Container = styled.div<IContainerProps>`\n max-width: ${({ width }) => width};\n`;\n","const img = require('./alice.png'); export default img;","const img = require('./space.gif'); export default img;","export const chunkString = (str: string, length: number) => {\n return str.match(new RegExp('.{1,' + length + '}', 'g'));\n};\n","import React, { useEffect, useState } from 'react';\nimport styled from 'styled-components';\n\ninterface IProps {\n text: string;\n onFinish?: () => void;\n onStart?: () => void;\n}\n\nexport const DynamicText: React.FC<IProps> = ({ text, onFinish, onStart }) => {\n const [textState, setTextState] = useState<string>('');\n\n useEffect(() => {\n let i = 0;\n const interval = setInterval(() => {\n // on every interval, show one more character\n\n if (i === 0) {\n if (onStart) {\n onStart();\n }\n }\n\n if (i < text.length) {\n setTextState(text.substring(0, i + 1));\n i++;\n } else {\n clearInterval(interval);\n if (onFinish) {\n onFinish();\n }\n }\n }, 50);\n\n return () => {\n clearInterval(interval);\n };\n }, [text]);\n\n return <TextContainer>{textState}</TextContainer>;\n};\n\nconst TextContainer = styled.p`\n font-size: 0.7rem !important;\n color: white;\n text-shadow: 1px 1px 0px #000000;\n letter-spacing: 1.2px;\n`;\n","import React, { useEffect, useState } from 'react';\nimport styled from 'styled-components';\nimport { chunkString } from '../libs/StringHelpers';\nimport { DynamicText } from '../typography/DynamicText';\n\ninterface IProps {\n text: string;\n onClose: () => void;\n onEndStep: () => void;\n onStartStep: () => void;\n}\n\nexport const NPCDialogText: React.FC<IProps> = ({\n text,\n onClose,\n onEndStep,\n onStartStep,\n}) => {\n const textChunks = chunkString(text, 85);\n\n const [chunkIndex, setChunkIndex] = useState<number>(0);\n\n const onHandleSpacePress = (event: KeyboardEvent) => {\n if (event.code === 'Space') {\n console.log('space pressed!');\n\n const hasNextChunk = textChunks?.[chunkIndex + 1] || false;\n console.log(textChunks);\n console.log(chunkIndex);\n console.log(hasNextChunk);\n\n if (hasNextChunk) {\n setChunkIndex((prev) => prev + 1);\n } else {\n // if there's no more text chunks, close the dialog\n onClose();\n }\n }\n };\n\n useEffect(() => {\n document.addEventListener('keydown', onHandleSpacePress);\n\n return () => document.removeEventListener('keydown', onHandleSpacePress);\n }, [chunkIndex]);\n\n return (\n <Container>\n <DynamicText\n text={textChunks?.[chunkIndex] || ''}\n onFinish={onEndStep}\n onStart={onStartStep}\n />\n </Container>\n );\n};\n\nconst Container = styled.div``;\n","import React, { useState } from 'react';\nimport styled from 'styled-components';\nimport { RPGUI } from '../RPGUI/RPGUI';\nimport { RPGUIContainer } from '../RPGUI/RPGUIContainer';\nimport aliceDefaultThumbnail from './img/npcDialog/npcThumbnails/alice.png';\nimport pressSpaceGif from './img/space.gif';\nimport { NPCDialogText } from './NPCDialogText';\nexport enum NPCDialogType {\n TextOnly = 'TextOnly',\n TextAndThumbnail = 'TextAndThumbnail',\n}\n\nexport interface INPCDialogProps {\n text: string;\n type: NPCDialogType;\n imagePath?: string;\n onClose?: () => void;\n}\n\nexport const NPCDialog: React.FC<INPCDialogProps> = ({\n text,\n type,\n onClose,\n imagePath,\n}) => {\n const [isOpen, setIsOpen] = useState<boolean>(true);\n const [showGoNextIndicator, setShowGoNextIndicator] =\n useState<boolean>(false);\n\n return isOpen ? (\n <RPGUI>\n <RPGUIContainer type=\"framed-golden\">\n <Container>\n <TextContainer\n flex={type === NPCDialogType.TextAndThumbnail ? '70%' : '100%'}\n >\n <NPCDialogText\n onStartStep={() => setShowGoNextIndicator(false)}\n onEndStep={() => setShowGoNextIndicator(true)}\n text={text}\n onClose={() => {\n if (onClose) {\n onClose();\n setIsOpen(false);\n }\n }}\n />\n </TextContainer>\n {type === NPCDialogType.TextAndThumbnail && (\n <ThumbnailContainer>\n <NPCThumbnail src={imagePath || aliceDefaultThumbnail} />\n </ThumbnailContainer>\n )}\n </Container>\n {showGoNextIndicator && (\n <PressSpaceIndicator\n right={type === NPCDialogType.TextOnly ? '1rem' : '10.5rem'}\n src={pressSpaceGif}\n />\n )}\n </RPGUIContainer>\n </RPGUI>\n ) : null;\n};\n\nconst Container = styled.div`\n display: flex;\n width: 100%;\n height: 125px;\n box-sizing: border-box;\n justify-content: center;\n align-items: flex-start;\n position: relative;\n`;\n\ninterface ITextContainerProps {\n flex: string;\n}\n\nconst TextContainer = styled.div<ITextContainerProps>`\n flex: ${({ flex }) => flex} 0 0;\n width: 355px;\n`;\n\nconst ThumbnailContainer = styled.div`\n flex: 30% 0 0;\n display: flex;\n justify-content: flex-end;\n`;\n\nconst NPCThumbnail = styled.img`\n image-rendering: pixelated;\n height: 128px;\n width: 128px;\n`;\n\ninterface IPressSpaceIndicatorProps {\n right: string;\n}\n\nconst PressSpaceIndicator = styled.img<IPressSpaceIndicatorProps>`\n position: absolute;\n right: ${({ right }) => right};\n bottom: 1rem;\n height: 20.7px;\n image-rendering: -webkit-optimize-contrast;\n`;\n"],"names":["RPGUI","children","React","className","RPGUIContainer","type","width","Container","styled","div","img","chunkString","str","length","match","RegExp","DynamicText","text","onFinish","onStart","useState","textState","setTextState","useEffect","i","interval","setInterval","substring","clearInterval","TextContainer","p","NPCDialogText","onClose","onEndStep","onStartStep","textChunks","chunkIndex","setChunkIndex","onHandleSpacePress","event","code","console","log","hasNextChunk","prev","document","addEventListener","removeEventListener","NPCDialogType","NPCDialog","imagePath","isOpen","setIsOpen","showGoNextIndicator","setShowGoNextIndicator","flex","TextAndThumbnail","ThumbnailContainer","NPCThumbnail","src","aliceDefaultThumbnail","PressSpaceIndicator","right","TextOnly","pressSpaceGif"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"long-bow.esm.js","sources":["../src/RPGUI/RPGUIRoot.tsx","../src/components/ListMenu.tsx","../src/hooks/useEventListener.ts","../src/RPGUI/RPGUIContainer.tsx","../src/NPCDialog/img/npcDialog/npcThumbnails/alice.png","../src/NPCDialog/img/space.gif","../src/libs/StringHelpers.ts","../src/typography/DynamicText.tsx","../src/NPCDialog/NPCDialogText.tsx","../src/NPCDialog/QuestionDialog/QuestionDialog.tsx","../src/NPCDialog/NPCDialog.tsx","../src/RPGUI/RPGUISlider.tsx"],"sourcesContent":["import React from 'react';\nimport 'rpgui/rpgui.min.css';\nimport 'rpgui/rpgui.min.js';\n\ninterface IProps {\n children: React.ReactNode;\n}\n\n//@ts-ignore\nexport const _RPGUI = RPGUI;\n\nexport const RPGUIRoot: React.FC<IProps> = ({ children }) => {\n return <div className=\"rpgui-content\">{children}</div>;\n};\n","import React from 'react';\nimport styled from 'styled-components';\nimport { RPGUIRoot } from '../RPGUI/RPGUIRoot';\n\nexport interface IListMenuProps {\n title: string;\n options: [\n {\n id: string;\n text: string;\n }\n ];\n onSelected: (selectedOptionId: string) => void;\n}\n\nexport const ListMenu: React.FC<IListMenuProps> = ({\n title,\n options,\n onSelected,\n}) => {\n return (\n <RPGUIRoot>\n <Container>\n <p>{title}: </p>\n <ul className=\"rpgui-list-imp\" style={{ overflow: 'hidden' }}>\n {options.map((params) => (\n <li\n key={params.text}\n onClick={() => {\n onSelected(params.id);\n }}\n >\n {params.text}\n </li>\n ))}\n </ul>\n </Container>\n </RPGUIRoot>\n );\n};\n\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n justify-content: start;\n align-items: flex-start;\n`;\n","import React from 'react';\n\n//@ts-ignore\nexport const useEventListener = (type, handler, el = window) => {\n const savedHandler = React.useRef();\n\n React.useEffect(() => {\n savedHandler.current = handler;\n }, [handler]);\n\n React.useEffect(() => {\n //@ts-ignore\n const listener = (e) => savedHandler.current(e);\n\n el.addEventListener(type, listener);\n\n return () => {\n el.removeEventListener(type, listener);\n };\n }, [type, el]);\n};\n","import React from 'react';\nimport styled from 'styled-components';\n\ninterface IProps {\n type: 'framed' | 'framed-golden' | 'framed-golden-2' | 'framed-grey';\n children: React.ReactNode;\n width?: string;\n height?: string;\n}\n\nexport const RPGUIContainer: React.FC<IProps> = ({\n children,\n type,\n width = '50%',\n height,\n}) => {\n return (\n <Container\n width={width}\n height={height || 'auto'}\n className={`rpgui-container ${type}`}\n >\n {children}\n </Container>\n );\n};\n\ninterface IContainerProps {\n width: string;\n height: string;\n}\n\nconst Container = styled.div<IContainerProps>`\n height: ${(props) => props.height};\n width: ${({ width }) => width};\n display: flex;\n flex-wrap: wrap;\n`;\n","const img = require('./alice.png'); export default img;","const img = require('./space.gif'); export default img;","export const chunkString = (str: string, length: number) => {\n return str.match(new RegExp('.{1,' + length + '}', 'g'));\n};\n","import React, { useEffect, useState } from 'react';\nimport styled from 'styled-components';\n\ninterface IProps {\n text: string;\n onFinish?: () => void;\n onStart?: () => void;\n}\n\nexport const DynamicText: React.FC<IProps> = ({ text, onFinish, onStart }) => {\n const [textState, setTextState] = useState<string>('');\n\n useEffect(() => {\n let i = 0;\n const interval = setInterval(() => {\n // on every interval, show one more character\n\n if (i === 0) {\n if (onStart) {\n onStart();\n }\n }\n\n if (i < text.length) {\n setTextState(text.substring(0, i + 1));\n i++;\n } else {\n clearInterval(interval);\n if (onFinish) {\n onFinish();\n }\n }\n }, 50);\n\n return () => {\n clearInterval(interval);\n };\n }, [text]);\n\n return <TextContainer>{textState}</TextContainer>;\n};\n\nconst TextContainer = styled.p`\n font-size: 0.7rem !important;\n color: white;\n text-shadow: 1px 1px 0px #000000;\n letter-spacing: 1.2px;\n word-break: normal;\n`;\n","import React, { useEffect, useState } from 'react';\nimport styled from 'styled-components';\nimport { chunkString } from '../libs/StringHelpers';\nimport { DynamicText } from '../typography/DynamicText';\n\ninterface IProps {\n text: string;\n onClose: () => void;\n onEndStep: () => void;\n onStartStep: () => void;\n}\n\nexport const NPCDialogText: React.FC<IProps> = ({\n text,\n onClose,\n onEndStep,\n onStartStep,\n}) => {\n const textChunks = chunkString(text, 85);\n\n const [chunkIndex, setChunkIndex] = useState<number>(0);\n\n const onHandleSpacePress = (event: KeyboardEvent) => {\n if (event.code === 'Space') {\n const hasNextChunk = textChunks?.[chunkIndex + 1] || false;\n\n if (hasNextChunk) {\n setChunkIndex((prev) => prev + 1);\n } else {\n // if there's no more text chunks, close the dialog\n onClose();\n }\n }\n };\n\n useEffect(() => {\n document.addEventListener('keydown', onHandleSpacePress);\n\n return () => document.removeEventListener('keydown', onHandleSpacePress);\n }, [chunkIndex]);\n\n return (\n <Container>\n <DynamicText\n text={textChunks?.[chunkIndex] || ''}\n onFinish={onEndStep}\n onStart={onStartStep}\n />\n </Container>\n );\n};\n\nconst Container = styled.div``;\n","import React, { useEffect, useState } from 'react';\nimport styled from 'styled-components';\nimport { useEventListener } from '../../hooks/useEventListener';\nimport { DynamicText } from '../../typography/DynamicText';\n\nexport interface IQuestionDialogAnswer {\n id: number;\n text: string;\n nextQuestionId?: number;\n}\n\nexport interface IQuestionDialog {\n id: number;\n text: string;\n answerIds?: number[];\n}\n\nexport interface IProps {\n questions: IQuestionDialog[];\n answers: IQuestionDialogAnswer[];\n onClose: () => void;\n}\n\nexport const QuestionDialog: React.FC<IProps> = ({\n questions,\n answers,\n onClose,\n}) => {\n const [currentQuestion, setCurrentQuestion] = useState(questions[0]);\n\n const [canShowAnswers, setCanShowAnswers] = useState<boolean>(false);\n\n const onGetFirstAnswer = () => {\n if (!currentQuestion.answerIds || currentQuestion.answerIds.length === 0) {\n return null;\n }\n\n const firstAnswerId = currentQuestion.answerIds![0];\n\n return answers.find((answer) => answer.id === firstAnswerId);\n };\n\n const [currentAnswer, setCurrentAnswer] =\n useState<IQuestionDialogAnswer | null>(onGetFirstAnswer()!);\n\n useEffect(() => {\n setCurrentAnswer(onGetFirstAnswer()!);\n }, [currentQuestion]);\n\n const onGetAnswers = (answerIds: number[]) => {\n return answerIds.map((answerId: number) =>\n answers.find((answer) => answer.id === answerId)\n );\n };\n\n const onKeyPress = (e: KeyboardEvent) => {\n switch (e.key) {\n case 'ArrowDown':\n // select next answer, if any.\n // if no next answer, select first answer\n // const nextAnswer = onGetAnswers(currentQuestion.answerIds!).find(\n // (answer) => answer?.id === currentAnswer!.id + 1\n // );\n\n const nextAnswerIndex = onGetAnswers(\n currentQuestion.answerIds!\n ).findIndex((answer) => answer?.id === currentAnswer!.id + 1);\n\n const nextAnswerID = currentQuestion.answerIds![nextAnswerIndex];\n\n // console.log(nextAnswerIndex);\n\n const nextAnswer = onGetAnswers(currentQuestion.answerIds!).find(\n (answer) => answer?.id === nextAnswerID\n );\n\n setCurrentAnswer(nextAnswer || onGetFirstAnswer()!);\n\n break;\n case 'ArrowUp':\n // select previous answer, if any.\n // if no previous answer, select last answer\n\n const previousAnswerIndex = onGetAnswers(\n currentQuestion.answerIds!\n ).findIndex((answer) => answer?.id === currentAnswer!.id - 1);\n\n const previousAnswerID =\n currentQuestion.answerIds &&\n currentQuestion.answerIds[previousAnswerIndex];\n\n const previousAnswer = onGetAnswers(currentQuestion.answerIds!).find(\n (answer) => answer?.id === previousAnswerID\n );\n\n if (previousAnswer) {\n setCurrentAnswer(previousAnswer);\n } else {\n setCurrentAnswer(onGetAnswers(currentQuestion.answerIds!).pop()!);\n }\n\n break;\n case 'Enter':\n setCanShowAnswers(false);\n\n if (!currentAnswer?.nextQuestionId) {\n onClose();\n return;\n } else {\n setCurrentQuestion(\n questions.find(\n (question) => question.id === currentAnswer!.nextQuestionId\n )!\n );\n }\n\n break;\n }\n };\n useEventListener('keydown', onKeyPress);\n\n const onAnswerClick = (answer: IQuestionDialogAnswer) => {\n setCanShowAnswers(false);\n if (answer.nextQuestionId) {\n // if there is a next question, go to it\n setCurrentQuestion(\n questions.find((question) => question.id === answer.nextQuestionId)!\n );\n } else {\n // else, finish dialog!\n onClose();\n }\n };\n\n const onRenderCurrentAnswers = () => {\n const answerIds = currentQuestion.answerIds;\n if (!answerIds) {\n return null;\n }\n\n const answers = onGetAnswers(answerIds);\n\n if (!answers) {\n return null;\n }\n\n return answers.map((answer) => {\n const isSelected = currentAnswer?.id === answer?.id;\n const selectedColor = isSelected ? 'yellow' : 'white';\n\n if (answer) {\n return (\n <AnswerRow key={`answer_${answer.id}`}>\n <AnswerSelectedIcon color={selectedColor}>\n {isSelected ? 'X' : null}\n </AnswerSelectedIcon>\n\n <Answer\n key={answer.id}\n onClick={() => onAnswerClick(answer)}\n color={selectedColor}\n >\n {answer.text}\n </Answer>\n </AnswerRow>\n );\n }\n\n return null;\n });\n };\n\n return (\n <Container>\n <QuestionContainer>\n <DynamicText\n text={currentQuestion.text}\n onStart={() => setCanShowAnswers(false)}\n onFinish={() => setCanShowAnswers(true)}\n />\n </QuestionContainer>\n\n {canShowAnswers && (\n <AnswersContainer>{onRenderCurrentAnswers()}</AnswersContainer>\n )}\n </Container>\n );\n};\n\nconst Container = styled.div`\n display: flex;\n\n word-break: break-all;\n\n box-sizing: border-box;\n justify-content: flex-start;\n align-items: flex-start;\n flex-wrap: wrap;\n`;\n\nconst QuestionContainer = styled.div`\n flex: 100%;\n width: 100%;\n`;\n\nconst AnswersContainer = styled.div`\n flex: 100%;\n`;\n\ninterface IAnswerProps {\n color: string;\n}\n\nconst Answer = styled.p<IAnswerProps>`\n flex: auto;\n color: ${(props) => props.color} !important;\n font-size: 0.65rem !important;\n background: inherit;\n border: none;\n`;\n\nconst AnswerSelectedIcon = styled.span<IAnswerProps>`\n flex: 5% 0 0;\n color: ${(props) => props.color} !important;\n`;\n\nconst AnswerRow = styled.div`\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n align-items: center;\n margin-bottom: 0.5rem;\n height: 22px;\n\n p {\n line-height: unset;\n margin-top: 0;\n margin-bottom: 0rem;\n }\n`;\n","import React, { useState } from 'react';\nimport styled from 'styled-components';\nimport { IQuestionDialog, IQuestionDialogAnswer } from '..';\nimport { RPGUIContainer } from '../RPGUI/RPGUIContainer';\nimport { RPGUIRoot } from '../RPGUI/RPGUIRoot';\nimport aliceDefaultThumbnail from './img/npcDialog/npcThumbnails/alice.png';\nimport pressSpaceGif from './img/space.gif';\nimport { NPCDialogText } from './NPCDialogText';\nimport { QuestionDialog } from './QuestionDialog/QuestionDialog';\nexport enum NPCDialogType {\n TextOnly = 'TextOnly',\n TextAndThumbnail = 'TextAndThumbnail',\n}\n\nexport interface INPCDialogProps {\n text?: string;\n type: NPCDialogType;\n imagePath?: string;\n onClose?: () => void;\n isQuestionDialog: boolean;\n answers?: IQuestionDialogAnswer[];\n questions?: IQuestionDialog[];\n}\n\nexport const NPCDialog: React.FC<INPCDialogProps> = ({\n text,\n type,\n onClose,\n imagePath,\n isQuestionDialog = false,\n questions,\n answers,\n}) => {\n const [showGoNextIndicator, setShowGoNextIndicator] =\n useState<boolean>(false);\n\n return (\n <RPGUIRoot>\n <RPGUIContainer\n type=\"framed-golden\"\n width={isQuestionDialog ? '600px' : '50%'}\n height={'180px'}\n >\n {isQuestionDialog && questions && answers ? (\n <>\n <TextContainer\n flex={type === NPCDialogType.TextAndThumbnail ? '70%' : '100%'}\n >\n <QuestionDialog\n questions={questions}\n answers={answers}\n onClose={() => {\n if (onClose) {\n onClose();\n }\n }}\n />\n </TextContainer>\n {type === NPCDialogType.TextAndThumbnail && (\n <ThumbnailContainer>\n <NPCThumbnail src={imagePath || aliceDefaultThumbnail} />\n </ThumbnailContainer>\n )}\n </>\n ) : (\n <>\n <Container>\n <TextContainer\n flex={type === NPCDialogType.TextAndThumbnail ? '70%' : '100%'}\n >\n <NPCDialogText\n onStartStep={() => setShowGoNextIndicator(false)}\n onEndStep={() => setShowGoNextIndicator(true)}\n text={text || 'No text provided.'}\n onClose={() => {\n if (onClose) {\n onClose();\n }\n }}\n />\n </TextContainer>\n {type === NPCDialogType.TextAndThumbnail && (\n <ThumbnailContainer>\n <NPCThumbnail src={imagePath || aliceDefaultThumbnail} />\n </ThumbnailContainer>\n )}\n </Container>\n {showGoNextIndicator && (\n <PressSpaceIndicator\n right={type === NPCDialogType.TextOnly ? '1rem' : '10.5rem'}\n src={pressSpaceGif}\n />\n )}\n </>\n )}\n </RPGUIContainer>\n </RPGUIRoot>\n );\n};\n\nconst Container = styled.div`\n display: flex;\n width: 100%;\n height: 100%;\n\n box-sizing: border-box;\n justify-content: center;\n align-items: flex-start;\n position: relative;\n`;\n\ninterface ITextContainerProps {\n flex: string;\n}\n\nconst TextContainer = styled.div<ITextContainerProps>`\n flex: ${({ flex }) => flex} 0 0;\n width: 355px;\n`;\n\nconst ThumbnailContainer = styled.div`\n flex: 30% 0 0;\n display: flex;\n justify-content: flex-end;\n`;\n\nconst NPCThumbnail = styled.img`\n image-rendering: pixelated;\n height: 128px;\n width: 128px;\n`;\n\ninterface IPressSpaceIndicatorProps {\n right: string;\n}\n\nconst PressSpaceIndicator = styled.img<IPressSpaceIndicatorProps>`\n position: absolute;\n right: ${({ right }) => right};\n bottom: 1rem;\n height: 20.7px;\n image-rendering: -webkit-optimize-contrast;\n`;\n","import React, { useState } from 'react';\nimport styled from 'styled-components';\nimport { v4 as uuidv4 } from 'uuid';\nimport { useEventListener } from '../hooks/useEventListener';\nimport { RPGUIRoot, _RPGUI } from './RPGUIRoot';\n\nexport enum SliderType {\n Slider = 'rpgui-slider',\n GoldSlider = 'rpgui-slider golden',\n}\n\nexport interface ISliderProps {\n type: SliderType;\n valueMin: number;\n valueMax: number;\n width: string;\n\n onChange: (value: number) => void;\n}\n\nexport const RPGUISlider: React.FC<ISliderProps> = ({\n type,\n valueMin,\n valueMax,\n width,\n onChange,\n}) => {\n const sliderId = uuidv4();\n\n const [wasMouseDownFirst, setWasMouseDownFirst] = useState<boolean>(false);\n\n useEventListener('mouseup', () => {\n if (wasMouseDownFirst) {\n onHandleMouseUp();\n }\n setWasMouseDownFirst(false);\n });\n\n const onHandleMouseUp = () => {\n const rpguiSlider = document.getElementById(`rpgui-slider-${sliderId}`);\n const value = _RPGUI.get_value(rpguiSlider);\n\n onChange(Number(value));\n };\n\n return (\n <RPGUIRoot>\n <div\n onMouseUp={onHandleMouseUp}\n onMouseDown={() => setWasMouseDownFirst(true)}\n >\n <Input\n className={\n type === SliderType.Slider\n ? SliderType.Slider\n : SliderType.GoldSlider\n }\n type=\"range\"\n style={{ width: width }}\n min={valueMin}\n max={valueMax}\n id={`rpgui-slider-${sliderId}`}\n />\n </div>\n </RPGUIRoot>\n );\n};\n\nconst Input = styled.input`\n opacity: 0;\n`;\n"],"names":["_RPGUI","RPGUI","RPGUIRoot","children","React","className","ListMenu","title","options","onSelected","Container","style","overflow","map","params","key","text","onClick","id","styled","div","useEventListener","type","handler","el","window","savedHandler","useRef","useEffect","current","listener","e","addEventListener","removeEventListener","RPGUIContainer","width","height","props","img","chunkString","str","length","match","RegExp","DynamicText","onFinish","onStart","useState","textState","setTextState","i","interval","setInterval","substring","clearInterval","TextContainer","p","NPCDialogText","onClose","onEndStep","onStartStep","textChunks","chunkIndex","setChunkIndex","onHandleSpacePress","event","code","hasNextChunk","prev","document","QuestionDialog","questions","answers","currentQuestion","setCurrentQuestion","canShowAnswers","setCanShowAnswers","onGetFirstAnswer","answerIds","firstAnswerId","find","answer","currentAnswer","setCurrentAnswer","onGetAnswers","answerId","onKeyPress","nextAnswerIndex","findIndex","nextAnswerID","nextAnswer","previousAnswerIndex","previousAnswerID","previousAnswer","pop","nextQuestionId","question","onAnswerClick","onRenderCurrentAnswers","isSelected","selectedColor","AnswerRow","AnswerSelectedIcon","color","Answer","QuestionContainer","AnswersContainer","span","NPCDialogType","NPCDialog","imagePath","isQuestionDialog","showGoNextIndicator","setShowGoNextIndicator","flex","TextAndThumbnail","ThumbnailContainer","NPCThumbnail","src","aliceDefaultThumbnail","PressSpaceIndicator","right","TextOnly","pressSpaceGif","SliderType","RPGUISlider","valueMin","valueMax","onChange","sliderId","uuidv4","wasMouseDownFirst","setWasMouseDownFirst","onHandleMouseUp","rpguiSlider","getElementById","value","get_value","Number","onMouseUp","onMouseDown","Input","Slider","GoldSlider","min","max","input"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rpg-engine/long-bow",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.24",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
"@types/react": "^17.0.40",
|
|
69
69
|
"@types/react-dom": "^17.0.13",
|
|
70
70
|
"@types/styled-components": "^5.1.24",
|
|
71
|
+
"@types/uuid": "^8.3.4",
|
|
71
72
|
"babel-loader": "^8.2.3",
|
|
72
73
|
"babel-plugin-styled-components": "^2.0.6",
|
|
73
74
|
"husky": "^7.0.4",
|
|
@@ -75,10 +76,12 @@
|
|
|
75
76
|
"react-dom": "^17.0.2",
|
|
76
77
|
"react-is": "^17.0.2",
|
|
77
78
|
"size-limit": "^7.0.8",
|
|
79
|
+
"storybook-dark-mode": "^1.0.9",
|
|
78
80
|
"styled-components": "^5.3.3",
|
|
79
81
|
"tsdx": "^0.14.1",
|
|
80
82
|
"tslib": "^2.3.1",
|
|
81
|
-
"typescript": "^4.6.2"
|
|
83
|
+
"typescript": "^4.6.2",
|
|
84
|
+
"uuid": "^8.3.2"
|
|
82
85
|
},
|
|
83
86
|
"dependencies": {
|
|
84
87
|
"@rollup/plugin-image": "^2.1.1",
|
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
2
|
import styled from 'styled-components';
|
|
3
|
-
import {
|
|
3
|
+
import { IQuestionDialog, IQuestionDialogAnswer } from '..';
|
|
4
4
|
import { RPGUIContainer } from '../RPGUI/RPGUIContainer';
|
|
5
|
+
import { RPGUIRoot } from '../RPGUI/RPGUIRoot';
|
|
5
6
|
import aliceDefaultThumbnail from './img/npcDialog/npcThumbnails/alice.png';
|
|
6
7
|
import pressSpaceGif from './img/space.gif';
|
|
7
8
|
import { NPCDialogText } from './NPCDialogText';
|
|
9
|
+
import { QuestionDialog } from './QuestionDialog/QuestionDialog';
|
|
8
10
|
export enum NPCDialogType {
|
|
9
11
|
TextOnly = 'TextOnly',
|
|
10
12
|
TextAndThumbnail = 'TextAndThumbnail',
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
export interface INPCDialogProps {
|
|
14
|
-
text
|
|
16
|
+
text?: string;
|
|
15
17
|
type: NPCDialogType;
|
|
16
18
|
imagePath?: string;
|
|
17
19
|
onClose?: () => void;
|
|
20
|
+
isQuestionDialog: boolean;
|
|
21
|
+
answers?: IQuestionDialogAnswer[];
|
|
22
|
+
questions?: IQuestionDialog[];
|
|
18
23
|
}
|
|
19
24
|
|
|
20
25
|
export const NPCDialog: React.FC<INPCDialogProps> = ({
|
|
@@ -22,51 +27,82 @@ export const NPCDialog: React.FC<INPCDialogProps> = ({
|
|
|
22
27
|
type,
|
|
23
28
|
onClose,
|
|
24
29
|
imagePath,
|
|
30
|
+
isQuestionDialog = false,
|
|
31
|
+
questions,
|
|
32
|
+
answers,
|
|
25
33
|
}) => {
|
|
26
|
-
const [isOpen, setIsOpen] = useState<boolean>(true);
|
|
27
34
|
const [showGoNextIndicator, setShowGoNextIndicator] =
|
|
28
35
|
useState<boolean>(false);
|
|
29
36
|
|
|
30
|
-
return
|
|
31
|
-
<
|
|
32
|
-
<RPGUIContainer
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
37
|
+
return (
|
|
38
|
+
<RPGUIRoot>
|
|
39
|
+
<RPGUIContainer
|
|
40
|
+
type="framed-golden"
|
|
41
|
+
width={isQuestionDialog ? '600px' : '50%'}
|
|
42
|
+
height={'180px'}
|
|
43
|
+
>
|
|
44
|
+
{isQuestionDialog && questions && answers ? (
|
|
45
|
+
<>
|
|
46
|
+
<TextContainer
|
|
47
|
+
flex={type === NPCDialogType.TextAndThumbnail ? '70%' : '100%'}
|
|
48
|
+
>
|
|
49
|
+
<QuestionDialog
|
|
50
|
+
questions={questions}
|
|
51
|
+
answers={answers}
|
|
52
|
+
onClose={() => {
|
|
53
|
+
if (onClose) {
|
|
54
|
+
onClose();
|
|
55
|
+
}
|
|
56
|
+
}}
|
|
57
|
+
/>
|
|
58
|
+
</TextContainer>
|
|
59
|
+
{type === NPCDialogType.TextAndThumbnail && (
|
|
60
|
+
<ThumbnailContainer>
|
|
61
|
+
<NPCThumbnail src={imagePath || aliceDefaultThumbnail} />
|
|
62
|
+
</ThumbnailContainer>
|
|
63
|
+
)}
|
|
64
|
+
</>
|
|
65
|
+
) : (
|
|
66
|
+
<>
|
|
67
|
+
<Container>
|
|
68
|
+
<TextContainer
|
|
69
|
+
flex={type === NPCDialogType.TextAndThumbnail ? '70%' : '100%'}
|
|
70
|
+
>
|
|
71
|
+
<NPCDialogText
|
|
72
|
+
onStartStep={() => setShowGoNextIndicator(false)}
|
|
73
|
+
onEndStep={() => setShowGoNextIndicator(true)}
|
|
74
|
+
text={text || 'No text provided.'}
|
|
75
|
+
onClose={() => {
|
|
76
|
+
if (onClose) {
|
|
77
|
+
onClose();
|
|
78
|
+
}
|
|
79
|
+
}}
|
|
80
|
+
/>
|
|
81
|
+
</TextContainer>
|
|
82
|
+
{type === NPCDialogType.TextAndThumbnail && (
|
|
83
|
+
<ThumbnailContainer>
|
|
84
|
+
<NPCThumbnail src={imagePath || aliceDefaultThumbnail} />
|
|
85
|
+
</ThumbnailContainer>
|
|
86
|
+
)}
|
|
87
|
+
</Container>
|
|
88
|
+
{showGoNextIndicator && (
|
|
89
|
+
<PressSpaceIndicator
|
|
90
|
+
right={type === NPCDialogType.TextOnly ? '1rem' : '10.5rem'}
|
|
91
|
+
src={pressSpaceGif}
|
|
92
|
+
/>
|
|
93
|
+
)}
|
|
94
|
+
</>
|
|
60
95
|
)}
|
|
61
96
|
</RPGUIContainer>
|
|
62
|
-
</
|
|
63
|
-
)
|
|
97
|
+
</RPGUIRoot>
|
|
98
|
+
);
|
|
64
99
|
};
|
|
65
100
|
|
|
66
101
|
const Container = styled.div`
|
|
67
102
|
display: flex;
|
|
68
103
|
width: 100%;
|
|
69
|
-
height:
|
|
104
|
+
height: 100%;
|
|
105
|
+
|
|
70
106
|
box-sizing: border-box;
|
|
71
107
|
justify-content: center;
|
|
72
108
|
align-items: flex-start;
|
|
@@ -22,12 +22,7 @@ export const NPCDialogText: React.FC<IProps> = ({
|
|
|
22
22
|
|
|
23
23
|
const onHandleSpacePress = (event: KeyboardEvent) => {
|
|
24
24
|
if (event.code === 'Space') {
|
|
25
|
-
console.log('space pressed!');
|
|
26
|
-
|
|
27
25
|
const hasNextChunk = textChunks?.[chunkIndex + 1] || false;
|
|
28
|
-
console.log(textChunks);
|
|
29
|
-
console.log(chunkIndex);
|
|
30
|
-
console.log(hasNextChunk);
|
|
31
26
|
|
|
32
27
|
if (hasNextChunk) {
|
|
33
28
|
setChunkIndex((prev) => prev + 1);
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
import { useEventListener } from '../../hooks/useEventListener';
|
|
4
|
+
import { DynamicText } from '../../typography/DynamicText';
|
|
5
|
+
|
|
6
|
+
export interface IQuestionDialogAnswer {
|
|
7
|
+
id: number;
|
|
8
|
+
text: string;
|
|
9
|
+
nextQuestionId?: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface IQuestionDialog {
|
|
13
|
+
id: number;
|
|
14
|
+
text: string;
|
|
15
|
+
answerIds?: number[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface IProps {
|
|
19
|
+
questions: IQuestionDialog[];
|
|
20
|
+
answers: IQuestionDialogAnswer[];
|
|
21
|
+
onClose: () => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const QuestionDialog: React.FC<IProps> = ({
|
|
25
|
+
questions,
|
|
26
|
+
answers,
|
|
27
|
+
onClose,
|
|
28
|
+
}) => {
|
|
29
|
+
const [currentQuestion, setCurrentQuestion] = useState(questions[0]);
|
|
30
|
+
|
|
31
|
+
const [canShowAnswers, setCanShowAnswers] = useState<boolean>(false);
|
|
32
|
+
|
|
33
|
+
const onGetFirstAnswer = () => {
|
|
34
|
+
if (!currentQuestion.answerIds || currentQuestion.answerIds.length === 0) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const firstAnswerId = currentQuestion.answerIds![0];
|
|
39
|
+
|
|
40
|
+
return answers.find((answer) => answer.id === firstAnswerId);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const [currentAnswer, setCurrentAnswer] =
|
|
44
|
+
useState<IQuestionDialogAnswer | null>(onGetFirstAnswer()!);
|
|
45
|
+
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
setCurrentAnswer(onGetFirstAnswer()!);
|
|
48
|
+
}, [currentQuestion]);
|
|
49
|
+
|
|
50
|
+
const onGetAnswers = (answerIds: number[]) => {
|
|
51
|
+
return answerIds.map((answerId: number) =>
|
|
52
|
+
answers.find((answer) => answer.id === answerId)
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const onKeyPress = (e: KeyboardEvent) => {
|
|
57
|
+
switch (e.key) {
|
|
58
|
+
case 'ArrowDown':
|
|
59
|
+
// select next answer, if any.
|
|
60
|
+
// if no next answer, select first answer
|
|
61
|
+
// const nextAnswer = onGetAnswers(currentQuestion.answerIds!).find(
|
|
62
|
+
// (answer) => answer?.id === currentAnswer!.id + 1
|
|
63
|
+
// );
|
|
64
|
+
|
|
65
|
+
const nextAnswerIndex = onGetAnswers(
|
|
66
|
+
currentQuestion.answerIds!
|
|
67
|
+
).findIndex((answer) => answer?.id === currentAnswer!.id + 1);
|
|
68
|
+
|
|
69
|
+
const nextAnswerID = currentQuestion.answerIds![nextAnswerIndex];
|
|
70
|
+
|
|
71
|
+
// console.log(nextAnswerIndex);
|
|
72
|
+
|
|
73
|
+
const nextAnswer = onGetAnswers(currentQuestion.answerIds!).find(
|
|
74
|
+
(answer) => answer?.id === nextAnswerID
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
setCurrentAnswer(nextAnswer || onGetFirstAnswer()!);
|
|
78
|
+
|
|
79
|
+
break;
|
|
80
|
+
case 'ArrowUp':
|
|
81
|
+
// select previous answer, if any.
|
|
82
|
+
// if no previous answer, select last answer
|
|
83
|
+
|
|
84
|
+
const previousAnswerIndex = onGetAnswers(
|
|
85
|
+
currentQuestion.answerIds!
|
|
86
|
+
).findIndex((answer) => answer?.id === currentAnswer!.id - 1);
|
|
87
|
+
|
|
88
|
+
const previousAnswerID =
|
|
89
|
+
currentQuestion.answerIds &&
|
|
90
|
+
currentQuestion.answerIds[previousAnswerIndex];
|
|
91
|
+
|
|
92
|
+
const previousAnswer = onGetAnswers(currentQuestion.answerIds!).find(
|
|
93
|
+
(answer) => answer?.id === previousAnswerID
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
if (previousAnswer) {
|
|
97
|
+
setCurrentAnswer(previousAnswer);
|
|
98
|
+
} else {
|
|
99
|
+
setCurrentAnswer(onGetAnswers(currentQuestion.answerIds!).pop()!);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
break;
|
|
103
|
+
case 'Enter':
|
|
104
|
+
setCanShowAnswers(false);
|
|
105
|
+
|
|
106
|
+
if (!currentAnswer?.nextQuestionId) {
|
|
107
|
+
onClose();
|
|
108
|
+
return;
|
|
109
|
+
} else {
|
|
110
|
+
setCurrentQuestion(
|
|
111
|
+
questions.find(
|
|
112
|
+
(question) => question.id === currentAnswer!.nextQuestionId
|
|
113
|
+
)!
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
useEventListener('keydown', onKeyPress);
|
|
121
|
+
|
|
122
|
+
const onAnswerClick = (answer: IQuestionDialogAnswer) => {
|
|
123
|
+
setCanShowAnswers(false);
|
|
124
|
+
if (answer.nextQuestionId) {
|
|
125
|
+
// if there is a next question, go to it
|
|
126
|
+
setCurrentQuestion(
|
|
127
|
+
questions.find((question) => question.id === answer.nextQuestionId)!
|
|
128
|
+
);
|
|
129
|
+
} else {
|
|
130
|
+
// else, finish dialog!
|
|
131
|
+
onClose();
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const onRenderCurrentAnswers = () => {
|
|
136
|
+
const answerIds = currentQuestion.answerIds;
|
|
137
|
+
if (!answerIds) {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const answers = onGetAnswers(answerIds);
|
|
142
|
+
|
|
143
|
+
if (!answers) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return answers.map((answer) => {
|
|
148
|
+
const isSelected = currentAnswer?.id === answer?.id;
|
|
149
|
+
const selectedColor = isSelected ? 'yellow' : 'white';
|
|
150
|
+
|
|
151
|
+
if (answer) {
|
|
152
|
+
return (
|
|
153
|
+
<AnswerRow key={`answer_${answer.id}`}>
|
|
154
|
+
<AnswerSelectedIcon color={selectedColor}>
|
|
155
|
+
{isSelected ? 'X' : null}
|
|
156
|
+
</AnswerSelectedIcon>
|
|
157
|
+
|
|
158
|
+
<Answer
|
|
159
|
+
key={answer.id}
|
|
160
|
+
onClick={() => onAnswerClick(answer)}
|
|
161
|
+
color={selectedColor}
|
|
162
|
+
>
|
|
163
|
+
{answer.text}
|
|
164
|
+
</Answer>
|
|
165
|
+
</AnswerRow>
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return null;
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
return (
|
|
174
|
+
<Container>
|
|
175
|
+
<QuestionContainer>
|
|
176
|
+
<DynamicText
|
|
177
|
+
text={currentQuestion.text}
|
|
178
|
+
onStart={() => setCanShowAnswers(false)}
|
|
179
|
+
onFinish={() => setCanShowAnswers(true)}
|
|
180
|
+
/>
|
|
181
|
+
</QuestionContainer>
|
|
182
|
+
|
|
183
|
+
{canShowAnswers && (
|
|
184
|
+
<AnswersContainer>{onRenderCurrentAnswers()}</AnswersContainer>
|
|
185
|
+
)}
|
|
186
|
+
</Container>
|
|
187
|
+
);
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const Container = styled.div`
|
|
191
|
+
display: flex;
|
|
192
|
+
|
|
193
|
+
word-break: break-all;
|
|
194
|
+
|
|
195
|
+
box-sizing: border-box;
|
|
196
|
+
justify-content: flex-start;
|
|
197
|
+
align-items: flex-start;
|
|
198
|
+
flex-wrap: wrap;
|
|
199
|
+
`;
|
|
200
|
+
|
|
201
|
+
const QuestionContainer = styled.div`
|
|
202
|
+
flex: 100%;
|
|
203
|
+
width: 100%;
|
|
204
|
+
`;
|
|
205
|
+
|
|
206
|
+
const AnswersContainer = styled.div`
|
|
207
|
+
flex: 100%;
|
|
208
|
+
`;
|
|
209
|
+
|
|
210
|
+
interface IAnswerProps {
|
|
211
|
+
color: string;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const Answer = styled.p<IAnswerProps>`
|
|
215
|
+
flex: auto;
|
|
216
|
+
color: ${(props) => props.color} !important;
|
|
217
|
+
font-size: 0.65rem !important;
|
|
218
|
+
background: inherit;
|
|
219
|
+
border: none;
|
|
220
|
+
`;
|
|
221
|
+
|
|
222
|
+
const AnswerSelectedIcon = styled.span<IAnswerProps>`
|
|
223
|
+
flex: 5% 0 0;
|
|
224
|
+
color: ${(props) => props.color} !important;
|
|
225
|
+
`;
|
|
226
|
+
|
|
227
|
+
const AnswerRow = styled.div`
|
|
228
|
+
display: flex;
|
|
229
|
+
flex-wrap: wrap;
|
|
230
|
+
justify-content: center;
|
|
231
|
+
align-items: center;
|
|
232
|
+
margin-bottom: 0.5rem;
|
|
233
|
+
height: 22px;
|
|
234
|
+
|
|
235
|
+
p {
|
|
236
|
+
line-height: unset;
|
|
237
|
+
margin-top: 0;
|
|
238
|
+
margin-bottom: 0rem;
|
|
239
|
+
}
|
|
240
|
+
`;
|
|
@@ -5,15 +5,21 @@ interface IProps {
|
|
|
5
5
|
type: 'framed' | 'framed-golden' | 'framed-golden-2' | 'framed-grey';
|
|
6
6
|
children: React.ReactNode;
|
|
7
7
|
width?: string;
|
|
8
|
+
height?: string;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export const RPGUIContainer: React.FC<IProps> = ({
|
|
11
12
|
children,
|
|
12
13
|
type,
|
|
13
14
|
width = '50%',
|
|
15
|
+
height,
|
|
14
16
|
}) => {
|
|
15
17
|
return (
|
|
16
|
-
<Container
|
|
18
|
+
<Container
|
|
19
|
+
width={width}
|
|
20
|
+
height={height || 'auto'}
|
|
21
|
+
className={`rpgui-container ${type}`}
|
|
22
|
+
>
|
|
17
23
|
{children}
|
|
18
24
|
</Container>
|
|
19
25
|
);
|
|
@@ -21,8 +27,12 @@ export const RPGUIContainer: React.FC<IProps> = ({
|
|
|
21
27
|
|
|
22
28
|
interface IContainerProps {
|
|
23
29
|
width: string;
|
|
30
|
+
height: string;
|
|
24
31
|
}
|
|
25
32
|
|
|
26
33
|
const Container = styled.div<IContainerProps>`
|
|
27
|
-
|
|
34
|
+
height: ${(props) => props.height};
|
|
35
|
+
width: ${({ width }) => width};
|
|
36
|
+
display: flex;
|
|
37
|
+
flex-wrap: wrap;
|
|
28
38
|
`;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import 'rpgui/rpgui.min.css';
|
|
3
|
+
import 'rpgui/rpgui.min.js';
|
|
4
|
+
|
|
5
|
+
interface IProps {
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
//@ts-ignore
|
|
10
|
+
export const _RPGUI = RPGUI;
|
|
11
|
+
|
|
12
|
+
export const RPGUIRoot: React.FC<IProps> = ({ children }) => {
|
|
13
|
+
return <div className="rpgui-content">{children}</div>;
|
|
14
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
4
|
+
import { useEventListener } from '../hooks/useEventListener';
|
|
5
|
+
import { RPGUIRoot, _RPGUI } from './RPGUIRoot';
|
|
6
|
+
|
|
7
|
+
export enum SliderType {
|
|
8
|
+
Slider = 'rpgui-slider',
|
|
9
|
+
GoldSlider = 'rpgui-slider golden',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ISliderProps {
|
|
13
|
+
type: SliderType;
|
|
14
|
+
valueMin: number;
|
|
15
|
+
valueMax: number;
|
|
16
|
+
width: string;
|
|
17
|
+
|
|
18
|
+
onChange: (value: number) => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const RPGUISlider: React.FC<ISliderProps> = ({
|
|
22
|
+
type,
|
|
23
|
+
valueMin,
|
|
24
|
+
valueMax,
|
|
25
|
+
width,
|
|
26
|
+
onChange,
|
|
27
|
+
}) => {
|
|
28
|
+
const sliderId = uuidv4();
|
|
29
|
+
|
|
30
|
+
const [wasMouseDownFirst, setWasMouseDownFirst] = useState<boolean>(false);
|
|
31
|
+
|
|
32
|
+
useEventListener('mouseup', () => {
|
|
33
|
+
if (wasMouseDownFirst) {
|
|
34
|
+
onHandleMouseUp();
|
|
35
|
+
}
|
|
36
|
+
setWasMouseDownFirst(false);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const onHandleMouseUp = () => {
|
|
40
|
+
const rpguiSlider = document.getElementById(`rpgui-slider-${sliderId}`);
|
|
41
|
+
const value = _RPGUI.get_value(rpguiSlider);
|
|
42
|
+
|
|
43
|
+
onChange(Number(value));
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<RPGUIRoot>
|
|
48
|
+
<div
|
|
49
|
+
onMouseUp={onHandleMouseUp}
|
|
50
|
+
onMouseDown={() => setWasMouseDownFirst(true)}
|
|
51
|
+
>
|
|
52
|
+
<Input
|
|
53
|
+
className={
|
|
54
|
+
type === SliderType.Slider
|
|
55
|
+
? SliderType.Slider
|
|
56
|
+
: SliderType.GoldSlider
|
|
57
|
+
}
|
|
58
|
+
type="range"
|
|
59
|
+
style={{ width: width }}
|
|
60
|
+
min={valueMin}
|
|
61
|
+
max={valueMax}
|
|
62
|
+
id={`rpgui-slider-${sliderId}`}
|
|
63
|
+
/>
|
|
64
|
+
</div>
|
|
65
|
+
</RPGUIRoot>
|
|
66
|
+
);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const Input = styled.input`
|
|
70
|
+
opacity: 0;
|
|
71
|
+
`;
|