@veracity/vui 2.15.1 → 2.15.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"avatar.d.ts","sourceRoot":"","sources":["../../../src/avatar/avatar.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAY5C,eAAO,MAAM,UAAU,gIAoBtB,CAAA;AAED,kEAAkE;AAClE,eAAO,MAAM,MAAM,qDA8DjB,CAAA;AAGF,eAAe,MAAM,CAAA"}
1
+ {"version":3,"file":"avatar.d.ts","sourceRoot":"","sources":["../../../src/avatar/avatar.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAG5C,eAAO,MAAM,UAAU,gIAoBtB,CAAA;AAED,kEAAkE;AAClE,eAAO,MAAM,MAAM,qDA8DjB,CAAA;AAsCF,eAAe,MAAM,CAAA"}
@@ -1,4 +1,27 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __rest = (this && this.__rest) || function (s, e) {
3
26
  var t = {};
4
27
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
@@ -15,18 +38,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
15
38
  };
16
39
  Object.defineProperty(exports, "__esModule", { value: true });
17
40
  exports.Avatar = exports.AvatarBase = void 0;
18
- const react_1 = __importDefault(require("react"));
41
+ const react_1 = __importStar(require("react"));
19
42
  const core_1 = require("../core");
20
43
  const icon_1 = __importDefault(require("../icon"));
21
44
  const image_1 = __importDefault(require("../image"));
22
45
  const utils_1 = require("../utils");
46
+ const images_1 = require("../utils/images");
23
47
  const helpers_1 = require("./helpers");
24
- function imageExists(image_url) {
25
- const http = new XMLHttpRequest();
26
- http.open('HEAD', image_url, false);
27
- http.send();
28
- return http.status !== 404;
29
- }
30
48
  exports.AvatarBase = core_1.styled.spanBox `
31
49
  align-items: center;
32
50
  display: inline-flex;
@@ -54,7 +72,6 @@ exports.Avatar = (0, core_1.vui)((props, ref) => {
54
72
  const _b = (0, core_1.useStyleConfig)('Avatar', props), { activeBg, h, hoverBg, iconSize } = _b, styles = __rest(_b, ["activeBg", "h", "hoverBg", "iconSize"]);
55
73
  const borderRadius = isSquare ? (props.size === 'sm' ? '3px' : '6px') : '50%';
56
74
  const initials = getInitials(name);
57
- const internalIcon = src && !imageExists(src) ? 'falUser' : icon;
58
75
  const interactiveProps = !disabled && isInteractive
59
76
  ? {
60
77
  cursor: 'pointer',
@@ -71,7 +88,21 @@ exports.Avatar = (0, core_1.vui)((props, ref) => {
71
88
  borderRadius: borderRadius,
72
89
  'aria-disabled': disabled
73
90
  });
74
- return (react_1.default.createElement(exports.AvatarBase, Object.assign({ borderRadius: borderRadius, className: (0, utils_1.cs)('vui-avatar', className), h: h, ref: ref, w: h }, styles, interactiveProps, aliasedProps, rest), children ? (children) : src && imageExists(src) ? (react_1.default.createElement(image_1.default, Object.assign({}, { borderRadius, src }))) : internalIcon ? (react_1.default.createElement(icon_1.default, { name: internalIcon, size: iconSize })) : initials ? (initials) : null));
91
+ return (react_1.default.createElement(exports.AvatarBase, Object.assign({ borderRadius: borderRadius, className: (0, utils_1.cs)('vui-avatar', className), h: h, ref: ref, w: h }, styles, interactiveProps, aliasedProps, rest), children ? (children) : src ? (react_1.default.createElement(LazyImageOrDefault, { borderRadius: borderRadius, icon: icon, iconSize: iconSize, initials: initials, src: src })) : icon ? (react_1.default.createElement(icon_1.default, { name: icon, size: iconSize })) : initials ? (initials) : (react_1.default.createElement(icon_1.default, { name: "falUser", size: iconSize }))));
75
92
  });
93
+ function LazyImageOrDefault({ src, borderRadius, icon, iconSize, initials }) {
94
+ const [imgLoaded, setImgLoaded] = (0, react_1.useState)(false);
95
+ (0, react_1.useEffect)(() => {
96
+ let cancelled = false;
97
+ (0, images_1.loadImageUrl)(src).then(res => {
98
+ if (!cancelled)
99
+ setImgLoaded(res);
100
+ });
101
+ return () => {
102
+ cancelled = true;
103
+ };
104
+ }, [src]);
105
+ return imgLoaded ? (react_1.default.createElement(image_1.default, { borderRadius: borderRadius, src: src })) : icon ? (react_1.default.createElement(icon_1.default, { name: icon, size: iconSize })) : initials ? (react_1.default.createElement(react_1.default.Fragment, null, "initials")) : (react_1.default.createElement(icon_1.default, { name: "falUser", size: iconSize }));
106
+ }
76
107
  exports.Avatar.displayName = 'Avatar';
77
108
  exports.default = exports.Avatar;
@@ -0,0 +1,3 @@
1
+ /** Attempts to load the image and returns a boolean indicating success or not. */
2
+ export declare function loadImageUrl(url: string): Promise<boolean>;
3
+ //# sourceMappingURL=images.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"images.d.ts","sourceRoot":"","sources":["../../../src/utils/images.ts"],"names":[],"mappings":"AAEA,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,oBAgBvC"}
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadImageUrl = void 0;
4
+ const loadImagePromises = new Map();
5
+ /** Attempts to load the image and returns a boolean indicating success or not. */
6
+ function loadImageUrl(url) {
7
+ let promise = loadImagePromises.get(url);
8
+ if (promise)
9
+ return promise;
10
+ promise = new Promise(resolve => {
11
+ const img = new Image();
12
+ img.onload = () => {
13
+ // After this event occurs, you can use the url in the DOM. The browser will not make another request for the image; there will be no delay.
14
+ resolve(true);
15
+ };
16
+ img.onerror = () => {
17
+ resolve(false);
18
+ };
19
+ img.src = url;
20
+ });
21
+ loadImagePromises.set(url, promise);
22
+ return promise;
23
+ }
24
+ exports.loadImageUrl = loadImageUrl;
@@ -1 +1 @@
1
- {"version":3,"file":"avatar.d.ts","sourceRoot":"","sources":["../../../src/avatar/avatar.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAY5C,eAAO,MAAM,UAAU,gIAoBtB,CAAA;AAED,kEAAkE;AAClE,eAAO,MAAM,MAAM,qDA8DjB,CAAA;AAGF,eAAe,MAAM,CAAA"}
1
+ {"version":3,"file":"avatar.d.ts","sourceRoot":"","sources":["../../../src/avatar/avatar.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAG5C,eAAO,MAAM,UAAU,gIAoBtB,CAAA;AAED,kEAAkE;AAClE,eAAO,MAAM,MAAM,qDA8DjB,CAAA;AAsCF,eAAe,MAAM,CAAA"}
@@ -1,15 +1,10 @@
1
- import React from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import { omitThemingProps, styled, useStyleConfig, vui } from '../core';
3
3
  import Icon from '../icon';
4
4
  import Image from '../image';
5
5
  import { cs, filterUndefined } from '../utils';
6
+ import { loadImageUrl } from '../utils/images';
6
7
  import { defaultGetInitials } from './helpers';
7
- function imageExists(image_url) {
8
- const http = new XMLHttpRequest();
9
- http.open('HEAD', image_url, false);
10
- http.send();
11
- return http.status !== 404;
12
- }
13
8
  export const AvatarBase = styled.spanBox `
14
9
  align-items: center;
15
10
  display: inline-flex;
@@ -37,7 +32,6 @@ export const Avatar = vui((props, ref) => {
37
32
  const { activeBg, h, hoverBg, iconSize, ...styles } = useStyleConfig('Avatar', props);
38
33
  const borderRadius = isSquare ? (props.size === 'sm' ? '3px' : '6px') : '50%';
39
34
  const initials = getInitials(name);
40
- const internalIcon = src && !imageExists(src) ? 'falUser' : icon;
41
35
  const interactiveProps = !disabled && isInteractive
42
36
  ? {
43
37
  cursor: 'pointer',
@@ -54,7 +48,21 @@ export const Avatar = vui((props, ref) => {
54
48
  borderRadius: borderRadius,
55
49
  'aria-disabled': disabled
56
50
  });
57
- return (React.createElement(AvatarBase, { borderRadius: borderRadius, className: cs('vui-avatar', className), h: h, ref: ref, w: h, ...styles, ...interactiveProps, ...aliasedProps, ...rest }, children ? (children) : src && imageExists(src) ? (React.createElement(Image, { ...{ borderRadius, src } })) : internalIcon ? (React.createElement(Icon, { name: internalIcon, size: iconSize })) : initials ? (initials) : null));
51
+ return (React.createElement(AvatarBase, { borderRadius: borderRadius, className: cs('vui-avatar', className), h: h, ref: ref, w: h, ...styles, ...interactiveProps, ...aliasedProps, ...rest }, children ? (children) : src ? (React.createElement(LazyImageOrDefault, { borderRadius: borderRadius, icon: icon, iconSize: iconSize, initials: initials, src: src })) : icon ? (React.createElement(Icon, { name: icon, size: iconSize })) : initials ? (initials) : (React.createElement(Icon, { name: "falUser", size: iconSize }))));
58
52
  });
53
+ function LazyImageOrDefault({ src, borderRadius, icon, iconSize, initials }) {
54
+ const [imgLoaded, setImgLoaded] = useState(false);
55
+ useEffect(() => {
56
+ let cancelled = false;
57
+ loadImageUrl(src).then(res => {
58
+ if (!cancelled)
59
+ setImgLoaded(res);
60
+ });
61
+ return () => {
62
+ cancelled = true;
63
+ };
64
+ }, [src]);
65
+ return imgLoaded ? (React.createElement(Image, { borderRadius: borderRadius, src: src })) : icon ? (React.createElement(Icon, { name: icon, size: iconSize })) : initials ? (React.createElement(React.Fragment, null, "initials")) : (React.createElement(Icon, { name: "falUser", size: iconSize }));
66
+ }
59
67
  Avatar.displayName = 'Avatar';
60
68
  export default Avatar;
@@ -0,0 +1,3 @@
1
+ /** Attempts to load the image and returns a boolean indicating success or not. */
2
+ export declare function loadImageUrl(url: string): Promise<boolean>;
3
+ //# sourceMappingURL=images.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"images.d.ts","sourceRoot":"","sources":["../../../src/utils/images.ts"],"names":[],"mappings":"AAEA,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,oBAgBvC"}
@@ -0,0 +1,20 @@
1
+ const loadImagePromises = new Map();
2
+ /** Attempts to load the image and returns a boolean indicating success or not. */
3
+ export function loadImageUrl(url) {
4
+ let promise = loadImagePromises.get(url);
5
+ if (promise)
6
+ return promise;
7
+ promise = new Promise(resolve => {
8
+ const img = new Image();
9
+ img.onload = () => {
10
+ // After this event occurs, you can use the url in the DOM. The browser will not make another request for the image; there will be no delay.
11
+ resolve(true);
12
+ };
13
+ img.onerror = () => {
14
+ resolve(false);
15
+ };
16
+ img.src = url;
17
+ });
18
+ loadImagePromises.set(url, promise);
19
+ return promise;
20
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veracity/vui",
3
- "version": "2.15.1",
3
+ "version": "2.15.2",
4
4
  "description": "Veracity UI is a React component library crafted for use within Veracity applications and pages. Based on Styled Components and @xstyled.",
5
5
  "module": "./dist/esm/index.js",
6
6
  "main": "./dist/cjs/index.js",
@@ -1,21 +1,13 @@
1
- import React from 'react'
1
+ import React, { useEffect, useState } from 'react'
2
2
 
3
3
  import { omitThemingProps, styled, useStyleConfig, vui } from '../core'
4
- import Icon from '../icon'
4
+ import Icon, { IconProp, IconProps } from '../icon'
5
5
  import Image from '../image'
6
6
  import { cs, filterUndefined } from '../utils'
7
+ import { loadImageUrl } from '../utils/images'
7
8
  import { AvatarProps } from './avatar.types'
8
9
  import { defaultGetInitials } from './helpers'
9
10
 
10
- function imageExists(image_url: string) {
11
- const http = new XMLHttpRequest()
12
-
13
- http.open('HEAD', image_url, false)
14
- http.send()
15
-
16
- return http.status !== 404
17
- }
18
-
19
11
  export const AvatarBase = styled.spanBox`
20
12
  align-items: center;
21
13
  display: inline-flex;
@@ -57,8 +49,6 @@ export const Avatar = vui<'span', AvatarProps>((props, ref) => {
57
49
  const borderRadius = isSquare ? (props.size === 'sm' ? '3px' : '6px') : '50%'
58
50
  const initials = getInitials(name)
59
51
 
60
- const internalIcon = src && !imageExists(src) ? 'falUser' : icon
61
-
62
52
  const interactiveProps =
63
53
  !disabled && isInteractive
64
54
  ? ({
@@ -92,16 +82,53 @@ export const Avatar = vui<'span', AvatarProps>((props, ref) => {
92
82
  >
93
83
  {children ? (
94
84
  children
95
- ) : src && imageExists(src) ? (
96
- <Image {...{ borderRadius, src }} />
97
- ) : internalIcon ? (
98
- <Icon name={internalIcon} size={iconSize} />
85
+ ) : src ? (
86
+ <LazyImageOrDefault borderRadius={borderRadius} icon={icon} iconSize={iconSize} initials={initials} src={src} />
87
+ ) : icon ? (
88
+ <Icon name={icon} size={iconSize} />
99
89
  ) : initials ? (
100
90
  initials
101
- ) : null}
91
+ ) : (
92
+ <Icon name="falUser" size={iconSize} />
93
+ )}
102
94
  </AvatarBase>
103
95
  )
104
96
  })
105
97
 
98
+ function LazyImageOrDefault({
99
+ src,
100
+ borderRadius,
101
+ icon,
102
+ iconSize,
103
+ initials
104
+ }: {
105
+ src: string
106
+ borderRadius: string
107
+ icon: IconProp | undefined
108
+ iconSize: IconProps['size']
109
+ initials: string
110
+ }) {
111
+ const [imgLoaded, setImgLoaded] = useState(false)
112
+ useEffect(() => {
113
+ let cancelled = false
114
+ loadImageUrl(src).then(res => {
115
+ if (!cancelled) setImgLoaded(res)
116
+ })
117
+ return () => {
118
+ cancelled = true
119
+ }
120
+ }, [src])
121
+
122
+ return imgLoaded ? (
123
+ <Image borderRadius={borderRadius} src={src} />
124
+ ) : icon ? (
125
+ <Icon name={icon} size={iconSize} />
126
+ ) : initials ? (
127
+ <>initials</>
128
+ ) : (
129
+ <Icon name="falUser" size={iconSize} />
130
+ )
131
+ }
132
+
106
133
  Avatar.displayName = 'Avatar'
107
134
  export default Avatar
@@ -0,0 +1,20 @@
1
+ const loadImagePromises = new Map<string, Promise<boolean>>()
2
+
3
+ /** Attempts to load the image and returns a boolean indicating success or not. */
4
+ export function loadImageUrl(url: string) {
5
+ let promise = loadImagePromises.get(url)
6
+ if (promise) return promise
7
+ promise = new Promise(resolve => {
8
+ const img = new Image()
9
+ img.onload = () => {
10
+ // After this event occurs, you can use the url in the DOM. The browser will not make another request for the image; there will be no delay.
11
+ resolve(true)
12
+ }
13
+ img.onerror = () => {
14
+ resolve(false)
15
+ }
16
+ img.src = url
17
+ })
18
+ loadImagePromises.set(url, promise)
19
+ return promise
20
+ }