| 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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312 |
230x
230x
230x
230x
230x
6x
2x
2x
1x
1x
2x
2x
1x
1x
230x
460x
460x
460x
230x
21x
230x
23x
223x
223x
2x
230x
6x
230x
23x
230x
230x
24x
1x
1x
23x
230x
230x
230x
229x
230x
230x
228x
186x
184x
183x
224x
230x
230x
230x
2x
230x
230x
230x
89x
89x
89x
| /**
* @category styles
* @component icon
* @variations collab-ui-react
*/
import React from 'react';
import PropTypes from 'prop-types';
import {
chain,
find,
trimEnd,
uniqueId
} from 'lodash';
import iconPaths from '@collab-ui/icons/data/iconsData.json';
import colors from '@collab-ui/core/data/colors.json';
import { Button } from '@collab-ui/react';
class Icon extends React.PureComponent {
render() {
const {
ariaLabel,
buttonClassName,
color,
className,
description,
isAria, // TODO(pajeter): remove isAria code with next major release
onClick,
name,
size,
title,
type,
...otherProps
} = this.props;
const iconCount = uniqueId();
const titleId = `icon-title-${iconCount}`;
const descId = description ? `icon-desc-${iconCount}` : undefined;
const consoleHandler = (message, data) => {
/* eslint-disable no-console */
switch (message) {
case 'isAria-warn': // TODO(pajeter): remove isAria code with next major release
console.warn(
`[@collab-ui/react] Icon: isAria prop is deprecated and will be removed. Title, description or ariaLabel props should be used to add accessibility.`
);
break;
case 'color-warn':
console.warn(
`[@collab-ui/react] Icon: ${data} may not exist in the design system,` +
` please use a color name from http://core.collab-ui.com/styles/colors`
);
break;
case 'color-error':
console.warn(
`[@collab-ui/react] Icon: ${data} does not exist in the design system,` +
` please use a color name from http://core.collab-ui.com/styles/colors`
);
break;
case 'name-error':
console.warn(
`[@collab-ui/react] Icon: Icon ${data} does not exist in the design system.` +
` Visit http://icons.collab-ui.com for a list of available icons or to request a new icon.`
);
break;
}
/* eslint-enable no-console */
};
const getSize = () => {
const defaultSize = 16;
const sizeFromName = Number(name.split('_')[1]);
return size || sizeFromName || defaultSize;
};
const getColorSpec = colorObj =>
colorObj.hex
? colorObj.hex
: colorObj.opacity && isolateRoot(colorObj.variable) === 'white'
? `rgba(255, 255, 255, ${colorObj.opacity / 100})`
: `rgba(0, 0, 0, ${colorObj.opacity / 100})`;
const getHexFromJSON = colorName => {
for (let c of colors) {
const variation = find(c.variations, ['variable', colorName]);
if (variation) return getColorSpec(variation);
}
return consoleHandler('color-error', colorName);
};
const isolateRoot = str => (
chain(str)
.trimStart('$')
.split('-')
.value()[0]
);
const formatColor = () => {
return color.startsWith('$')
? color
: color.endsWith('-base')
? trimEnd(color, '-base')
: `$${color}`;
};
const getColor = () => {
if (!color) return 'inherit';
if (color.startsWith('#')) {
consoleHandler('color-warn', color);
return color;
}
return getHexFromJSON(formatColor());
};
const getPaths = () => {
const iconName = name.startsWith('icon-')
? name.replace(/^(icon-)/,'')
: name;
return iconPaths[iconName]
? iconPaths[iconName].map((icoPath, index) => (
<path d={icoPath} key={index} />
))
: consoleHandler('name-error', iconName);
};
const getAriaLabelledBy = () => {
if (!isAria) return deprecationWarning(); // TODO(pajeter): remove isAria code with next major release
if (!ariaLabel) {
if (title && description) return (`${titleId} ${descId}`);
if (title) return (`${titleId}`);
if (description) return (`${descId}`);
}
return null;
};
const getAriaLabel = () => (
(isAria // TODO(pajeter): remove isAria code with next major release
&& ariaLabel) ? ariaLabel : null
);
const deprecationWarning = () => { // TODO(pajeter): remove isAria code with next major release
consoleHandler('isAria-warn');
};
const getIcon = () => {
return (
<svg
className={
`cui-icon` +
`${(className && ` ${className}`) || ''}`
}
name={name}
width={getSize()}
height={getSize()}
aria-labelledby={!onClick ? getAriaLabelledBy() : null}
aria-label={!onClick ? getAriaLabel() : null}
{...!onClick && {...otherProps}}
>
{isAria // TODO(pajeter): remove isAria code with next major release
&& title && <title id={titleId}>{title}</title>}
{isAria // TODO(pajeter): remove isAria code with next major release
&& description && <desc id={descId}>{description}</desc>}
<g fill={getColor()} fillRule="evenodd">
{getPaths()}
</g>
</svg>
);
};
return (
onClick
?
<Button
className={
'cui-button--icon' +
`${(type && ` cui-button--icon-${type}`) || ''}` +
`${(buttonClassName && ` ${buttonClassName}`) || ''}`
}
ariaLabel={getAriaLabel()}
ariaLabelledBy={
isAria // TODO(pajeter): remove isAria code with next major release
? getAriaLabelledBy()
: deprecationWarning() // TODO(pajeter): remove isAria code with next major release
}
onClick={onClick}
{...otherProps}
>
{getIcon()}
</Button>
:
getIcon()
);
}
}
Icon.propTypes = {
/** @prop Text to display for blindness accessibility features | null */
ariaLabel: PropTypes.string,
/** @prop Optional Button class name string | '' */
buttonClassName: PropTypes.string,
/** @prop Optional color css styling | '' */
color: PropTypes.string,
/** @prop Optional class name string | '' */
className: PropTypes.string,
/** @prop Icon description text | '' */
description: PropTypes.string,
/** @prop Depreciated prop that supports accessibility features | true */
isAria: PropTypes.bool, // TODO(pajeter): remove isAria code with next major release
/** @prop Required Icon name */
name: PropTypes.string.isRequired,
/** @prop Handler invoked by click of the user | null */
onClick: PropTypes.func,
/** @prop Sets Icon size | null */
size: PropTypes.number,
/** @prop Sets Icon Title prop | '' */
title: PropTypes.string,
/** @prop Sets Icon Type | '' */
type: PropTypes.oneOf(['', 'white'])
};
Icon.defaultProps = {
ariaLabel: null,
buttonClassName: '',
color: '',
className: '',
description: '',
isAria: true, // TODO(pajeter): remove isAria code with next major release
onClick: null,
size: null,
title: '',
type: ''
};
Icon.displayName = 'Icon';
export default Icon;
/**
* @component icons
* @section default
* @react
*
import { Icon } from '@collab-ui/react';
export default class IconDefault extends React.PureComponent {
render() {
return(
<div>
<Icon name='accessories_16' />
<Icon name='accessories_20' />
<Icon name='accessories_36' />
<Icon name='accessories_56' />
</div>
);
}
}
**/
/**
* @component icons
* @section color
* @react
*
import { Icon } from '@collab-ui/react';
export default class IconColor extends React.PureComponent {
render() {
return(
<div>
<Icon name='accessories_16' color='blue' />
<Icon name='accessories_20' color='blue' />
<Icon name='accessories_36' color='blue' />
<Icon name='accessories_56' color='blue' />
</div>
);
}
}
**/
/**
* @component icons
* @section white
* @react
*
import { Icon } from '@collab-ui/react';
export default class Default extends React.PureComponent {
render() {
return(
<div style={{ backgroundColor: 'black', padding: '5px', width: 'fit-content' }}>
<Icon
name='clear-active_24'
ariaLabel='Clear'
type='white'
onClick={() => console.log('Icon 36 - clicked')}
/>
</div>
);
}
}
**/
|