@rpg-engine/long-bow 0.8.229 → 0.8.231
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 +127 -28
- 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 +127 -29
- package/dist/long-bow.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Item/Cards/ItemTooltip.tsx +27 -16
- package/src/components/RadioSelectCard/RadioSelectCard.tsx +123 -0
- package/src/components/shared/SimpleTooltip.tsx +32 -19
- package/src/index.tsx +1 -0
package/package.json
CHANGED
|
@@ -20,38 +20,49 @@ export const ItemTooltip: React.FC<IItemTooltipProps> = ({
|
|
|
20
20
|
equipmentSet,
|
|
21
21
|
}) => {
|
|
22
22
|
const ref = useRef<HTMLDivElement>(null);
|
|
23
|
+
const rafId = useRef<number | null>(null);
|
|
23
24
|
|
|
24
25
|
useEffect(() => {
|
|
25
26
|
const { current } = ref;
|
|
26
27
|
|
|
27
28
|
if (current) {
|
|
28
29
|
const handleMouseMove = (event: MouseEvent) => {
|
|
30
|
+
if (rafId.current !== null) return;
|
|
31
|
+
|
|
29
32
|
const { clientX, clientY } = event;
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
rafId.current = requestAnimationFrame(() => {
|
|
35
|
+
rafId.current = null;
|
|
36
|
+
|
|
37
|
+
// Adjust the position of the tooltip based on the mouse position
|
|
38
|
+
const rect = current.getBoundingClientRect();
|
|
33
39
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
const tooltipWidth = rect.width;
|
|
41
|
+
const tooltipHeight = rect.height;
|
|
42
|
+
const isOffScreenRight =
|
|
43
|
+
clientX + tooltipWidth + offset > window.innerWidth;
|
|
44
|
+
const isOffScreenBottom =
|
|
45
|
+
clientY + tooltipHeight + offset > window.innerHeight;
|
|
46
|
+
const x = isOffScreenRight
|
|
47
|
+
? clientX - tooltipWidth - offset
|
|
48
|
+
: clientX + offset;
|
|
49
|
+
const y = isOffScreenBottom
|
|
50
|
+
? clientY - tooltipHeight - offset
|
|
51
|
+
: clientY + offset;
|
|
46
52
|
|
|
47
|
-
|
|
48
|
-
|
|
53
|
+
current.style.transform = `translate(${x}px, ${y}px)`;
|
|
54
|
+
current.style.opacity = '1';
|
|
55
|
+
});
|
|
49
56
|
};
|
|
50
57
|
|
|
51
58
|
window.addEventListener('mousemove', handleMouseMove);
|
|
52
59
|
|
|
53
60
|
return () => {
|
|
54
61
|
window.removeEventListener('mousemove', handleMouseMove);
|
|
62
|
+
if (rafId.current !== null) {
|
|
63
|
+
cancelAnimationFrame(rafId.current);
|
|
64
|
+
rafId.current = null;
|
|
65
|
+
}
|
|
55
66
|
};
|
|
56
67
|
}
|
|
57
68
|
|
|
@@ -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
|
+
`;
|
|
@@ -28,6 +28,7 @@ export const SimpleTooltip: React.FC<TooltipProps> = ({
|
|
|
28
28
|
const tooltipRef = useRef<HTMLDivElement>(null);
|
|
29
29
|
const triggerRef = useRef<HTMLDivElement>(null);
|
|
30
30
|
const timeoutRef = useRef<NodeJS.Timeout>();
|
|
31
|
+
const rafId = useRef<number | null>(null);
|
|
31
32
|
|
|
32
33
|
const calculatePosition = () => {
|
|
33
34
|
if (!triggerRef.current || !tooltipRef.current) return;
|
|
@@ -87,26 +88,34 @@ export const SimpleTooltip: React.FC<TooltipProps> = ({
|
|
|
87
88
|
|
|
88
89
|
useEffect(() => {
|
|
89
90
|
const handleMouseMove = (event: MouseEvent) => {
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
91
|
+
if (rafId.current !== null) return;
|
|
92
|
+
|
|
93
|
+
const { clientX, clientY } = event;
|
|
94
|
+
|
|
95
|
+
rafId.current = requestAnimationFrame(() => {
|
|
96
|
+
rafId.current = null;
|
|
97
|
+
|
|
98
|
+
if (visible && tooltipRef.current && triggerRef.current) {
|
|
99
|
+
const tooltipRect = tooltipRef.current.getBoundingClientRect();
|
|
100
|
+
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
101
|
+
|
|
102
|
+
const isOutsideTooltip =
|
|
103
|
+
clientX < tooltipRect.left ||
|
|
104
|
+
clientX > tooltipRect.right ||
|
|
105
|
+
clientY < tooltipRect.top ||
|
|
106
|
+
clientY > tooltipRect.bottom;
|
|
107
|
+
|
|
108
|
+
const isOutsideTrigger =
|
|
109
|
+
clientX < triggerRect.left ||
|
|
110
|
+
clientX > triggerRect.right ||
|
|
111
|
+
clientY < triggerRect.top ||
|
|
112
|
+
clientY > triggerRect.bottom;
|
|
113
|
+
|
|
114
|
+
if (isOutsideTooltip && isOutsideTrigger) {
|
|
115
|
+
hideTooltip();
|
|
116
|
+
}
|
|
108
117
|
}
|
|
109
|
-
}
|
|
118
|
+
});
|
|
110
119
|
};
|
|
111
120
|
|
|
112
121
|
const handleScroll = () => {
|
|
@@ -129,6 +138,10 @@ export const SimpleTooltip: React.FC<TooltipProps> = ({
|
|
|
129
138
|
document.removeEventListener('mousemove', handleMouseMove);
|
|
130
139
|
window.removeEventListener('scroll', handleScroll);
|
|
131
140
|
window.removeEventListener('resize', handleResize);
|
|
141
|
+
if (rafId.current !== null) {
|
|
142
|
+
cancelAnimationFrame(rafId.current);
|
|
143
|
+
rafId.current = null;
|
|
144
|
+
}
|
|
132
145
|
clearTimeout(timeoutRef.current);
|
|
133
146
|
};
|
|
134
147
|
}, [visible]);
|
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';
|