11import { ListItem } from './list-item.types' ;
22import { ListSeparator } from '../../global/shared-types/separator.types' ;
3- import { MenuItem } from '../menu/menu.types' ;
43import { h } from '@stencil/core' ;
5- import { CheckboxTemplate } from '../checkbox/checkbox.template' ;
64import { ListRendererConfig } from './list-renderer-config' ;
7- import { RadioButtonTemplate } from '../radio-button-group/radio-button.template' ;
8- import {
9- getIconColor ,
10- getIconName ,
11- getIconTitle ,
12- } from '../icon/get-icon-props' ;
13- import { isEmpty } from 'lodash-es' ;
145
156export class ListRenderer {
167 private defaultConfig : ListRendererConfig = {
@@ -20,11 +11,6 @@ export class ListRenderer {
2011
2112 private config : ListRendererConfig ;
2213
23- private hasIcons : boolean ;
24- private twoLines : boolean ;
25- private avatarList : boolean ;
26- private commandKey : boolean ;
27-
2814 private applyTabIndexToItemAtIndex : number ;
2915
3016 public render (
@@ -34,17 +20,6 @@ export class ListRenderer {
3420 items = items || [ ] ;
3521 this . config = { ...this . defaultConfig , ...config } ;
3622
37- this . twoLines = items . some ( ( item ) => {
38- return 'secondaryText' in item && ! ! item . secondaryText ;
39- } ) ;
40-
41- this . hasIcons = items . some ( ( item ) => {
42- return 'icon' in item && ! ! item . icon ;
43- } ) ;
44-
45- this . avatarList = this . config . badgeIcons && this . hasIcons ;
46- const selectableListTypes = [ 'selectable' , 'radio' , 'checkbox' ] ;
47-
4823 let role ;
4924 switch ( this . config . type ) {
5025 case 'checkbox' : {
@@ -63,19 +38,12 @@ export class ListRenderer {
6338 this . applyTabIndexToItemAtIndex =
6439 this . getIndexForWhichToApplyTabIndex ( items ) ;
6540
66- const classNames = {
67- 'mdc-deprecated-list' : true ,
68- 'mdc-deprecated-list--two-line' : this . twoLines ,
69- selectable : selectableListTypes . includes ( this . config . type ) ,
70- 'mdc-deprecated-list--avatar-list' : this . avatarList ,
71- 'list--compact' :
72- this . twoLines &&
73- this . commandKey &&
74- [ 'small' , 'x-small' ] . includes ( this . config . iconSize ) ,
75- } ;
76-
7741 return (
78- < ul class = { classNames } role = { role } aria-orientation = "vertical" >
42+ < ul
43+ class = "mdc-deprecated-list"
44+ role = { role }
45+ aria-orientation = "vertical"
46+ >
7947 { items . map ( this . renderListItem ) }
8048 </ ul >
8149 ) ;
@@ -140,37 +108,37 @@ export class ListRenderer {
140108 ) ;
141109 }
142110
143- if ( [ 'radio' , 'checkbox' ] . includes ( this . config . type ) ) {
144- return this . renderVariantListItem ( this . config , item , index ) ;
145- }
146-
147- const classNames = {
148- 'mdc-deprecated-list-item' : true ,
149- 'mdc-deprecated-list-item--disabled' : item . disabled ,
150- 'mdc-deprecated-list-item--selected' : item . selected ,
151- 'has-primary-component' : this . hasPrimaryComponent ( item ) ,
152- } ;
153-
154111 const attributes : { tabindex ?: string } = { } ;
155112 if ( index === this . applyTabIndexToItemAtIndex ) {
156113 attributes . tabindex = '0' ;
157114 }
158115
116+ let itemType : 'radio' | 'checkbox' | 'option' | 'listitem' ;
117+ if ( this . config . type === 'radio' || this . config . type === 'checkbox' ) {
118+ itemType = this . config . type ;
119+ } else if ( this . config . type === 'selectable' ) {
120+ itemType = 'option' ;
121+ } else {
122+ itemType = 'listitem' ;
123+ }
124+
159125 return (
160- < li
161- class = { classNames }
162- aria-disabled = { item . disabled ? 'true' : 'false' }
163- aria-selected = { item . selected ? 'true' : 'false' }
164- data-index = { index }
126+ < limel-list-item
127+ class = "mdc-deprecated-list-item" // required for keyboard navigation with arrow keys
165128 { ...attributes }
166- >
167- { this . renderIcon ( this . config , item ) }
168- { this . renderPicture ( item ) }
169- { this . getPrimaryComponent ( item ) }
170- { this . renderText ( item ) }
171- { this . twoLines && this . avatarList ? this . renderDivider ( ) : null }
172- { this . renderActionMenu ( item . actions ) }
173- </ li >
129+ data-index = { index }
130+ type = { itemType }
131+ text = { item . text }
132+ secondaryText = { item . secondaryText }
133+ icon = { item . icon }
134+ image = { item . image }
135+ primaryComponent = { item . primaryComponent }
136+ badgeIcon = { this . config . badgeIcons }
137+ iconSize = { this . config . iconSize }
138+ selected = { item . selected }
139+ disabled = { item . disabled }
140+ actions = { item . actions }
141+ />
174142 ) ;
175143 } ;
176144
@@ -179,202 +147,4 @@ export class ListRenderer {
179147 return < h2 class = "limel-list-divider-title" > { item . text } </ h2 > ;
180148 }
181149 } ;
182-
183- private getPrimaryComponent ( item : ListItem ) : Element {
184- if ( ! this . hasPrimaryComponent ( item ) ) {
185- return ;
186- }
187-
188- const PrimaryComponent = item . primaryComponent . name ;
189- const props = item . primaryComponent . props ;
190-
191- return < PrimaryComponent { ...props } /> ;
192- }
193-
194- private hasPrimaryComponent = ( item : ListItem ) => {
195- return ! ! item ?. primaryComponent ?. name ;
196- } ;
197-
198- /**
199- * Render the text of the list item
200- *
201- * @param item - the list item
202- * @returns the text for the list item
203- */
204- private renderText = ( item : ListItem ) => {
205- if ( this . isSimpleItem ( item ) ) {
206- return (
207- < span class = "mdc-deprecated-list-item__text" > { item . text } </ span >
208- ) ;
209- }
210-
211- return (
212- < div class = "mdc-deprecated-list-item__text" >
213- < div class = "mdc-deprecated-list-item__primary-command-text" >
214- < div class = "mdc-deprecated-list-item__primary-text" >
215- { item . text }
216- </ div >
217- </ div >
218- < div class = "mdc-deprecated-list-item__secondary-text" >
219- { item . secondaryText }
220- </ div >
221- </ div >
222- ) ;
223- } ;
224-
225- private isSimpleItem = ( item : ListItem ) : boolean => {
226- return ! ( 'secondaryText' in item ) ;
227- } ;
228-
229- /**
230- * Render an icon for a list item
231- *
232- * @param config - the config object, passed on from the `renderListItem` function
233- * @param item - the list item
234- * @returns the icon element
235- */
236- private renderIcon = ( config : ListRendererConfig , item : ListItem ) => {
237- const style : any = { } ;
238- const name = getIconName ( item . icon ) ;
239- if ( ! name ) {
240- return ;
241- }
242-
243- const color = getIconColor ( item . icon , item . iconColor ) ;
244- const title = getIconTitle ( item . icon ) ;
245-
246- if ( color ) {
247- if ( config . badgeIcons ) {
248- style [ '--icon-background-color' ] = color ;
249- } else {
250- style . color = color ;
251- }
252- }
253-
254- return (
255- < limel-icon
256- badge = { config . badgeIcons }
257- class = "mdc-deprecated-list-item__graphic"
258- name = { name }
259- style = { style }
260- size = { config . iconSize }
261- aria-label = { title }
262- aria-hidden = { title ? null : 'true' }
263- />
264- ) ;
265- } ;
266-
267- private renderPicture ( item : ListItem ) {
268- const image = item . image ;
269- if ( isEmpty ( image ) ) {
270- return ;
271- }
272-
273- return < img src = { image . src } alt = { image . alt } loading = "lazy" /> ;
274- }
275-
276- private renderDivider = ( ) => {
277- const classes = {
278- 'mdc-deprecated-list-divider' : true ,
279- 'mdc-deprecated-list-divider--inset' : true ,
280- } ;
281- if ( this . config . iconSize ) {
282- classes [ this . config . iconSize ] = true ;
283- }
284-
285- return < hr class = { classes } /> ;
286- } ;
287-
288- private renderActionMenu = ( actions : Array < MenuItem | ListSeparator > ) => {
289- if ( ! actions || actions . length === 0 ) {
290- return ;
291- }
292-
293- return (
294- < limel-menu
295- class = "mdc-deprecated-list-item__meta"
296- items = { actions }
297- openDirection = "left-start"
298- >
299- < limel-icon-button
300- class = "action-menu-trigger"
301- slot = "trigger"
302- icon = "menu_2"
303- />
304- </ limel-menu >
305- ) ;
306- } ;
307-
308- private renderVariantListItem = (
309- config : ListRendererConfig ,
310- item : ListItem ,
311- index : number
312- ) => {
313- let itemTemplate ;
314- if ( config . type === 'radio' ) {
315- itemTemplate = (
316- < RadioButtonTemplate
317- id = { `c_${ index } ` }
318- checked = { item . selected }
319- disabled = { item . disabled }
320- />
321- ) ;
322- } else if ( config . type === 'checkbox' ) {
323- itemTemplate = (
324- < CheckboxTemplate
325- id = { `c_${ index } ` }
326- checked = { item . selected }
327- disabled = { item . disabled }
328- />
329- ) ;
330- }
331-
332- const classNames = {
333- 'mdc-deprecated-list-item' : true ,
334- 'mdc-deprecated-list-item--disabled' : item . disabled ,
335- 'mdc-deprecated-list-item__text' : ! item . secondaryText ,
336- 'has-primary-component' : this . hasPrimaryComponent ( item ) ,
337- } ;
338-
339- const attributes : { tabindex ?: string } = { } ;
340- if ( index === this . applyTabIndexToItemAtIndex ) {
341- attributes . tabindex = '0' ;
342- }
343-
344- return (
345- < li
346- class = { classNames }
347- role = { config . type }
348- aria-checked = { item . selected ? 'true' : 'false' }
349- aria-disabled = { item . disabled ? 'true' : 'false' }
350- data-index = { index }
351- { ...attributes }
352- >
353- { this . renderVariantListItemContent ( config , item , itemTemplate ) }
354- </ li >
355- ) ;
356- } ;
357-
358- private renderVariantListItemContent = (
359- config : ListRendererConfig ,
360- item : ListItem ,
361- itemTemplate : any
362- ) => {
363- if ( this . hasIcons ) {
364- return [
365- item . icon ? this . renderIcon ( config , item ) : null ,
366- this . getPrimaryComponent ( item ) ,
367- this . renderText ( item ) ,
368- < div class = "mdc-deprecated-list-item__meta" >
369- { itemTemplate }
370- </ div > ,
371- ] ;
372- }
373-
374- return [
375- < div class = "mdc-deprecated-list-item__graphic" > { itemTemplate } </ div > ,
376- this . getPrimaryComponent ( item ) ,
377- this . renderText ( item ) ,
378- ] ;
379- } ;
380150}
0 commit comments