polen 0.10.0-next.12 → 0.10.0-next.13
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/build/lib/graphql-document/components/CopyButton.d.ts +19 -0
- package/build/lib/graphql-document/components/CopyButton.d.ts.map +1 -0
- package/build/lib/graphql-document/components/CopyButton.js +43 -0
- package/build/lib/graphql-document/components/CopyButton.js.map +1 -0
- package/build/lib/graphql-document/components/GraphQLDocument.d.ts +0 -4
- package/build/lib/graphql-document/components/GraphQLDocument.d.ts.map +1 -1
- package/build/lib/graphql-document/components/GraphQLDocument.js +31 -74
- package/build/lib/graphql-document/components/GraphQLDocument.js.map +1 -1
- package/build/lib/graphql-document/components/GraphQLIdentifierPopover.d.ts +33 -0
- package/build/lib/graphql-document/components/GraphQLIdentifierPopover.d.ts.map +1 -0
- package/build/lib/graphql-document/components/GraphQLIdentifierPopover.js +48 -0
- package/build/lib/graphql-document/components/GraphQLIdentifierPopover.js.map +1 -0
- package/build/lib/graphql-document/components/IdentifierLink.d.ts +15 -13
- package/build/lib/graphql-document/components/IdentifierLink.d.ts.map +1 -1
- package/build/lib/graphql-document/components/IdentifierLink.js +51 -117
- package/build/lib/graphql-document/components/IdentifierLink.js.map +1 -1
- package/build/lib/graphql-document/components/graphql-document-styles.d.ts +5 -0
- package/build/lib/graphql-document/components/graphql-document-styles.d.ts.map +1 -0
- package/build/lib/graphql-document/components/graphql-document-styles.js +167 -0
- package/build/lib/graphql-document/components/graphql-document-styles.js.map +1 -0
- package/build/lib/graphql-document/components/index.d.ts +2 -1
- package/build/lib/graphql-document/components/index.d.ts.map +1 -1
- package/build/lib/graphql-document/components/index.js +2 -1
- package/build/lib/graphql-document/components/index.js.map +1 -1
- package/build/lib/graphql-document/hooks/use-tooltip-state.d.ts +43 -0
- package/build/lib/graphql-document/hooks/use-tooltip-state.d.ts.map +1 -0
- package/build/lib/graphql-document/hooks/use-tooltip-state.js +132 -0
- package/build/lib/graphql-document/hooks/use-tooltip-state.js.map +1 -0
- package/package.json +2 -1
- package/src/lib/graphql-document/components/CopyButton.tsx +76 -0
- package/src/lib/graphql-document/components/GraphQLDocument.tsx +52 -86
- package/src/lib/graphql-document/components/GraphQLIdentifierPopover.tsx +197 -0
- package/src/lib/graphql-document/components/IdentifierLink.tsx +105 -166
- package/src/lib/graphql-document/components/graphql-document-styles.ts +167 -0
- package/src/lib/graphql-document/components/index.ts +2 -1
- package/src/lib/graphql-document/hooks/use-tooltip-state.test.ts +76 -0
- package/src/lib/graphql-document/hooks/use-tooltip-state.ts +191 -0
- package/build/lib/graphql-document/components/HoverTooltip.d.ts +0 -35
- package/build/lib/graphql-document/components/HoverTooltip.d.ts.map +0 -1
- package/build/lib/graphql-document/components/HoverTooltip.js +0 -132
- package/build/lib/graphql-document/components/HoverTooltip.js.map +0 -1
- package/src/lib/graphql-document/components/HoverTooltip.tsx +0 -282
@@ -0,0 +1,191 @@
|
|
1
|
+
/**
|
2
|
+
* State management for GraphQL document tooltips
|
3
|
+
*
|
4
|
+
* Handles hover delays, pinning, and multiple tooltip coordination
|
5
|
+
*/
|
6
|
+
|
7
|
+
import { React } from '#dep/react/index'
|
8
|
+
|
9
|
+
export interface TooltipState {
|
10
|
+
/** Currently visible tooltip (via hover) */
|
11
|
+
hoveredId: string | null
|
12
|
+
/** Set of pinned tooltip IDs */
|
13
|
+
pinnedIds: Set<string>
|
14
|
+
/** ID pending show (waiting for delay) */
|
15
|
+
pendingShowId: string | null
|
16
|
+
/** ID pending hide (waiting for grace period) */
|
17
|
+
pendingHideId: string | null
|
18
|
+
}
|
19
|
+
|
20
|
+
export interface UseTooltipStateOptions {
|
21
|
+
/** Delay before showing tooltip on hover (ms) */
|
22
|
+
showDelay?: number
|
23
|
+
/** Delay before hiding tooltip on mouse leave (ms) */
|
24
|
+
hideDelay?: number
|
25
|
+
/** Whether to allow multiple pinned tooltips */
|
26
|
+
allowMultiplePins?: boolean
|
27
|
+
}
|
28
|
+
|
29
|
+
export interface UseTooltipStateReturn {
|
30
|
+
/** Check if a tooltip should be visible */
|
31
|
+
isOpen: (id: string) => boolean
|
32
|
+
/** Check if a tooltip is pinned */
|
33
|
+
isPinned: (id: string) => boolean
|
34
|
+
/** Handle hover start */
|
35
|
+
onHoverStart: (id: string) => void
|
36
|
+
/** Handle hover end */
|
37
|
+
onHoverEnd: (id: string) => void
|
38
|
+
/** Handle click (toggle pin) */
|
39
|
+
onTogglePin: (id: string) => void
|
40
|
+
/** Handle tooltip content hover (cancels hide) */
|
41
|
+
onTooltipHover: (id: string) => void
|
42
|
+
/** Unpin a specific tooltip */
|
43
|
+
unpin: (id: string) => void
|
44
|
+
/** Unpin all tooltips */
|
45
|
+
unpinAll: () => void
|
46
|
+
}
|
47
|
+
|
48
|
+
export const useTooltipState = (options: UseTooltipStateOptions = {}): UseTooltipStateReturn => {
|
49
|
+
const {
|
50
|
+
showDelay = 300,
|
51
|
+
hideDelay = 200,
|
52
|
+
allowMultiplePins = true,
|
53
|
+
} = options
|
54
|
+
|
55
|
+
const [hoveredId, setHoveredId] = React.useState<string | null>(null)
|
56
|
+
const [pinnedIds, setPinnedIds] = React.useState<Set<string>>(new Set())
|
57
|
+
const [pendingShowId, setPendingShowId] = React.useState<string | null>(null)
|
58
|
+
const [pendingHideId, setPendingHideId] = React.useState<string | null>(null)
|
59
|
+
|
60
|
+
// Timer refs
|
61
|
+
const showTimerRef = React.useRef<NodeJS.Timeout | null>(null)
|
62
|
+
const hideTimerRef = React.useRef<NodeJS.Timeout | null>(null)
|
63
|
+
|
64
|
+
// Clear any pending timers
|
65
|
+
const clearTimers = React.useCallback(() => {
|
66
|
+
if (showTimerRef.current) {
|
67
|
+
clearTimeout(showTimerRef.current)
|
68
|
+
showTimerRef.current = null
|
69
|
+
}
|
70
|
+
if (hideTimerRef.current) {
|
71
|
+
clearTimeout(hideTimerRef.current)
|
72
|
+
hideTimerRef.current = null
|
73
|
+
}
|
74
|
+
setPendingShowId(null)
|
75
|
+
setPendingHideId(null)
|
76
|
+
}, [])
|
77
|
+
|
78
|
+
// Check if tooltip should be visible
|
79
|
+
const isOpen = React.useCallback((id: string): boolean => {
|
80
|
+
return hoveredId === id || pinnedIds.has(id)
|
81
|
+
}, [hoveredId, pinnedIds])
|
82
|
+
|
83
|
+
// Check if tooltip is pinned
|
84
|
+
const isPinned = React.useCallback((id: string): boolean => {
|
85
|
+
return pinnedIds.has(id)
|
86
|
+
}, [pinnedIds])
|
87
|
+
|
88
|
+
// Handle hover start
|
89
|
+
const onHoverStart = React.useCallback((id: string) => {
|
90
|
+
// Don't show if already pinned
|
91
|
+
if (pinnedIds.has(id)) return
|
92
|
+
|
93
|
+
// Cancel any pending hide for this ID
|
94
|
+
if (pendingHideId === id) {
|
95
|
+
clearTimeout(hideTimerRef.current!)
|
96
|
+
hideTimerRef.current = null
|
97
|
+
setPendingHideId(null)
|
98
|
+
return
|
99
|
+
}
|
100
|
+
|
101
|
+
// Clear any other pending operations
|
102
|
+
clearTimers()
|
103
|
+
|
104
|
+
// Schedule show
|
105
|
+
setPendingShowId(id)
|
106
|
+
showTimerRef.current = setTimeout(() => {
|
107
|
+
setHoveredId(id)
|
108
|
+
setPendingShowId(null)
|
109
|
+
}, showDelay)
|
110
|
+
}, [pinnedIds, pendingHideId, clearTimers, showDelay])
|
111
|
+
|
112
|
+
// Handle hover end
|
113
|
+
const onHoverEnd = React.useCallback((id: string) => {
|
114
|
+
// Don't hide if pinned
|
115
|
+
if (pinnedIds.has(id)) return
|
116
|
+
|
117
|
+
// Cancel pending show if still waiting
|
118
|
+
if (pendingShowId === id) {
|
119
|
+
clearTimeout(showTimerRef.current!)
|
120
|
+
showTimerRef.current = null
|
121
|
+
setPendingShowId(null)
|
122
|
+
return
|
123
|
+
}
|
124
|
+
|
125
|
+
// Only hide if currently showing this tooltip
|
126
|
+
if (hoveredId === id) {
|
127
|
+
setPendingHideId(id)
|
128
|
+
hideTimerRef.current = setTimeout(() => {
|
129
|
+
// First set hovered to null to trigger close animation
|
130
|
+
setHoveredId(null)
|
131
|
+
setPendingHideId(null)
|
132
|
+
}, hideDelay)
|
133
|
+
}
|
134
|
+
}, [pinnedIds, pendingShowId, hoveredId, hideDelay])
|
135
|
+
|
136
|
+
// Handle tooltip content hover (cancels hide)
|
137
|
+
const onTooltipHover = React.useCallback((id: string) => {
|
138
|
+
if (pendingHideId === id) {
|
139
|
+
clearTimeout(hideTimerRef.current!)
|
140
|
+
hideTimerRef.current = null
|
141
|
+
setPendingHideId(null)
|
142
|
+
}
|
143
|
+
}, [pendingHideId])
|
144
|
+
|
145
|
+
// Toggle pin state
|
146
|
+
const onTogglePin = React.useCallback((id: string) => {
|
147
|
+
clearTimers()
|
148
|
+
|
149
|
+
setPinnedIds((prev: Set<string>) => {
|
150
|
+
const next = new Set(prev)
|
151
|
+
if (next.has(id)) {
|
152
|
+
// Unpin
|
153
|
+
next.delete(id)
|
154
|
+
setHoveredId(null) // Also clear hover state
|
155
|
+
} else {
|
156
|
+
// Pin
|
157
|
+
if (!allowMultiplePins) {
|
158
|
+
next.clear() // Clear other pins
|
159
|
+
}
|
160
|
+
next.add(id)
|
161
|
+
setHoveredId(null) // Clear hover state since it's now pinned
|
162
|
+
}
|
163
|
+
return next
|
164
|
+
})
|
165
|
+
}, [clearTimers, allowMultiplePins])
|
166
|
+
|
167
|
+
// Unpin specific tooltip
|
168
|
+
const unpin = React.useCallback((id: string) => {
|
169
|
+
setPinnedIds((prev: Set<string>) => {
|
170
|
+
const next = new Set(prev)
|
171
|
+
next.delete(id)
|
172
|
+
return next
|
173
|
+
})
|
174
|
+
}, [])
|
175
|
+
|
176
|
+
// Unpin all tooltips
|
177
|
+
const unpinAll = React.useCallback(() => {
|
178
|
+
setPinnedIds(new Set())
|
179
|
+
}, [])
|
180
|
+
|
181
|
+
return {
|
182
|
+
isOpen,
|
183
|
+
isPinned,
|
184
|
+
onHoverStart,
|
185
|
+
onHoverEnd,
|
186
|
+
onTogglePin,
|
187
|
+
onTooltipHover,
|
188
|
+
unpin,
|
189
|
+
unpinAll,
|
190
|
+
}
|
191
|
+
}
|
@@ -1,35 +0,0 @@
|
|
1
|
-
import type { React } from '#dep/react/index';
|
2
|
-
import type { DOMPosition } from '../positioning-simple.ts';
|
3
|
-
import type { Documentation } from '../schema-integration.ts';
|
4
|
-
import type { Identifier } from '../types.ts';
|
5
|
-
/**
|
6
|
-
* Props for the HoverTooltip component
|
7
|
-
*/
|
8
|
-
export interface HoverTooltipProps {
|
9
|
-
/** The identifier being hovered */
|
10
|
-
identifier: Identifier;
|
11
|
-
/** Documentation from schema */
|
12
|
-
documentation: Documentation;
|
13
|
-
/** Position of the identifier */
|
14
|
-
position: DOMPosition;
|
15
|
-
/** Whether this identifier has an error */
|
16
|
-
hasError?: boolean;
|
17
|
-
/** Reference URL for "View docs" link */
|
18
|
-
referenceUrl: string;
|
19
|
-
/** Callback to close the tooltip */
|
20
|
-
onClose?: () => void;
|
21
|
-
/** Callback to navigate to docs */
|
22
|
-
onNavigate?: () => void;
|
23
|
-
}
|
24
|
-
/**
|
25
|
-
* Tooltip shown on hover over GraphQL identifiers
|
26
|
-
*
|
27
|
-
* Displays type information, descriptions, deprecation warnings,
|
28
|
-
* and links to full documentation.
|
29
|
-
*/
|
30
|
-
export declare const HoverTooltip: React.FC<HoverTooltipProps>;
|
31
|
-
/**
|
32
|
-
* Default styles for hover tooltips
|
33
|
-
*/
|
34
|
-
export declare const hoverTooltipStyles = "\n.graphql-hover-tooltip {\n /* Tooltip animation */\n animation: graphql-tooltip-fade-in 0.2s ease-out;\n}\n\n@keyframes graphql-tooltip-fade-in {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* Ensure tooltips appear above other content */\n.graphql-hover-tooltip .rt-Card {\n box-shadow: 0 10px 38px -10px rgba(22, 23, 24, 0.35), \n 0 10px 20px -15px rgba(22, 23, 24, 0.2);\n}\n";
|
35
|
-
//# sourceMappingURL=HoverTooltip.d.ts.map
|
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"HoverTooltip.d.ts","sourceRoot":"","sources":["../../../../src/lib/graphql-document/components/HoverTooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAG7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAE7C;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,mCAAmC;IACnC,UAAU,EAAE,UAAU,CAAA;IACtB,gCAAgC;IAChC,aAAa,EAAE,aAAa,CAAA;IAC5B,iCAAiC;IACjC,QAAQ,EAAE,WAAW,CAAA;IACrB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,yCAAyC;IACzC,YAAY,EAAE,MAAM,CAAA;IACpB,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,mCAAmC;IACnC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;CACxB;AAED;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA6NpD,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB,yeAsB9B,CAAA"}
|
@@ -1,132 +0,0 @@
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
2
|
-
import { Badge, Box, Card, Flex, Text } from '@radix-ui/themes';
|
3
|
-
import { useEffect, useRef, useState } from 'react';
|
4
|
-
/**
|
5
|
-
* Tooltip shown on hover over GraphQL identifiers
|
6
|
-
*
|
7
|
-
* Displays type information, descriptions, deprecation warnings,
|
8
|
-
* and links to full documentation.
|
9
|
-
*/
|
10
|
-
export const HoverTooltip = ({ identifier, documentation, position, hasError = false, referenceUrl, onClose, onNavigate, }) => {
|
11
|
-
const tooltipRef = useRef(null);
|
12
|
-
const [tooltipPosition, setTooltipPosition] = useState({ top: 0, left: 0 });
|
13
|
-
// Calculate tooltip position to avoid viewport edges
|
14
|
-
useEffect(() => {
|
15
|
-
if (!tooltipRef.current)
|
16
|
-
return;
|
17
|
-
const tooltip = tooltipRef.current;
|
18
|
-
const rect = tooltip.getBoundingClientRect();
|
19
|
-
const viewportWidth = window.innerWidth;
|
20
|
-
const viewportHeight = window.innerHeight;
|
21
|
-
// Default position: above the identifier
|
22
|
-
let top = position.top - rect.height - 8;
|
23
|
-
let left = position.left;
|
24
|
-
// Adjust if tooltip would go off screen
|
25
|
-
if (top < 0) {
|
26
|
-
// Show below if not enough space above
|
27
|
-
top = position.top + position.height + 8;
|
28
|
-
}
|
29
|
-
if (left + rect.width > viewportWidth) {
|
30
|
-
// Align right edge with identifier if too wide
|
31
|
-
left = position.left + position.width - rect.width;
|
32
|
-
}
|
33
|
-
if (left < 0) {
|
34
|
-
// Keep on screen
|
35
|
-
left = 8;
|
36
|
-
}
|
37
|
-
setTooltipPosition({ top, left });
|
38
|
-
}, [position]);
|
39
|
-
// Determine badge color based on identifier kind
|
40
|
-
const getBadgeColor = () => {
|
41
|
-
switch (identifier.kind) {
|
42
|
-
case 'Type':
|
43
|
-
return 'blue';
|
44
|
-
case 'Field':
|
45
|
-
return 'green';
|
46
|
-
case 'Argument':
|
47
|
-
return 'orange';
|
48
|
-
case 'Variable':
|
49
|
-
return 'purple';
|
50
|
-
case 'Directive':
|
51
|
-
return 'amber';
|
52
|
-
case 'Fragment':
|
53
|
-
return 'cyan';
|
54
|
-
default:
|
55
|
-
return 'gray';
|
56
|
-
}
|
57
|
-
};
|
58
|
-
return (_jsx("div", { ref: tooltipRef, className: 'graphql-hover-tooltip', style: {
|
59
|
-
position: 'absolute',
|
60
|
-
top: tooltipPosition.top,
|
61
|
-
left: tooltipPosition.left,
|
62
|
-
zIndex: 100,
|
63
|
-
maxWidth: '400px',
|
64
|
-
pointerEvents: 'auto', // Make tooltip interactive
|
65
|
-
}, children: _jsx(Card, { size: '2', variant: 'surface', children: _jsxs(Flex, { direction: 'column', gap: '2', children: [_jsxs(Flex, { justify: 'between', align: 'center', children: [_jsxs(Flex, { align: 'center', gap: '2', children: [_jsx(Text, { size: '2', weight: 'bold', children: identifier.name }), _jsx(Badge, { color: getBadgeColor(), size: '1', children: identifier.kind })] }), onClose && (_jsx("button", { onClick: onClose, style: {
|
66
|
-
background: 'none',
|
67
|
-
border: 'none',
|
68
|
-
cursor: 'pointer',
|
69
|
-
padding: '4px',
|
70
|
-
color: 'var(--gray-11)',
|
71
|
-
fontSize: '18px',
|
72
|
-
lineHeight: '1',
|
73
|
-
fontWeight: 'bold',
|
74
|
-
borderRadius: '4px',
|
75
|
-
transition: 'background-color 0.2s',
|
76
|
-
}, onMouseEnter: (e) => {
|
77
|
-
e.currentTarget.style.backgroundColor = 'var(--gray-a3)';
|
78
|
-
}, onMouseLeave: (e) => {
|
79
|
-
e.currentTarget.style.backgroundColor = 'transparent';
|
80
|
-
}, "aria-label": 'Close tooltip', children: "\u00D7" }))] }), _jsx(Box, { children: _jsxs(Text, { size: '1', color: 'gray', children: ["Type: ", _jsx(Text, { as: 'span', size: '1', style: { fontFamily: 'monospace' }, children: documentation.typeInfo })] }) }), documentation.description && (_jsx(Box, { children: _jsx(Text, { size: '1', children: documentation.description }) })), documentation.defaultValue && (_jsx(Box, { children: _jsxs(Text, { size: '1', color: 'gray', children: ["Default:", ' ', _jsx(Text, { as: 'span', size: '1', style: { fontFamily: 'monospace' }, children: documentation.defaultValue })] }) })), documentation.deprecated && (_jsxs(Box, { style: {
|
81
|
-
padding: '8px',
|
82
|
-
backgroundColor: 'var(--amber-2)',
|
83
|
-
borderRadius: '4px',
|
84
|
-
border: '1px solid var(--amber-6)',
|
85
|
-
}, children: [_jsxs(Text, { size: '1', color: 'amber', children: ["\u26A0\uFE0F Deprecated: ", documentation.deprecated.reason] }), documentation.deprecated.replacement && (_jsxs(Text, { size: '1', color: 'amber', children: ["Use ", documentation.deprecated.replacement, " instead."] }))] })), hasError && (_jsx(Box, { style: {
|
86
|
-
padding: '8px',
|
87
|
-
backgroundColor: 'var(--red-2)',
|
88
|
-
borderRadius: '4px',
|
89
|
-
border: '1px solid var(--red-6)',
|
90
|
-
}, children: _jsxs(Text, { size: '1', color: 'red', children: ["\u274C ", identifier.kind, " not found in schema"] }) })), _jsx(Box, { children: _jsxs(Text, { size: '1', color: 'gray', children: ["Path: ", identifier.schemaPath.join(' → ')] }) }), onNavigate && (_jsx(Box, { children: _jsx(Text, { size: '1', children: _jsx("a", { href: referenceUrl, onClick: (e) => {
|
91
|
-
e.preventDefault();
|
92
|
-
onNavigate();
|
93
|
-
onClose?.();
|
94
|
-
}, style: {
|
95
|
-
color: 'var(--accent-9)',
|
96
|
-
textDecoration: 'none',
|
97
|
-
borderBottom: '1px solid transparent',
|
98
|
-
transition: 'border-color 0.2s',
|
99
|
-
cursor: 'pointer',
|
100
|
-
}, onMouseEnter: (e) => {
|
101
|
-
e.currentTarget.style.borderBottomColor = 'var(--accent-9)';
|
102
|
-
}, onMouseLeave: (e) => {
|
103
|
-
e.currentTarget.style.borderBottomColor = 'transparent';
|
104
|
-
}, children: "View full documentation \u2192" }) }) }))] }) }) }));
|
105
|
-
};
|
106
|
-
/**
|
107
|
-
* Default styles for hover tooltips
|
108
|
-
*/
|
109
|
-
export const hoverTooltipStyles = `
|
110
|
-
.graphql-hover-tooltip {
|
111
|
-
/* Tooltip animation */
|
112
|
-
animation: graphql-tooltip-fade-in 0.2s ease-out;
|
113
|
-
}
|
114
|
-
|
115
|
-
@keyframes graphql-tooltip-fade-in {
|
116
|
-
from {
|
117
|
-
opacity: 0;
|
118
|
-
transform: translateY(4px);
|
119
|
-
}
|
120
|
-
to {
|
121
|
-
opacity: 1;
|
122
|
-
transform: translateY(0);
|
123
|
-
}
|
124
|
-
}
|
125
|
-
|
126
|
-
/* Ensure tooltips appear above other content */
|
127
|
-
.graphql-hover-tooltip .rt-Card {
|
128
|
-
box-shadow: 0 10px 38px -10px rgba(22, 23, 24, 0.35),
|
129
|
-
0 10px 20px -15px rgba(22, 23, 24, 0.2);
|
130
|
-
}
|
131
|
-
`;
|
132
|
-
//# sourceMappingURL=HoverTooltip.js.map
|
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"HoverTooltip.js","sourceRoot":"","sources":["../../../../src/lib/graphql-document/components/HoverTooltip.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAyBnD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAgC,CAAC,EACxD,UAAU,EACV,aAAa,EACb,QAAQ,EACR,QAAQ,GAAG,KAAK,EAChB,YAAY,EACZ,OAAO,EACP,UAAU,GACX,EAAE,EAAE;IACH,MAAM,UAAU,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAA;IAC/C,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAA;IAE3E,qDAAqD;IACrD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,UAAU,CAAC,OAAO;YAAE,OAAM;QAE/B,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAA;QAClC,MAAM,IAAI,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAA;QAC5C,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,CAAA;QACvC,MAAM,cAAc,GAAG,MAAM,CAAC,WAAW,CAAA;QAEzC,yCAAyC;QACzC,IAAI,GAAG,GAAG,QAAQ,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAA;QACxC,IAAI,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAA;QAExB,wCAAwC;QACxC,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;YACZ,uCAAuC;YACvC,GAAG,GAAG,QAAQ,CAAC,GAAG,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAA;QAC1C,CAAC;QAED,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,GAAG,aAAa,EAAE,CAAC;YACtC,+CAA+C;YAC/C,IAAI,GAAG,QAAQ,CAAC,IAAI,GAAG,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;QACpD,CAAC;QAED,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;YACb,iBAAiB;YACjB,IAAI,GAAG,CAAC,CAAA;QACV,CAAC;QAED,kBAAkB,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAA;IACnC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAA;IAEd,iDAAiD;IACjD,MAAM,aAAa,GAAG,GAAG,EAAE;QACzB,QAAQ,UAAU,CAAC,IAAI,EAAE,CAAC;YACxB,KAAK,MAAM;gBACT,OAAO,MAAM,CAAA;YACf,KAAK,OAAO;gBACV,OAAO,OAAO,CAAA;YAChB,KAAK,UAAU;gBACb,OAAO,QAAQ,CAAA;YACjB,KAAK,UAAU;gBACb,OAAO,QAAQ,CAAA;YACjB,KAAK,WAAW;gBACd,OAAO,OAAO,CAAA;YAChB,KAAK,UAAU;gBACb,OAAO,MAAM,CAAA;YACf;gBACE,OAAO,MAAM,CAAA;QACjB,CAAC;IACH,CAAC,CAAA;IAED,OAAO,CACL,cACE,GAAG,EAAE,UAAU,EACf,SAAS,EAAC,uBAAuB,EACjC,KAAK,EAAE;YACL,QAAQ,EAAE,UAAU;YACpB,GAAG,EAAE,eAAe,CAAC,GAAG;YACxB,IAAI,EAAE,eAAe,CAAC,IAAI;YAC1B,MAAM,EAAE,GAAG;YACX,QAAQ,EAAE,OAAO;YACjB,aAAa,EAAE,MAAM,EAAE,2BAA2B;SACnD,YAED,KAAC,IAAI,IAAC,IAAI,EAAC,GAAG,EAAC,OAAO,EAAC,SAAS,YAC9B,MAAC,IAAI,IAAC,SAAS,EAAC,QAAQ,EAAC,GAAG,EAAC,GAAG,aAE9B,MAAC,IAAI,IAAC,OAAO,EAAC,SAAS,EAAC,KAAK,EAAC,QAAQ,aACpC,MAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,EAAC,GAAG,EAAC,GAAG,aAC1B,KAAC,IAAI,IAAC,IAAI,EAAC,GAAG,EAAC,MAAM,EAAC,MAAM,YACzB,UAAU,CAAC,IAAI,GACX,EACP,KAAC,KAAK,IAAC,KAAK,EAAE,aAAa,EAAE,EAAE,IAAI,EAAC,GAAG,YACpC,UAAU,CAAC,IAAI,GACV,IACH,EACN,OAAO,IAAI,CACV,iBACE,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE;oCACL,UAAU,EAAE,MAAM;oCAClB,MAAM,EAAE,MAAM;oCACd,MAAM,EAAE,SAAS;oCACjB,OAAO,EAAE,KAAK;oCACd,KAAK,EAAE,gBAAgB;oCACvB,QAAQ,EAAE,MAAM;oCAChB,UAAU,EAAE,GAAG;oCACf,UAAU,EAAE,MAAM;oCAClB,YAAY,EAAE,KAAK;oCACnB,UAAU,EAAE,uBAAuB;iCACpC,EACD,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE;oCAClB,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,eAAe,GAAG,gBAAgB,CAAA;gCAC1D,CAAC,EACD,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE;oCAClB,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,eAAe,GAAG,aAAa,CAAA;gCACvD,CAAC,gBACU,eAAe,uBAGnB,CACV,IACI,EAGP,KAAC,GAAG,cACF,MAAC,IAAI,IAAC,IAAI,EAAC,GAAG,EAAC,KAAK,EAAC,MAAM,uBACnB,KAAC,IAAI,IAAC,EAAE,EAAC,MAAM,EAAC,IAAI,EAAC,GAAG,EAAC,KAAK,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,YAAG,aAAa,CAAC,QAAQ,GAAQ,IAC7F,GACH,EAGL,aAAa,CAAC,WAAW,IAAI,CAC5B,KAAC,GAAG,cACF,KAAC,IAAI,IAAC,IAAI,EAAC,GAAG,YACX,aAAa,CAAC,WAAW,GACrB,GACH,CACP,EAGA,aAAa,CAAC,YAAY,IAAI,CAC7B,KAAC,GAAG,cACF,MAAC,IAAI,IAAC,IAAI,EAAC,GAAG,EAAC,KAAK,EAAC,MAAM,yBAChB,GAAG,EACZ,KAAC,IAAI,IAAC,EAAE,EAAC,MAAM,EAAC,IAAI,EAAC,GAAG,EAAC,KAAK,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,YAAG,aAAa,CAAC,YAAY,GAAQ,IAC3F,GACH,CACP,EAGA,aAAa,CAAC,UAAU,IAAI,CAC3B,MAAC,GAAG,IACF,KAAK,EAAE;4BACL,OAAO,EAAE,KAAK;4BACd,eAAe,EAAE,gBAAgB;4BACjC,YAAY,EAAE,KAAK;4BACnB,MAAM,EAAE,0BAA0B;yBACnC,aAED,MAAC,IAAI,IAAC,IAAI,EAAC,GAAG,EAAC,KAAK,EAAC,OAAO,0CACV,aAAa,CAAC,UAAU,CAAC,MAAM,IAC1C,EACN,aAAa,CAAC,UAAU,CAAC,WAAW,IAAI,CACvC,MAAC,IAAI,IAAC,IAAI,EAAC,GAAG,EAAC,KAAK,EAAC,OAAO,qBACrB,aAAa,CAAC,UAAU,CAAC,WAAW,iBACpC,CACR,IACG,CACP,EAGA,QAAQ,IAAI,CACX,KAAC,GAAG,IACF,KAAK,EAAE;4BACL,OAAO,EAAE,KAAK;4BACd,eAAe,EAAE,cAAc;4BAC/B,YAAY,EAAE,KAAK;4BACnB,MAAM,EAAE,wBAAwB;yBACjC,YAED,MAAC,IAAI,IAAC,IAAI,EAAC,GAAG,EAAC,KAAK,EAAC,KAAK,wBACrB,UAAU,CAAC,IAAI,4BACb,GACH,CACP,EAGD,KAAC,GAAG,cACF,MAAC,IAAI,IAAC,IAAI,EAAC,GAAG,EAAC,KAAK,EAAC,MAAM,uBAClB,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IACnC,GACH,EAGL,UAAU,IAAI,CACb,KAAC,GAAG,cACF,KAAC,IAAI,IAAC,IAAI,EAAC,GAAG,YACZ,YACE,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;oCACb,CAAC,CAAC,cAAc,EAAE,CAAA;oCAClB,UAAU,EAAE,CAAA;oCACZ,OAAO,EAAE,EAAE,CAAA;gCACb,CAAC,EACD,KAAK,EAAE;oCACL,KAAK,EAAE,iBAAiB;oCACxB,cAAc,EAAE,MAAM;oCACtB,YAAY,EAAE,uBAAuB;oCACrC,UAAU,EAAE,mBAAmB;oCAC/B,MAAM,EAAE,SAAS;iCAClB,EACD,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE;oCAClB,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,iBAAiB,GAAG,iBAAiB,CAAA;gCAC7D,CAAC,EACD,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE;oCAClB,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,iBAAiB,GAAG,aAAa,CAAA;gCACzD,CAAC,+CAGC,GACC,GACH,CACP,IACI,GACF,GACH,CACP,CAAA;AACH,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;CAsBjC,CAAA"}
|
@@ -1,282 +0,0 @@
|
|
1
|
-
import type { React } from '#dep/react/index'
|
2
|
-
import { Badge, Box, Card, Flex, Text } from '@radix-ui/themes'
|
3
|
-
import { useEffect, useRef, useState } from 'react'
|
4
|
-
import type { DOMPosition } from '../positioning-simple.ts'
|
5
|
-
import type { Documentation } from '../schema-integration.ts'
|
6
|
-
import type { Identifier } from '../types.ts'
|
7
|
-
|
8
|
-
/**
|
9
|
-
* Props for the HoverTooltip component
|
10
|
-
*/
|
11
|
-
export interface HoverTooltipProps {
|
12
|
-
/** The identifier being hovered */
|
13
|
-
identifier: Identifier
|
14
|
-
/** Documentation from schema */
|
15
|
-
documentation: Documentation
|
16
|
-
/** Position of the identifier */
|
17
|
-
position: DOMPosition
|
18
|
-
/** Whether this identifier has an error */
|
19
|
-
hasError?: boolean
|
20
|
-
/** Reference URL for "View docs" link */
|
21
|
-
referenceUrl: string
|
22
|
-
/** Callback to close the tooltip */
|
23
|
-
onClose?: () => void
|
24
|
-
/** Callback to navigate to docs */
|
25
|
-
onNavigate?: () => void
|
26
|
-
}
|
27
|
-
|
28
|
-
/**
|
29
|
-
* Tooltip shown on hover over GraphQL identifiers
|
30
|
-
*
|
31
|
-
* Displays type information, descriptions, deprecation warnings,
|
32
|
-
* and links to full documentation.
|
33
|
-
*/
|
34
|
-
export const HoverTooltip: React.FC<HoverTooltipProps> = ({
|
35
|
-
identifier,
|
36
|
-
documentation,
|
37
|
-
position,
|
38
|
-
hasError = false,
|
39
|
-
referenceUrl,
|
40
|
-
onClose,
|
41
|
-
onNavigate,
|
42
|
-
}) => {
|
43
|
-
const tooltipRef = useRef<HTMLDivElement>(null)
|
44
|
-
const [tooltipPosition, setTooltipPosition] = useState({ top: 0, left: 0 })
|
45
|
-
|
46
|
-
// Calculate tooltip position to avoid viewport edges
|
47
|
-
useEffect(() => {
|
48
|
-
if (!tooltipRef.current) return
|
49
|
-
|
50
|
-
const tooltip = tooltipRef.current
|
51
|
-
const rect = tooltip.getBoundingClientRect()
|
52
|
-
const viewportWidth = window.innerWidth
|
53
|
-
const viewportHeight = window.innerHeight
|
54
|
-
|
55
|
-
// Default position: above the identifier
|
56
|
-
let top = position.top - rect.height - 8
|
57
|
-
let left = position.left
|
58
|
-
|
59
|
-
// Adjust if tooltip would go off screen
|
60
|
-
if (top < 0) {
|
61
|
-
// Show below if not enough space above
|
62
|
-
top = position.top + position.height + 8
|
63
|
-
}
|
64
|
-
|
65
|
-
if (left + rect.width > viewportWidth) {
|
66
|
-
// Align right edge with identifier if too wide
|
67
|
-
left = position.left + position.width - rect.width
|
68
|
-
}
|
69
|
-
|
70
|
-
if (left < 0) {
|
71
|
-
// Keep on screen
|
72
|
-
left = 8
|
73
|
-
}
|
74
|
-
|
75
|
-
setTooltipPosition({ top, left })
|
76
|
-
}, [position])
|
77
|
-
|
78
|
-
// Determine badge color based on identifier kind
|
79
|
-
const getBadgeColor = () => {
|
80
|
-
switch (identifier.kind) {
|
81
|
-
case 'Type':
|
82
|
-
return 'blue'
|
83
|
-
case 'Field':
|
84
|
-
return 'green'
|
85
|
-
case 'Argument':
|
86
|
-
return 'orange'
|
87
|
-
case 'Variable':
|
88
|
-
return 'purple'
|
89
|
-
case 'Directive':
|
90
|
-
return 'amber'
|
91
|
-
case 'Fragment':
|
92
|
-
return 'cyan'
|
93
|
-
default:
|
94
|
-
return 'gray'
|
95
|
-
}
|
96
|
-
}
|
97
|
-
|
98
|
-
return (
|
99
|
-
<div
|
100
|
-
ref={tooltipRef}
|
101
|
-
className='graphql-hover-tooltip'
|
102
|
-
style={{
|
103
|
-
position: 'absolute',
|
104
|
-
top: tooltipPosition.top,
|
105
|
-
left: tooltipPosition.left,
|
106
|
-
zIndex: 100,
|
107
|
-
maxWidth: '400px',
|
108
|
-
pointerEvents: 'auto', // Make tooltip interactive
|
109
|
-
}}
|
110
|
-
>
|
111
|
-
<Card size='2' variant='surface'>
|
112
|
-
<Flex direction='column' gap='2'>
|
113
|
-
{/* Header with name, kind, and close button */}
|
114
|
-
<Flex justify='between' align='center'>
|
115
|
-
<Flex align='center' gap='2'>
|
116
|
-
<Text size='2' weight='bold'>
|
117
|
-
{identifier.name}
|
118
|
-
</Text>
|
119
|
-
<Badge color={getBadgeColor()} size='1'>
|
120
|
-
{identifier.kind}
|
121
|
-
</Badge>
|
122
|
-
</Flex>
|
123
|
-
{onClose && (
|
124
|
-
<button
|
125
|
-
onClick={onClose}
|
126
|
-
style={{
|
127
|
-
background: 'none',
|
128
|
-
border: 'none',
|
129
|
-
cursor: 'pointer',
|
130
|
-
padding: '4px',
|
131
|
-
color: 'var(--gray-11)',
|
132
|
-
fontSize: '18px',
|
133
|
-
lineHeight: '1',
|
134
|
-
fontWeight: 'bold',
|
135
|
-
borderRadius: '4px',
|
136
|
-
transition: 'background-color 0.2s',
|
137
|
-
}}
|
138
|
-
onMouseEnter={(e) => {
|
139
|
-
e.currentTarget.style.backgroundColor = 'var(--gray-a3)'
|
140
|
-
}}
|
141
|
-
onMouseLeave={(e) => {
|
142
|
-
e.currentTarget.style.backgroundColor = 'transparent'
|
143
|
-
}}
|
144
|
-
aria-label='Close tooltip'
|
145
|
-
>
|
146
|
-
×
|
147
|
-
</button>
|
148
|
-
)}
|
149
|
-
</Flex>
|
150
|
-
|
151
|
-
{/* Type signature */}
|
152
|
-
<Box>
|
153
|
-
<Text size='1' color='gray'>
|
154
|
-
Type: <Text as='span' size='1' style={{ fontFamily: 'monospace' }}>{documentation.typeInfo}</Text>
|
155
|
-
</Text>
|
156
|
-
</Box>
|
157
|
-
|
158
|
-
{/* Description */}
|
159
|
-
{documentation.description && (
|
160
|
-
<Box>
|
161
|
-
<Text size='1'>
|
162
|
-
{documentation.description}
|
163
|
-
</Text>
|
164
|
-
</Box>
|
165
|
-
)}
|
166
|
-
|
167
|
-
{/* Default value for arguments */}
|
168
|
-
{documentation.defaultValue && (
|
169
|
-
<Box>
|
170
|
-
<Text size='1' color='gray'>
|
171
|
-
Default:{' '}
|
172
|
-
<Text as='span' size='1' style={{ fontFamily: 'monospace' }}>{documentation.defaultValue}</Text>
|
173
|
-
</Text>
|
174
|
-
</Box>
|
175
|
-
)}
|
176
|
-
|
177
|
-
{/* Deprecation warning */}
|
178
|
-
{documentation.deprecated && (
|
179
|
-
<Box
|
180
|
-
style={{
|
181
|
-
padding: '8px',
|
182
|
-
backgroundColor: 'var(--amber-2)',
|
183
|
-
borderRadius: '4px',
|
184
|
-
border: '1px solid var(--amber-6)',
|
185
|
-
}}
|
186
|
-
>
|
187
|
-
<Text size='1' color='amber'>
|
188
|
-
⚠️ Deprecated: {documentation.deprecated.reason}
|
189
|
-
</Text>
|
190
|
-
{documentation.deprecated.replacement && (
|
191
|
-
<Text size='1' color='amber'>
|
192
|
-
Use {documentation.deprecated.replacement} instead.
|
193
|
-
</Text>
|
194
|
-
)}
|
195
|
-
</Box>
|
196
|
-
)}
|
197
|
-
|
198
|
-
{/* Error message */}
|
199
|
-
{hasError && (
|
200
|
-
<Box
|
201
|
-
style={{
|
202
|
-
padding: '8px',
|
203
|
-
backgroundColor: 'var(--red-2)',
|
204
|
-
borderRadius: '4px',
|
205
|
-
border: '1px solid var(--red-6)',
|
206
|
-
}}
|
207
|
-
>
|
208
|
-
<Text size='1' color='red'>
|
209
|
-
❌ {identifier.kind} not found in schema
|
210
|
-
</Text>
|
211
|
-
</Box>
|
212
|
-
)}
|
213
|
-
|
214
|
-
{/* Schema path */}
|
215
|
-
<Box>
|
216
|
-
<Text size='1' color='gray'>
|
217
|
-
Path: {identifier.schemaPath.join(' → ')}
|
218
|
-
</Text>
|
219
|
-
</Box>
|
220
|
-
|
221
|
-
{/* View docs link */}
|
222
|
-
{onNavigate && (
|
223
|
-
<Box>
|
224
|
-
<Text size='1'>
|
225
|
-
<a
|
226
|
-
href={referenceUrl}
|
227
|
-
onClick={(e) => {
|
228
|
-
e.preventDefault()
|
229
|
-
onNavigate()
|
230
|
-
onClose?.()
|
231
|
-
}}
|
232
|
-
style={{
|
233
|
-
color: 'var(--accent-9)',
|
234
|
-
textDecoration: 'none',
|
235
|
-
borderBottom: '1px solid transparent',
|
236
|
-
transition: 'border-color 0.2s',
|
237
|
-
cursor: 'pointer',
|
238
|
-
}}
|
239
|
-
onMouseEnter={(e) => {
|
240
|
-
e.currentTarget.style.borderBottomColor = 'var(--accent-9)'
|
241
|
-
}}
|
242
|
-
onMouseLeave={(e) => {
|
243
|
-
e.currentTarget.style.borderBottomColor = 'transparent'
|
244
|
-
}}
|
245
|
-
>
|
246
|
-
View full documentation →
|
247
|
-
</a>
|
248
|
-
</Text>
|
249
|
-
</Box>
|
250
|
-
)}
|
251
|
-
</Flex>
|
252
|
-
</Card>
|
253
|
-
</div>
|
254
|
-
)
|
255
|
-
}
|
256
|
-
|
257
|
-
/**
|
258
|
-
* Default styles for hover tooltips
|
259
|
-
*/
|
260
|
-
export const hoverTooltipStyles = `
|
261
|
-
.graphql-hover-tooltip {
|
262
|
-
/* Tooltip animation */
|
263
|
-
animation: graphql-tooltip-fade-in 0.2s ease-out;
|
264
|
-
}
|
265
|
-
|
266
|
-
@keyframes graphql-tooltip-fade-in {
|
267
|
-
from {
|
268
|
-
opacity: 0;
|
269
|
-
transform: translateY(4px);
|
270
|
-
}
|
271
|
-
to {
|
272
|
-
opacity: 1;
|
273
|
-
transform: translateY(0);
|
274
|
-
}
|
275
|
-
}
|
276
|
-
|
277
|
-
/* Ensure tooltips appear above other content */
|
278
|
-
.graphql-hover-tooltip .rt-Card {
|
279
|
-
box-shadow: 0 10px 38px -10px rgba(22, 23, 24, 0.35),
|
280
|
-
0 10px 20px -15px rgba(22, 23, 24, 0.2);
|
281
|
-
}
|
282
|
-
`
|