-
Notifications
You must be signed in to change notification settings - Fork 31
/
icon.tsx
104 lines (88 loc) · 2.76 KB
/
icon.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import React, { FC, Ref, SVGProps, useEffect, useState } from 'react'
import classNames from 'classnames'
import { withForwardRef } from '../common/component-utils'
import { randomId } from '../common/random-id'
import { Icon } from './types'
export type A11yVariant = 'label';
export type EbayIconProps = SVGProps<SVGSVGElement> & {
className?: string;
name: Icon;
noSkinClasses?: boolean;
a11yText?: string;
a11yVariant?: A11yVariant;
forwardedRef?: Ref<SVGSVGElement>;
};
const EbayIcon: FC<EbayIconProps> = ({
name,
className: extraClass,
noSkinClasses = false,
a11yText,
a11yVariant,
forwardedRef,
...rest
}) => {
const [rId, setRandomId] = useState('')
useEffect(() => {
setRandomId(randomId())
}, [])
const withAriaLabel = a11yVariant === 'label'
const a11yTextId = a11yText && `icon-title-${rId}`
const a11yProps = a11yText ? {
'aria-labelledby': withAriaLabel ? undefined : a11yTextId,
'aria-label': withAriaLabel ? a11yText : undefined,
role: 'img'
} : {
'aria-hidden': true
}
const kebabName = kebabCased(name)
const size = getIconSize(kebabName) || kebabName
const skinClassName = [`icon`, `icon--${size}`, getFilledIconName(kebabName)].filter(Boolean).join(' ')
const className = classNames(extraClass,
{ [skinClassName]: !noSkinClasses }
)
return (
<svg
{...rest}
className={className}
xmlns="http://www.w3.org/2000/svg"
focusable={false}
ref={forwardedRef}
{...a11yProps}
>
{a11yText && !withAriaLabel && <title id={a11yTextId}>{a11yText}</title>}
<use xlinkHref={`#icon-${kebabName}`} />
</svg>
)
}
// This function extract the size of the icon name.
// The icon can have these name structures:
// - icon-name-24
// - icon-name-24-colored
// - icon-name-filled-24
// - icon-name-filled-24-colored
// - icon-name
function getIconSize(iconName: string) {
const iconNameArray = iconName.split('-')
const size = iconNameArray[iconNameArray.length - 1]
if (size === 'colored') {
return iconNameArray[iconNameArray.length - 2]
}
if (isNaN(Number(size))) {
return ''
}
return size
}
function getFilledIconName(iconName: string) {
const iconNameArray = iconName.split('-')
const filledIndex = iconNameArray.indexOf('filled')
if (filledIndex === -1) {
return ''
}
return `icon--${iconNameArray.slice(0, filledIndex + 1).join('-')}`
}
export function kebabCased(str: string): string {
return str
.replace(/([0-9]+)/g, (s, n) => `-${n}`)
.replace(/([A-Z])/g, (s, c) => `-${c.toLowerCase()}`)
}
export default withForwardRef(EbayIcon)