@@ -6,11 +6,9 @@ import {Group} from './Group'
6
6
import type { ItemProps } from './Item'
7
7
import { Item } from './Item'
8
8
import { Divider } from './Divider'
9
- import styled from 'styled-components'
10
- import { get } from '../../constants'
11
- import type { SystemCssProperties } from '@styled-system/css'
12
9
import { hasActiveDescendantAttribute } from '@primer/behaviors'
13
10
import type { Merge } from '../../utils/types/Merge'
11
+ import { BoxWithFallback } from '../../internal/components/BoxWithFallback'
14
12
15
13
export type RenderItemFn = ( props : ItemProps ) => React . ReactElement
16
14
@@ -108,42 +106,35 @@ function isGroupedListProps(props: ListProps): props is GroupedListProps {
108
106
*/
109
107
export type ListProps = ListPropsBase | GroupedListProps
110
108
111
- const StyledList = styled . div `
112
- font-size: ${ get ( 'fontSizes.1' ) } ;
113
- /* 14px font-size * 1.428571429 = 20px line height
114
- *
115
- * TODO: When rem-based spacing on a 4px scale lands, replace
116
- * hardcoded '20px'
117
- */
118
- line-height: 20px;
119
-
120
- &[${ hasActiveDescendantAttribute } ], &:focus-within {
121
- --item-hover-bg-override: none;
122
- --item-hover-divider-border-color-override: ${ get ( 'colors.border.muted' ) } ;
123
- }
124
- `
109
+ // Base styles for the List component
110
+ const listStyles : React . CSSProperties = {
111
+ fontSize : 'var(--text-body-size-medium, 14px)' ,
112
+ // 14px font-size * 1.428571429 = 20px line height
113
+ // TODO: When rem-based spacing on a 4px scale lands, replace hardcoded '20px'
114
+ lineHeight : '20px' ,
115
+ }
125
116
126
117
/**
127
- * Returns `sx` prop values for `List` children matching the given `List` style variation.
118
+ * Returns style objects for `List` children matching the given `List` style variation.
128
119
* @param variant `List` style variation.
129
120
*/
130
121
function useListVariant ( variant : ListProps [ 'variant' ] = 'inset' ) : {
131
- firstGroupStyle ?: SystemCssProperties
132
- lastGroupStyle ?: SystemCssProperties
133
- headerStyle ?: SystemCssProperties
134
- itemStyle ?: SystemCssProperties
122
+ firstGroupStyle ?: React . CSSProperties
123
+ lastGroupStyle ?: React . CSSProperties
124
+ headerStyle ?: React . CSSProperties
125
+ itemStyle ?: React . CSSProperties
135
126
} {
136
127
switch ( variant ) {
137
128
case 'full' :
138
129
return {
139
- headerStyle : { paddingX : get ( 'space.2' ) } ,
130
+ headerStyle : { paddingLeft : 'var(--base-size-8, 8px)' , paddingRight : 'var(--base-size-8, 8px)' } ,
140
131
itemStyle : { borderRadius : 0 } ,
141
132
}
142
133
default :
143
134
return {
144
- firstGroupStyle : { marginTop : get ( 'space.2' ) } ,
145
- lastGroupStyle : { marginBottom : get ( 'space.2' ) } ,
146
- itemStyle : { marginX : get ( 'space.2' ) } ,
135
+ firstGroupStyle : { marginTop : 'var(--base-size-8, 8px)' } ,
136
+ lastGroupStyle : { marginBottom : 'var(--base-size-8, 8px)' } ,
137
+ itemStyle : { marginLeft : 'var(--base-size-8, 8px)' , marginRight : 'var(--base-size-8, 8px)' } ,
147
138
}
148
139
}
149
140
}
@@ -152,8 +143,10 @@ function useListVariant(variant: ListProps['variant'] = 'inset'): {
152
143
* Lists `Item`s, either grouped or ungrouped, with a `Divider` between each `Group`.
153
144
*/
154
145
export const List = React . forwardRef < HTMLDivElement , ListProps > ( ( props , forwardedRef ) : JSX . Element => {
155
- // Get `sx` prop values for `List` children matching the given `List` style variation.
156
- const { firstGroupStyle, lastGroupStyle, headerStyle, itemStyle} = useListVariant ( props . variant )
146
+ // Extract style prop to avoid conflicts with BoxWithFallback
147
+ const { style, ...restProps } = props as ListProps & { style ?: React . CSSProperties }
148
+ // Get style objects for `List` children matching the given `List` style variation.
149
+ const { firstGroupStyle, lastGroupStyle, headerStyle, itemStyle} = useListVariant ( restProps . variant )
157
150
158
151
/**
159
152
* Render a `Group` using the first of the following renderers that is defined:
@@ -163,7 +156,7 @@ export const List = React.forwardRef<HTMLDivElement, ListProps>((props, forwarde
163
156
const renderGroup = (
164
157
groupProps : GroupProps | ( Partial < GroupProps > & { renderItem ?: typeof Item ; renderGroup ?: typeof Group } ) ,
165
158
) => {
166
- const GroupComponent = ( ( 'renderGroup' in groupProps && groupProps . renderGroup ) ?? props . renderGroup ) || Group
159
+ const GroupComponent = ( ( 'renderGroup' in groupProps && groupProps . renderGroup ) ?? restProps . renderGroup ) || Group
167
160
return < GroupComponent { ...groupProps } key = { groupProps . groupId } />
168
161
}
169
162
@@ -174,12 +167,12 @@ export const List = React.forwardRef<HTMLDivElement, ListProps>((props, forwarde
174
167
*/
175
168
const renderItem = ( itemProps : ItemInput , item : ItemInput , itemIndex : number ) => {
176
169
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
177
- const ItemComponent = ( 'renderItem' in itemProps && itemProps . renderItem ) || props . renderItem || Item
170
+ const ItemComponent = ( 'renderItem' in itemProps && itemProps . renderItem ) || restProps . renderItem || Item
178
171
const key = ( 'key' in itemProps ? itemProps . key : undefined ) ?? itemProps . id ?. toString ( ) ?? itemIndex . toString ( )
179
172
return (
180
173
< ItemComponent
181
- showDivider = { props . showItemDividers }
182
- selectionVariant = { props . selectionVariant }
174
+ showDivider = { restProps . showItemDividers }
175
+ selectionVariant = { restProps . selectionVariant }
183
176
{ ...itemProps }
184
177
key = { key }
185
178
sx = { { ...itemStyle , ...itemProps . sx } }
@@ -194,21 +187,21 @@ export const List = React.forwardRef<HTMLDivElement, ListProps>((props, forwarde
194
187
let groups : ( GroupProps | ( Partial < GroupProps > & { renderItem ?: typeof Item ; renderGroup ?: typeof Group } ) ) [ ] = [ ]
195
188
196
189
// Collect rendered `Item`s into `Group`s, avoiding excess iteration over the lists of `items` and `groupMetadata`:
197
- if ( ! isGroupedListProps ( props ) ) {
190
+ if ( ! isGroupedListProps ( restProps ) ) {
198
191
// When no `groupMetadata`s is provided, collect rendered `Item`s into a single anonymous `Group`.
199
- groups = [ { items : props . items . map ( ( item , index ) => renderItem ( item , item , index ) ) , groupId : '0' } ]
192
+ groups = [ { items : restProps . items . map ( ( item , index ) => renderItem ( item , item , index ) ) , groupId : '0' } ]
200
193
} else {
201
194
// When `groupMetadata` is provided, collect rendered `Item`s into their associated `Group`s.
202
195
203
196
/**
204
197
* A map of group identifiers to `Group`s, each with an associated array of `Item`s belonging to that `Group`.
205
198
*/
206
- const groupMap = props . groupMetadata . reduce (
199
+ const groupMap = restProps . groupMetadata . reduce (
207
200
( groupAccumulator , groupMetadata ) => groupAccumulator . set ( groupMetadata . groupId , groupMetadata ) ,
208
201
new Map < string , GroupProps | ( Partial < GroupProps > & { renderItem ?: typeof Item ; renderGroup ?: typeof Group } ) > ( ) ,
209
202
)
210
203
211
- for ( const itemProps of props . items ) {
204
+ for ( const itemProps of restProps . items ) {
212
205
// Look up the group associated with the current item.
213
206
const group = groupMap . get ( itemProps . groupId )
214
207
const itemIndex = group ?. items ?. length ?? 0
@@ -235,7 +228,20 @@ export const List = React.forwardRef<HTMLDivElement, ListProps>((props, forwarde
235
228
}
236
229
237
230
return (
238
- < StyledList { ...props } ref = { forwardedRef } >
231
+ < BoxWithFallback
232
+ { ...restProps }
233
+ ref = { forwardedRef }
234
+ style = { {
235
+ ...listStyles ,
236
+ ...( style || { } ) ,
237
+ } }
238
+ sx = { {
239
+ [ `&[${ hasActiveDescendantAttribute } ], &:focus-within` ] : {
240
+ '--item-hover-bg-override' : 'none' ,
241
+ '--item-hover-divider-border-color-override' : 'var(--borderColor-muted)' ,
242
+ } ,
243
+ } }
244
+ >
239
245
{ groups . map ( ( { header, ...groupProps } , index ) => {
240
246
const hasFilledHeader = header ?. variant === 'filled'
241
247
const shouldShowDivider = index > 0 && ! hasFilledHeader
@@ -259,7 +265,7 @@ export const List = React.forwardRef<HTMLDivElement, ListProps>((props, forwarde
259
265
</ React . Fragment >
260
266
)
261
267
} ) }
262
- </ StyledList >
268
+ </ BoxWithFallback >
263
269
)
264
270
} )
265
271
0 commit comments