@instructure/ui-tabs 11.7.10 → 11.7.11-snapshot-4
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/CHANGELOG.md +7 -0
- package/es/Tabs/v2/Tab/index.js +21 -2
- package/es/Tabs/v2/Tab/props.js +1 -1
- package/es/Tabs/v2/index.js +195 -85
- package/es/Tabs/v2/props.js +1 -1
- package/lib/Tabs/v2/Tab/index.js +21 -2
- package/lib/Tabs/v2/Tab/props.js +1 -1
- package/lib/Tabs/v2/index.js +194 -84
- package/lib/Tabs/v2/props.js +1 -1
- package/package.json +16 -16
- package/src/Tabs/v2/README.md +57 -1
- package/src/Tabs/v2/Tab/index.tsx +16 -2
- package/src/Tabs/v2/Tab/props.ts +7 -0
- package/src/Tabs/v2/index.tsx +227 -124
- package/src/Tabs/v2/props.ts +10 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/Tabs/v2/Tab/index.d.ts +6 -0
- package/types/Tabs/v2/Tab/index.d.ts.map +1 -1
- package/types/Tabs/v2/Tab/props.d.ts +5 -0
- package/types/Tabs/v2/Tab/props.d.ts.map +1 -1
- package/types/Tabs/v2/index.d.ts +25 -13
- package/types/Tabs/v2/index.d.ts.map +1 -1
- package/types/Tabs/v2/props.d.ts +8 -0
- package/types/Tabs/v2/props.d.ts.map +1 -1
package/src/Tabs/v2/index.tsx
CHANGED
|
@@ -41,8 +41,8 @@ import {
|
|
|
41
41
|
withDeterministicId
|
|
42
42
|
} from '@instructure/ui-react-utils'
|
|
43
43
|
import { logError as error } from '@instructure/console'
|
|
44
|
-
import {
|
|
45
|
-
import { getBoundingClientRect } from '@instructure/ui-dom-utils'
|
|
44
|
+
import { textDirectionContextConsumer } from '@instructure/ui-i18n'
|
|
45
|
+
import { contains, getBoundingClientRect } from '@instructure/ui-dom-utils'
|
|
46
46
|
import type { RectType } from '@instructure/ui-dom-utils'
|
|
47
47
|
import { debounce } from '@instructure/debounce'
|
|
48
48
|
import type { Debounced } from '@instructure/debounce'
|
|
@@ -64,6 +64,15 @@ import type { TabsPanelProps } from './Panel/props'
|
|
|
64
64
|
type TabChild = ComponentElement<TabsTabProps, any>
|
|
65
65
|
type PanelChild = ComponentElement<TabsPanelProps, Panel>
|
|
66
66
|
|
|
67
|
+
type TabDescriptor = {
|
|
68
|
+
index: number
|
|
69
|
+
tabDomId: string
|
|
70
|
+
panelDomId: string
|
|
71
|
+
isDisabled: boolean
|
|
72
|
+
isSelected: boolean
|
|
73
|
+
panel: PanelChild
|
|
74
|
+
}
|
|
75
|
+
|
|
67
76
|
/**
|
|
68
77
|
---
|
|
69
78
|
category: components
|
|
@@ -71,6 +80,7 @@ category: components
|
|
|
71
80
|
**/
|
|
72
81
|
@withDeterministicId()
|
|
73
82
|
@withStyleNew(generateStyle)
|
|
83
|
+
@textDirectionContextConsumer()
|
|
74
84
|
class Tabs extends Component<TabsProps, TabsState> {
|
|
75
85
|
static displayName = 'Tabs'
|
|
76
86
|
static readonly componentId = 'Tabs'
|
|
@@ -80,14 +90,14 @@ class Tabs extends Component<TabsProps, TabsState> {
|
|
|
80
90
|
static defaultProps = {
|
|
81
91
|
variant: 'default',
|
|
82
92
|
shouldFocusOnRender: false,
|
|
83
|
-
tabOverflow: 'stack'
|
|
93
|
+
tabOverflow: 'stack',
|
|
94
|
+
activationMode: 'auto'
|
|
84
95
|
}
|
|
85
96
|
|
|
86
97
|
static Panel = Panel
|
|
87
98
|
static Tab = Tab
|
|
88
99
|
|
|
89
100
|
private _tabList: Element | null = null
|
|
90
|
-
private _focusable: Focusable | null = null
|
|
91
101
|
private _tabListPosition?: RectType
|
|
92
102
|
private _debounced?: Debounced<typeof this.handleResize>
|
|
93
103
|
private _resizeListener?: ResizeObserver
|
|
@@ -252,30 +262,74 @@ class Tabs extends Component<TabsProps, TabsState> {
|
|
|
252
262
|
}
|
|
253
263
|
}
|
|
254
264
|
|
|
265
|
+
get isRtl() {
|
|
266
|
+
return this.props.dir === textDirectionContextConsumer.DIRECTION.rtl
|
|
267
|
+
}
|
|
268
|
+
|
|
255
269
|
handleTabClick: TabsTabProps['onClick'] = (event, { index }) => {
|
|
256
|
-
const
|
|
257
|
-
|
|
270
|
+
const target = this.getNextTab(this.getTabs(), index, 0)
|
|
271
|
+
|
|
272
|
+
if (target) {
|
|
273
|
+
this.fireOnChange(event, target)
|
|
274
|
+
}
|
|
258
275
|
}
|
|
259
276
|
|
|
260
277
|
handleTabKeyDown: TabsTabProps['onKeyDown'] = (event, { index }) => {
|
|
261
|
-
|
|
278
|
+
const tabs = this.getTabs()
|
|
279
|
+
let target: TabDescriptor | undefined
|
|
280
|
+
let isActivation = false
|
|
281
|
+
|
|
282
|
+
switch (event.keyCode) {
|
|
283
|
+
case keycode.codes.left:
|
|
284
|
+
target = this.getNextTab(tabs, index, this.isRtl ? 1 : -1)
|
|
285
|
+
break
|
|
286
|
+
case keycode.codes.right:
|
|
287
|
+
target = this.getNextTab(tabs, index, this.isRtl ? -1 : 1)
|
|
288
|
+
break
|
|
289
|
+
case keycode.codes.up:
|
|
290
|
+
target = this.getNextTab(tabs, index, -1)
|
|
291
|
+
break
|
|
292
|
+
case keycode.codes.down:
|
|
293
|
+
target = this.getNextTab(tabs, index, 1)
|
|
294
|
+
break
|
|
295
|
+
case keycode.codes.home:
|
|
296
|
+
target = this.getEdgeTab(tabs, 'first')
|
|
297
|
+
break
|
|
298
|
+
case keycode.codes.end:
|
|
299
|
+
target = this.getEdgeTab(tabs, 'last')
|
|
300
|
+
break
|
|
301
|
+
case keycode.codes.enter:
|
|
302
|
+
case keycode.codes.space:
|
|
303
|
+
target = this.getNextTab(tabs, index, 0)
|
|
304
|
+
isActivation = true
|
|
305
|
+
break
|
|
306
|
+
default:
|
|
307
|
+
return
|
|
308
|
+
}
|
|
262
309
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
) {
|
|
267
|
-
|
|
268
|
-
nextTab = this.getNextTab(index, -1)
|
|
269
|
-
} else if (
|
|
270
|
-
event.keyCode === keycode.codes.down ||
|
|
271
|
-
event.keyCode === keycode.codes.right
|
|
272
|
-
) {
|
|
273
|
-
// Select next tab to the right
|
|
274
|
-
nextTab = this.getNextTab(index, 1)
|
|
310
|
+
event.stopPropagation()
|
|
311
|
+
event.preventDefault()
|
|
312
|
+
|
|
313
|
+
if (!target) {
|
|
314
|
+
return
|
|
275
315
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
this.fireOnChange(event,
|
|
316
|
+
|
|
317
|
+
if (isActivation || this.props.activationMode !== 'manual') {
|
|
318
|
+
this.fireOnChange(event, target)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
this.focusTab(target.tabDomId)
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
handleTabFocus: TabsTabProps['onFocus'] = (_event, { id }) => {
|
|
325
|
+
if (this.state.focusedTabId !== id) {
|
|
326
|
+
this.setState({ focusedTabId: id })
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
handleTabListBlur = (event: React.FocusEvent) => {
|
|
331
|
+
if (!contains(event.currentTarget, event.relatedTarget)) {
|
|
332
|
+
this.setState({ focusedTabId: undefined })
|
|
279
333
|
}
|
|
280
334
|
}
|
|
281
335
|
|
|
@@ -288,75 +342,129 @@ class Tabs extends Component<TabsProps, TabsState> {
|
|
|
288
342
|
this._tabListPosition = getBoundingClientRect(this._tabList)
|
|
289
343
|
}
|
|
290
344
|
|
|
345
|
+
/**
|
|
346
|
+
* The single source of truth for tab order, ids and state.
|
|
347
|
+
*/
|
|
348
|
+
getTabs(): TabDescriptor[] {
|
|
349
|
+
const panels: { index: number; panel: PanelChild }[] = []
|
|
350
|
+
|
|
351
|
+
Children.toArray(this.props.children).forEach((child, index) => {
|
|
352
|
+
if (matchComponentTypes<PanelChild>(child, [Panel])) {
|
|
353
|
+
panels.push({ index, panel: child as PanelChild })
|
|
354
|
+
}
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
const explicitlySelected = panels.find(
|
|
358
|
+
({ panel }) => panel.props.isSelected && !panel.props.isDisabled
|
|
359
|
+
)
|
|
360
|
+
const fallbackIndex = explicitlySelected ? explicitlySelected.index : 0
|
|
361
|
+
|
|
362
|
+
return panels.map(({ index, panel }) => {
|
|
363
|
+
const baseId =
|
|
364
|
+
panel.props.id || this.props.deterministicId!(`Tabs_${index}`)
|
|
365
|
+
const isDisabled = !!panel.props.isDisabled
|
|
366
|
+
|
|
367
|
+
return {
|
|
368
|
+
index,
|
|
369
|
+
tabDomId: `tab-${baseId}`,
|
|
370
|
+
panelDomId: panel.props.id || `panel-${baseId}`,
|
|
371
|
+
isDisabled,
|
|
372
|
+
isSelected:
|
|
373
|
+
!isDisabled && (!!panel.props.isSelected || index === fallbackIndex),
|
|
374
|
+
panel
|
|
375
|
+
}
|
|
376
|
+
})
|
|
377
|
+
}
|
|
378
|
+
|
|
291
379
|
getNextTab(
|
|
380
|
+
tabs: TabDescriptor[],
|
|
292
381
|
startIndex: number,
|
|
293
382
|
step: -1 | 0 | 1
|
|
294
|
-
):
|
|
295
|
-
const tabs = Children.toArray(this.props.children).map(
|
|
296
|
-
(child) => matchComponentTypes<PanelChild>(child, [Panel]) && child
|
|
297
|
-
) as PanelChild[]
|
|
383
|
+
): TabDescriptor | undefined {
|
|
298
384
|
const count = tabs.length
|
|
299
|
-
const
|
|
385
|
+
const from = tabs.findIndex((tab) => tab.index === startIndex)
|
|
300
386
|
|
|
301
|
-
error(
|
|
302
|
-
startIndex >= 0 && startIndex < count,
|
|
303
|
-
`[Tabs] Invalid tab index: '${startIndex}'.`
|
|
304
|
-
)
|
|
387
|
+
error(from >= 0, `[Tabs] Invalid tab index: '${startIndex}'.`)
|
|
305
388
|
|
|
306
|
-
|
|
307
|
-
|
|
389
|
+
if (from < 0) {
|
|
390
|
+
return undefined
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (step === 0) {
|
|
394
|
+
return tabs[from]
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
for (let offset = 1; offset <= count; offset++) {
|
|
398
|
+
const candidate = tabs[(((from + step * offset) % count) + count) % count]
|
|
399
|
+
|
|
400
|
+
if (!candidate.isDisabled) {
|
|
401
|
+
return candidate
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return undefined
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
getEdgeTab(
|
|
409
|
+
tabs: TabDescriptor[],
|
|
410
|
+
edge: 'first' | 'last'
|
|
411
|
+
): TabDescriptor | undefined {
|
|
412
|
+
const enabled = tabs.filter((tab) => !tab.isDisabled)
|
|
413
|
+
|
|
414
|
+
return edge === 'first' ? enabled[0] : enabled[enabled.length - 1]
|
|
415
|
+
}
|
|
308
416
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
417
|
+
getRovingTabId(tabs: TabDescriptor[]): string | undefined {
|
|
418
|
+
const { focusedTabId } = this.state
|
|
419
|
+
const focused = tabs.find(
|
|
420
|
+
(tab) => tab.tabDomId === focusedTabId && !tab.isDisabled
|
|
421
|
+
)
|
|
313
422
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
423
|
+
return (
|
|
424
|
+
focused?.tabDomId ??
|
|
425
|
+
tabs.find((tab) => tab.isSelected)?.tabDomId ??
|
|
426
|
+
tabs.find((tab) => !tab.isDisabled)?.tabDomId
|
|
317
427
|
)
|
|
318
|
-
return { index: nextIndex, id: nextTab.props.id }
|
|
319
428
|
}
|
|
320
429
|
|
|
321
430
|
fireOnChange(
|
|
322
431
|
event: React.MouseEvent<ViewOwnProps> | React.KeyboardEvent<ViewOwnProps>,
|
|
323
|
-
{ index,
|
|
432
|
+
{ index, panel, tabDomId }: TabDescriptor
|
|
324
433
|
) {
|
|
325
434
|
if (typeof this.props.onRequestTabChange === 'function') {
|
|
326
|
-
this.props.onRequestTabChange(event, { index, id })
|
|
435
|
+
this.props.onRequestTabChange(event, { index, id: panel.props.id })
|
|
327
436
|
}
|
|
328
437
|
|
|
329
|
-
|
|
438
|
+
this.scrollTabIntoView(tabDomId)
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
scrollTabIntoView(tabDomId: string) {
|
|
330
442
|
// one "tick" later than the keypress
|
|
331
443
|
setTimeout(() => {
|
|
332
444
|
if (this.state.withTabListOverflow) {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
this.showActiveTabIfOverlayed(tab)
|
|
445
|
+
this.showActiveTabIfOverlayed(
|
|
446
|
+
this._tabList!.querySelector(`#${CSS.escape(tabDomId)}`)
|
|
447
|
+
)
|
|
337
448
|
}
|
|
338
449
|
}, 0)
|
|
339
450
|
}
|
|
340
451
|
|
|
341
|
-
createTab(
|
|
342
|
-
index
|
|
343
|
-
generatedId: string,
|
|
344
|
-
selected: boolean,
|
|
345
|
-
panel: PanelChild
|
|
346
|
-
): TabChild {
|
|
347
|
-
const id = panel.props.id || generatedId
|
|
452
|
+
createTab(tab: TabDescriptor, isTabbable: boolean): TabChild {
|
|
453
|
+
const { index, tabDomId, panelDomId, isSelected, isDisabled, panel } = tab
|
|
348
454
|
|
|
349
455
|
return (
|
|
350
456
|
<Tab
|
|
351
457
|
variant={this.props.variant}
|
|
352
458
|
key={`tab-${index}`}
|
|
353
|
-
id={
|
|
354
|
-
controls={
|
|
459
|
+
id={tabDomId}
|
|
460
|
+
controls={panelDomId}
|
|
355
461
|
index={index}
|
|
356
|
-
isSelected={
|
|
357
|
-
isDisabled={
|
|
462
|
+
isSelected={isSelected}
|
|
463
|
+
isDisabled={isDisabled}
|
|
464
|
+
isTabbable={isTabbable}
|
|
358
465
|
onClick={this.handleTabClick}
|
|
359
466
|
onKeyDown={this.handleTabKeyDown}
|
|
467
|
+
onFocus={this.handleTabFocus}
|
|
360
468
|
isOverflowScroll={this.props.tabOverflow === 'scroll'}
|
|
361
469
|
>
|
|
362
470
|
{panel.props.renderTitle}
|
|
@@ -364,22 +472,16 @@ class Tabs extends Component<TabsProps, TabsState> {
|
|
|
364
472
|
)
|
|
365
473
|
}
|
|
366
474
|
|
|
367
|
-
clonePanel(
|
|
368
|
-
index
|
|
369
|
-
generatedId: string,
|
|
370
|
-
selected: boolean,
|
|
371
|
-
panel: PanelChild,
|
|
372
|
-
activePanel?: PanelChild
|
|
373
|
-
) {
|
|
374
|
-
const id = panel.props.id || generatedId
|
|
475
|
+
clonePanel(tab: TabDescriptor, activePanel?: PanelChild) {
|
|
476
|
+
const { index, tabDomId, panelDomId, isSelected, panel } = tab
|
|
375
477
|
|
|
376
478
|
// fixHeight can be 0, so simply `fixheight` could return falsy value
|
|
377
479
|
const hasFixedHeight = typeof this.props.fixHeight !== 'undefined'
|
|
378
480
|
|
|
379
481
|
const commonProps = {
|
|
380
|
-
id:
|
|
381
|
-
labelledBy:
|
|
382
|
-
isSelected
|
|
482
|
+
id: panelDomId,
|
|
483
|
+
labelledBy: tabDomId,
|
|
484
|
+
isSelected,
|
|
383
485
|
variant: this.props.variant,
|
|
384
486
|
maxHeight: !hasFixedHeight ? this.props.maxHeight : undefined,
|
|
385
487
|
minHeight: !hasFixedHeight ? this.props.minHeight : '100%'
|
|
@@ -408,18 +510,25 @@ class Tabs extends Component<TabsProps, TabsState> {
|
|
|
408
510
|
}
|
|
409
511
|
}
|
|
410
512
|
|
|
411
|
-
handleFocusableRef = (el: Focusable | null) => {
|
|
412
|
-
this._focusable = el
|
|
413
|
-
}
|
|
414
|
-
|
|
415
513
|
handleTabListRef = (el: Element | null) => {
|
|
416
514
|
this._tabList = el
|
|
417
515
|
}
|
|
418
516
|
|
|
419
517
|
focus() {
|
|
420
|
-
this.
|
|
421
|
-
|
|
422
|
-
|
|
518
|
+
this.focusTab(this.getRovingTabId(this.getTabs()))
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
focusTab(tabDomId?: string) {
|
|
522
|
+
if (!tabDomId) {
|
|
523
|
+
return
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
const tab = this._tabList?.querySelector<HTMLElement>(
|
|
527
|
+
`#${CSS.escape(tabDomId)}`
|
|
528
|
+
)
|
|
529
|
+
|
|
530
|
+
tab?.focus()
|
|
531
|
+
this.scrollTabIntoView(tabDomId)
|
|
423
532
|
}
|
|
424
533
|
|
|
425
534
|
handleScroll = (
|
|
@@ -456,40 +565,37 @@ class Tabs extends Component<TabsProps, TabsState> {
|
|
|
456
565
|
onRequestTabChange,
|
|
457
566
|
tabOverflow,
|
|
458
567
|
styles,
|
|
568
|
+
dir,
|
|
459
569
|
...props
|
|
460
570
|
} = this.props
|
|
461
571
|
|
|
462
|
-
const
|
|
463
|
-
|
|
464
|
-
|
|
572
|
+
const tabDescriptors = this.getTabs()
|
|
573
|
+
const rovingTabId = this.getRovingTabId(tabDescriptors)
|
|
574
|
+
const tabsByIndex = new Map(tabDescriptors.map((tab) => [tab.index, tab]))
|
|
575
|
+
|
|
576
|
+
const activePanels = tabDescriptors
|
|
577
|
+
.map((tab) => tab.panel)
|
|
578
|
+
.filter((panel) => panel.props.active)
|
|
465
579
|
|
|
466
580
|
if (activePanels.length > 1) {
|
|
467
581
|
error(false, `[Tabs] Only one Panel can be marked as active.`)
|
|
468
582
|
}
|
|
469
583
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
.findIndex((child) => child.props.isSelected && !child.props.isDisabled)
|
|
584
|
+
Children.toArray(children).forEach((child, index) => {
|
|
585
|
+
const tab = tabsByIndex.get(index)
|
|
473
586
|
|
|
474
|
-
|
|
475
|
-
Children.toArray(children).map((child, index) => {
|
|
476
|
-
if (matchComponentTypes<PanelChild>(child, [Panel])) {
|
|
477
|
-
const selected =
|
|
478
|
-
!child.props.isDisabled &&
|
|
479
|
-
(child.props.isSelected || selectedIndex === index)
|
|
480
|
-
const id = this.props.deterministicId!(`Tabs_${index}`)
|
|
481
|
-
|
|
482
|
-
tabs.push(this.createTab(index, id, selected, child))
|
|
483
|
-
if (activePanels.length === 1) {
|
|
484
|
-
panels.push(
|
|
485
|
-
this.clonePanel(index, id, selected, child, activePanels[0])
|
|
486
|
-
)
|
|
487
|
-
} else {
|
|
488
|
-
panels.push(this.clonePanel(index, id, selected, child))
|
|
489
|
-
}
|
|
490
|
-
} else {
|
|
587
|
+
if (!tab) {
|
|
491
588
|
panels.push(child as PanelChild)
|
|
589
|
+
return
|
|
492
590
|
}
|
|
591
|
+
|
|
592
|
+
tabs.push(this.createTab(tab, tab.tabDomId === rovingTabId))
|
|
593
|
+
panels.push(
|
|
594
|
+
this.clonePanel(
|
|
595
|
+
tab,
|
|
596
|
+
activePanels.length === 1 ? activePanels[0] : undefined
|
|
597
|
+
)
|
|
598
|
+
)
|
|
493
599
|
})
|
|
494
600
|
|
|
495
601
|
const withScrollFade =
|
|
@@ -514,30 +620,27 @@ class Tabs extends Component<TabsProps, TabsState> {
|
|
|
514
620
|
css={styles?.container}
|
|
515
621
|
data-cid="Tabs"
|
|
516
622
|
>
|
|
517
|
-
<
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
</View>
|
|
539
|
-
)}
|
|
540
|
-
</Focusable>
|
|
623
|
+
<View
|
|
624
|
+
as="div"
|
|
625
|
+
position="relative"
|
|
626
|
+
borderRadius="medium"
|
|
627
|
+
shouldAnimateFocus={false}
|
|
628
|
+
css={styles?.tabs}
|
|
629
|
+
>
|
|
630
|
+
<View
|
|
631
|
+
as="div"
|
|
632
|
+
role="tablist"
|
|
633
|
+
css={styles?.tabList}
|
|
634
|
+
aria-label={screenReaderLabel}
|
|
635
|
+
elementRef={this.handleTabListRef}
|
|
636
|
+
onScroll={this.handleScroll}
|
|
637
|
+
onBlur={this.handleTabListBlur}
|
|
638
|
+
>
|
|
639
|
+
{tabs}
|
|
640
|
+
{withScrollFade && startScrollOverlay}
|
|
641
|
+
{withScrollFade && endScrollOverlay}
|
|
642
|
+
</View>
|
|
643
|
+
</View>
|
|
541
644
|
|
|
542
645
|
<div css={styles?.panelsContainer}>{panels}</div>
|
|
543
646
|
</View>
|
package/src/Tabs/v2/props.ts
CHANGED
|
@@ -79,6 +79,13 @@ type TabsOwnProps = {
|
|
|
79
79
|
*/
|
|
80
80
|
tabOverflow?: 'stack' | 'scroll'
|
|
81
81
|
shouldFocusOnRender?: boolean
|
|
82
|
+
/**
|
|
83
|
+
* With `auto`, arrow keys select a tab as soon as focus reaches it. With
|
|
84
|
+
* `manual`, arrow keys only move focus and Enter or Space selects the focused
|
|
85
|
+
* tab. Screen readers that reserve the arrow keys for their own cursor
|
|
86
|
+
* (VoiceOver) need `manual`.
|
|
87
|
+
*/
|
|
88
|
+
activationMode?: 'auto' | 'manual'
|
|
82
89
|
}
|
|
83
90
|
|
|
84
91
|
type PropKeys = keyof TabsOwnProps
|
|
@@ -107,6 +114,7 @@ type TabsState = {
|
|
|
107
114
|
withTabListOverflow: boolean
|
|
108
115
|
showStartOverLay: boolean
|
|
109
116
|
showEndOverLay: boolean
|
|
117
|
+
focusedTabId?: string
|
|
110
118
|
}
|
|
111
119
|
const allowedProps: AllowedPropKeys = [
|
|
112
120
|
'children',
|
|
@@ -122,7 +130,8 @@ const allowedProps: AllowedPropKeys = [
|
|
|
122
130
|
'textAlign',
|
|
123
131
|
'elementRef',
|
|
124
132
|
'tabOverflow',
|
|
125
|
-
'shouldFocusOnRender'
|
|
133
|
+
'shouldFocusOnRender',
|
|
134
|
+
'activationMode'
|
|
126
135
|
]
|
|
127
136
|
|
|
128
137
|
export type { TabsProps, TabsState, TabsStyle }
|