@instructure/ui-avatar 7.9.0 → 7.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,24 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [7.13.0](https://github.com/instructure/instructure-ui/compare/v7.12.0...v7.13.0) (2021-11-18)
7
+
8
+ ### Features
9
+
10
+ - **ui-avatar:** add `renderIcon` and `hasInverseColor` props to Avatar ([bb492d7](https://github.com/instructure/instructure-ui/commit/bb492d7)), backports [#781](https://github.com/instructure/instructure-ui/issues/781)
11
+
12
+ # [7.12.0](https://github.com/instructure/instructure-ui/compare/v7.11.0...v7.12.0) (2021-10-15)
13
+
14
+ **Note:** Version bump only for package @instructure/ui-avatar
15
+
16
+ # [7.11.0](https://github.com/instructure/instructure-ui/compare/v7.10.0...v7.11.0) (2021-09-17)
17
+
18
+ **Note:** Version bump only for package @instructure/ui-avatar
19
+
20
+ # [7.10.0](https://github.com/instructure/instructure-ui/compare/v7.9.0...v7.10.0) (2021-08-27)
21
+
22
+ **Note:** Version bump only for package @instructure/ui-avatar
23
+
6
24
  # [7.9.0](https://github.com/instructure/instructure-ui/compare/v7.8.0...v7.9.0) (2021-07-16)
7
25
 
8
26
  ### Features
@@ -21,13 +21,37 @@
21
21
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
22
  * SOFTWARE.
23
23
  */
24
+ import React from 'react';
25
+ import { IconGroupLine } from '@instructure/ui-icons';
24
26
  export default {
25
27
  excludeProps: ['inline', 'variant'],
26
28
  sectionProp: 'shape',
27
29
  propValues: {
28
- src: [null, require('./testImage.jpg')]
30
+ src: [null, require('./testImage.jpg')],
31
+ renderIcon: [void 0, /*#__PURE__*/React.createElement(IconGroupLine, {
32
+ key: "icon"
33
+ })]
29
34
  },
30
- getComponentProps: function getComponentProps(props) {
35
+ filter: function filter(props) {
36
+ if (props.color !== 'default' && props.size !== 'medium') {
37
+ return true;
38
+ }
39
+
40
+ if (props.renderIcon && props.src) {
41
+ return true;
42
+ }
43
+
44
+ if (props.src && props.color !== 'default') {
45
+ return true;
46
+ }
47
+
48
+ if (props.hasInverseColor && (props.size !== 'medium' || props.display !== 'block')) {
49
+ return true;
50
+ }
51
+
52
+ return false;
53
+ },
54
+ getComponentProps: function getComponentProps() {
31
55
  return {
32
56
  name: 'Kyle Montgomery'
33
57
  };
@@ -35,34 +35,36 @@ import PropTypes from 'prop-types';
35
35
  import classnames from 'classnames';
36
36
  import { View } from '@instructure/ui-view';
37
37
  import { themeable, ThemeablePropTypes } from '@instructure/ui-themeable';
38
- import { passthroughProps, deprecated } from '@instructure/ui-react-utils';
38
+ import { passthroughProps, deprecated, callRenderProp } from '@instructure/ui-react-utils';
39
39
  import { testable } from '@instructure/ui-testable';
40
40
  var styles = {
41
- componentId: 'dsJBj',
41
+ componentId: 'elMgC',
42
42
  template: function template(theme) {
43
- return "\n\n.dsJBj_bGBk{background-clip:content-box;background-color:".concat(theme.background || 'inherit', ";background-position:50%;background-repeat:no-repeat;background-size:cover;box-sizing:border-box;height:2.5em;line-height:0;overflow:hidden;text-align:center}\n\n[dir=ltr] .dsJBj_bGBk,[dir=rtl] .dsJBj_bGBk{text-align:center}\n\n.dsJBj_bGBk.dsJBj_uUeq{font-size:inherit}\n\n.dsJBj_bGBk.dsJBj_uUeq,.dsJBj_bGBk.dsJBj_UKsG{border-width:").concat(theme.borderWidthSmall || 'inherit', "}\n\n.dsJBj_bGBk.dsJBj_UKsG{font-size:0.5rem}\n\n.dsJBj_bGBk.dsJBj_dfBC{font-size:0.75rem}\n\n.dsJBj_bGBk.dsJBj_doqw,.dsJBj_bGBk.dsJBj_dfBC{border-width:").concat(theme.borderWidthSmall || 'inherit', "}\n\n.dsJBj_bGBk.dsJBj_doqw{font-size:1rem}\n\n.dsJBj_bGBk.dsJBj_ycrn{font-size:1.25rem}\n\n.dsJBj_bGBk.dsJBj_cMDj,.dsJBj_bGBk.dsJBj_ycrn{border-width:").concat(theme.borderWidthMedium || 'inherit', "}\n\n.dsJBj_bGBk.dsJBj_cMDj{font-size:1.5rem}\n\n.dsJBj_bGBk.dsJBj_eoMd{font-size:1.75rem}\n\n.dsJBj_bGBk.dsJBj_eoMd,.dsJBj_bGBk.dsJBj_fdca{border-width:").concat(theme.borderWidthMedium || 'inherit', "}\n\n.dsJBj_bGBk.dsJBj_fdca{font-size:2rem}\n\n.dsJBj_bGBk.dsJBj_cHTY{border:0;box-shadow:inset 0 0 ").concat(theme.boxShadowBlur || 'inherit', " 0 ").concat(theme.boxShadowColor || 'inherit', "}\n\n.dsJBj_bGBk:not(.dsJBj_cHTY){border-color:").concat(theme.borderColor || 'inherit', ";border-style:solid}\n\n.dsJBj_eYKj{font-family:").concat(theme.fontFamily || 'inherit', ";font-weight:").concat(theme.fontWeight || 'inherit', ";letter-spacing:0.0313em;line-height:2.375em}\n\n.dsJBj_ddES .dsJBj_eYKj{color:").concat(theme.color || 'inherit', "}\n\n.dsJBj_ekuM .dsJBj_eYKj{color:").concat(theme.colorShamrock || 'inherit', "}\n\n.dsJBj_bXnN .dsJBj_eYKj{color:").concat(theme.colorBarney || 'inherit', "}\n\n.dsJBj_byip .dsJBj_eYKj{color:").concat(theme.colorCrimson || 'inherit', "}\n\n.dsJBj_dKVo .dsJBj_eYKj{color:").concat(theme.colorFire || 'inherit', "}\n\n.dsJBj_eaOe .dsJBj_eYKj{color:").concat(theme.colorLicorice || 'inherit', "}\n\n.dsJBj_fuVp .dsJBj_eYKj{color:").concat(theme.colorAsh || 'inherit', "}\n\n.dsJBj_MrJH{display:none}\n\n.dsJBj_cJVF{border-radius:100%;overflow:hidden;position:relative;width:2.5em}\n\n.dsJBj_bRWf{width:3em}");
43
+ return "\n\n.elMgC_bGBk{background-clip:content-box;background-color:".concat(theme.background || 'inherit', ";background-position:50%;background-repeat:no-repeat;background-size:cover;box-sizing:border-box;height:2.5em;line-height:0;overflow:hidden;text-align:center}\n\n[dir=ltr] .elMgC_bGBk,[dir=rtl] .elMgC_bGBk{text-align:center}\n\n.elMgC_bGBk.elMgC_uUeq{font-size:inherit}\n\n.elMgC_bGBk.elMgC_uUeq,.elMgC_bGBk.elMgC_UKsG{border-width:").concat(theme.borderWidthSmall || 'inherit', "}\n\n.elMgC_bGBk.elMgC_UKsG{font-size:0.5rem}\n\n.elMgC_bGBk.elMgC_dfBC{font-size:0.75rem}\n\n.elMgC_bGBk.elMgC_doqw,.elMgC_bGBk.elMgC_dfBC{border-width:").concat(theme.borderWidthSmall || 'inherit', "}\n\n.elMgC_bGBk.elMgC_doqw{font-size:1rem}\n\n.elMgC_bGBk.elMgC_ycrn{font-size:1.25rem}\n\n.elMgC_bGBk.elMgC_cMDj,.elMgC_bGBk.elMgC_ycrn{border-width:").concat(theme.borderWidthMedium || 'inherit', "}\n\n.elMgC_bGBk.elMgC_cMDj{font-size:1.5rem}\n\n.elMgC_bGBk.elMgC_eoMd{font-size:1.75rem}\n\n.elMgC_bGBk.elMgC_eoMd,.elMgC_bGBk.elMgC_fdca{border-width:").concat(theme.borderWidthMedium || 'inherit', "}\n\n.elMgC_bGBk.elMgC_fdca{font-size:2rem}\n\n.elMgC_bGBk.elMgC_cHTY{border:0;box-shadow:inset 0 0 ").concat(theme.boxShadowBlur || 'inherit', " 0 ").concat(theme.boxShadowColor || 'inherit', "}\n\n.elMgC_bGBk:not(.elMgC_cHTY){border-color:").concat(theme.borderColor || 'inherit', ";border-style:solid}\n\n.elMgC_bGBk:not(.elMgC_cHTY).elMgC_fKgA{background-clip:border-box;border:0;padding:0}\n\n.elMgC_bGBk:not(.elMgC_cHTY).elMgC_fKgA.elMgC_uUeq,.elMgC_bGBk:not(.elMgC_cHTY).elMgC_fKgA.elMgC_doqw,.elMgC_bGBk:not(.elMgC_cHTY).elMgC_fKgA.elMgC_dfBC,.elMgC_bGBk:not(.elMgC_cHTY).elMgC_fKgA.elMgC_UKsG{padding:").concat(theme.borderWidthSmall || 'inherit', "}\n\n.elMgC_bGBk:not(.elMgC_cHTY).elMgC_fKgA.elMgC_cMDj,.elMgC_bGBk:not(.elMgC_cHTY).elMgC_fKgA.elMgC_ycrn,.elMgC_bGBk:not(.elMgC_cHTY).elMgC_fKgA.elMgC_eoMd,.elMgC_bGBk:not(.elMgC_cHTY).elMgC_fKgA.elMgC_fdca{padding:").concat(theme.borderWidthMedium || 'inherit', "}\n\n.elMgC_eYKj{font-family:").concat(theme.fontFamily || 'inherit', ";font-weight:").concat(theme.fontWeight || 'inherit', ";letter-spacing:0.0313em;line-height:2.375em}\n\n.elMgC_ddES{color:").concat(theme.color || 'inherit', "}\n\n.elMgC_ekuM{color:").concat(theme.colorShamrock || 'inherit', "}\n\n.elMgC_bXnN{color:").concat(theme.colorBarney || 'inherit', "}\n\n.elMgC_byip{color:").concat(theme.colorCrimson || 'inherit', "}\n\n.elMgC_dKVo{color:").concat(theme.colorFire || 'inherit', "}\n\n.elMgC_eaOe{color:").concat(theme.colorLicorice || 'inherit', "}\n\n.elMgC_fuVp{color:").concat(theme.colorAsh || 'inherit', "}\n\n.elMgC_fKgA{color:").concat(theme.background || 'inherit', "}\n\n.elMgC_fKgA.elMgC_ddES{background-color:").concat(theme.color || 'inherit', "}\n\n.elMgC_fKgA.elMgC_ekuM{background-color:").concat(theme.colorShamrock || 'inherit', "}\n\n.elMgC_fKgA.elMgC_bXnN{background-color:").concat(theme.colorBarney || 'inherit', "}\n\n.elMgC_fKgA.elMgC_byip{background-color:").concat(theme.colorCrimson || 'inherit', "}\n\n.elMgC_fKgA.elMgC_dKVo{background-color:").concat(theme.colorFire || 'inherit', "}\n\n.elMgC_fKgA.elMgC_eaOe{background-color:").concat(theme.colorLicorice || 'inherit', "}\n\n.elMgC_fKgA.elMgC_fuVp{background-color:").concat(theme.colorAsh || 'inherit', "}\n\n.elMgC_MrJH{display:none}\n\n.elMgC_cJVF{border-radius:100%;overflow:hidden;position:relative;width:2.5em}\n\n.elMgC_bRWf{width:3em}\n\n.elMgC_eoCh{align-items:center;display:flex;height:100%;justify-content:center;width:100%}\n\n.elMgC_eoCh svg{fill:currentColor;height:1em;width:1em}");
44
44
  },
45
- 'root': 'dsJBj_bGBk',
46
- 'auto': 'dsJBj_uUeq',
47
- 'xx-small': 'dsJBj_UKsG',
48
- 'x-small': 'dsJBj_dfBC',
49
- 'small': 'dsJBj_doqw',
50
- 'medium': 'dsJBj_ycrn',
51
- 'large': 'dsJBj_cMDj',
52
- 'x-large': 'dsJBj_eoMd',
53
- 'xx-large': 'dsJBj_fdca',
54
- 'loaded': 'dsJBj_cHTY',
55
- 'initials': 'dsJBj_eYKj',
56
- 'default': 'dsJBj_ddES',
57
- 'shamrock': 'dsJBj_ekuM',
58
- 'barney': 'dsJBj_bXnN',
59
- 'crimson': 'dsJBj_byip',
60
- 'fire': 'dsJBj_dKVo',
61
- 'licorice': 'dsJBj_eaOe',
62
- 'ash': 'dsJBj_fuVp',
63
- 'loadImage': 'dsJBj_MrJH',
64
- 'circle': 'dsJBj_cJVF',
65
- 'rectangle': 'dsJBj_bRWf'
45
+ 'root': 'elMgC_bGBk',
46
+ 'auto': 'elMgC_uUeq',
47
+ 'xx-small': 'elMgC_UKsG',
48
+ 'x-small': 'elMgC_dfBC',
49
+ 'small': 'elMgC_doqw',
50
+ 'medium': 'elMgC_ycrn',
51
+ 'large': 'elMgC_cMDj',
52
+ 'x-large': 'elMgC_eoMd',
53
+ 'xx-large': 'elMgC_fdca',
54
+ 'loaded': 'elMgC_cHTY',
55
+ 'hasInverseColor': 'elMgC_fKgA',
56
+ 'initials': 'elMgC_eYKj',
57
+ 'default': 'elMgC_ddES',
58
+ 'shamrock': 'elMgC_ekuM',
59
+ 'barney': 'elMgC_bXnN',
60
+ 'crimson': 'elMgC_byip',
61
+ 'fire': 'elMgC_dKVo',
62
+ 'licorice': 'elMgC_eaOe',
63
+ 'ash': 'elMgC_fuVp',
64
+ 'loadImage': 'elMgC_MrJH',
65
+ 'circle': 'elMgC_cJVF',
66
+ 'rectangle': 'elMgC_bRWf',
67
+ 'iconSVG': 'elMgC_eoCh'
66
68
  };
67
69
  import theme from "./theme.js";
68
70
  /**
@@ -105,6 +107,16 @@ var Avatar = (_dec = testable(), _dec2 = deprecated('8.0.0', {
105
107
  }
106
108
 
107
109
  _createClass(Avatar, [{
110
+ key: "componentDidUpdate",
111
+ value: function componentDidUpdate() {
112
+ // in case the image is unset in an update, show icons/initials again
113
+ if (this.state.loaded && !this.props.src) {
114
+ this.setState({
115
+ loaded: false
116
+ });
117
+ }
118
+ }
119
+ }, {
108
120
  key: "makeInitialsFromName",
109
121
  value: function makeInitialsFromName() {
110
122
  var name = this.props.name;
@@ -146,6 +158,19 @@ var Avatar = (_dec = testable(), _dec2 = deprecated('8.0.0', {
146
158
  "aria-hidden": "true"
147
159
  }, this.makeInitialsFromName());
148
160
  }
161
+ }, {
162
+ key: "renderContent",
163
+ value: function renderContent() {
164
+ var renderIcon = this.props.renderIcon;
165
+
166
+ if (!renderIcon) {
167
+ return this.renderInitials();
168
+ }
169
+
170
+ return /*#__PURE__*/React.createElement("span", {
171
+ className: styles.iconSVG
172
+ }, callRenderProp(renderIcon));
173
+ }
149
174
  }, {
150
175
  key: "render",
151
176
  value: function render() {
@@ -160,14 +185,14 @@ var Avatar = (_dec = testable(), _dec2 = deprecated('8.0.0', {
160
185
  style: {
161
186
  backgroundImage: loaded ? "url('".concat(this.props.src, "')") : void 0
162
187
  },
163
- className: classnames((_classnames = {}, _defineProperty(_classnames, styles.root, true), _defineProperty(_classnames, styles[this.props.size], true), _defineProperty(_classnames, styles[this.props.variant || this.props.shape], true), _defineProperty(_classnames, styles[this.props.color], true), _defineProperty(_classnames, styles.loaded, loaded), _classnames)),
188
+ className: classnames((_classnames = {}, _defineProperty(_classnames, styles.root, true), _defineProperty(_classnames, styles[this.props.size], true), _defineProperty(_classnames, styles[this.props.variant || this.props.shape], true), _defineProperty(_classnames, styles[this.props.color], true), _defineProperty(_classnames, styles.loaded, loaded), _defineProperty(_classnames, styles.hasInverseColor, this.props.hasInverseColor), _classnames)),
164
189
  "aria-label": this.props.alt ? this.props.alt : null,
165
190
  role: this.props.alt ? 'img' : null,
166
191
  as: this.props.as,
167
192
  elementRef: this.props.elementRef,
168
193
  margin: this.props.margin,
169
194
  display: this.props.display === 'block' || this.props.inline === false ? 'block' : 'inline-block'
170
- }), this.renderLoadImage(), !loaded && this.renderInitials());
195
+ }), this.renderLoadImage(), !loaded && this.renderContent());
171
196
  }
172
197
  }]);
