polen 0.10.0-next.12 → 0.10.0-next.14
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/api/vite/plugins/build.d.ts.map +1 -1
- package/build/api/vite/plugins/build.js +11 -3
- package/build/api/vite/plugins/build.js.map +1 -1
- package/build/api/vite/plugins/core.d.ts.map +1 -1
- package/build/api/vite/plugins/core.js +12 -10
- package/build/api/vite/plugins/core.js.map +1 -1
- package/build/api/vite/plugins/pages.d.ts.map +1 -1
- package/build/api/vite/plugins/pages.js +6 -7
- package/build/api/vite/plugins/pages.js.map +1 -1
- package/build/api/vite/plugins/serve.d.ts.map +1 -1
- package/build/api/vite/plugins/serve.js +47 -7
- package/build/api/vite/plugins/serve.js.map +1 -1
- package/build/lib/file-router/diagnostic-reporter.js +2 -2
- package/build/lib/file-router/diagnostic-reporter.js.map +1 -1
- 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 +52 -83
- 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/build/lib/graphql-document/positioning-simple.d.ts +0 -5
- package/build/lib/graphql-document/positioning-simple.d.ts.map +1 -1
- package/build/lib/graphql-document/positioning-simple.js +78 -90
- package/build/lib/graphql-document/positioning-simple.js.map +1 -1
- package/build/lib/kit-temp.d.ts +103 -0
- package/build/lib/kit-temp.d.ts.map +1 -1
- package/build/lib/kit-temp.js +236 -2
- package/build/lib/kit-temp.js.map +1 -1
- package/build/lib/vite-plugin-reactive-data/vite-plugin-reactive-data.d.ts +1 -8
- package/build/lib/vite-plugin-reactive-data/vite-plugin-reactive-data.d.ts.map +1 -1
- package/build/lib/vite-plugin-reactive-data/vite-plugin-reactive-data.js +48 -53
- package/build/lib/vite-plugin-reactive-data/vite-plugin-reactive-data.js.map +1 -1
- package/build/package-paths.js +3 -3
- package/build/package-paths.js.map +1 -1
- package/build/template/components/Link.d.ts +1 -1
- package/build/template/components/Link.d.ts.map +1 -1
- package/build/template/components/Link.js +14 -5
- package/build/template/components/Link.js.map +1 -1
- package/build/template/components/content/GraphQLDocumentWithSchema.d.ts.map +1 -1
- package/build/template/components/content/GraphQLDocumentWithSchema.js +0 -3
- package/build/template/components/content/GraphQLDocumentWithSchema.js.map +1 -1
- package/build/template/components/content/GraphQLDocumentWrapper.d.ts.map +1 -1
- package/build/template/components/content/GraphQLDocumentWrapper.js +8 -7
- package/build/template/components/content/GraphQLDocumentWrapper.js.map +1 -1
- package/build/template/components/sidebar/SidebarItem.js +2 -2
- package/build/template/entry.client.d.ts.map +1 -1
- package/build/template/entry.client.js +0 -3
- package/build/template/entry.client.js.map +1 -1
- package/build/template/hooks/useClientOnly.d.ts +9 -0
- package/build/template/hooks/useClientOnly.d.ts.map +1 -0
- package/build/template/hooks/useClientOnly.js +16 -0
- package/build/template/hooks/useClientOnly.js.map +1 -0
- package/build/template/routes/root.d.ts.map +1 -1
- package/build/template/routes/root.js +2 -150
- package/build/template/routes/root.js.map +1 -1
- package/build/template/server/app.d.ts +8 -1
- package/build/template/server/app.d.ts.map +1 -1
- package/build/template/server/app.js +21 -21
- package/build/template/server/app.js.map +1 -1
- package/build/template/server/create-page-html-response.d.ts +7 -0
- package/build/template/server/create-page-html-response.d.ts.map +1 -0
- package/build/template/server/{render-page.js → create-page-html-response.js} +11 -16
- package/build/template/server/create-page-html-response.js.map +1 -0
- package/build/template/server/main.js +2 -1
- package/build/template/server/main.js.map +1 -1
- package/build/template/server/middleware/page.d.ts +4 -0
- package/build/template/server/middleware/page.d.ts.map +1 -0
- package/build/template/server/middleware/page.js +15 -0
- package/build/template/server/middleware/page.js.map +1 -0
- package/build/template/server/middleware/unsupported-assets.d.ts +10 -0
- package/build/template/server/middleware/unsupported-assets.d.ts.map +1 -0
- package/build/template/server/middleware/unsupported-assets.js +21 -0
- package/build/template/server/middleware/unsupported-assets.js.map +1 -0
- package/build/template/server/ssg/generate.d.ts.map +1 -1
- package/build/template/server/ssg/generate.js +33 -34
- package/build/template/server/ssg/generate.js.map +1 -1
- package/build/template/styles/code-block.css +218 -0
- package/package.json +4 -2
- package/src/api/singletons/markdown/markdown.test.ts +1 -1
- package/src/api/vite/plugins/build.ts +97 -89
- package/src/api/vite/plugins/core.ts +15 -10
- package/src/api/vite/plugins/pages.ts +9 -7
- package/src/api/vite/plugins/serve.ts +62 -9
- package/src/lib/file-router/diagnostic-reporter.ts +2 -2
- package/src/lib/graphql-document/components/CopyButton.tsx +76 -0
- package/src/lib/graphql-document/components/GraphQLDocument.tsx +73 -95
- 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/src/lib/graphql-document/positioning-simple.test.ts +18 -22
- package/src/lib/graphql-document/positioning-simple.ts +97 -108
- package/src/lib/kit-temp.test.ts +15 -3
- package/src/lib/kit-temp.ts +304 -4
- package/src/lib/vite-plugin-reactive-data/vite-plugin-reactive-data.ts +52 -58
- package/src/package-paths.ts +3 -3
- package/src/template/components/Link.tsx +20 -12
- package/src/template/components/content/GraphQLDocumentWithSchema.tsx +0 -5
- package/src/template/components/content/GraphQLDocumentWrapper.tsx +14 -7
- package/src/template/components/sidebar/SidebarItem.tsx +2 -2
- package/src/template/entry.client.tsx +0 -3
- package/src/template/hooks/useClientOnly.ts +21 -0
- package/src/template/routes/root.tsx +0 -159
- package/src/template/server/app.ts +33 -23
- package/src/template/server/{render-page.tsx → create-page-html-response.ts} +19 -16
- package/src/template/server/main.ts +2 -1
- package/src/template/server/middleware/page.ts +19 -0
- package/src/template/server/middleware/unsupported-assets.ts +25 -0
- package/src/template/server/ssg/generate.ts +68 -72
- 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/build/template/server/render-page.d.ts +0 -3
- package/build/template/server/render-page.d.ts.map +0 -1
- package/build/template/server/render-page.js.map +0 -1
- package/src/lib/graphql-document/components/HoverTooltip.tsx +0 -282
@@ -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
|
@@ -64,52 +65,45 @@ export const GraphQLDocument: React.FC<GraphQLDocumentProps> = ({
|
|
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 })
|
96
|
+
// Debug logging handled by debug prop
|
103
97
|
return result
|
104
|
-
}, [children, plain, schema])
|
98
|
+
}, [children, plain, schema, debug])
|
105
99
|
|
106
100
|
// Layer 2: Schema resolution
|
107
|
-
const resolver = useMemo(() => {
|
101
|
+
const resolver = ReactHooks.useMemo(() => {
|
108
102
|
if (!schema || plain) return null
|
109
103
|
return createPolenSchemaResolver(schema)
|
110
104
|
}, [schema, plain])
|
111
105
|
|
112
|
-
const resolutions = useMemo(() => {
|
106
|
+
const resolutions = ReactHooks.useMemo(() => {
|
113
107
|
if (!analysisResult || !resolver) {
|
114
108
|
return new Map()
|
115
109
|
}
|
@@ -125,16 +119,19 @@ export const GraphQLDocument: React.FC<GraphQLDocumentProps> = ({
|
|
125
119
|
}, [analysisResult, resolver])
|
126
120
|
|
127
121
|
// Layer 3: Position calculation
|
128
|
-
const positionCalculator = useMemo(() => {
|
122
|
+
const positionCalculator = ReactHooks.useMemo(() => {
|
129
123
|
if (plain) return null
|
130
124
|
return createSimplePositionCalculator()
|
131
125
|
}, [plain])
|
132
126
|
|
133
|
-
const [positions, setPositions] = useState<Map<string, { position: any; identifier: Identifier }>>(
|
127
|
+
const [positions, setPositions] = ReactHooks.useState<Map<string, { position: any; identifier: Identifier }>>(
|
128
|
+
new Map(),
|
129
|
+
)
|
134
130
|
|
135
131
|
// Prepare code block and calculate positions after render
|
136
|
-
useEffect(() => {
|
132
|
+
ReactHooks.useEffect(() => {
|
137
133
|
if (!containerRef.current || !analysisResult || !positionCalculator || plain) {
|
134
|
+
// Skip position calculation - debug handled by debug prop
|
138
135
|
return
|
139
136
|
}
|
140
137
|
|
@@ -143,11 +140,13 @@ export const GraphQLDocument: React.FC<GraphQLDocumentProps> = ({
|
|
143
140
|
|| containerRef.current.querySelector('pre code')
|
144
141
|
|| containerRef.current.querySelector('code')
|
145
142
|
if (!codeElement) {
|
143
|
+
// No code element found - skip
|
146
144
|
return
|
147
145
|
}
|
148
146
|
|
149
147
|
// Prepare the code block (wrap identifiers)
|
150
148
|
const identifiers = Array.from(analysisResult.identifiers.byPosition.values())
|
149
|
+
// Prepare code block with identifiers
|
151
150
|
positionCalculator.prepareCodeBlock(codeElement as Element, identifiers)
|
152
151
|
|
153
152
|
// Get positions after DOM update
|
@@ -155,45 +154,52 @@ export const GraphQLDocument: React.FC<GraphQLDocumentProps> = ({
|
|
155
154
|
// Pass containerRef.current as the reference element for positioning
|
156
155
|
if (containerRef.current) {
|
157
156
|
const newPositions = positionCalculator.getIdentifierPositions(codeElement as Element, containerRef.current)
|
157
|
+
// Position calculation complete
|
158
158
|
setPositions(newPositions)
|
159
159
|
setIsReady(true)
|
160
160
|
}
|
161
161
|
})
|
162
162
|
}, [analysisResult, positionCalculator, plain, highlightedHtml])
|
163
163
|
|
164
|
-
// Handle resize events
|
165
|
-
useEffect(() => {
|
164
|
+
// Handle resize events with debouncing
|
165
|
+
ReactHooks.useEffect(() => {
|
166
166
|
if (!containerRef.current || !positionCalculator || plain) return
|
167
167
|
|
168
|
+
let resizeTimer: NodeJS.Timeout
|
168
169
|
const handleResize = () => {
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
170
|
+
clearTimeout(resizeTimer)
|
171
|
+
resizeTimer = setTimeout(() => {
|
172
|
+
const codeElement = containerRef.current?.querySelector('pre.shiki code')
|
173
|
+
|| containerRef.current?.querySelector('pre code')
|
174
|
+
|| containerRef.current?.querySelector('code')
|
175
|
+
if (codeElement && containerRef.current) {
|
176
|
+
const newPositions = positionCalculator.getIdentifierPositions(codeElement as Element, containerRef.current)
|
177
|
+
setPositions(newPositions)
|
178
|
+
}
|
179
|
+
}, 100) // Debounce resize events
|
176
180
|
}
|
177
181
|
|
178
182
|
window.addEventListener('resize', handleResize)
|
179
|
-
return () =>
|
183
|
+
return () => {
|
184
|
+
clearTimeout(resizeTimer)
|
185
|
+
window.removeEventListener('resize', handleResize)
|
186
|
+
}
|
180
187
|
}, [positionCalculator, plain])
|
181
188
|
|
182
189
|
// Validation errors
|
183
|
-
const validationErrors = useMemo(() => {
|
190
|
+
const validationErrors = ReactHooks.useMemo(() => {
|
184
191
|
if (!validate || !analysisResult || !schema) return []
|
185
192
|
return analysisResult.errors
|
186
193
|
}, [validate, analysisResult, schema])
|
187
194
|
|
188
195
|
return (
|
189
196
|
<>
|
190
|
-
{
|
191
|
-
<style dangerouslySetInnerHTML={{ __html: identifierLinkStyles + '\n' + hoverTooltipStyles }} />
|
192
|
-
|
197
|
+
<style dangerouslySetInnerHTML={{ __html: graphqlDocumentStyles }} />
|
193
198
|
<div
|
194
199
|
ref={containerRef}
|
195
|
-
className={`graphql-document ${className} ${debug ? 'graphql-debug-mode' : ''}
|
196
|
-
|
200
|
+
className={`graphql-document ${className} ${debug ? 'graphql-debug-mode' : ''} ${
|
201
|
+
!isReady && !plain ? 'graphql-loading' : ''
|
202
|
+
}`}
|
197
203
|
>
|
198
204
|
{/* Base syntax highlighting */}
|
199
205
|
{highlightedHtml ? <div dangerouslySetInnerHTML={{ __html: highlightedHtml }} /> : (
|
@@ -202,6 +208,15 @@ export const GraphQLDocument: React.FC<GraphQLDocumentProps> = ({
|
|
202
208
|
</pre>
|
203
209
|
)}
|
204
210
|
|
211
|
+
{/* Copy button */}
|
212
|
+
{!plain && (
|
213
|
+
<CopyButton
|
214
|
+
text={children}
|
215
|
+
className='graphql-document-copy'
|
216
|
+
size='2'
|
217
|
+
/>
|
218
|
+
)}
|
219
|
+
|
205
220
|
{/* Interactive overlay layer */}
|
206
221
|
{!plain && isReady && (
|
207
222
|
<div className='graphql-interaction-layer' style={{ pointerEvents: 'none' }}>
|
@@ -219,8 +234,12 @@ export const GraphQLDocument: React.FC<GraphQLDocumentProps> = ({
|
|
219
234
|
position={position}
|
220
235
|
onNavigate={handleNavigate}
|
221
236
|
debug={debug}
|
222
|
-
isOpen={
|
223
|
-
|
237
|
+
isOpen={tooltipState.isOpen(id)}
|
238
|
+
isPinned={tooltipState.isPinned(id)}
|
239
|
+
onHoverStart={() => tooltipState.onHoverStart(id)}
|
240
|
+
onHoverEnd={() => tooltipState.onHoverEnd(id)}
|
241
|
+
onTogglePin={() => tooltipState.onTogglePin(id)}
|
242
|
+
onTooltipHover={() => tooltipState.onTooltipHover(id)}
|
224
243
|
/>
|
225
244
|
)
|
226
245
|
})}
|
@@ -241,44 +260,3 @@ export const GraphQLDocument: React.FC<GraphQLDocumentProps> = ({
|
|
241
260
|
</>
|
242
261
|
)
|
243
262
|
}
|
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
|
+
}
|