1- import type { ReactTableHooks , TableInstance } from '@/components/AnalyticalTable/types/index.js' ;
21import dataLarge from '@sb/mockData/Friends500.json' ;
32import dataTree from '@sb/mockData/FriendsTree.json' ;
43import type { Meta , StoryObj } from '@storybook/react-vite' ;
54import '@ui5/webcomponents-icons/dist/delete.js' ;
65import '@ui5/webcomponents-icons/dist/edit.js' ;
76import '@ui5/webcomponents-icons/dist/settings.js' ;
87import NoDataIllustration from '@ui5/webcomponents-fiori/dist/illustrations/NoData.js' ;
9- import {
10- FocusEventHandler ,
11- KeyboardEventHandler ,
12- useCallback ,
13- useEffect ,
14- useMemo ,
15- useReducer ,
16- useRef ,
17- useState ,
18- } from 'react' ;
8+ import { useCallback , useEffect , useMemo , useReducer , useRef , useState } from 'react' ;
199import {
2010 AnalyticalTablePopinDisplay ,
2111 AnalyticalTableScaleWidthMode ,
@@ -39,7 +29,6 @@ import { SegmentedButtonItem } from '../../webComponents/SegmentedButtonItem/ind
3929import { Select } from '../../webComponents/Select/index.js' ;
4030import { Tag } from '../../webComponents/Tag/index.js' ;
4131import { Text } from '../../webComponents/Text/index.js' ;
42- import { Input } from '../../webComponents/input/index.js' ;
4332import { FlexBox } from '../FlexBox/index.js' ;
4433import type { AnalyticalTableColumnDefinition } from './index.js' ;
4534import { AnalyticalTable } from './index.js' ;
@@ -636,162 +625,3 @@ export const KitchenSink: Story = {
636625 return context . viewMode === 'story' ? < AnalyticalTable { ...args } /> : < ToggleableTable { ...args } /> ;
637626 } ,
638627} ;
639-
640- const inputCols = [
641- {
642- Header : 'Input' ,
643- id : 'input' ,
644- Cell : ( props ) => {
645- return (
646- < Input
647- onFocus = { console . log }
648- tabIndex = { props . state . cellTabIndex }
649- inert = { Object . hasOwn ( props . state , 'tabIndex' ) ? props . state . cellTabIndex < 0 : true }
650- />
651- ) ;
652- } ,
653- interactiveElementName : 'Input' ,
654- } ,
655- {
656- Header : 'Button' ,
657- id : 'btn' ,
658- Cell : ( props ) => (
659- < Button tabIndex = { props . state . cellTabIndex } inert = { props . state . cellTabIndex < 0 } >
660- Button
661- </ Button >
662- ) ,
663- interactiveElementName : ( ) => 'Button' ,
664- } ,
665- ] ;
666-
667- const useGetTableProps = ( props , { instance } ) => {
668- const handleFocus : FocusEventHandler < HTMLDivElement > = ( e ) => {
669- const isCell = e . target . hasAttribute ( 'gridcell' ) || e . target . hasAttribute ( 'columnheader' ) ;
670- if ( isCell ) {
671- }
672- if ( typeof props . onFocus === 'function' ) {
673- props . onFocus ( e ) ;
674- }
675- } ;
676-
677- const handleKeyDown : KeyboardEventHandler < HTMLDivElement > = ( e ) => { } ;
678-
679- return [ props , { onFocus : handleFocus , onKeyDown : handleKeyDown } ] ;
680- } ;
681-
682- function findFirstFocusableInside ( element ) {
683- if ( ! element ) return null ;
684-
685- function recursiveFindInteractiveElement ( el ) {
686- for ( const child of el . children ) {
687- const style = getComputedStyle ( child ) ;
688- if ( child . disabled || style . display === 'none' || style . visibility === 'hidden' ) {
689- continue ; // skip non-interactive
690- }
691-
692- const focusableSelectors = [
693- 'a[href]' ,
694- 'button' ,
695- 'input' ,
696- 'textarea' ,
697- 'select' ,
698- '[tabindex]:not([tabindex="-1"])' ,
699- ] ;
700-
701- if ( child . matches ( focusableSelectors . join ( ',' ) ) ) {
702- return child ;
703- }
704-
705- if ( child . shadowRoot ) {
706- const shadowFocusable = recursiveFindInteractiveElement ( child . shadowRoot ) ;
707- if ( shadowFocusable ) return shadowFocusable ;
708- }
709-
710- const nestedFocusable = recursiveFindInteractiveElement ( child ) ;
711- if ( nestedFocusable ) return nestedFocusable ;
712- }
713- return null ;
714- }
715-
716- return recursiveFindInteractiveElement ( element ) ;
717- }
718-
719- const useCellTabIndex = ( cols , { instance : { state } } ) => {
720- console . log ( state . cellTabIndex ) ;
721- return cols . map ( ( col ) => {
722- const origCell = col . Cell ;
723-
724- // only wrap function renderers, non-function renderers don't receive props anyway.
725- if ( typeof origCell !== 'function' ) return col ;
726-
727- return {
728- ...col ,
729- Cell : ( props : any ) => {
730- return origCell ( { ...props , tabIndex : state . cellTabIndex ?? - 1 } ) ;
731- } ,
732- } ;
733- } ) ;
734- } ;
735-
736- const useGetCellProps = ( props , { cell, instance, userProps } ) => {
737- const { interactiveElementName, Cell } = cell . column ;
738-
739- const handleKeyDown : KeyboardEventHandler < HTMLDivElement > = ( e ) => {
740- if ( e . key === 'F2' ) {
741- if ( e . currentTarget === e . target && interactiveElementName ) {
742- let name : string ;
743- const interactiveElement = findFirstFocusableInside ( e . target ) ;
744- if ( interactiveElement ) {
745- e . currentTarget . tabIndex = - 1 ;
746- interactiveElement . focus ( ) ;
747- instance . dispatch ( { type : 'CELL_TAB_INDEX' , payload : 0 } ) ;
748- if ( typeof interactiveElementName === 'function' ) {
749- name = interactiveElementName ( cell ) ;
750- } else {
751- name = interactiveElementName ;
752- }
753- }
754- }
755- if ( e . currentTarget !== e . target ) {
756- e . currentTarget . tabIndex = 0 ;
757- e . currentTarget . focus ( ) ;
758- instance . dispatch ( { type : 'CELL_TAB_INDEX' , payload : - 1 } ) ;
759- }
760- }
761- } ;
762-
763- return [ props , { onKeyDown : handleKeyDown } ] ;
764- } ;
765-
766- const stateReducer = ( state , action , _prevState , instance : TableInstance ) => {
767- const { payload, type } = action ;
768-
769- if ( type === 'CELL_TAB_INDEX' ) {
770- return { ...state , cellTabIndex : payload } ;
771- }
772- return state ;
773- } ;
774-
775- const useF2Navigation = ( hooks : ReactTableHooks ) => {
776- // const prevFocusedCell = useRef<HTMLDivElement>(null);
777- //todo: param names claim functions are hooks, but they aren't
778- hooks . visibleColumns . push ( useCellTabIndex ) ;
779- hooks . getCellProps . push ( useGetCellProps ) ;
780- hooks . stateReducers . push ( stateReducer ) ;
781- // hooks.getTableProps.push(useGetTableProps);
782- // hooks.getHeaderProps.push(setHeaderProps);
783- } ;
784-
785- const tableHooks = [ useF2Navigation ] ;
786-
787- export const Test : Story = {
788- render ( args ) {
789- return (
790- < >
791- < button > Click</ button >
792- < AnalyticalTable { ...args } columns = { [ inputCols [ 0 ] , ...args . columns , inputCols [ 1 ] ] } tableHooks = { tableHooks } />
793- < button > Click</ button >
794- </ >
795- ) ;
796- } ,
797- } ;
0 commit comments