173
198
 
@@ -187,6 +212,11 @@ var Avatar = (_dec = testable(), _dec2 = deprecated('8.0.0', {
187
212
  alt: PropTypes.string,
188
213
  size: PropTypes.oneOf(['auto', 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large']),
189
214
  color: PropTypes.oneOf(['default', 'shamrock', 'barney', 'crimson', 'fire', 'licorice', 'ash']),
215
+
216
+ /**
217
+ * In inverse color mode the background and text/icon colors are inverted
218
+ */
219
+ hasInverseColor: PropTypes.bool,
190
220
  shape: PropTypes.oneOf(['circle', 'rectangle']),
191
221
 
192
222
  /**
@@ -213,6 +243,11 @@ var Avatar = (_dec = testable(), _dec2 = deprecated('8.0.0', {
213
243
  */
214
244
  elementRef: PropTypes.func,
215
245
 
246
+ /**
247
+ * An icon, or function that returns an icon that gets displayed. If the `src` prop is provided, `src` will have priority.
248
+ */
249
+ renderIcon: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
250
+
216
251
  /* eslint-disable react/require-default-props */
217
252
 
218
253
  /**
@@ -233,9 +268,11 @@ var Avatar = (_dec = testable(), _dec2 = deprecated('8.0.0', {
233
268
  elementRef: void 0,
234
269
  size: 'medium',
235
270
  color: 'default',
271
+ hasInverseColor: false,
236
272
  shape: 'circle',
237
273
  display: 'inline-block',
238
- onImageLoaded: function onImageLoaded(event) {}
274
+ onImageLoaded: function onImageLoaded(event) {},
275
+ renderIcon: null
239
276
  }, _temp)) || _class) || _class) || _class);
240
277
  export default Avatar;
241
278
  export { Avatar };
@@ -1,10 +1,16 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
3
5
  Object.defineProperty(exports, "__esModule", {
4
6
  value: true
5
7
  });
6
8
  exports.default = void 0;
7
9
 
10
+ var _react = _interopRequireDefault(require("react"));
11
+
12
+ var _IconGroupLine = require("@instructure/ui-icons/lib/IconGroupLine.js");
13
+
8
14
  /*
9
15
  * The MIT License (MIT)
10
16
  *
@@ -32,9 +38,31 @@ var _default = {
32
38
  excludeProps: ['inline', 'variant'],
33
39
  sectionProp: 'shape',
34
40
  propValues: {
35
- src: [null, require('./testImage.jpg')]
41
+ src: [null, require('./testImage.jpg')],
42
+ renderIcon: [void 0, /*#__PURE__*/_react.default.createElement(_IconGroupLine.IconGroupLine, {
43
+ key: "icon"
44
+ })]
45
+ },
46
+ filter: function filter(props) {
47
+ if (props.color !== 'default' && props.size !== 'medium') {
48
+ return true;
49
+ }
50
+
51
+ if (props.renderIcon && props.src) {
52
+ return true;
53
+ }
54
+
55
+ if (props.src && props.color !== 'default') {
56
+ return true;
57
+ }
58
+
59
+ if (props.hasInverseColor && (props.size !== 'medium' || props.display !== 'block')) {
60
+ return true;
61
+ }
62
+
63
+ return false;
36
64
  },
37
- getComponentProps: function getComponentProps(props) {
65
+ getComponentProps: function getComponentProps() {
38
66
  return {
39
67
  name: 'Kyle Montgomery'
40
68
  };
@@ -37,6 +37,8 @@ var _passthroughProps = require("@instructure/ui-react-utils/lib/passthroughProp
37
37
 
38
38
  var _deprecated = require("@instructure/ui-react-utils/lib/deprecated.js");
39
39
 
40
+ var _callRenderProp = require("@instructure/ui-react-utils/lib/callRenderProp.js");
41
+
40
42
  var _testable = require("@instructure/ui-testable/lib/testable.js");
41
43
 
42
44
  var _theme = _interopRequireDefault(require("./theme.js"));
@@ -44,31 +46,33 @@ var _theme = _interopRequireDefault(require("./theme.js"));
44
46
  var _dec, _dec2, _dec3, _class, _class2, _temp;
45
47
 
46
48
  var styles = {
47
- componentId: 'dsJBj',
49
+ componentId: 'elMgC',
48
50
  template: function template(theme) {
49
- return "\n\n.dsJBj_bGBk{background-clip:content-box;background-color:".concat(theme.background || 'inherit', ";background-position:50%;background-repeat:no-repeat;background-size:cover;box-sizing:border-box;height:2.5em;line-height:0;overflow:hidden;text-align:center}\n\n[dir=ltr] .dsJBj_bGBk,[dir=rtl] .dsJBj_bGBk{text-align:center}\n\n.dsJBj_bGBk.dsJBj_uUeq{font-size:inherit}\n\n.dsJBj_bGBk.dsJBj_uUeq,.dsJBj_bGBk.dsJBj_UKsG{border-width:").concat(theme.borderWidthSmall || 'inherit', "}\n\n.dsJBj_bGBk.dsJBj_UKsG{font-size:0.5rem}\n\n.dsJBj_bGBk.dsJBj_dfBC{font-size:0.75rem}\n\n.dsJBj_bGBk.dsJBj_doqw,.dsJBj_bGBk.dsJBj_dfBC{border-width:").concat(theme.borderWidthSmall || 'inherit', "}\n\n.dsJBj_bGBk.dsJBj_doqw{font-size:1rem}\n\n.dsJBj_bGBk.dsJBj_ycrn{font-size:1.25rem}\n\n.dsJBj_bGBk.dsJBj_cMDj,.dsJBj_bGBk.dsJBj_ycrn{border-width:").concat(theme.borderWidthMedium || 'inherit', "}\n\n.dsJBj_bGBk.dsJBj_cMDj{font-size:1.5rem}\n\n.dsJBj_bGBk.dsJBj_eoMd{font-size:1.75rem}\n\n.dsJBj_bGBk.dsJBj_eoMd,.dsJBj_bGBk.dsJBj_fdca{border-width:").concat(theme.borderWidthMedium || 'inherit', "}\n\n.dsJBj_bGBk.dsJBj_fdca{font-size:2rem}\n\n.dsJBj_bGBk.dsJBj_cHTY{border:0;box-shadow:inset 0 0 ").concat(theme.boxShadowBlur || 'inherit', " 0 ").concat(theme.boxShadowColor || 'inherit', "}\n\n.dsJBj_bGBk:not(.dsJBj_cHTY){border-color:").concat(theme.borderColor || 'inherit', ";border-style:solid}\n\n.dsJBj_eYKj{font-family:").concat(theme.fontFamily || 'inherit', ";font-weight:").concat(theme.fontWeight || 'inherit', ";letter-spacing:0.0313em;line-height:2.375em}\n\n.dsJBj_ddES .dsJBj_eYKj{color:").concat(theme.color || 'inherit', "}\n\n.dsJBj_ekuM .dsJBj_eYKj{color:").concat(theme.colorShamrock || 'inherit', "}\n\n.dsJBj_bXnN .dsJBj_eYKj{color:").concat(theme.colorBarney || 'inherit', "}\n\n.dsJBj_byip .dsJBj_eYKj{color:").concat(theme.colorCrimson || 'inherit', "}\n\n.dsJBj_dKVo .dsJBj_eYKj{color:").concat(theme.colorFire || 'inherit', "}\n\n.dsJBj_eaOe .dsJBj_eYKj{color:").concat(theme.colorLicorice || 'inherit', "}\n\n.dsJBj_fuVp .dsJBj_eYKj{color:").concat(theme.colorAsh || 'inherit', "}\n\n.dsJBj_MrJH{display:none}\n\n.dsJBj_cJVF{border-radius:100%;overflow:hidden;position:relative;width:2.5em}\n\n.dsJBj_bRWf{width:3em}");
51
+ return "\n\n.elMgC_bGBk{background-clip:content-box;background-color:".concat(theme.background || 'inherit', ";background-position:50%;background-repeat:no-repeat;background-size:cover;box-sizing:border-box;height:2.5em;line-height:0;overflow:hidden;text-align:center}\n\n[dir=ltr] .elMgC_bGBk,[dir=rtl] .elMgC_bGBk{text-align:center}\n\n.elMgC_bGBk.elMgC_uUeq{font-size:inherit}\n\n.elMgC_bGBk.elMgC_uUeq,.elMgC_bGBk.elMgC_UKsG{border-width:").concat(theme.borderWidthSmall || 'inherit', "}\n\n.elMgC_bGBk.elMgC_UKsG{font-size:0.5rem}\n\n.elMgC_bGBk.elMgC_dfBC{font-size:0.75rem}\n\n.elMgC_bGBk.elMgC_doqw,.elMgC_bGBk.elMgC_dfBC{border-width:").concat(theme.borderWidthSmall || 'inherit', "}\n\n.elMgC_bGBk.elMgC_doqw{font-size:1rem}\n\n.elMgC_bGBk.elMgC_ycrn{font-size:1.25rem}\n\n.elMgC_bGBk.elMgC_cMDj,.elMgC_bGBk.elMgC_ycrn{border-width:").concat(theme.borderWidthMedium || 'inherit', "}\n\n.elMgC_bGBk.elMgC_cMDj{font-size:1.5rem}\n\n.elMgC_bGBk.elMgC_eoMd{font-size:1.75rem}\n\n.elMgC_bGBk.elMgC_eoMd,.elMgC_bGBk.elMgC_fdca{border-width:").concat(theme.borderWidthMedium || 'inherit', "}\n\n.elMgC_bGBk.elMgC_fdca{font-size:2rem}\n\n.elMgC_bGBk.elMgC_cHTY{border:0;box-shadow:inset 0 0 ").concat(theme.boxShadowBlur || 'inherit', " 0 ").concat(theme.boxShadowColor || 'inherit', "}\n\n.elMgC_bGBk:not(.elMgC_cHTY){border-color:").concat(theme.borderColor || 'inherit', ";border-style:solid}\n\n.elMgC_bGBk:not(.elMgC_cHTY).elMgC_fKgA{background-clip:border-box;border:0;padding:0}\n\n.elMgC_bGBk:not(.elMgC_cHTY).elMgC_fKgA.elMgC_uUeq,.elMgC_bGBk:not(.elMgC_cHTY).elMgC_fKgA.elMgC_doqw,.elMgC_bGBk:not(.elMgC_cHTY).elMgC_fKgA.elMgC_dfBC,.elMgC_bGBk:not(.elMgC_cHTY).elMgC_fKgA.elMgC_UKsG{padding:").concat(theme.borderWidthSmall || 'inherit', "}\n\n.elMgC_bGBk:not(.elMgC_cHTY).elMgC_fKgA.elMgC_cMDj,.elMgC_bGBk:not(.elMgC_cHTY).elMgC_fKgA.elMgC_ycrn,.elMgC_bGBk:not(.elMgC_cHTY).elMgC_fKgA.elMgC_eoMd,.elMgC_bGBk:not(.elMgC_cHTY).elMgC_fKgA.elMgC_fdca{padding:").concat(theme.borderWidthMedium || 'inherit', "}\n\n.elMgC_eYKj{font-family:").concat(theme.fontFamily || 'inherit', ";font-weight:").concat(theme.fontWeight || 'inherit', ";letter-spacing:0.0313em;line-height:2.375em}\n\n.elMgC_ddES{color:").concat(theme.color || 'inherit', "}\n\n.elMgC_ekuM{color:").concat(theme.colorShamrock || 'inherit', "}\n\n.elMgC_bXnN{color:").concat(theme.colorBarney || 'inherit', "}\n\n.elMgC_byip{color:").concat(theme.colorCrimson || 'inherit', "}\n\n.elMgC_dKVo{color:").concat(theme.colorFire || 'inherit', "}\n\n.elMgC_eaOe{color:").concat(theme.colorLicorice || 'inherit', "}\n\n.elMgC_fuVp{color:").concat(theme.colorAsh || 'inherit', "}\n\n.elMgC_fKgA{color:").concat(theme.background || 'inherit', "}\n\n.elMgC_fKgA.elMgC_ddES{background-color:").concat(theme.color || 'inherit', "}\n\n.elMgC_fKgA.elMgC_ekuM{background-color:").concat(theme.colorShamrock || 'inherit', "}\n\n.elMgC_fKgA.elMgC_bXnN{background-color:").concat(theme.colorBarney || 'inherit', "}\n\n.elMgC_fKgA.elMgC_byip{background-color:").concat(theme.colorCrimson || 'inherit', "}\n\n.elMgC_fKgA.elMgC_dKVo{background-color:").concat(theme.colorFire || 'inherit', "}\n\n.elMgC_fKgA.elMgC_eaOe{background-color:").concat(theme.colorLicorice || 'inherit', "}\n\n.elMgC_fKgA.elMgC_fuVp{background-color:").concat(theme.colorAsh || 'inherit', "}\n\n.elMgC_MrJH{display:none}\n\n.elMgC_cJVF{border-radius:100%;overflow:hidden;position:relative;width:2.5em}\n\n.elMgC_bRWf{width:3em}\n\n.elMgC_eoCh{align-items:center;display:flex;height:100%;justify-content:center;width:100%}\n\n.elMgC_eoCh svg{fill:currentColor;height:1em;width:1em}");
50
52
  },
51
- 'root': 'dsJBj_bGBk',
52
- 'auto': 'dsJBj_uUeq',
53
- 'xx-small': 'dsJBj_UKsG',
54
- 'x-small': 'dsJBj_dfBC',
55
- 'small': 'dsJBj_doqw',
56
- 'medium': 'dsJBj_ycrn',
57
- 'large': 'dsJBj_cMDj',
58
- 'x-large': 'dsJBj_eoMd',
59
- 'xx-large': 'dsJBj_fdca',
60
- 'loaded': 'dsJBj_cHTY',
61
- 'initials': 'dsJBj_eYKj',
62
- 'default': 'dsJBj_ddES',
63
- 'shamrock': 'dsJBj_ekuM',
64
- 'barney': 'dsJBj_bXnN',
65
- 'crimson': 'dsJBj_byip',
66
- 'fire': 'dsJBj_dKVo',
67
- 'licorice': 'dsJBj_eaOe',
68
- 'ash': 'dsJBj_fuVp',
69
- 'loadImage': 'dsJBj_MrJH',
70
- 'circle': 'dsJBj_cJVF',
71
- 'rectangle': 'dsJBj_bRWf'
53
+ 'root': 'elMgC_bGBk',
54
+ 'auto': 'elMgC_uUeq',
55
+ 'xx-small': 'elMgC_UKsG',
56
+ 'x-small': 'elMgC_dfBC',
57
+ 'small': 'elMgC_doqw',
58
+ 'medium': 'elMgC_ycrn',
59
+ 'large': 'elMgC_cMDj',
60
+ 'x-large': 'elMgC_eoMd',
61
+ 'xx-large': 'elMgC_fdca',
62
+ 'loaded': 'elMgC_cHTY',
63
+ 'hasInverseColor': 'elMgC_fKgA',
64
+ 'initials': 'elMgC_eYKj',
65
+ 'default': 'elMgC_ddES',
66
+ 'shamrock': 'elMgC_ekuM',
67
+ 'barney': 'elMgC_bXnN',
68
+ 'crimson': 'elMgC_byip',
69
+ 'fire': 'elMgC_dKVo',
70
+ 'licorice': 'elMgC_eaOe',
71
+ 'ash': 'elMgC_fuVp',
72
+ 'loadImage': 'elMgC_MrJH',
73
+ 'circle': 'elMgC_cJVF',
74
+ 'rectangle': 'elMgC_bRWf',
75
+ 'iconSVG': 'elMgC_eoCh'
72
76
  };
73
77
 
74
78
  /**
@@ -110,6 +114,16 @@ var Avatar = (_dec = (0, _testable.testable)(), _dec2 = (0, _deprecated.deprecat
110
114
  }
111
115
 
112
116
  (0, _createClass2.default)(Avatar, [{
117
+ key: "componentDidUpdate",
118
+ value: function componentDidUpdate() {
119
+ // in case the image is unset in an update, show icons/initials again
120
+ if (this.state.loaded && !this.props.src) {
121
+ this.setState({
122
+ loaded: false
123
+ });
124
+ }
125
+ }
126
+ }, {
113
127
  key: "makeInitialsFromName",
114
128
  value: function makeInitialsFromName() {
115
129
  var name = this.props.name;
@@ -151,6 +165,19 @@ var Avatar = (_dec = (0, _testable.testable)(), _dec2 = (0, _deprecated.deprecat
151
165
  "aria-hidden": "true"
152
166
  }, this.makeInitialsFromName());
153
167
  }
168
+ }, {
169
+ key: "renderContent",
170
+ value: function renderContent() {
171
+ var renderIcon = this.props.renderIcon;
172
+
173
+ if (!renderIcon) {
174
+ return this.renderInitials();
175
+ }
176
+
177
+ return /*#__PURE__*/_react.default.createElement("span", {
178
+ className: styles.iconSVG
179
+ }, (0, _callRenderProp.callRenderProp)(renderIcon));
180
+ }
154
181
  }, {
155
182
  key: "render",
156
183
  value: function render() {
@@ -164,14 +191,14 @@ var Avatar = (_dec = (0, _testable.testable)(), _dec2 = (0, _deprecated.deprecat
164
191
  style: {
165
192
  backgroundImage: loaded ? "url('".concat(this.props.src, "')") : void 0
166
193
  },
167
- className: (0, _classnames2.default)((_classnames = {}, (0, _defineProperty2.default)(_classnames, styles.root, true), (0, _defineProperty2.default)(_classnames, styles[this.props.size], true), (0, _defineProperty2.default)(_classnames, styles[this.props.variant || this.props.shape], true), (0, _defineProperty2.default)(_classnames, styles[this.props.color], true), (0, _defineProperty2.default)(_classnames, styles.loaded, loaded), _classnames)),
194
+ className: (0, _classnames2.default)((_classnames = {}, (0, _defineProperty2.default)(_classnames, styles.root, true), (0, _defineProperty2.default)(_classnames, styles[this.props.size], true), (0, _defineProperty2.default)(_classnames, styles[this.props.variant || this.props.shape], true), (0, _defineProperty2.default)(_classnames, styles[this.props.color], true), (0, _defineProperty2.default)(_classnames, styles.loaded, loaded), (0, _defineProperty2.default)(_classnames, styles.hasInverseColor, this.props.hasInverseColor), _classnames)),
168
195
  "aria-label": this.props.alt ? this.props.alt : null,
169
196
  role: this.props.alt ? 'img' : null,
170
197
  as: this.props.as,
171
198
  elementRef: this.props.elementRef,
172
199
  margin: this.props.margin,
173
200
  display: this.props.display === 'block' || this.props.inline === false ? 'block' : 'inline-block'
174
- }), this.renderLoadImage(), !loaded && this.renderInitials());
201
+ }), this.renderLoadImage(), !loaded && this.renderContent());
175
202
  }
176
203
  }]);
