@@ -5,6 +5,8 @@ import React, { useCallback, useMemo } from 'react';
5
5
import { useHash , useIsMounted } from '@/components/hooks' ;
6
6
import * as storage from '@/lib/local-storage' ;
7
7
import { type ClassValue , tcls } from '@/lib/tailwind' ;
8
+ import type { DocumentBlockTabs } from '@gitbook/api' ;
9
+ import { HashLinkButton } from '../HashLinkButton' ;
8
10
9
11
interface TabsState {
10
12
activeIds : {
@@ -68,9 +70,10 @@ export function DynamicTabs(
68
70
props : TabsInput & {
69
71
tabsBody : React . ReactNode [ ] ;
70
72
style : ClassValue ;
73
+ block : DocumentBlockTabs ;
71
74
}
72
75
) {
73
- const { id, tabs, tabsBody, style } = props ;
76
+ const { id, block , tabs, tabsBody, style } = props ;
74
77
75
78
const hash = useHash ( ) ;
76
79
const [ tabsState , setTabsState ] = useTabsState ( ) ;
@@ -138,107 +141,115 @@ export function DynamicTabs(
138
141
} , [ hash , tabs , onSelectTab ] ) ;
139
142
140
143
return (
141
- < div
142
- className = { tcls (
143
- 'rounded-lg' ,
144
- 'straight-corners:rounded-sm' ,
145
- 'ring-1' ,
146
- 'ring-inset' ,
147
- 'ring-tint-subtle' ,
148
- 'flex' ,
149
- 'overflow-hidden' ,
150
- 'flex-col' ,
151
- style
152
- ) }
153
- >
144
+ < div className = { tcls ( 'relative' , 'group' ) } >
145
+ < HashLinkButton
146
+ id = { getTabButtonId ( active . id ) }
147
+ block = { block }
148
+ className = { tcls ( 'absolute' , 'left-0' , 'top-1' ) }
149
+ />
150
+
154
151
< div
155
- role = "tablist"
156
152
className = { tcls (
157
- 'group/tabs' ,
158
- 'inline-flex' ,
159
- 'flex-row' ,
160
- 'self-stretch' ,
161
- 'after:flex-[1]' ,
162
- 'after:bg-tint-12/1' ,
163
- // if last tab is selected, apply rounded to :after element
164
- '[&:has(button.active-tab:last-of-type):after]:rounded-bl-md'
153
+ 'rounded-lg' ,
154
+ 'straight-corners:rounded-sm' ,
155
+ 'ring-1' ,
156
+ 'ring-inset' ,
157
+ 'ring-tint-subtle' ,
158
+ 'flex' ,
159
+ 'overflow-hidden' ,
160
+ 'flex-col' ,
161
+ style
165
162
) }
166
163
>
167
- { tabs . map ( ( tab ) => (
168
- < button
164
+ < div
165
+ role = "tablist"
166
+ className = { tcls (
167
+ 'group/tabs' ,
168
+ 'inline-flex' ,
169
+ 'flex-row' ,
170
+ 'self-stretch' ,
171
+ 'after:flex-[1]' ,
172
+ 'after:bg-tint-12/1' ,
173
+ // if last tab is selected, apply rounded to :after element
174
+ '[&:has(button.active-tab:last-of-type):after]:rounded-bl-md'
175
+ ) }
176
+ >
177
+ { tabs . map ( ( tab ) => (
178
+ < button
179
+ key = { tab . id }
180
+ role = "tab"
181
+ aria-selected = { active . id === tab . id }
182
+ aria-controls = { getTabPanelId ( tab . id ) }
183
+ id = { getTabButtonId ( tab . id ) }
184
+ onClick = { ( ) => {
185
+ onSelectTab ( tab ) ;
186
+ } }
187
+ className = { tcls (
188
+ //prev from active-tab
189
+ '[&:has(+_.active-tab)]:rounded-br-md' ,
190
+
191
+ //next from active-tab
192
+ '[.active-tab_+_&]:rounded-bl-md' ,
193
+
194
+ //next from active-tab
195
+ '[.active-tab_+_:after]:rounded-br-md' ,
196
+
197
+ 'inline-block' ,
198
+ 'text-sm' ,
199
+ 'px-3.5' ,
200
+ 'py-2' ,
201
+ 'transition-[color]' ,
202
+ 'font-[500]' ,
203
+ 'relative' ,
204
+
205
+ 'after:transition-colors' ,
206
+ 'after:border-r' ,
207
+ 'after:absolute' ,
208
+ 'after:left-[unset]' ,
209
+ 'after:right-0' ,
210
+ 'after:border-tint' ,
211
+ 'after:top-[15%]' ,
212
+ 'after:h-[70%]' ,
213
+ 'after:w-[1px]' ,
214
+
215
+ 'last:after:border-transparent' ,
216
+
217
+ 'text-tint' ,
218
+ 'bg-tint-12/1' ,
219
+ 'hover:text-tint-strong' ,
220
+
221
+ 'truncate' ,
222
+ 'max-w-full' ,
223
+
224
+ active . id === tab . id
225
+ ? [
226
+ 'shrink-0' ,
227
+ 'active-tab' ,
228
+ 'text-tint-strong' ,
229
+ 'bg-transparent' ,
230
+ 'after:[&.active-tab]:border-transparent' ,
231
+ 'after:[:has(+_&.active-tab)]:border-transparent' ,
232
+ 'after:[:has(&_+)]:border-transparent' ,
233
+ ]
234
+ : null
235
+ ) }
236
+ >
237
+ { tab . title }
238
+ </ button >
239
+ ) ) }
240
+ </ div >
241
+ { tabs . map ( ( tab , index ) => (
242
+ < div
169
243
key = { tab . id }
170
- role = "tab"
171
- aria-selected = { active . id === tab . id }
172
- aria-controls = { getTabPanelId ( tab . id ) }
173
- id = { getTabButtonId ( tab . id ) }
174
- onClick = { ( ) => {
175
- onSelectTab ( tab ) ;
176
- } }
177
- className = { tcls (
178
- //prev from active-tab
179
- '[&:has(+_.active-tab)]:rounded-br-md' ,
180
-
181
- //next from active-tab
182
- '[.active-tab_+_&]:rounded-bl-md' ,
183
-
184
- //next from active-tab
185
- '[.active-tab_+_:after]:rounded-br-md' ,
186
-
187
- 'inline-block' ,
188
- 'text-sm' ,
189
- 'px-3.5' ,
190
- 'py-2' ,
191
- 'transition-[color]' ,
192
- 'font-[500]' ,
193
- 'relative' ,
194
-
195
- 'after:transition-colors' ,
196
- 'after:border-r' ,
197
- 'after:absolute' ,
198
- 'after:left-[unset]' ,
199
- 'after:right-0' ,
200
- 'after:border-tint' ,
201
- 'after:top-[15%]' ,
202
- 'after:h-[70%]' ,
203
- 'after:w-[1px]' ,
204
-
205
- 'last:after:border-transparent' ,
206
-
207
- 'text-tint' ,
208
- 'bg-tint-12/1' ,
209
- 'hover:text-tint-strong' ,
210
-
211
- 'truncate' ,
212
- 'max-w-full' ,
213
-
214
- active . id === tab . id
215
- ? [
216
- 'shrink-0' ,
217
- 'active-tab' ,
218
- 'text-tint-strong' ,
219
- 'bg-transparent' ,
220
- 'after:[&.active-tab]:border-transparent' ,
221
- 'after:[:has(+_&.active-tab)]:border-transparent' ,
222
- 'after:[:has(&_+)]:border-transparent' ,
223
- ]
224
- : null
225
- ) }
244
+ role = "tabpanel"
245
+ id = { getTabPanelId ( tab . id ) }
246
+ aria-labelledby = { getTabButtonId ( tab . id ) }
247
+ className = { tcls ( 'p-4' , tab . id !== active . id ? 'hidden' : null ) }
226
248
>
227
- { tab . title }
228
- </ button >
249
+ { tabsBody [ index ] }
250
+ </ div >
229
251
) ) }
230
252
</ div >
231
- { tabs . map ( ( tab , index ) => (
232
- < div
233
- key = { tab . id }
234
- role = "tabpanel"
235
- id = { getTabPanelId ( tab . id ) }
236
- aria-labelledby = { getTabButtonId ( tab . id ) }
237
- className = { tcls ( 'p-4' , tab . id !== active . id ? 'hidden' : null ) }
238
- >
239
- { tabsBody [ index ] }
240
- </ div >
241
- ) ) }
242
253
</ div >
243
254
) ;
244
255
}
0 commit comments