@rpg-engine/long-bow 0.8.228 → 0.8.230
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/components/RadioSelectCard/RadioSelectCard.d.ts +16 -0
- package/dist/index.d.ts +1 -0
- package/dist/long-bow.cjs.development.js +135 -57
- 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 +135 -58
- package/dist/long-bow.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/NPCDialog/NPCDialog.tsx +56 -16
- package/src/components/NPCDialog/NPCDialogText.tsx +18 -5
- package/src/components/RadioSelectCard/RadioSelectCard.tsx +123 -0
- package/src/components/typography/DynamicText.tsx +3 -1
- package/src/index.tsx +1 -0
package/package.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { FaTimes } from 'react-icons/fa';
|
|
2
3
|
import styled from 'styled-components';
|
|
3
4
|
import { RPGUIContainer, RPGUIContainerTypes } from '../RPGUI/RPGUIContainer';
|
|
4
5
|
import { NPCDialogText } from './NPCDialogText';
|
|
@@ -65,9 +66,8 @@ export const NPCDialog: React.FC<INPCDialogProps> = ({
|
|
|
65
66
|
) : (
|
|
66
67
|
<>
|
|
67
68
|
<Container>
|
|
68
|
-
<CloseIcon onPointerDown={onClose}>X</CloseIcon>
|
|
69
69
|
<TextContainer
|
|
70
|
-
flex={type === NPCDialogType.TextAndThumbnail ? '
|
|
70
|
+
flex={type === NPCDialogType.TextAndThumbnail ? '1' : '100%'}
|
|
71
71
|
>
|
|
72
72
|
<NPCDialogText
|
|
73
73
|
type={type}
|
|
@@ -82,6 +82,9 @@ export const NPCDialog: React.FC<INPCDialogProps> = ({
|
|
|
82
82
|
</TextContainer>
|
|
83
83
|
{type === NPCDialogType.TextAndThumbnail && (
|
|
84
84
|
<ThumbnailContainer>
|
|
85
|
+
<CloseButton onPointerDown={onClose}>
|
|
86
|
+
<FaTimes size={12} />
|
|
87
|
+
</CloseButton>
|
|
85
88
|
<NPCThumbnail src={imagePath || aliceDefaultThumbnail} />
|
|
86
89
|
</ThumbnailContainer>
|
|
87
90
|
)}
|
|
@@ -96,20 +99,41 @@ const Container = styled.div`
|
|
|
96
99
|
display: flex;
|
|
97
100
|
width: 100%;
|
|
98
101
|
height: 100%;
|
|
99
|
-
|
|
100
102
|
box-sizing: border-box;
|
|
101
|
-
justify-content:
|
|
102
|
-
align-items:
|
|
103
|
+
justify-content: flex-start;
|
|
104
|
+
align-items: center;
|
|
103
105
|
position: relative;
|
|
106
|
+
padding: 1rem 1rem 0.5rem 1rem;
|
|
104
107
|
`;
|
|
105
108
|
|
|
106
|
-
const
|
|
109
|
+
const CloseButton = styled.button`
|
|
107
110
|
position: absolute;
|
|
108
|
-
top: -
|
|
109
|
-
right: -
|
|
111
|
+
top: -12px;
|
|
112
|
+
right: -12px;
|
|
113
|
+
width: 26px;
|
|
114
|
+
height: 26px;
|
|
115
|
+
background: #000;
|
|
116
|
+
border: 2px solid #fff;
|
|
117
|
+
border-radius: 2px;
|
|
118
|
+
color: #fff;
|
|
119
|
+
display: flex;
|
|
120
|
+
justify-content: center;
|
|
121
|
+
align-items: center;
|
|
110
122
|
cursor: pointer;
|
|
111
|
-
|
|
112
|
-
|
|
123
|
+
z-index: 10;
|
|
124
|
+
padding: 0;
|
|
125
|
+
box-shadow: 0 2px 0px rgba(0, 0, 0, 1);
|
|
126
|
+
transition: all 0.1s;
|
|
127
|
+
|
|
128
|
+
&:hover {
|
|
129
|
+
background: #333;
|
|
130
|
+
border-color: #eee;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
&:active {
|
|
134
|
+
transform: translateY(2px);
|
|
135
|
+
box-shadow: 0 0 0px rgba(0, 0, 0, 1);
|
|
136
|
+
}
|
|
113
137
|
`;
|
|
114
138
|
|
|
115
139
|
interface ITextContainerProps {
|
|
@@ -117,18 +141,34 @@ interface ITextContainerProps {
|
|
|
117
141
|
}
|
|
118
142
|
|
|
119
143
|
const TextContainer = styled.div<ITextContainerProps>`
|
|
120
|
-
flex: ${({ flex }) => flex}
|
|
121
|
-
|
|
144
|
+
flex: ${({ flex }) => flex};
|
|
145
|
+
height: 100%;
|
|
146
|
+
padding-right: 1.5rem;
|
|
147
|
+
display: flex;
|
|
148
|
+
flex-direction: column;
|
|
122
149
|
`;
|
|
123
150
|
|
|
124
151
|
const ThumbnailContainer = styled.div`
|
|
125
|
-
flex:
|
|
152
|
+
flex-shrink: 0;
|
|
153
|
+
position: relative;
|
|
154
|
+
width: 116px;
|
|
155
|
+
height: 116px;
|
|
156
|
+
/* Layered pixel-art borders: inner black -> gold -> outer black */
|
|
157
|
+
border: 4px solid #1a100c;
|
|
158
|
+
border-radius: 2px;
|
|
159
|
+
box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.4), 0 0 0 2px #d4a373, 0 0 0 4px #000;
|
|
160
|
+
background: #3e2723;
|
|
126
161
|
display: flex;
|
|
127
|
-
justify-content:
|
|
162
|
+
justify-content: center;
|
|
163
|
+
align-items: center;
|
|
164
|
+
margin-right: 8px;
|
|
165
|
+
padding: 2px;
|
|
128
166
|
`;
|
|
129
167
|
|
|
130
168
|
const NPCThumbnail = styled.img`
|
|
131
169
|
image-rendering: pixelated;
|
|
132
|
-
height:
|
|
133
|
-
width:
|
|
170
|
+
height: 100%;
|
|
171
|
+
width: 100%;
|
|
172
|
+
object-fit: contain;
|
|
173
|
+
border-radius: 1px;
|
|
134
174
|
`;
|
|
@@ -118,14 +118,24 @@ export const NPCDialogText: React.FC<IProps> = ({
|
|
|
118
118
|
);
|
|
119
119
|
};
|
|
120
120
|
|
|
121
|
-
const Container = styled.div
|
|
121
|
+
const Container = styled.div`
|
|
122
|
+
width: 100%;
|
|
123
|
+
height: 100%;
|
|
124
|
+
display: flex;
|
|
125
|
+
flex-direction: column;
|
|
126
|
+
position: relative;
|
|
127
|
+
padding-bottom: 24px;
|
|
128
|
+
`;
|
|
122
129
|
|
|
123
130
|
const TextContainer = styled.p`
|
|
124
|
-
font-size: 0.
|
|
131
|
+
font-size: 0.8rem !important;
|
|
132
|
+
line-height: 1.6;
|
|
125
133
|
color: white;
|
|
126
134
|
text-shadow: 1px 1px 0px #000000;
|
|
127
135
|
letter-spacing: 1.2px;
|
|
128
136
|
word-break: normal;
|
|
137
|
+
margin: 0;
|
|
138
|
+
flex: 1;
|
|
129
139
|
`;
|
|
130
140
|
|
|
131
141
|
interface IPressSpaceIndicatorProps {
|
|
@@ -134,8 +144,11 @@ interface IPressSpaceIndicatorProps {
|
|
|
134
144
|
|
|
135
145
|
const PressSpaceIndicator = styled.img<IPressSpaceIndicatorProps>`
|
|
136
146
|
position: absolute;
|
|
137
|
-
|
|
138
|
-
bottom:
|
|
139
|
-
height:
|
|
147
|
+
left: 0;
|
|
148
|
+
bottom: -0.5rem;
|
|
149
|
+
height: 20px;
|
|
150
|
+
object-fit: contain;
|
|
151
|
+
object-position: left;
|
|
140
152
|
image-rendering: -webkit-optimize-contrast;
|
|
153
|
+
cursor: pointer;
|
|
141
154
|
`;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
|
|
4
|
+
export interface IRadioSelectCardProps {
|
|
5
|
+
label: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
badge?: string;
|
|
8
|
+
icon?: React.ReactNode;
|
|
9
|
+
active?: boolean;
|
|
10
|
+
onClick: () => void;
|
|
11
|
+
'data-testid'?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Dark RPG-themed radio-style card.
|
|
16
|
+
* Matches the aesthetic of MarketplaceSettingsPanel OptionCard.
|
|
17
|
+
* Uses !important overrides to survive RPGUI global CSS.
|
|
18
|
+
*/
|
|
19
|
+
export const RadioSelectCard: React.FC<IRadioSelectCardProps> = ({
|
|
20
|
+
label,
|
|
21
|
+
description,
|
|
22
|
+
badge,
|
|
23
|
+
icon,
|
|
24
|
+
active = false,
|
|
25
|
+
onClick,
|
|
26
|
+
'data-testid': testId
|
|
27
|
+
}) => {
|
|
28
|
+
return (
|
|
29
|
+
<Card $active={active} onClick={onClick} data-testid={testId} type="button">
|
|
30
|
+
{icon && <IconWrap>{icon}</IconWrap>}
|
|
31
|
+
<Body>
|
|
32
|
+
<Label $active={active}>{label}</Label>
|
|
33
|
+
{description && <Description>{description}</Description>}
|
|
34
|
+
</Body>
|
|
35
|
+
{badge && <Badge $active={active}>{badge}</Badge>}
|
|
36
|
+
</Card>
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// ─── Styled Components ────────────────────────────────────────────────────────
|
|
41
|
+
|
|
42
|
+
const Card = styled.button<{ $active: boolean }>`
|
|
43
|
+
display: flex !important;
|
|
44
|
+
flex-direction: row !important;
|
|
45
|
+
align-items: center !important;
|
|
46
|
+
gap: 0.6rem !important;
|
|
47
|
+
width: 100% !important;
|
|
48
|
+
padding: 0.75rem 0.9rem !important;
|
|
49
|
+
background: ${({ $active }) =>
|
|
50
|
+
$active ? 'rgba(245, 158, 11, 0.12)' : 'rgba(0, 0, 0, 0.25)'} !important;
|
|
51
|
+
border: 2px solid
|
|
52
|
+
${({ $active }) =>
|
|
53
|
+
$active ? '#f59e0b' : 'rgba(255, 255, 255, 0.08)'} !important;
|
|
54
|
+
border-radius: 6px !important;
|
|
55
|
+
cursor: pointer !important;
|
|
56
|
+
text-align: left !important;
|
|
57
|
+
transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease !important;
|
|
58
|
+
font-family: inherit !important;
|
|
59
|
+
box-sizing: border-box !important;
|
|
60
|
+
|
|
61
|
+
&:hover {
|
|
62
|
+
border-color: ${({ $active }) =>
|
|
63
|
+
$active ? '#f59e0b' : 'rgba(255, 255, 255, 0.3)'} !important;
|
|
64
|
+
background: ${({ $active }) =>
|
|
65
|
+
$active ? 'rgba(245, 158, 11, 0.18)' : 'rgba(255, 255, 255, 0.04)'} !important;
|
|
66
|
+
box-shadow: ${({ $active }) =>
|
|
67
|
+
$active
|
|
68
|
+
? '0 0 14px rgba(245, 158, 11, 0.3)'
|
|
69
|
+
: '0 0 8px rgba(255, 255, 255, 0.05)'} !important;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
&:active {
|
|
73
|
+
background: rgba(0, 0, 0, 0.5) !important;
|
|
74
|
+
}
|
|
75
|
+
`;
|
|
76
|
+
|
|
77
|
+
const IconWrap = styled.span`
|
|
78
|
+
font-size: 1.4rem !important;
|
|
79
|
+
line-height: 1 !important;
|
|
80
|
+
flex-shrink: 0 !important;
|
|
81
|
+
`;
|
|
82
|
+
|
|
83
|
+
const Body = styled.div`
|
|
84
|
+
flex: 1 !important;
|
|
85
|
+
min-width: 0 !important;
|
|
86
|
+
display: flex !important;
|
|
87
|
+
flex-direction: column !important;
|
|
88
|
+
gap: 0.2rem !important;
|
|
89
|
+
`;
|
|
90
|
+
|
|
91
|
+
const Label = styled.span<{ $active: boolean }>`
|
|
92
|
+
font-size: 0.72rem !important;
|
|
93
|
+
font-weight: bold !important;
|
|
94
|
+
color: ${({ $active }) =>
|
|
95
|
+
$active ? '#f59e0b' : 'rgba(255, 255, 255, 0.9)'} !important;
|
|
96
|
+
text-transform: uppercase !important;
|
|
97
|
+
letter-spacing: 0.8px !important;
|
|
98
|
+
line-height: 1.2 !important;
|
|
99
|
+
`;
|
|
100
|
+
|
|
101
|
+
const Description = styled.span`
|
|
102
|
+
font-size: 0.62rem !important;
|
|
103
|
+
color: rgba(255, 255, 255, 0.45) !important;
|
|
104
|
+
line-height: 1.4 !important;
|
|
105
|
+
`;
|
|
106
|
+
|
|
107
|
+
const Badge = styled.span<{ $active: boolean }>`
|
|
108
|
+
flex-shrink: 0 !important;
|
|
109
|
+
padding: 0.15rem 0.45rem !important;
|
|
110
|
+
background: ${({ $active }) =>
|
|
111
|
+
$active ? 'rgba(245, 158, 11, 0.2)' : 'rgba(255, 255, 255, 0.06)'} !important;
|
|
112
|
+
border: 1px solid
|
|
113
|
+
${({ $active }) =>
|
|
114
|
+
$active ? 'rgba(245, 158, 11, 0.5)' : 'rgba(255, 255, 255, 0.12)'} !important;
|
|
115
|
+
border-radius: 20px !important;
|
|
116
|
+
font-size: 0.55rem !important;
|
|
117
|
+
font-weight: bold !important;
|
|
118
|
+
letter-spacing: 0.5px !important;
|
|
119
|
+
text-transform: uppercase !important;
|
|
120
|
+
color: ${({ $active }) =>
|
|
121
|
+
$active ? '#f59e0b' : 'rgba(255, 255, 255, 0.45)'} !important;
|
|
122
|
+
white-space: nowrap !important;
|
|
123
|
+
`;
|
|
@@ -41,9 +41,11 @@ export const DynamicText: React.FC<IProps> = ({ text, onFinish, onStart }) => {
|
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
const TextContainer = styled.p`
|
|
44
|
-
font-size: 0.
|
|
44
|
+
font-size: 0.8rem !important;
|
|
45
|
+
line-height: 1.6;
|
|
45
46
|
color: white;
|
|
46
47
|
text-shadow: 1px 1px 0px #000000;
|
|
47
48
|
letter-spacing: 1.2px;
|
|
48
49
|
word-break: normal;
|
|
50
|
+
margin: 0;
|
|
49
51
|
`;
|
package/src/index.tsx
CHANGED
|
@@ -63,6 +63,7 @@ export * from './components/QuantitySelector/QuantitySelectorModal';
|
|
|
63
63
|
export * from './components/Quests/QuestInfo/QuestInfo';
|
|
64
64
|
export * from './components/Quests/QuestList';
|
|
65
65
|
export * from './components/RadioButton';
|
|
66
|
+
export * from './components/RadioSelectCard/RadioSelectCard';
|
|
66
67
|
export * from './components/RangeSlider';
|
|
67
68
|
export * from './components/RPGUI/RPGUIContainer';
|
|
68
69
|
export * from './components/RPGUI/RPGUIRoot';
|