177
204
  Avatar.displayName = "Avatar";
@@ -190,6 +217,11 @@ var Avatar = (_dec = (0, _testable.testable)(), _dec2 = (0, _deprecated.deprecat
190
217
  alt: _propTypes.default.string,
191
218
  size: _propTypes.default.oneOf(['auto', 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large']),
192
219
  color: _propTypes.default.oneOf(['default', 'shamrock', 'barney', 'crimson', 'fire', 'licorice', 'ash']),
220
+
221
+ /**
222
+ * In inverse color mode the background and text/icon colors are inverted
223
+ */
224
+ hasInverseColor: _propTypes.default.bool,
193
225
  shape: _propTypes.default.oneOf(['circle', 'rectangle']),
194
226
 
195
227
  /**
@@ -216,6 +248,11 @@ var Avatar = (_dec = (0, _testable.testable)(), _dec2 = (0, _deprecated.deprecat
216
248
  */
217
249
  elementRef: _propTypes.default.func,
218
250
 
251
+ /**
252
+ * An icon, or function that returns an icon that gets displayed. If the `src` prop is provided, `src` will have priority.
253
+ */
254
+ renderIcon: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.func]),
255
+
219
256
  /* eslint-disable react/require-default-props */
220
257
 
221
258
  /**
@@ -236,9 +273,11 @@ var Avatar = (_dec = (0, _testable.testable)(), _dec2 = (0, _deprecated.deprecat
236
273
  elementRef: void 0,
237
274
  size: 'medium',
238
275
  color: 'default',
276
+ hasInverseColor: false,
239
277
  shape: 'circle',
240
278
  display: 'inline-block',
241
- onImageLoaded: function onImageLoaded(event) {}
279
+ onImageLoaded: function onImageLoaded(event) {},
280
+ renderIcon: null
242
281
  }, _temp)) || _class) || _class) || _class);
243
282
  exports.Avatar = Avatar;
244
283
  var _default = Avatar;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instructure/ui-avatar",
3
- "version": "7.9.0",
3
+ "version": "7.13.0",
4
4
  "description": "An image or letters that represents a user.",
5
5
  "author": "Instructure, Inc. Engineering and Product Design",
6
6
  "type": "commonjs",
@@ -24,19 +24,20 @@
24
24
  "license": "MIT",
25
25
  "dependencies": {
26
26
  "@babel/runtime": "^7.9.2",
27
- "@instructure/console": "^7.9.0",
28
- "@instructure/ui-react-utils": "^7.9.0",
29
- "@instructure/ui-testable": "^7.9.0",
30
- "@instructure/ui-themeable": "^7.9.0",
31
- "@instructure/ui-view": "^7.9.0",
27
+ "@instructure/console": "^7.13.0",
28
+ "@instructure/ui-icons": "^7.13.0",
29
+ "@instructure/ui-react-utils": "^7.13.0",
30
+ "@instructure/ui-testable": "^7.13.0",
31
+ "@instructure/ui-themeable": "^7.13.0",
32
+ "@instructure/ui-view": "^7.13.0",
32
33
  "classnames": "^2",
33
34
  "prop-types": "^15"
34
35
  },
35
36
  "devDependencies": {
36
- "@instructure/ui-babel-preset": "^7.9.0",
37
- "@instructure/ui-color-utils": "^7.9.0",
38
- "@instructure/ui-test-locator": "^7.9.0",
39
- "@instructure/ui-test-utils": "^7.9.0"
37
+ "@instructure/ui-babel-preset": "^7.13.0",
38
+ "@instructure/ui-color-utils": "^7.13.0",
39
+ "@instructure/ui-test-locator": "^7.13.0",
40
+ "@instructure/ui-test-utils": "^7.13.0"
40
41
  },
41
42
  "peerDependencies": {
42
43
  "react": "^16.8"
@@ -15,7 +15,11 @@ guidelines: true
15
15
  </Guidelines>
16
16
  ```
17
17
 
18
- When an image src is not supplied the user's initials will display. The avatar can be `circle` _(default)_ or `rectangle`. Use the `margin` prop to add space between Avatar and other content.
18
+ The avatar component can be used to display a user's avatar. When an image src is not supplied the user's initials will display.
19
+
20
+ Instead of the initials, an SVG icon can be displayed with the `renderIcon` property.
21
+
22
+ The avatar can be `circle` _(default)_ or `rectangle`. Use the `margin` prop to add space between Avatar and other content.
19
23
 
20
24
  ```js
21
25
  ---
@@ -24,8 +28,9 @@ example: true
24
28
  <div>
25
29
  <Avatar name="Sarah Robinson" src={avatarSquare} margin="0 small 0 0" />
26
30
  <Avatar name="Sarah Robinson" margin="0 small 0 0" />
27
- <Avatar name="Kyle Montgomery" src={avatarSquare} shape="rectangle" margin="0 small 0 0" />
28
- <Avatar name="Kyle Montgomery" shape="rectangle" />
31
+ <Avatar name="Sarah Robinson" renderIcon={<IconGroupLine />} margin="0 small 0 0" />
32
+ <Avatar name="Kyle Montgomery" src={avatarSquare} shape="rectangle" margin="0 small 0 0" /> <Avatar name="Kyle Montgomery" shape="rectangle" margin="0 small 0 0" />
33
+ <Avatar name="Kyle Montgomery" renderIcon={<IconGroupLine />} shape="rectangle" />
29
34
  </div>
30
35
  ```
31
36
 
@@ -56,25 +61,75 @@ example: true
56
61
  <Avatar name="David Herbert" size="x-large" margin="0 small 0 0" src={avatarSquare} />
57
62
  <Avatar name="Isaac Asimov" size="xx-large" src={avatarSquare} />
58
63
  </View>
64
+ <View display="block" padding="small medium">
65
+ <Avatar name="Arthur C. Clarke" renderIcon={<IconGroupLine />} size="xx-small" margin="0 small 0 0" />
66
+ <Avatar name="James Arias" renderIcon={<IconGroupLine />} size="x-small" margin="0 small 0 0" />
67
+ <Avatar name="Charles Kimball" renderIcon={<IconGroupLine />} size="small" margin="0 small 0 0" />
68
+ <Avatar name="Melissa Reed" renderIcon={<IconGroupLine />} size="medium" margin="0 small 0 0" />
69
+ <Avatar name="Heather Wheeler" renderIcon={<IconGroupLine />} size="large" margin="0 small 0 0" />
70
+ <Avatar name="David Herbert" renderIcon={<IconGroupLine />} size="x-large" margin="0 small 0 0" />
71
+ <Avatar name="Isaac Asimov" renderIcon={<IconGroupLine />} size="xx-large" />
72
+ </View>
73
+ </div>
74
+ ```
75
+
76
+ ### Colors
77
+
78
+ The color of the initials and icons can be set with the `color` prop, and it allows you to select from `default`, `shamrock`, `barney`, `crimson`, `fire`, `licorice` and `ash`.
79
+
80
+ ```js
81
+ ---
82
+ example: true
83
+ ---
84
+ <div>
85
+ <View display="block" padding="small medium">
86
+ <Avatar name="Arthur C. Clarke" margin="0 small 0 0" />
87
+ <Avatar name="James Arias" color="shamrock" margin="0 small 0 0" />
88
+ <Avatar name="Charles Kimball" color="barney" margin="0 small 0 0" />
89
+ <Avatar name="Melissa Reed" color="crimson" margin="0 small 0 0" />
90
+ <Avatar name="Heather Wheeler" color="fire" margin="0 small 0 0" />
91
+ <Avatar name="David Herbert" color="licorice" margin="0 small 0 0" />
92
+ <Avatar name="Isaac Asimov" color="ash" />
93
+ </View>
94
+ <View display="block" padding="small medium">
95
+ <Avatar renderIcon={<IconGroupLine />} name="Arthur C. Clarke" margin="0 small 0 0" />
96
+ <Avatar renderIcon={<IconGroupLine />} name="James Arias" color="shamrock" margin="0 small 0 0" />
97
+ <Avatar renderIcon={<IconGroupLine />} name="Charles Kimball" color="barney" margin="0 small 0 0" />
98
+ <Avatar renderIcon={<IconGroupLine />} name="Melissa Reed" color="crimson" margin="0 small 0 0" />
99
+ <Avatar renderIcon={<IconGroupLine />} name="Heather Wheeler" color="fire" margin="0 small 0 0" />
100
+ <Avatar renderIcon={<IconGroupLine />} name="David Herbert" color="licorice" margin="0 small 0 0" />
101
+ <Avatar renderIcon={<IconGroupLine />} name="Isaac Asimov" color="ash" />
102
+ </View>
59
103
  </div>
60
104
  ```
61
105
 
62
- ### Color of the initials
106
+ The `hasInverseColor` prop inverts the background color and the text/icon color.
63
107
 
64
- The color of the initials can be set with the `color` prop, and it allows you to select from `default`, `shamrock`, `barney`, `crimson`, `fire`, `licorice` and `ash`.
108
+ Inverted Avatars have **no border**.
65
109
 
66
110
  ```js
67
111
  ---
68
112
  example: true
69
113
  ---
70
114
  <div>
71
- <Avatar name="Arthur C. Clarke" margin="0 small 0 0" />
72
- <Avatar name="James Arias" color="shamrock" margin="0 small 0 0" />
73
- <Avatar name="Charles Kimball" color="barney" margin="0 small 0 0" />
74
- <Avatar name="Melissa Reed" color="crimson" margin="0 small 0 0" />
75
- <Avatar name="Heather Wheeler" color="fire" margin="0 small 0 0" />
76
- <Avatar name="David Herbert" color="licorice" margin="0 small 0 0" />
77
- <Avatar name="Isaac Asimov" color="ash" />
115
+ <View display="block" padding="small medium" background="primary">
116
+ <Avatar name="Arthur C. Clarke" hasInverseColor margin="0 small 0 0" />
117
+ <Avatar name="James Arias" color="shamrock" hasInverseColor margin="0 small 0 0" />
118
+ <Avatar name="Charles Kimball" color="barney" hasInverseColor margin="0 small 0 0" />
119
+ <Avatar name="Melissa Reed" color="crimson" hasInverseColor margin="0 small 0 0" />
120
+ <Avatar name="Heather Wheeler" color="fire" hasInverseColor margin="0 small 0 0" />
121
+ <Avatar name="David Herbert" color="licorice" hasInverseColor margin="0 small 0 0" />
122
+ <Avatar name="Isaac Asimov" color="ash" hasInverseColor />
123
+ </View>
124
+ <View display="block" padding="small medium" background="primary">
125
+ <Avatar renderIcon={<IconGroupLine />} name="Arthur C. Clarke" hasInverseColor margin="0 small 0 0" />
126
+ <Avatar renderIcon={<IconGroupLine />} name="James Arias" color="shamrock" hasInverseColor margin="0 small 0 0" />
127
+ <Avatar renderIcon={<IconGroupLine />} name="Charles Kimball" color="barney" hasInverseColor margin="0 small 0 0" />
128
+ <Avatar renderIcon={<IconGroupLine />} name="Melissa Reed" color="crimson" hasInverseColor margin="0 small 0 0" />
129
+ <Avatar renderIcon={<IconGroupLine />} name="Heather Wheeler" color="fire" hasInverseColor margin="0 small 0 0" />
130
+ <Avatar renderIcon={<IconGroupLine />} name="David Herbert" color="licorice" hasInverseColor margin="0 small 0 0" />
131
+ <Avatar renderIcon={<IconGroupLine />} name="Isaac Asimov" color="ash" hasInverseColor />
132
+ </View>
78
133
  </div>
79
134
  ```
80
135
 
@@ -85,8 +140,10 @@ In case you need more control over the color, feel free to use the `theme` prop,
85
140
  example: true
86
141
  ---
87
142
  <div>
88
- <Avatar name="Isaac Asimov" theme={{ color: '#efb410' }} margin="0 small 0 0" />
89
- <Avatar name="Heather Wheeler" color="fire" theme={{ colorFire: 'magenta' }} />
143
+ <Avatar name="Isaac Asimov" renderIcon={<IconGroupLine />} theme={{ color: '#efb410' }} margin="0 small 0 0" />
144
+ <Avatar name="Heather Wheeler" color="fire" theme={{ colorFire: 'magenta' }} margin="0 small 0 0" />
145
+ <Avatar name="Charles Kimball" renderIcon={<IconGroupLine />} hasInverseColor theme={{ color: 'lightblue', background: 'black' }} margin="0 small 0 0" />
146
+ <Avatar name="David Herbert" hasInverseColor color="fire" theme={{ colorFire: '#efb410' }} />
90
147
  </div>
91
148
  ```
92
149
 
@@ -21,13 +21,41 @@
21
21
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
22
  * SOFTWARE.
23
23
  */
24
+
25
+ import React from 'react'
26
+
27
+ import { IconGroupLine } from '@instructure/ui-icons'
28
+
24
29
  export default {
25
30
  excludeProps: ['inline', 'variant'],
26
31
  sectionProp: 'shape',
27
32
  propValues: {
28
- src: [null, require('./testImage.jpg')]
33
+ src: [null, require('./testImage.jpg')],
34
+ renderIcon: [undefined, <IconGroupLine key="icon" />]
29
35
  },
30
- getComponentProps: (props) => {
36
+ filter: (props) => {
37
+ if (props.color !== 'default' && props.size !== 'medium') {
38
+ return true
39
+ }
40
+
41
+ if (props.renderIcon && props.src) {
42
+ return true
43
+ }
44
+
45
+ if (props.src && props.color !== 'default') {
46
+ return true
47
+ }
48
+
49
+ if (
50
+ props.hasInverseColor &&
51
+ (props.size !== 'medium' || props.display !== 'block')
52
+ ) {
53
+ return true
54
+ }
55
+
56
+ return false
57
+ },
58
+ getComponentProps: () => {
31
59
  return {
32
60
  name: 'Kyle Montgomery'
33
61
  }
@@ -27,7 +27,11 @@ import classnames from 'classnames'
27
27
 
28
28
  import { View } from '@instructure/ui-view'
29
29
  import { themeable, ThemeablePropTypes } from '@instructure/ui-themeable'
30
- import { passthroughProps, deprecated } from '@instructure/ui-react-utils'
30
+ import {
31
+ passthroughProps,
32
+ deprecated,
33
+ callRenderProp
34
+ } from '@instructure/ui-react-utils'
31
35
  import { testable } from '@instructure/ui-testable'
32
36
 
33
37
  import styles from './styles.css'
@@ -75,6 +79,10 @@ class Avatar extends Component {
75
79
  'licorice',
76
80
  'ash'
77
81
  ]),
82
+ /**
83
+ * In inverse color mode the background and text/icon colors are inverted
84
+ */
85
+ hasInverseColor: PropTypes.bool,
78
86
  shape: PropTypes.oneOf(['circle', 'rectangle']),
79
87
  /**
80
88
  * Valid values are `0`, `none`, `auto`, `xxx-small`, `xx-small`, `x-small`,
@@ -95,6 +103,11 @@ class Avatar extends Component {
95
103
  * provides a reference to the underlying html element
96
104
  */
97
105
  elementRef: PropTypes.func,
106
+ /**
107
+ * An icon, or function that returns an icon that gets displayed. If the `src` prop is provided, `src` will have priority.
108
+ */
109
+ renderIcon: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
110
+
98
111
  /* eslint-disable react/require-default-props */
99
112
  /**
100
113
  * __Deprecated - use `display`__
@@ -114,13 +127,22 @@ class Avatar extends Component {
114
127
  elementRef: undefined,
115
128
  size: 'medium',
116
129
  color: 'default',
130
+ hasInverseColor: false,
117
131
  shape: 'circle',
118
132
  display: 'inline-block',
119
- onImageLoaded: (event) => {}
133
+ onImageLoaded: (event) => {},
134
+ renderIcon: null
120
135
  }
121
136
 
122
137
  state = { loaded: false }
123
138
 
139
+ componentDidUpdate() {
140
+ // in case the image is unset in an update, show icons/initials again
141
+ if (this.state.loaded && !this.props.src) {
142
+ this.setState({ loaded: false })
143
+ }
144
+ }
145
+
124
146
  makeInitialsFromName() {
125
147
  let name = this.props.name
126
148
 
@@ -166,6 +188,16 @@ class Avatar extends Component {
166
188
  )
167
189
  }
168
190
 
191
+ renderContent() {
192
+ const { renderIcon } = this.props
193
+
194
+ if (!renderIcon) {
195
+ return this.renderInitials()
196
+ }
197
+
198
+ return <span className={styles.iconSVG}>{callRenderProp(renderIcon)}</span>
199
+ }
200
+
169
201
  render() {
170
202
  const { onImageLoaded, ...props } = this.props
171
203
  const { loaded } = this.state
@@ -181,7 +213,8 @@ class Avatar extends Component {
181
213
  [styles[this.props.size]]: true,
182
214
  [styles[this.props.variant || this.props.shape]]: true,
183
215
  [styles[this.props.color]]: true,
184
- [styles.loaded]: loaded
216
+ [styles.loaded]: loaded,
217
+ [styles.hasInverseColor]: this.props.hasInverseColor
185
218
  })}
186
219
  aria-label={this.props.alt ? this.props.alt : null}
187
220
  role={this.props.alt ? 'img' : null}
@@ -195,7 +228,7 @@ class Avatar extends Component {
195
228
  }
196
229
  >
197
230
  {this.renderLoadImage()}
198
- {!loaded && this.renderInitials()}
231
+ {!loaded && this.renderContent()}
199
232
  </View>
200
233
  )
201
234
  }
@@ -79,44 +79,118 @@
79
79
  box-shadow: inset 0 0 var(--boxShadowBlur) 0 var(--boxShadowColor);
80
80
  }
81
81
 
82
+ /* stylelint-disable max-nesting-depth, selector-max-class */
83
+
82
84
  &:not(.loaded) {
83
85
  border-style: solid;
84
86
  border-color: var(--borderColor);
87
+
88
+ &.hasInverseColor {
89
+ border: 0;
90
+ padding: 0;
91
+ background-clip: border-box;
92
+
93
+ &.auto {
94
+ padding: var(--borderWidthSmall);
95
+ }
96
+
97
+ &.xx-small {
98
+ padding: var(--borderWidthSmall);
99
+ }
100
+
101
+ &.x-small {
102
+ padding: var(--borderWidthSmall);
103
+ }
104
+
105
+ &.small {
106
+ padding: var(--borderWidthSmall);
107
+ }
108
+
109
+ &.medium {
110
+ padding: var(--borderWidthMedium);
111
+ }
112
+
113
+ &.large {
114
+ padding: var(--borderWidthMedium);
115
+ }
116
+
117
+ &.x-large {
118
+ padding: var(--borderWidthMedium);
119
+ }
120
+
121
+ &.xx-large {
122
+ padding: var(--borderWidthMedium);
123
+ }
124
+ }
85
125
  }
86
126
  }
87
127
 
128
+ /* stylelint-enable max-nesting-depth, selector-max-class */
129
+
88
130
  .initials {
89
131
  line-height: 2.375em;
90
132
  font-family: var(--fontFamily);
91
133
  font-weight: var(--fontWeight);
92
134
  letter-spacing: 0.0313em;
135
+ }
136
+
137
+ .default {
138
+ color: var(--color);
139
+ }
140
+
141
+ .shamrock {
142
+ color: var(--colorShamrock);
143
+ }
93
144
 
94
- .default & {
95
- color: var(--color);
145
+ .barney {
146
+ color: var(--colorBarney);
147
+ }
148
+
149
+ .crimson {
150
+ color: var(--colorCrimson);
151
+ }
152
+
153
+ .fire {
154
+ color: var(--colorFire);
155
+ }
156
+
157
+ .licorice {
158
+ color: var(--colorLicorice);
159
+ }
160
+
161
+ .ash {
162
+ color: var(--colorAsh);
163
+ }
164
+
165
+ .hasInverseColor {
166
+ color: var(--background);
167
+
168
+ &.default {
169
+ background-color: var(--color);
96
170
  }
97
171
 
98
- .shamrock & {
99
- color: var(--colorShamrock);
172
+ &.shamrock {
173
+ background-color: var(--colorShamrock);
100
174
  }
101
175
 
102
- .barney & {
103
- color: var(--colorBarney);
176
+ &.barney {
177
+ background-color: var(--colorBarney);
104
178
  }
105
179
 
106
- .crimson & {
107
- color: var(--colorCrimson);
180
+ &.crimson {
181
+ background-color: var(--colorCrimson);
108
182
  }
109
183
 
110
- .fire & {
111
- color: var(--colorFire);
184
+ &.fire {
185
+ background-color: var(--colorFire);
112
186
  }
113
187
 
114
- .licorice & {
115
- color: var(--colorLicorice);
188
+ &.licorice {
189
+ background-color: var(--colorLicorice);
116
190
  }
117
191
 
118
- .ash & {
119
- color: var(--colorAsh);
192
+ &.ash {
193
+ background-color: var(--colorAsh);
120
194
  }
121
195
  }
122
196
 
@@ -134,3 +208,18 @@
134
208
  .rectangle {
135
209
  width: 3em;
136
210
  }
211
+
212
+ .iconSVG {
213
+ display: flex;
214
+ align-items: center;
215
+ justify-content: center;
216
+ height: 100%;
217
+ width: 100%;
218
+
219
+ /* stylelint-disable-next-line selector-max-type */
220
+ svg {
221
+ fill: currentColor;
222
+ height: 1em;
223
+ width: 1em;
224
+ }
225
+ }
package/types/index.d.ts CHANGED
@@ -8,6 +8,8 @@ export type AvatarShape = "circle" | "rectangle";
8
8
 
9
9
  export type AvatarDisplay = "inline-block" | "block";
10
10
 
11
+ export type AvatarRenderIcon = React.ReactNode | ((...args: any[])=>any);
12
+
11
13
  export type AvatarVariant = "circle" | "rectangle";
12
14
 
13
15
  export interface AvatarProps {
@@ -22,6 +24,10 @@ export interface AvatarProps {
22
24
  alt?: string;
23
25
  size?: AvatarSize;
24
26
  color?: AvatarColor;
27
+ /**
28
+ * In inverse color mode the background and text/icon colors are inverted
29
+ */
30
+ hasInverseColor?: boolean;
25
31
  shape?: AvatarShape;
26
32
  /**
27
33
  * Valid values are `0`, `none`, `auto`, `xxx-small`, `xx-small`, `x-small`,
@@ -39,6 +45,10 @@ export interface AvatarProps {
39
45
  */
40
46
  as?: any;
41
47
  elementRef?: (...args: any[])=>any;
48
+ /**
49
+ * An icon, or function that returns an icon that gets displayed. If the `src` prop is provided, `src` will have priority.
50
+ */
51
+ renderIcon?: AvatarRenderIcon;
42
52
  /**
43
53
  * eslint-disable react/require-default-props
44
54
  */