@@ -5,9 +5,10 @@ import {
55} from '@gouvfr-lasuite/ui-kit' ;
66import { useRouter } from 'next/navigation' ;
77import { useState } from 'react' ;
8+ import { useTranslation } from 'react-i18next' ;
89import { css } from 'styled-components' ;
910
10- import { Box , Icon , Text } from '@/components' ;
11+ import { Box , BoxButton , Icon , Text } from '@/components' ;
1112import { useCunninghamTheme } from '@/cunningham' ;
1213import {
1314 Doc ,
@@ -20,6 +21,7 @@ import { useResponsiveStore } from '@/stores';
2021
2122import SubPageIcon from './../assets/sub-page-logo.svg' ;
2223import { DocTreeItemActions } from './DocTreeItemActions' ;
24+ import { useKeyboardActivation } from '../hooks/useKeyboardActivation' ;
2325
2426const ItemTextCss = css `
2527 overflow : hidden;
@@ -38,14 +40,23 @@ export const DocSubPageItem = (props: TreeViewNodeProps<Doc>) => {
3840 const { node } = props ;
3941 const { spacingsTokens } = useCunninghamTheme ( ) ;
4042 const { isDesktop } = useResponsiveStore ( ) ;
41- const [ actionsOpen , setActionsOpen ] = useState ( false ) ;
43+ const { t } = useTranslation ( ) ;
44+
45+ const [ menuOpen , setMenuOpen ] = useState ( false ) ;
46+ const isSelectedNow = treeContext ?. treeData . selectedNode ?. id === doc . id ;
47+ const isActive = node . isFocused || menuOpen || isSelectedNow ;
4248
4349 const router = useRouter ( ) ;
4450 const { togglePanel } = useLeftPanelStore ( ) ;
4551
4652 const { emoji, titleWithoutEmoji } = getEmojiAndTitle ( doc . title || '' ) ;
4753 const displayTitle = titleWithoutEmoji || untitledDocument ;
4854
55+ const handleActivate = ( ) => {
56+ treeContext ?. treeData . setSelectedNode ( doc ) ;
57+ router . push ( `/docs/${ doc . id } ` ) ;
58+ } ;
59+
4960 const afterCreate = ( createdDoc : Doc ) => {
5061 const actualChildren = node . data . children ?? [ ] ;
5162
@@ -76,62 +87,75 @@ export const DocSubPageItem = (props: TreeViewNodeProps<Doc>) => {
7687 }
7788 } ;
7889
90+ useKeyboardActivation (
91+ [ 'Enter' ] ,
92+ isActive && ! menuOpen ,
93+ handleActivate ,
94+ true ,
95+ '.c__tree-view' ,
96+ ) ;
97+
98+ const docTitle = doc . title || untitledDocument ;
99+ const hasChildren = ( doc . children ?. length || 0 ) > 0 ;
100+ const isExpanded = node . isOpen ;
101+ const isSelected = isSelectedNow ;
102+ const ariaLabel = docTitle ;
103+
79104 return (
80105 < Box
81106 className = "--docs-sub-page-item"
82107 draggable = { doc . abilities . move && isDesktop }
83108 $position = "relative"
109+ role = "treeitem"
110+ aria-label = { ariaLabel }
111+ aria-selected = { isSelected }
112+ aria-expanded = { hasChildren ? isExpanded : undefined }
84113 $css = { css `
85- background-color : ${ actionsOpen
114+ background-color : ${ menuOpen
86115 ? 'var(--c--theme--colors--greyscale-100)'
87116 : 'var(--c--theme--colors--greyscale-000)' } ;
88-
89117 .light-doc-item-actions {
90- display : ${ actionsOpen || ! isDesktop ? 'flex' : 'none' } ;
118+ display : ${ menuOpen || ! isDesktop ? 'flex' : 'none' } ;
91119 position : absolute;
92120 right : 0 ;
93121 background : ${ isDesktop
94122 ? 'var(--c--theme--colors--greyscale-100)'
95123 : 'var(--c--theme--colors--greyscale-000)' } ;
96124 }
97-
98125 .c__tree-view--node .isSelected {
99126 .light-doc-item-actions {
100127 background : var (--c--theme--colors--greyscale-100 );
101128 }
102129 }
103-
104130 & : hover {
105131 background-color : var (--c--theme--colors--greyscale-100 );
106132 border-radius : 4px ;
107-
108133 .light-doc-item-actions {
109134 display : flex;
110135 background : var (--c--theme--colors--greyscale-100 );
111136 }
112137 }
113-
114138 .row .preview & {
115139 background-color : inherit;
116140 }
117141 ` }
118142 >
119- < TreeViewItem
120- { ...props }
121- onClick = { ( ) => {
122- treeContext ?. treeData . setSelectedNode ( props . node . data . value as Doc ) ;
123- router . push ( `/docs/${ props . node . data . value . id } ` ) ;
124- } }
125- >
126- < Box
127- data-testid = { `doc-sub-page-item-${ props . node . data . value . id } ` }
143+ < TreeViewItem { ...props } onClick = { handleActivate } >
144+ < BoxButton
145+ onClick = { ( e ) => {
146+ e . stopPropagation ( ) ;
147+ handleActivate ( ) ;
148+ } }
128149 $width = "100%"
129150 $direction = "row"
130151 $gap = { spacingsTokens [ 'xs' ] }
131- role = "button"
132- tabIndex = { 0 }
133152 $align = "center"
134153 $minHeight = "24px"
154+ data-testid = { `doc-sub-page-item-${ doc . id } ` }
155+ aria-label = { `${ t ( 'Open document {{title}}' , { title : docTitle } ) } ` }
156+ $css = { css `
157+ text-align : left;
158+ ` }
135159 >
136160 < Box $width = "16px" $height = "16px" >
137161 < DocIcon emoji = { emoji } defaultIcon = { < SubPageIcon /> } $size = "sm" />
@@ -157,23 +181,25 @@ export const DocSubPageItem = (props: TreeViewNodeProps<Doc>) => {
157181 iconName = "group"
158182 $size = "16px"
159183 $variation = "400"
184+ aria-hidden = "true"
160185 />
161186 ) }
162187 </ Box >
163-
164- < Box
165- $direction = "row"
166- $align = "center"
167- className = "light-doc-item-actions"
168- >
169- < DocTreeItemActions
170- doc = { doc }
171- isOpen = { actionsOpen }
172- onOpenChange = { setActionsOpen }
173- parentId = { node . data . parentKey }
174- onCreateSuccess = { afterCreate }
175- />
176- </ Box >
188+ </ BoxButton >
189+ < Box
190+ $direction = "row"
191+ $align = "center"
192+ className = "light-doc-item-actions"
193+ role = "toolbar"
194+ aria-label = { `${ t ( 'Actions for {{title}}' , { title : docTitle } ) } ` }
195+ >
196+ < DocTreeItemActions
197+ doc = { doc }
198+ isOpen = { menuOpen }
199+ onOpenChange = { setMenuOpen }
200+ parentId = { node . data . parentKey }
201+ onCreateSuccess = { afterCreate }
202+ />
177203 </ Box >
178204 </ TreeViewItem >
179205 </ Box >
0 commit comments