@@ -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,66 @@ export const DocSubPageItem = (props: TreeViewNodeProps<Doc>) => {
7687 }
7788 } ;
7889
90+ useKeyboardActivation (
91+ [ 'Enter' , ' ' ] ,
92+ isActive && ! menuOpen ,
93+ handleActivate ,
94+ true ,
95+ ) ;
96+
97+ const docTitle = doc . title || untitledDocument ;
98+ const hasChildren = ( doc . children ?. length || 0 ) > 0 ;
99+ const isExpanded = node . isOpen ;
100+ const isSelected = isSelectedNow ;
101+ const ariaLabel = docTitle ;
102+
79103 return (
80104 < Box
81105 className = "--docs-sub-page-item"
82106 draggable = { doc . abilities . move && isDesktop }
83107 $position = "relative"
108+ role = "treeitem"
109+ aria-label = { ariaLabel }
110+ aria-selected = { isSelected }
111+ aria-expanded = { hasChildren ? isExpanded : undefined }
84112 $css = { css `
85- background-color : ${ actionsOpen
86- ? 'var(--c--theme--colors--greyscale-100)'
87- : 'var(--c--theme--colors--greyscale-000)' } ;
88-
89- .light-doc-item-actions {
90- display : ${ actionsOpen || ! isDesktop ? 'flex' : 'none' } ;
91- position : absolute;
92- right : 0 ;
93- background : ${ isDesktop
94- ? 'var(--c--theme--colors--greyscale-100)'
95- : 'var(--c--theme--colors--greyscale-000)' } ;
96- }
97-
98- .c__tree-view--node .isSelected {
99- .light-doc-item-actions {
100- background : var (--c--theme--colors--greyscale-100 );
101- }
113+ .c__tree-view--node {
114+ padding : ${ spacingsTokens [ '3xs' ] } ;
115+ border-radius : 4px ;
102116 }
103117
104- & : hover {
118+ . c__tree-view--node : hover {
105119 background-color : var (--c--theme--colors--greyscale-100 );
106- border-radius : 4 px ;
120+ }
107121
108- .light-doc-item-actions {
109- display : flex;
110- background : var (--c--theme--colors--greyscale-100 );
111- }
122+ .light-doc-item-actions {
123+ display : flex;
124+ opacity : ${ isActive || ! isDesktop ? 1 : 0 } ;
125+ position : absolute;
126+ right : 0 ;
127+ top : 0 ;
128+ height : 100% ;
129+ z-index : 10 ;
112130 }
113131
114132 .row .preview & {
115133 background-color : inherit;
116134 }
117135 ` }
118136 >
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 } ` }
137+ < TreeViewItem { ...props } onClick = { handleActivate } >
138+ < BoxButton
139+ onClick = { ( e ) => {
140+ e . stopPropagation ( ) ;
141+ handleActivate ( ) ;
142+ } }
128143 $width = "100%"
129144 $direction = "row"
130145 $gap = { spacingsTokens [ 'xs' ] }
131- role = "button"
132- tabIndex = { 0 }
133146 $align = "center"
134147 $minHeight = "24px"
148+ data-testid = { `doc-sub-page-item-${ doc . id } ` }
149+ aria-label = { `${ t ( 'Open document' ) } ${ docTitle } ` }
135150 >
136151 < Box $width = "16px" $height = "16px" >
137152 < DocIcon emoji = { emoji } defaultIcon = { < SubPageIcon /> } $size = "sm" />
@@ -157,25 +172,28 @@ export const DocSubPageItem = (props: TreeViewNodeProps<Doc>) => {
157172 iconName = "group"
158173 $size = "16px"
159174 $variation = "400"
175+ aria-hidden = "true"
160176 />
161177 ) }
162178 </ 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 >
177- </ Box >
179+ </ BoxButton >
178180 </ TreeViewItem >
181+
182+ < Box
183+ $direction = "row"
184+ $align = "center"
185+ className = "light-doc-item-actions"
186+ role = "toolbar"
187+ aria-label = { `${ t ( 'Actions for' ) } ${ docTitle } ` }
188+ >
189+ < DocTreeItemActions
190+ doc = { doc }
191+ isOpen = { menuOpen }
192+ onOpenChange = { setMenuOpen }
193+ parentId = { node . data . parentKey }
194+ onCreateSuccess = { afterCreate }
195+ />
196+ </ Box >
179197 </ Box >
180198 ) ;
181199} ;
0 commit comments