1
- import { Pre } from "codehike/code " ;
2
- import { useMemo } from "react" ;
3
- import { CopyButton } from "./copy-button .js" ;
1
+ import { LazyMotion , domMax } from "motion/react " ;
2
+ import React from "react" ;
3
+ import { SpeakeasyCodeSamplesCore } from "../core .js" ;
4
4
import {
5
5
GetCodeSamplesRequest ,
6
6
MethodPaths ,
7
7
} from "../models/operations/getcodesamples.js" ;
8
+ import { OperationId } from "../types/custom.js" ;
9
+ import { useCodeSampleState } from "./code-sample.state.js" ;
8
10
import classes from "./code-sample.styles.js" ;
9
- import {
10
- useHighlightedCodeSamples ,
11
- useSafeSpeakeasyCodeSamplesContext ,
12
- useSelectedSnippet ,
13
- } from "./hooks.js" ;
11
+ import { CodeViewer , ErrorDisplay } from "./code-viewer.js" ;
12
+ import codehikeTheme from "./codehike/theme.js" ;
13
+ import { CopyButton } from "./copy-button.js" ;
14
14
import { LanguageSelector } from "./language-selector.js" ;
15
- import { lineNumbers } from "./codehike/line-numbers.js" ;
16
- import {
17
- LanguageSelectorSkeleton ,
18
- LoadingSkeleton ,
19
- TitleSkeleton ,
20
- } from "./skeleton.js" ;
21
- import { getCssVars , githubColorVars , useSystemColorMode } from "./styles.js" ;
22
- import { CodeSampleFilenameTitle , CodeSampleTitleComponent } from "./titles.js" ;
23
- import { tokenTransitions } from "./codehike/token-transitions.js" ;
24
- import { SpeakeasyCodeSamplesCore } from "../core.js" ;
25
- import { OperationId } from "../types/custom.js" ;
26
- import { LazyMotion , domAnimation } from "motion/react" ;
15
+ import { LanguageSelectorSkeleton , LoadingSkeleton } from "./skeleton.js" ;
16
+ import { getCssVars , useSystemColorMode } from "./styles.js" ;
17
+ import { type CodeSampleTitleComponent , CodeSampleTitle } from "./titles.js" ;
27
18
28
19
export type CodeSamplesViewerProps = {
29
20
/** Whether the code snippet should be copyable. */
@@ -46,7 +37,7 @@ export type CodeSamplesViewerProps = {
46
37
* @see CodeSampleFilenameTitle
47
38
* @default CodeSampleMethodTitle
48
39
*/
49
- title ?: CodeSampleTitleComponent ;
40
+ title ?: CodeSampleTitleComponent | React . ReactNode | string ;
50
41
/** The operation to get a code sample for. Can be queried by either
51
42
* operationId or method+path.
52
43
*/
@@ -67,45 +58,38 @@ export function CodeSamplesViewer({
67
58
operation,
68
59
style,
69
60
copyable,
70
- defaultLang,
71
61
client : clientProp ,
72
62
} : CodeSamplesViewerProps ) {
73
- const TitleComponent = title ;
74
-
75
- const systemColorMode = useSystemColorMode ( ) ;
76
-
77
- const codeTheme = useMemo ( ( ) => {
78
- if ( theme === "system" ) return githubColorVars [ systemColorMode ] ;
79
- return githubColorVars [ theme ] ;
80
- } , [ theme , systemColorMode ] ) ;
81
-
82
- const request : GetCodeSamplesRequest = useMemo ( ( ) => {
63
+ const request : GetCodeSamplesRequest = React . useMemo ( ( ) => {
83
64
if ( typeof operation === "string" ) return { operationIds : [ operation ] } ;
84
65
return { methoPaths : [ operation ] } ;
85
66
} , [ operation ] ) ;
86
67
87
- const client = useSafeSpeakeasyCodeSamplesContext ( clientProp ) ;
88
- const { status, data, error } = useHighlightedCodeSamples ( client , request ) ;
68
+ const { state, setSelectedLanguage } = useCodeSampleState ( {
69
+ client : clientProp ,
70
+ requestParams : request ,
71
+ } ) ;
89
72
90
- const { selectedSnippet, selectedLang, setSelectedLang } = useSelectedSnippet (
91
- data ,
92
- defaultLang ,
93
- ) ;
73
+ const systemColorMode = useSystemColorMode ( ) ;
74
+ const codeTheme = React . useMemo ( ( ) => {
75
+ if ( theme === "system" ) return codehikeTheme [ systemColorMode ] ;
76
+ return codehikeTheme [ theme ] ;
77
+ } , [ theme , systemColorMode ] ) ;
94
78
95
- const longestCodeHeight = useMemo ( ( ) => {
79
+ const longestCodeHeight = React . useMemo ( ( ) => {
96
80
const largestLines = Math . max (
97
- ...Object . values ( data ?? [ ] )
81
+ ...Object . values ( state . snippets ?? [ ] )
98
82
. filter ( ( snippet ) => snippet . code !== undefined )
99
83
. map ( ( code ) => code . code ! . split ( "\n" ) . length ) ,
100
84
) ;
101
85
102
86
const lineHeight = 23 ;
103
87
const padding = 12 ;
104
88
return largestLines * lineHeight + padding * 2 ;
105
- } , [ data ] ) ;
89
+ } , [ state . snippets ] ) ;
106
90
107
91
return (
108
- < LazyMotion strict features = { domAnimation } >
92
+ < LazyMotion strict features = { domMax } >
109
93
< div
110
94
style = { {
111
95
...codeTheme ,
@@ -117,39 +101,37 @@ export function CodeSamplesViewer({
117
101
className = { `${ classes . root } ${ className ?? "" } ` }
118
102
>
119
103
< div className = { classes . heading } >
120
- { status === "loading" && error === undefined ? (
121
- < TitleSkeleton />
122
- ) : TitleComponent && selectedSnippet ? (
123
- < TitleComponent { ...selectedSnippet ! . raw } />
124
- ) : (
125
- < CodeSampleFilenameTitle { ...selectedSnippet ! . raw } />
104
+ < CodeSampleTitle
105
+ component = { title }
106
+ status = { state . status }
107
+ data = { state . selectedSnippet ?. raw }
108
+ />
109
+ < >
110
+ { state . status === "loading" && < LanguageSelectorSkeleton /> }
111
+ { state . status === "success" && (
112
+ < LanguageSelector
113
+ value = { state . selectedSnippet ?. lang }
114
+ onChange = { setSelectedLanguage }
115
+ snippets = { state . snippets ?? [ ] }
116
+ className = { classes . selector }
117
+ />
118
+ ) }
119
+ </ >
120
+ </ div >
121
+ < div className = { classes . codeContainer } >
122
+ { state . status === "success" && copyable && (
123
+ < CopyButton code = { state . selectedSnippet . code } />
126
124
) }
127
- { status === "loading" && error === undefined ? (
128
- < LanguageSelectorSkeleton />
129
- ) : (
130
- < LanguageSelector
131
- value = { selectedLang }
132
- onChange = { setSelectedLang }
133
- snippets = { data ?? [ ] }
134
- className = { classes . selector }
125
+ { state . status === "loading" && < LoadingSkeleton /> }
126
+ { state . status === "error" && < ErrorDisplay error = { state . error } /> }
127
+ { state . status === "success" && (
128
+ < CodeViewer
129
+ status = { state . status }
130
+ code = { state . selectedSnippet }
131
+ longestCodeHeight = { longestCodeHeight }
135
132
/>
136
133
) }
137
134
</ div >
138
- < div className = { classes . codeContainer } >
139
- { status === "loading" ? (
140
- < LoadingSkeleton />
141
- ) : selectedSnippet ? (
142
- < >
143
- { copyable && < CopyButton code = { selectedSnippet . code } /> }
144
- < Pre
145
- className = { classes . pre }
146
- style = { { height : longestCodeHeight } }
147
- handlers = { [ lineNumbers , tokenTransitions ] }
148
- code = { selectedSnippet }
149
- />
150
- </ >
151
- ) : null }
152
- </ div >
153
135
</ div >
154
136
</ LazyMotion >
155
137
) ;
0 commit comments