5
5
6
6
import React , { useEffect , useState , useRef } from 'react' ;
7
7
import PropTypes from 'prop-types' ;
8
+ import cx from 'classnames' ;
8
9
import { FormattedMessage , injectIntl } from 'react-intl' ;
9
10
import AnchorLink from 'react-anchor-link-smooth-scroll' ;
10
11
import { Accordion , Icon } from 'semantic-ui-react' ;
11
12
import Slugger from 'github-slugger' ;
13
+
14
+ import { MaybeWrap } from '@plone/volto/components' ;
12
15
import { normalizeString } from './helpers' ;
13
16
import './less/accordion-menu.less' ;
14
17
15
- const RenderAccordionItems = ( { items } ) => {
16
- const [ activeItems , setActiveItems ] = useState ( { } ) ;
17
-
18
- const handleClick = ( index , hasSubItems ) => {
19
- if ( hasSubItems ) {
20
- setActiveItems ( ( prevActiveItems ) => ( {
21
- ...prevActiveItems ,
22
- [ index ] : ! prevActiveItems [ index ] ,
23
- } ) ) ;
24
- }
25
- } ;
26
-
27
- return (
28
- < Accordion fluid styled >
29
- { items . map ( ( item , index ) => {
30
- const { title, override_toc, plaintext, items : subItems } = item ;
31
- const slug = override_toc
32
- ? Slugger . slug ( normalizeString ( plaintext ) )
33
- : Slugger . slug ( normalizeString ( title ) ) ;
34
-
35
- const isActive = ! ! activeItems [ index ] ;
36
- const hasSubItems = subItems && subItems . length > 0 ;
37
-
38
- return (
39
- < React . Fragment key = { index } >
40
- < Accordion . Title
41
- active = { isActive }
42
- onClick = { ( ) => handleClick ( index , hasSubItems ) }
43
- >
44
- { subItems && subItems . length > 0 && (
45
- < Icon name = { isActive ? 'angle up' : 'angle right' } />
46
- ) }
47
- < AnchorLink href = { `#${ slug } ` } > { title } </ AnchorLink >
48
- </ Accordion . Title >
49
- < Accordion . Content active = { isActive } >
50
- { subItems && subItems . length > 0 && (
51
- < RenderAccordionItems items = { subItems } />
52
- ) }
53
- </ Accordion . Content >
54
- </ React . Fragment >
55
- ) ;
56
- } ) }
57
- </ Accordion >
58
- ) ;
59
- } ;
60
-
61
18
/**
62
19
* View toc block class.
63
20
* @class View
64
21
* @extends Component
65
22
*/
66
23
const View = ( { data, tocEntries } ) => {
24
+ const { bulleted_list = false } = data ;
67
25
const tocRef = useRef ( ) ; // Ref for the ToC component
68
26
const spacerRef = useRef ( ) ; // Ref for the spacer div
27
+ const [ activeItems , setActiveItems ] = useState ( { } ) ;
69
28
//get relative offsetTop of an element
70
29
function getOffsetTop ( elem ) {
71
30
let offsetTop = 0 ;
@@ -130,6 +89,58 @@ const View = ({ data, tocEntries }) => {
130
89
}
131
90
} , [ data . sticky ] ) ;
132
91
92
+ const RenderAccordionItems = ( { item } ) => {
93
+ const handleClick = ( id , hasSubItems ) => {
94
+ if ( hasSubItems ) {
95
+ setActiveItems ( ( prevActiveItems ) => ( {
96
+ ...prevActiveItems ,
97
+ [ id ] : ! prevActiveItems [ id ] ,
98
+ } ) ) ;
99
+ }
100
+ } ;
101
+
102
+ const { title, override_toc, plaintext, items : subItems , id, level } = item ;
103
+ const slug = override_toc
104
+ ? Slugger . slug ( normalizeString ( plaintext ) )
105
+ : Slugger . slug ( normalizeString ( title ) ) ;
106
+
107
+ const isActive = ! ! activeItems [ id ] ;
108
+ const hasSubItems = subItems && subItems . length > 0 ;
109
+
110
+ return (
111
+ < MaybeWrap
112
+ className = { cx ( `list-item level-${ level } ` , {
113
+ 'accordion-item' : level > 2 && hasSubItems ,
114
+ } ) }
115
+ condition = { level > 2 }
116
+ as = { ( props ) => < li key = { id } { ...props } /> }
117
+ >
118
+ < Accordion fluid styled >
119
+ < Accordion . Title
120
+ active = { isActive }
121
+ onClick = { ( ) => handleClick ( id , hasSubItems ) }
122
+ >
123
+ { subItems && subItems . length > 0 && (
124
+ < Icon name = { isActive ? 'angle up' : 'angle right' } />
125
+ ) }
126
+ < AnchorLink href = { `#${ slug } ` } > { title } </ AnchorLink >
127
+ </ Accordion . Title >
128
+ { hasSubItems && (
129
+ < Accordion . Content active = { isActive } >
130
+ < ul
131
+ className = { cx ( 'accordion-list' , {
132
+ 'accordion-list-bulleted' : bulleted_list ,
133
+ } ) }
134
+ >
135
+ { subItems . map ( ( child ) => RenderAccordionItems ( { item : child } ) ) }
136
+ </ ul >
137
+ </ Accordion . Content >
138
+ ) }
139
+ </ Accordion >
140
+ </ MaybeWrap >
141
+ ) ;
142
+ } ;
143
+
133
144
return (
134
145
< >
135
146
{ data . title && ! data . hide_title && (
@@ -144,7 +155,7 @@ const View = ({ data, tocEntries }) => {
144
155
) }
145
156
< div ref = { spacerRef } /> { /* Spacer div */ }
146
157
< div ref = { tocRef } className = "accordionMenu" >
147
- < RenderAccordionItems items = { tocEntries } data = { data } />
158
+ { tocEntries . map ( ( item ) => RenderAccordionItems ( { item } ) ) }
148
159
</ div >
149
160
</ >
150
161
) ;
0 commit comments