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,76 @@
|
|
1
|
+
/**
|
2
|
+
* Copy button component for GraphQL documents
|
3
|
+
*/
|
4
|
+
|
5
|
+
import type { React } from '#dep/react/index'
|
6
|
+
import { React as ReactHooks } from '#dep/react/index'
|
7
|
+
import { CheckIcon, CopyIcon } from '@radix-ui/react-icons'
|
8
|
+
import { Button } from '@radix-ui/themes'
|
9
|
+
|
10
|
+
export interface CopyButtonProps {
|
11
|
+
/** The text to copy */
|
12
|
+
text: string
|
13
|
+
/** Optional className */
|
14
|
+
className?: string
|
15
|
+
/** Size variant */
|
16
|
+
size?: '1' | '2' | '3'
|
17
|
+
}
|
18
|
+
|
19
|
+
/**
|
20
|
+
* Copy button for GraphQL code blocks
|
21
|
+
*
|
22
|
+
* Shows a copy icon that changes to a checkmark when clicked
|
23
|
+
*/
|
24
|
+
export const CopyButton: React.FC<CopyButtonProps> = ({
|
25
|
+
text,
|
26
|
+
className = '',
|
27
|
+
size = '1',
|
28
|
+
}) => {
|
29
|
+
const [copied, setCopied] = ReactHooks.useState(false)
|
30
|
+
const timeoutRef = ReactHooks.useRef<NodeJS.Timeout | null>(null)
|
31
|
+
|
32
|
+
const handleCopy = ReactHooks.useCallback(async (e: React.MouseEvent) => {
|
33
|
+
e.preventDefault()
|
34
|
+
e.stopPropagation()
|
35
|
+
|
36
|
+
try {
|
37
|
+
await navigator.clipboard.writeText(text)
|
38
|
+
setCopied(true)
|
39
|
+
|
40
|
+
// Clear any existing timeout
|
41
|
+
if (timeoutRef.current) {
|
42
|
+
clearTimeout(timeoutRef.current)
|
43
|
+
}
|
44
|
+
|
45
|
+
// Reset after 2 seconds
|
46
|
+
timeoutRef.current = setTimeout(() => {
|
47
|
+
setCopied(false)
|
48
|
+
timeoutRef.current = null
|
49
|
+
}, 2000)
|
50
|
+
} catch (err) {
|
51
|
+
console.error('Failed to copy text:', err)
|
52
|
+
}
|
53
|
+
}, [text])
|
54
|
+
|
55
|
+
// Cleanup timeout on unmount
|
56
|
+
ReactHooks.useEffect(() => {
|
57
|
+
return () => {
|
58
|
+
if (timeoutRef.current) {
|
59
|
+
clearTimeout(timeoutRef.current)
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}, [])
|
63
|
+
|
64
|
+
return (
|
65
|
+
<Button
|
66
|
+
size={size}
|
67
|
+
variant='ghost'
|
68
|
+
className={`graphql-copy-button ${className}`}
|
69
|
+
onClick={handleCopy}
|
70
|
+
aria-label={copied ? 'Copied!' : 'Copy code'}
|
71
|
+
data-copied={copied}
|
72
|
+
>
|
73
|
+
{copied ? <CheckIcon width='16' height='16' /> : <CopyIcon width='16' height='16' />}
|
74
|
+
</Button>
|
75
|
+
)
|
76
|
+
}
|
@@ -1,14 +1,15 @@
|
|
1
1
|
import type { React } from '#dep/react/index'
|
2
|
+
import { React as ReactHooks } from '#dep/react/index'
|
2
3
|
import type { GraphQLSchema } from 'graphql'
|
3
|
-
import { useEffect, useMemo, useRef, useState } from 'react'
|
4
4
|
import { useNavigate } from 'react-router'
|
5
5
|
import { analyze } from '../analysis.ts'
|
6
|
+
import { useTooltipState } from '../hooks/use-tooltip-state.ts'
|
6
7
|
import { createSimplePositionCalculator } from '../positioning-simple.ts'
|
7
8
|
import { createPolenSchemaResolver } from '../schema-integration.ts'
|
8
9
|
import type { Identifier } from '../types.ts'
|
9
|
-
import {
|
10
|
+
import { CopyButton } from './CopyButton.tsx'
|
11
|
+
import { graphqlDocumentStyles } from './graphql-document-styles.ts'
|
10
12
|
import { IdentifierLink } from './IdentifierLink.tsx'
|
11
|
-
import { identifierLinkStyles } from './IdentifierLink.tsx'
|
12
13
|
|
13
14
|
/**
|
14
15
|
* Options for the GraphQL document component
|
@@ -58,58 +59,50 @@ export const GraphQLDocument: React.FC<GraphQLDocumentProps> = ({
|
|
58
59
|
onNavigate,
|
59
60
|
validate = true,
|
60
61
|
className = '',
|
61
|
-
} = options
|
62
|
+
} = options || {}
|
62
63
|
|
63
64
|
const navigate = useNavigate()
|
64
65
|
const handleNavigate = onNavigate || ((url: string) => navigate(url))
|
65
66
|
|
66
67
|
// Container ref for positioning calculations
|
67
|
-
const containerRef = useRef<HTMLDivElement>(null)
|
68
|
-
const [isReady, setIsReady] = useState(false)
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
if (
|
81
|
-
|
82
|
-
|| target.closest('.graphql-hover-tooltip')
|
83
|
-
) {
|
84
|
-
return
|
68
|
+
const containerRef = ReactHooks.useRef<HTMLDivElement>(null)
|
69
|
+
const [isReady, setIsReady] = ReactHooks.useState(false)
|
70
|
+
|
71
|
+
// Use tooltip state management
|
72
|
+
const tooltipState = useTooltipState({
|
73
|
+
showDelay: 300,
|
74
|
+
hideDelay: 200, // Increased for smoother experience
|
75
|
+
allowMultiplePins: true,
|
76
|
+
})
|
77
|
+
|
78
|
+
// Handle escape key to unpin all
|
79
|
+
ReactHooks.useEffect(() => {
|
80
|
+
const handleKeyDown = (event: KeyboardEvent) => {
|
81
|
+
if (event.key === 'Escape') {
|
82
|
+
tooltipState.unpinAll()
|
85
83
|
}
|
86
|
-
|
87
|
-
// Close the tooltip
|
88
|
-
setOpenTooltipId(null)
|
89
84
|
}
|
90
85
|
|
91
|
-
|
92
|
-
document.addEventListener('mousedown', handleClickOutside)
|
93
|
-
|
86
|
+
document.addEventListener('keydown', handleKeyDown)
|
94
87
|
return () => {
|
95
|
-
document.removeEventListener('
|
88
|
+
document.removeEventListener('keydown', handleKeyDown)
|
96
89
|
}
|
97
|
-
}, [
|
90
|
+
}, [tooltipState])
|
98
91
|
|
99
92
|
// Layer 1: Parse and analyze
|
100
|
-
const analysisResult = useMemo(() => {
|
93
|
+
const analysisResult = ReactHooks.useMemo(() => {
|
101
94
|
if (plain) return null
|
102
95
|
const result = analyze(children, { schema })
|
103
96
|
return result
|
104
97
|
}, [children, plain, schema])
|
105
98
|
|
106
99
|
// Layer 2: Schema resolution
|
107
|
-
const resolver = useMemo(() => {
|
100
|
+
const resolver = ReactHooks.useMemo(() => {
|
108
101
|
if (!schema || plain) return null
|
109
102
|
return createPolenSchemaResolver(schema)
|
110
103
|
}, [schema, plain])
|
111
104
|
|
112
|
-
const resolutions = useMemo(() => {
|
105
|
+
const resolutions = ReactHooks.useMemo(() => {
|
113
106
|
if (!analysisResult || !resolver) {
|
114
107
|
return new Map()
|
115
108
|
}
|
@@ -125,15 +118,17 @@ export const GraphQLDocument: React.FC<GraphQLDocumentProps> = ({
|
|
125
118
|
}, [analysisResult, resolver])
|
126
119
|
|
127
120
|
// Layer 3: Position calculation
|
128
|
-
const positionCalculator = useMemo(() => {
|
121
|
+
const positionCalculator = ReactHooks.useMemo(() => {
|
129
122
|
if (plain) return null
|
130
123
|
return createSimplePositionCalculator()
|
131
124
|
}, [plain])
|
132
125
|
|
133
|
-
const [positions, setPositions] = useState<Map<string, { position: any; identifier: Identifier }>>(
|
126
|
+
const [positions, setPositions] = ReactHooks.useState<Map<string, { position: any; identifier: Identifier }>>(
|
127
|
+
new Map(),
|
128
|
+
)
|
134
129
|
|
135
130
|
// Prepare code block and calculate positions after render
|
136
|
-
useEffect(() => {
|
131
|
+
ReactHooks.useEffect(() => {
|
137
132
|
if (!containerRef.current || !analysisResult || !positionCalculator || plain) {
|
138
133
|
return
|
139
134
|
}
|
@@ -162,7 +157,7 @@ export const GraphQLDocument: React.FC<GraphQLDocumentProps> = ({
|
|
162
157
|
}, [analysisResult, positionCalculator, plain, highlightedHtml])
|
163
158
|
|
164
159
|
// Handle resize events
|
165
|
-
useEffect(() => {
|
160
|
+
ReactHooks.useEffect(() => {
|
166
161
|
if (!containerRef.current || !positionCalculator || plain) return
|
167
162
|
|
168
163
|
const handleResize = () => {
|
@@ -180,20 +175,19 @@ export const GraphQLDocument: React.FC<GraphQLDocumentProps> = ({
|
|
180
175
|
}, [positionCalculator, plain])
|
181
176
|
|
182
177
|
// Validation errors
|
183
|
-
const validationErrors = useMemo(() => {
|
178
|
+
const validationErrors = ReactHooks.useMemo(() => {
|
184
179
|
if (!validate || !analysisResult || !schema) return []
|
185
180
|
return analysisResult.errors
|
186
181
|
}, [validate, analysisResult, schema])
|
187
182
|
|
188
183
|
return (
|
189
184
|
<>
|
190
|
-
{
|
191
|
-
<style dangerouslySetInnerHTML={{ __html: identifierLinkStyles + '\n' + hoverTooltipStyles }} />
|
192
|
-
|
185
|
+
<style dangerouslySetInnerHTML={{ __html: graphqlDocumentStyles }} />
|
193
186
|
<div
|
194
187
|
ref={containerRef}
|
195
|
-
className={`graphql-document ${className} ${debug ? 'graphql-debug-mode' : ''}
|
196
|
-
|
188
|
+
className={`graphql-document ${className} ${debug ? 'graphql-debug-mode' : ''} ${
|
189
|
+
!isReady && !plain ? 'graphql-loading' : ''
|
190
|
+
}`}
|
197
191
|
>
|
198
192
|
{/* Base syntax highlighting */}
|
199
193
|
{highlightedHtml ? <div dangerouslySetInnerHTML={{ __html: highlightedHtml }} /> : (
|
@@ -202,6 +196,15 @@ export const GraphQLDocument: React.FC<GraphQLDocumentProps> = ({
|
|
202
196
|
</pre>
|
203
197
|
)}
|
204
198
|
|
199
|
+
{/* Copy button */}
|
200
|
+
{!plain && (
|
201
|
+
<CopyButton
|
202
|
+
text={children}
|
203
|
+
className='graphql-document-copy'
|
204
|
+
size='2'
|
205
|
+
/>
|
206
|
+
)}
|
207
|
+
|
205
208
|
{/* Interactive overlay layer */}
|
206
209
|
{!plain && isReady && (
|
207
210
|
<div className='graphql-interaction-layer' style={{ pointerEvents: 'none' }}>
|
@@ -219,8 +222,12 @@ export const GraphQLDocument: React.FC<GraphQLDocumentProps> = ({
|
|
219
222
|
position={position}
|
220
223
|
onNavigate={handleNavigate}
|
221
224
|
debug={debug}
|
222
|
-
isOpen={
|
223
|
-
|
225
|
+
isOpen={tooltipState.isOpen(id)}
|
226
|
+
isPinned={tooltipState.isPinned(id)}
|
227
|
+
onHoverStart={() => tooltipState.onHoverStart(id)}
|
228
|
+
onHoverEnd={() => tooltipState.onHoverEnd(id)}
|
229
|
+
onTogglePin={() => tooltipState.onTogglePin(id)}
|
230
|
+
onTooltipHover={() => tooltipState.onTooltipHover(id)}
|
224
231
|
/>
|
225
232
|
)
|
226
233
|
})}
|
@@ -241,44 +248,3 @@ export const GraphQLDocument: React.FC<GraphQLDocumentProps> = ({
|
|
241
248
|
</>
|
242
249
|
)
|
243
250
|
}
|
244
|
-
|
245
|
-
/**
|
246
|
-
* Default styles for the GraphQL document component
|
247
|
-
*/
|
248
|
-
export const graphqlDocumentStyles = `
|
249
|
-
.graphql-document {
|
250
|
-
position: relative;
|
251
|
-
}
|
252
|
-
|
253
|
-
.graphql-interaction-layer {
|
254
|
-
position: absolute;
|
255
|
-
top: 0;
|
256
|
-
left: 0;
|
257
|
-
right: 0;
|
258
|
-
bottom: 0;
|
259
|
-
pointer-events: none;
|
260
|
-
}
|
261
|
-
|
262
|
-
.graphql-interaction-layer > * {
|
263
|
-
pointer-events: auto;
|
264
|
-
}
|
265
|
-
|
266
|
-
.graphql-validation-errors {
|
267
|
-
margin-top: 1rem;
|
268
|
-
padding: 0.5rem;
|
269
|
-
background-color: var(--red-2);
|
270
|
-
border: 1px solid var(--red-6);
|
271
|
-
border-radius: 4px;
|
272
|
-
}
|
273
|
-
|
274
|
-
.graphql-error {
|
275
|
-
color: var(--red-11);
|
276
|
-
font-size: 0.875rem;
|
277
|
-
margin: 0.25rem 0;
|
278
|
-
}
|
279
|
-
|
280
|
-
.graphql-debug-mode [data-graphql-id] {
|
281
|
-
background-color: rgba(59, 130, 246, 0.1);
|
282
|
-
outline: 1px solid rgba(59, 130, 246, 0.3);
|
283
|
-
}
|
284
|
-
`
|
@@ -0,0 +1,197 @@
|
|
1
|
+
/**
|
2
|
+
* GraphQL Identifier Popover using Radix Themes
|
3
|
+
*
|
4
|
+
* Displays rich information about GraphQL identifiers on hover/click
|
5
|
+
*/
|
6
|
+
|
7
|
+
import type { React } from '#dep/react/index'
|
8
|
+
import { Cross2Icon } from '@radix-ui/react-icons'
|
9
|
+
import { Badge, Box, Card, Flex, IconButton, Link, Popover, Text } from '@radix-ui/themes'
|
10
|
+
import type { Documentation } from '../schema-integration.ts'
|
11
|
+
import type { Identifier } from '../types.ts'
|
12
|
+
|
13
|
+
export interface GraphQLIdentifierPopoverProps {
|
14
|
+
/** The identifier being shown */
|
15
|
+
identifier: Identifier
|
16
|
+
/** Documentation from schema */
|
17
|
+
documentation: Documentation
|
18
|
+
/** Whether this identifier has an error */
|
19
|
+
hasError?: boolean
|
20
|
+
/** Reference URL for "View docs" link */
|
21
|
+
referenceUrl: string
|
22
|
+
/** Whether popover is open */
|
23
|
+
open: boolean
|
24
|
+
/** Whether popover is pinned */
|
25
|
+
isPinned: boolean
|
26
|
+
/** Callback when open state changes */
|
27
|
+
onOpenChange: (open: boolean) => void
|
28
|
+
/** Callback to navigate to docs */
|
29
|
+
onNavigate?: (url: string) => void
|
30
|
+
/** The trigger element */
|
31
|
+
children: React.ReactNode
|
32
|
+
}
|
33
|
+
|
34
|
+
/**
|
35
|
+
* Popover content for GraphQL identifiers
|
36
|
+
*/
|
37
|
+
export const GraphQLIdentifierPopover: React.FC<GraphQLIdentifierPopoverProps> = ({
|
38
|
+
identifier,
|
39
|
+
documentation,
|
40
|
+
hasError = false,
|
41
|
+
referenceUrl,
|
42
|
+
open,
|
43
|
+
isPinned,
|
44
|
+
onOpenChange,
|
45
|
+
onNavigate,
|
46
|
+
children,
|
47
|
+
}) => {
|
48
|
+
// Determine badge color based on identifier kind
|
49
|
+
const getBadgeColor = () => {
|
50
|
+
switch (identifier.kind) {
|
51
|
+
case 'Type':
|
52
|
+
return 'blue'
|
53
|
+
case 'Field':
|
54
|
+
return 'green'
|
55
|
+
case 'Argument':
|
56
|
+
return 'orange'
|
57
|
+
case 'Variable':
|
58
|
+
return 'purple'
|
59
|
+
case 'Directive':
|
60
|
+
return 'amber'
|
61
|
+
case 'Fragment':
|
62
|
+
return 'cyan'
|
63
|
+
default:
|
64
|
+
return 'gray'
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
return (
|
69
|
+
<Popover.Root open={open} onOpenChange={onOpenChange}>
|
70
|
+
<Popover.Trigger>
|
71
|
+
{children}
|
72
|
+
</Popover.Trigger>
|
73
|
+
|
74
|
+
<Popover.Content
|
75
|
+
className='graphql-identifier-popover'
|
76
|
+
style={{ maxWidth: 400 }}
|
77
|
+
onInteractOutside={(e) => {
|
78
|
+
// Prevent closing when clicking inside popover if pinned
|
79
|
+
if (isPinned) {
|
80
|
+
e.preventDefault()
|
81
|
+
}
|
82
|
+
}}
|
83
|
+
>
|
84
|
+
<Flex direction='column' gap='2'>
|
85
|
+
{/* Header with name, kind, and close button */}
|
86
|
+
<Flex justify='between' align='center'>
|
87
|
+
<Flex align='center' gap='2'>
|
88
|
+
<Text size='2' weight='bold'>
|
89
|
+
{identifier.name}
|
90
|
+
</Text>
|
91
|
+
<Badge color={getBadgeColor()} size='1'>
|
92
|
+
{identifier.kind}
|
93
|
+
</Badge>
|
94
|
+
</Flex>
|
95
|
+
{isPinned && (
|
96
|
+
<IconButton
|
97
|
+
size='1'
|
98
|
+
variant='ghost'
|
99
|
+
onClick={() => onOpenChange(false)}
|
100
|
+
aria-label='Close popover'
|
101
|
+
>
|
102
|
+
<Cross2Icon />
|
103
|
+
</IconButton>
|
104
|
+
)}
|
105
|
+
</Flex>
|
106
|
+
|
107
|
+
{/* Type signature */}
|
108
|
+
<Box>
|
109
|
+
<Text size='1' color='gray'>
|
110
|
+
Type: <Text as='span' size='1' style={{ fontFamily: 'monospace' }}>{documentation.typeInfo}</Text>
|
111
|
+
</Text>
|
112
|
+
</Box>
|
113
|
+
|
114
|
+
{/* Description */}
|
115
|
+
{documentation.description && (
|
116
|
+
<Box>
|
117
|
+
<Text size='1'>
|
118
|
+
{documentation.description}
|
119
|
+
</Text>
|
120
|
+
</Box>
|
121
|
+
)}
|
122
|
+
|
123
|
+
{/* Default value for arguments */}
|
124
|
+
{documentation.defaultValue && (
|
125
|
+
<Box>
|
126
|
+
<Text size='1' color='gray'>
|
127
|
+
Default:{' '}
|
128
|
+
<Text as='span' size='1' style={{ fontFamily: 'monospace' }}>{documentation.defaultValue}</Text>
|
129
|
+
</Text>
|
130
|
+
</Box>
|
131
|
+
)}
|
132
|
+
|
133
|
+
{/* Deprecation warning */}
|
134
|
+
{documentation.deprecated && (
|
135
|
+
<Box
|
136
|
+
style={{
|
137
|
+
padding: '8px',
|
138
|
+
backgroundColor: 'var(--amber-2)',
|
139
|
+
borderRadius: '4px',
|
140
|
+
border: '1px solid var(--amber-6)',
|
141
|
+
}}
|
142
|
+
>
|
143
|
+
<Text size='1' color='amber'>
|
144
|
+
⚠️ Deprecated: {documentation.deprecated.reason}
|
145
|
+
</Text>
|
146
|
+
{documentation.deprecated.replacement && (
|
147
|
+
<Text size='1' color='amber'>
|
148
|
+
Use {documentation.deprecated.replacement} instead.
|
149
|
+
</Text>
|
150
|
+
)}
|
151
|
+
</Box>
|
152
|
+
)}
|
153
|
+
|
154
|
+
{/* Error message */}
|
155
|
+
{hasError && (
|
156
|
+
<Box
|
157
|
+
style={{
|
158
|
+
padding: '8px',
|
159
|
+
backgroundColor: 'var(--red-2)',
|
160
|
+
borderRadius: '4px',
|
161
|
+
border: '1px solid var(--red-6)',
|
162
|
+
}}
|
163
|
+
>
|
164
|
+
<Text size='1' color='red'>
|
165
|
+
❌ {identifier.kind} not found in schema
|
166
|
+
</Text>
|
167
|
+
</Box>
|
168
|
+
)}
|
169
|
+
|
170
|
+
{/* Schema path */}
|
171
|
+
<Box>
|
172
|
+
<Text size='1' color='gray'>
|
173
|
+
Path: {identifier.schemaPath.join(' → ')}
|
174
|
+
</Text>
|
175
|
+
</Box>
|
176
|
+
|
177
|
+
{/* View docs link */}
|
178
|
+
{onNavigate && !hasError && (
|
179
|
+
<Box>
|
180
|
+
<Link
|
181
|
+
size='1'
|
182
|
+
href={referenceUrl}
|
183
|
+
onClick={(e: React.MouseEvent) => {
|
184
|
+
e.preventDefault()
|
185
|
+
onNavigate(referenceUrl)
|
186
|
+
onOpenChange(false)
|
187
|
+
}}
|
188
|
+
>
|
189
|
+
View full documentation →
|
190
|
+
</Link>
|
191
|
+
</Box>
|
192
|
+
)}
|
193
|
+
</Flex>
|
194
|
+
</Popover.Content>
|
195
|
+
</Popover.Root>
|
196
|
+
)
|
197
|
+
}
|