@arcblock/ux 3.0.33 → 3.0.34

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.
@@ -21,6 +21,7 @@ export type AvatarProps = {
21
21
  shape?: "" | "rectangle" | "square" | "hexagon" | "circle";
22
22
  blockiesPadding?: true | false;
23
23
  responsive?: false | true;
24
+ useProxyFallback?: boolean;
24
25
  } & Omit<import('../Img').ImgProps, "size" | "src">;
25
26
  export { Avatar as AvatarProps };
26
27
  /**
@@ -34,6 +35,7 @@ export { Avatar as AvatarProps };
34
35
  * shape?: '' | 'rectangle' | 'square' | 'hexagon' | 'circle';
35
36
  * blockiesPadding?: true | false;
36
37
  * responsive?: false | true;
38
+ * useProxyFallback?: boolean;
37
39
  * } & Omit<import('../Img').ImgProps, 'size' | 'src'>} AvatarProps
38
40
  */
39
41
  /**
@@ -51,6 +53,7 @@ declare namespace Avatar {
51
53
  let shape: PropTypes.Requireable<string>;
52
54
  let blockiesPadding: PropTypes.Requireable<boolean>;
53
55
  let responsive: PropTypes.Requireable<boolean>;
56
+ let useProxyFallback: PropTypes.Requireable<boolean>;
54
57
  }
55
58
  export { propTypes_1 as propTypes };
56
59
  }
@@ -1,6 +1,6 @@
1
1
  import { jsx as o } from "react/jsx-runtime";
2
- import { useState as k, useMemo as P } from "react";
3
- import t from "prop-types";
2
+ import { useState as I, useMemo as P } from "react";
3
+ import a from "prop-types";
4
4
  import { ErrorBoundary as z } from "react-error-boundary";
5
5
  import { Shape as D } from "@arcblock/did-motif";
6
6
  import { Box as u } from "@mui/material";
@@ -13,12 +13,12 @@ import { DID_PREFIX as f } from "../Util/constant.js";
13
13
  function d({ ...s }) {
14
14
  const r = Object.assign({}, s);
15
15
  n(r.did) && (r.did = ""), n(r.size) && (r.size = 36), n(r.variant) && (r.variant = "default"), n(r.animation) && (r.animation = !1), n(r.shape) && (r.shape = ""), n(r.blockiesPadding) && (r.blockiesPadding = !0), n(r.responsive) && (r.responsive = !1);
16
- const [c, h] = k(!1), g = E(r, d, []), { did: i = "", size: e, src: p, variant: b, animation: v, shape: x, blockiesPadding: y, responsive: w, ...a } = g, l = P(() => R(i) ? T.createIcon({
16
+ const [l, h] = I(!1), g = E(r, d, []), { did: i = "", size: e, src: p, variant: b, animation: v, shape: x, blockiesPadding: y, responsive: k, ...t } = g, c = P(() => R(i) ? T.createIcon({
17
17
  seed: i.replace(f, "").toLowerCase(),
18
18
  size: 8,
19
19
  scale: 16
20
20
  }).toDataURL() : null, [i]);
21
- if (p && !c)
21
+ if (p && !l)
22
22
  return /* @__PURE__ */ o(
23
23
  m,
24
24
  {
@@ -26,8 +26,9 @@ function d({ ...s }) {
26
26
  src: p,
27
27
  alt: i,
28
28
  onError: () => h(!0),
29
- ...a,
30
- className: `avatar-img--${b} ${a?.className || ""}`,
29
+ ...t,
30
+ className: `avatar-img--${b} ${t?.className || ""}`,
31
+ useProxyFallback: !0,
31
32
  sx: {
32
33
  "& .avatar-img--rounded": {
33
34
  borderRadius: "4px",
@@ -37,17 +38,17 @@ function d({ ...s }) {
37
38
  borderRadius: "100%",
38
39
  overflow: "hidden"
39
40
  },
40
- ...a.sx
41
+ ...t.sx
41
42
  }
42
43
  }
43
44
  );
44
- if (l) {
45
+ if (c) {
45
46
  if (y) {
46
- const I = e > 24 ? 4 : 2;
47
+ const w = e > 24 ? 4 : 2;
47
48
  return /* @__PURE__ */ o(
48
49
  u,
49
50
  {
50
- ...a,
51
+ ...t,
51
52
  sx: {
52
53
  display: "flex",
53
54
  alignItems: "center",
@@ -63,13 +64,13 @@ function d({ ...s }) {
63
64
  borderRadius: `${Math.min(10, Math.floor(0.1 * e + 2))}px`,
64
65
  background: "#ddd"
65
66
  },
66
- ...a.sx
67
+ ...t.sx
67
68
  },
68
- children: /* @__PURE__ */ o("div", { className: "blocky-icon-inner", children: /* @__PURE__ */ o(m, { width: e * 0.7 - I * 2, src: l, alt: i }) })
69
+ children: /* @__PURE__ */ o("div", { className: "blocky-icon-inner", children: /* @__PURE__ */ o(m, { width: e * 0.7 - w * 2, src: c, alt: i }) })
69
70
  }
70
71
  );
71
72
  }
72
- return /* @__PURE__ */ o(m, { ...a, width: e, src: l, alt: i, style: { marginRight: 4 } });
73
+ return /* @__PURE__ */ o(m, { ...t, width: e, src: c, alt: i, style: { marginRight: 4 } });
73
74
  }
74
75
  if (i)
75
76
  return /* @__PURE__ */ o(
@@ -79,25 +80,26 @@ function d({ ...s }) {
79
80
  size: e,
80
81
  animation: v,
81
82
  shape: D[(x || "").toUpperCase()],
82
- responsive: w,
83
- ...a
83
+ responsive: k,
84
+ ...t
84
85
  }
85
86
  );
86
87
  throw new Error(`Invalid DID: ${i}`);
87
88
  }
88
89
  d.propTypes = {
89
- did: t.string,
90
- size: t.number,
91
- variant: t.oneOf(["circle", "rounded", "default"]),
90
+ did: a.string,
91
+ size: a.number,
92
+ variant: a.oneOf(["circle", "rounded", "default"]),
92
93
  // animation 仅对 did motif 有效
93
- animation: t.bool,
94
+ animation: a.bool,
94
95
  // shape 仅对 did motif 有效, 明确指定 motif shape, 而非由 did role type 自动推断 shape
95
- shape: t.oneOf(["", "rectangle", "square", "hexagon", "circle"]),
96
- blockiesPadding: t.bool,
97
- responsive: t.bool
96
+ shape: a.oneOf(["", "rectangle", "square", "hexagon", "circle"]),
97
+ blockiesPadding: a.bool,
98
+ responsive: a.bool,
99
+ useProxyFallback: a.bool
98
100
  };
99
101
  function $(s) {
100
- const r = s.size || 36, c = { rounded: "4px", circle: "100%" }[s.variant] || 0;
102
+ const r = s.size || 36, l = { rounded: "4px", circle: "100%" }[s.variant] || 0;
101
103
  return /* @__PURE__ */ o(
102
104
  z,
103
105
  {
@@ -108,7 +110,7 @@ function $(s) {
108
110
  width: r,
109
111
  height: r,
110
112
  bgcolor: "grey.300",
111
- borderRadius: c
113
+ borderRadius: l
112
114
  }
113
115
  }
114
116
  ),
@@ -1,21 +1,12 @@
1
- import { jsxs as a, jsx as o } from "react/jsx-runtime";
2
- import { Box as r, Typography as n } from "@mui/material";
1
+ import { jsxs as r, jsx as t } from "react/jsx-runtime";
2
+ import { Box as e, Typography as l } from "@mui/material";
3
3
  import i from "../../Img/index.js";
4
- import { BLOCKLET_SERVICE_PATH_PREFIX as s } from "../../Util/constant.js";
5
- const l = (e) => {
6
- if (!e) return "";
7
- try {
8
- return new URL(e).protocol !== "https:" ? (console.warn("Image URL must use HTTPS protocol:", e), "") : `${s}/proxy?url=${e}`;
9
- } catch (t) {
10
- return console.warn("Invalid image URL format:", e, t), "";
11
- }
12
- };
13
- function g({
14
- requestAppInfo: e,
15
- currentAppInfo: t
4
+ function m({
5
+ requestAppInfo: a,
6
+ currentAppInfo: o
16
7
  }) {
17
- return /* @__PURE__ */ a(
18
- r,
8
+ return /* @__PURE__ */ r(
9
+ e,
19
10
  {
20
11
  sx: {
21
12
  textAlign: "center",
@@ -25,8 +16,8 @@ function g({
25
16
  gap: 2
26
17
  },
27
18
  children: [
28
- /* @__PURE__ */ a(
29
- r,
19
+ /* @__PURE__ */ r(
20
+ e,
30
21
  {
31
22
  sx: {
32
23
  display: "flex",
@@ -34,18 +25,9 @@ function g({
34
25
  justifyContent: "center"
35
26
  },
36
27
  children: [
37
- /* @__PURE__ */ o(
38
- i,
39
- {
40
- src: t.appLogo,
41
- alt: "Server",
42
- width: 48,
43
- height: 48,
44
- fallback: l(t.appLogo)
45
- }
46
- ),
47
- /* @__PURE__ */ a(
48
- r,
28
+ /* @__PURE__ */ t(i, { src: o.appLogo, alt: "Server", width: 48, height: 48, useProxyFallback: !0 }),
29
+ /* @__PURE__ */ r(
30
+ e,
49
31
  {
50
32
  sx: {
51
33
  mx: 2,
@@ -60,27 +42,18 @@ function g({
60
42
  }
61
43
  },
62
44
  children: [
63
- /* @__PURE__ */ o(r, { className: "dot" }),
64
- /* @__PURE__ */ o(r, { className: "dot" }),
65
- /* @__PURE__ */ o(r, { className: "dot" })
45
+ /* @__PURE__ */ t(e, { className: "dot" }),
46
+ /* @__PURE__ */ t(e, { className: "dot" }),
47
+ /* @__PURE__ */ t(e, { className: "dot" })
66
48
  ]
67
49
  }
68
50
  ),
69
- /* @__PURE__ */ o(
70
- i,
71
- {
72
- src: e.appLogo,
73
- alt: e.appName,
74
- width: 48,
75
- height: 48,
76
- fallback: l(e.appLogo)
77
- }
78
- )
51
+ /* @__PURE__ */ t(i, { src: a.appLogo, alt: a.appName, width: 48, height: 48, useProxyFallback: !0 })
79
52
  ]
80
53
  }
81
54
  ),
82
- /* @__PURE__ */ a(
83
- n,
55
+ /* @__PURE__ */ r(
56
+ l,
84
57
  {
85
58
  sx: {
86
59
  mb: 1,
@@ -89,7 +62,7 @@ function g({
89
62
  children: [
90
63
  "Authorize",
91
64
  " ",
92
- /* @__PURE__ */ o(r, { component: "span", sx: { color: "primary.main" }, children: e.appName })
65
+ /* @__PURE__ */ t(e, { component: "span", sx: { color: "primary.main" }, children: a.appName })
93
66
  ]
94
67
  }
95
68
  )
@@ -98,5 +71,5 @@ function g({
98
71
  );
99
72
  }
100
73
  export {
101
- g as default
74
+ m as default
102
75
  };
@@ -19,6 +19,13 @@ export type ImgExProps = {
19
19
  lazy?: boolean | undefined;
20
20
  placeholder?: string | undefined;
21
21
  fallback?: string | undefined;
22
+ /**
23
+ * - 是否使用代理 fallback, 用于解决 CSP 的问题
24
+ */
25
+ /**
26
+ * - 是否使用代理 fallback, 用于解决 CSP 的问题
27
+ */
28
+ useProxyFallback?: boolean | undefined;
22
29
  className?: string | undefined;
23
30
  onError?: Function | undefined;
24
31
  onSuccess?: Function | undefined;
@@ -29,7 +36,7 @@ export type ImgProps = ImgExProps & import('@mui/material').BoxProps;
29
36
  * @param {ImgProps} props
30
37
  * @returns {React.ReactComponentElement}
31
38
  */
32
- declare function Img({ lazy, width, height, repeat, ratio, alt, size, position, src, placeholder, fallback, style, className, onError, onSuccess, ...rest }: ImgProps): import('react').ReactComponentElement<any, Pick<any, string | number | symbol>>;
39
+ declare function Img({ lazy, width, height, repeat, ratio, alt, size, position, src, useProxyFallback, placeholder, fallback, style, className, onError, onSuccess, ...rest }: ImgProps): import('react').ReactComponentElement<any, Pick<any, string | number | symbol>>;
33
40
  declare namespace Img {
34
41
  namespace propTypes {
35
42
  let src: PropTypes.Validator<string>;
@@ -47,5 +54,6 @@ declare namespace Img {
47
54
  let className: PropTypes.Requireable<string>;
48
55
  let onError: PropTypes.Requireable<(...args: any[]) => any>;
49
56
  let onSuccess: PropTypes.Requireable<(...args: any[]) => any>;
57
+ let useProxyFallback: PropTypes.Requireable<boolean>;
50
58
  }
51
59
  }
package/lib/Img/index.js CHANGED
@@ -1,91 +1,101 @@
1
- import { jsx as i, jsxs as X } from "react/jsx-runtime";
2
- import { useState as h, useMemo as b, useEffect as x } from "react";
1
+ import { jsx as s, jsxs as F } from "react/jsx-runtime";
2
+ import { useState as R, useMemo as d, useEffect as w } from "react";
3
3
  import e from "prop-types";
4
- import { useInView as _ } from "react-intersection-observer";
5
- import q from "@iconify-icons/material-symbols/warning-rounded";
6
- import B from "@iconify-icons/material-symbols/image-rounded";
7
- import { Icon as y } from "@iconify/react";
8
- import { Box as C } from "@mui/material";
9
- import S from "lodash/noop";
10
- import { mergeSx as D } from "../Util/style.js";
11
- const M = "Img", N = {
12
- root: `${M}-root`
4
+ import { useInView as V } from "react-intersection-observer";
5
+ import W from "@iconify-icons/material-symbols/warning-rounded";
6
+ import X from "@iconify-icons/material-symbols/image-rounded";
7
+ import { Icon as k } from "@iconify/react";
8
+ import { Box as B } from "@mui/material";
9
+ import $ from "lodash/noop";
10
+ import { mergeSx as q } from "../Util/style.js";
11
+ import { BLOCKLET_SERVICE_PATH_PREFIX as A } from "../Util/constant.js";
12
+ const D = (r) => {
13
+ if (!r) return "";
14
+ try {
15
+ return new URL(r).protocol !== "https:" ? (console.warn("Image URL must use HTTPS protocol:", r), "") : `${A}/proxy?url=${encodeURIComponent(r)}`;
16
+ } catch (t) {
17
+ return console.warn("Invalid image URL format:", r, t), "";
18
+ }
19
+ }, K = "Img", v = {
20
+ root: `${K}-root`
13
21
  };
14
- function O({
15
- lazy: v = !0,
16
- width: a = null,
17
- height: g = null,
18
- repeat: w = "no-repeat",
19
- ratio: $ = 1,
20
- alt: k = null,
21
- size: u = "cover",
22
- position: d = "top center",
23
- src: s,
24
- placeholder: l = null,
25
- fallback: t = null,
26
- style: R = null,
27
- className: E = "",
28
- onError: j = S,
29
- onSuccess: z = S,
30
- ...p
22
+ function M({
23
+ lazy: r = !0,
24
+ width: t = null,
25
+ height: f = null,
26
+ repeat: E = "no-repeat",
27
+ ratio: N = 1,
28
+ alt: P = null,
29
+ size: p = "cover",
30
+ position: I = "top center",
31
+ src: n,
32
+ useProxyFallback: b = !1,
33
+ // 是否使用代理 fallback, 用于解决 CSP 的问题
34
+ placeholder: c = null,
35
+ fallback: m = null,
36
+ style: T = null,
37
+ className: j = "",
38
+ onError: h = $,
39
+ onSuccess: L = $,
40
+ ...y
31
41
  }) {
32
- const [P, f] = v ? _({ threshold: 0, triggerOnce: !0 }) : [null, !0], [o, m] = h("init"), [n, I] = h(!1), c = b(() => {
42
+ const [U, x] = r ? V({ threshold: 0, triggerOnce: !0 }) : [null, !0], [o, g] = R("init"), [l, S] = R(!1), a = d(() => m || (b && n ? D(n) : m), [n, b, m]), u = d(() => {
33
43
  switch (o) {
34
44
  case "init":
35
45
  case "loading":
36
- return l;
46
+ return c;
37
47
  case "error":
38
- return n ? null : t;
48
+ return l ? null : a;
39
49
  case "loaded":
40
- return s;
50
+ return n;
41
51
  default:
42
52
  return null;
43
53
  }
44
- }, [l, t, s, o, n]), T = a && g ? 100 * g / a : $ * 100, W = b(
54
+ }, [c, a, n, o, l]), _ = t && f ? 100 * f / t : N * 100, C = d(
45
55
  () => ({
46
- backgroundImage: c ? `url(${c})` : "",
47
- backgroundPosition: d,
48
- backgroundSize: u,
49
- backgroundRepeat: w,
50
- paddingTop: `${T}%`
56
+ backgroundImage: u ? `url(${u})` : "",
57
+ backgroundPosition: I,
58
+ backgroundSize: p,
59
+ backgroundRepeat: E,
60
+ paddingTop: `${_}%`
51
61
  }),
52
62
  // eslint-disable-next-line react-hooks/exhaustive-deps
53
- [c, d, u, o]
54
- ), F = {
55
- ...R,
63
+ [u, I, p, o]
64
+ ), H = {
65
+ ...T,
56
66
  display: "inline-block",
57
- width: a ? `${a}px` : "100%"
67
+ width: t ? `${t}px` : "100%"
58
68
  };
59
- function H() {
60
- const r = new Image();
61
- r.src = s, m("loading"), I(!1), r.onload = () => {
62
- m("loaded"), z();
63
- }, r.onerror = (V) => {
64
- m("error"), j(V);
69
+ function O() {
70
+ const i = new Image();
71
+ i.src = n, g("loading"), S(!1), i.onload = () => {
72
+ g("loaded"), L();
73
+ }, i.onerror = () => {
74
+ g("error");
65
75
  };
66
76
  }
67
- return x(() => {
68
- f && H();
69
- }, [f]), x(() => {
70
- if (o === "error" && t && !n) {
71
- const r = new Image();
72
- r.src = t, r.onload = () => {
73
- }, r.onerror = () => {
74
- I(!0);
77
+ return w(() => {
78
+ x && O();
79
+ }, [x]), w(() => {
80
+ if (o === "error" && a && !l) {
81
+ const i = new Image();
82
+ i.src = a, i.onload = () => {
83
+ }, i.onerror = (z) => {
84
+ S(!0), o === "error" && h(z);
75
85
  };
76
86
  }
77
- }, [o, t, n]), // paddingTop 要求元素本身的宽度为 100%,所以只能加一个外层元素去限制宽度
78
- /* @__PURE__ */ i(
79
- C,
87
+ }, [o, a, l, h]), // paddingTop 要求元素本身的宽度为 100%,所以只能加一个外层元素去限制宽度
88
+ /* @__PURE__ */ s(
89
+ B,
80
90
  {
81
91
  "data-id": "2",
82
- ref: P,
83
- style: F,
92
+ ref: U,
93
+ style: H,
84
94
  className: "arcblock_ux_img-wrapper",
85
- ...p,
86
- sx: D(
95
+ ...y,
96
+ sx: q(
87
97
  {
88
- [`& .${N.root}`]: {
98
+ [`& .${v.root}`]: {
89
99
  position: "relative",
90
100
  overflow: "hidden",
91
101
  "& .image--state, & .image--img": {
@@ -117,17 +127,17 @@ function O({
117
127
  }
118
128
  }
119
129
  },
120
- p.sx
130
+ y.sx
121
131
  ),
122
- children: /* @__PURE__ */ X("div", { className: `image ${E} ${N.root}`, style: W, children: [
123
- (n || !t && o === "error") && /* @__PURE__ */ i("div", { className: "image--state", title: "Image load error", children: /* @__PURE__ */ i(y, { icon: q, className: "image--icon" }) }),
124
- !l && o === "loading" && /* @__PURE__ */ i("div", { className: "image--state", title: "loading image", children: /* @__PURE__ */ i(y, { icon: B, className: "image--icon" }) }),
125
- o === "loaded" && /* @__PURE__ */ i("img", { className: "image--img", src: s, alt: k })
132
+ children: /* @__PURE__ */ F("div", { className: `image ${j} ${v.root}`, style: C, children: [
133
+ (l || !a && o === "error") && /* @__PURE__ */ s("div", { className: "image--state", title: "Image load error", children: /* @__PURE__ */ s(k, { icon: W, className: "image--icon" }) }),
134
+ !c && o === "loading" && /* @__PURE__ */ s("div", { className: "image--state", title: "loading image", children: /* @__PURE__ */ s(k, { icon: X, className: "image--icon" }) }),
135
+ o === "loaded" && /* @__PURE__ */ s("img", { className: "image--img", src: n, alt: P })
126
136
  ] })
127
137
  }
128
138
  );
129
139
  }
130
- O.propTypes = {
140
+ M.propTypes = {
131
141
  src: e.string.isRequired,
132
142
  alt: e.string,
133
143
  size: e.string,
@@ -142,8 +152,9 @@ O.propTypes = {
142
152
  fallback: e.string,
143
153
  className: e.string,
144
154
  onError: e.func,
145
- onSuccess: e.func
155
+ onSuccess: e.func,
156
+ useProxyFallback: e.bool
146
157
  };
147
158
  export {
148
- O as default
159
+ M as default
149
160
  };
@@ -1,17 +1,17 @@
1
1
  import { jsx as a } from "react/jsx-runtime";
2
- import { Box as l, Avatar as f } from "@mui/material";
3
- import p from "../Avatar/index.js";
4
- import { createNameOnlyAvatar as u } from "./utils.js";
5
- const N = (r, t = 48, n = void 0, e = void 0, c = !1) => {
6
- const o = (i) => {
2
+ import { Box as o, Avatar as f } from "@mui/material";
3
+ import u from "../Avatar/index.js";
4
+ import { createNameOnlyAvatar as x } from "./utils.js";
5
+ const N = (r, t = 48, c = void 0, e = void 0, l = !1) => {
6
+ const n = (i) => {
7
7
  e?.(r, i);
8
8
  };
9
9
  if (!r.avatar) {
10
- const i = u(r), { className: s, style: d, alt: m } = n || {};
10
+ const i = x(r), { className: s, style: d, alt: m } = c || {};
11
11
  return /* @__PURE__ */ a(
12
12
  f,
13
13
  {
14
- onClick: o,
14
+ onClick: n,
15
15
  className: s,
16
16
  style: d,
17
17
  alt: m,
@@ -19,7 +19,7 @@ const N = (r, t = 48, n = void 0, e = void 0, c = !1) => {
19
19
  width: t,
20
20
  height: t,
21
21
  fontSize: t * 0.4,
22
- cursor: c || e ? "pointer" : "default"
22
+ cursor: l || e ? "pointer" : "default"
23
23
  },
24
24
  variant: "circular",
25
25
  children: i
@@ -27,30 +27,31 @@ const N = (r, t = 48, n = void 0, e = void 0, c = !1) => {
27
27
  );
28
28
  }
29
29
  return /* @__PURE__ */ a(
30
- l,
30
+ o,
31
31
  {
32
32
  className: "user-card__avatar",
33
33
  sx: {
34
34
  display: "flex"
35
35
  },
36
36
  children: /* @__PURE__ */ a(
37
- p,
37
+ u,
38
38
  {
39
39
  size: t,
40
40
  did: r.did,
41
41
  variant: "circle",
42
+ useProxyFallback: !0,
42
43
  style: {
43
- cursor: c || e ? "pointer" : "default"
44
+ cursor: l || e ? "pointer" : "default"
44
45
  },
45
- onClick: o,
46
+ onClick: n,
46
47
  src: r.avatar,
47
48
  alt: r.fullName || "",
48
- ...n || {}
49
+ ...c || {}
49
50
  }
50
51
  )
51
52
  }
52
53
  );
53
- }, _ = (r, t = 120) => r ? /* @__PURE__ */ a(l, { sx: { maxWidth: t }, className: "user-card__top-right-content", children: r() }) : null;
54
+ }, _ = (r, t = 120) => r ? /* @__PURE__ */ a(o, { sx: { maxWidth: t }, className: "user-card__top-right-content", children: r() }) : null;
54
55
  export {
55
56
  N as renderAvatar,
56
57
  _ as renderTopRight
@@ -1,34 +1,44 @@
1
1
  import { jsx as t } from "react/jsx-runtime";
2
- import { useRef as c, useState as h, useEffect as C } from "react";
3
- import { CardType as i } from "./types.js";
4
- import v from "./Cards/avatar-only.js";
5
- import f from "./Cards/index.js";
6
- import y from "./Container/dialog.js";
7
- import A from "./Container/card.js";
8
- import D from "../Avatar/index.js";
9
- import { isUserDid as P, getUserByDid as S } from "./utils.js";
2
+ import { useRef as v, useState as C, useEffect as y, useMemo as P } from "react";
3
+ import { CardType as o } from "./types.js";
4
+ import A from "./Cards/avatar-only.js";
5
+ import m from "./Cards/index.js";
6
+ import D from "./Container/dialog.js";
7
+ import S from "./Container/card.js";
8
+ import w from "../Avatar/index.js";
9
+ import { isUserDid as x, getUserByDid as U } from "./utils.js";
10
10
  function L(e) {
11
11
  if (!e) return null;
12
12
  let r = "";
13
13
  return e.fullName ? r = e.fullName.charAt(0).toUpperCase() : e.email ? r = e.email.split("@")[0].charAt(0).toUpperCase() : r = e.did ? e.did.charAt(0).toUpperCase() : "?", r;
14
14
  }
15
- function g(e) {
16
- const { cardType: r = i.Detailed, showHoverCard: d } = e, n = d !== void 0 ? d : r === i.AvatarOnly, m = c(null), [a, o] = h(() => e.user || null);
17
- if (C(() => {
18
- let u = !0;
19
- return e.user ? o(e.user) : e.did && P(e.did) && !e.user && S(e.did).then((s) => {
20
- u && o(s || { fullName: "Anonymous", did: e.did, avatar: "" });
15
+ function B(e) {
16
+ const { cardType: r = o.Detailed, showHoverCard: l } = e, u = l !== void 0 ? l : r === o.AvatarOnly, c = v(null), [i, f] = C(() => e.user || null);
17
+ y(() => {
18
+ let a = !0;
19
+ return e.user ? f(e.user) : e.did && x(e.did) && !e.user && U(e.did).then((d) => {
20
+ a && f(d || { fullName: "Anonymous", did: e.did, avatar: "" });
21
21
  }), () => {
22
- u = !1;
22
+ a = !1;
23
23
  };
24
- }, [e.did, e.user]), !a)
25
- return /* @__PURE__ */ t(D, { did: e.did, size: e.avatarSize, ...e.avatarProps });
26
- const l = () => /* @__PURE__ */ t(y, { sx: e.popupSx, children: /* @__PURE__ */ t(
27
- f,
24
+ }, [e.did, e.user]);
25
+ const n = P(() => {
26
+ if (!i)
27
+ return null;
28
+ const { avatar: a = "", ...d } = i, h = a.split("?")[1];
29
+ return a && !h ? {
30
+ ...d,
31
+ avatar: `${a}?imageFilter=resize&w=48&h=48`
32
+ } : i;
33
+ }, [i]);
34
+ if (!n)
35
+ return /* @__PURE__ */ t(w, { did: e.did, size: e.avatarSize, useProxyFallback: !0, ...e.avatarProps });
36
+ const s = () => /* @__PURE__ */ t(D, { sx: e.popupSx, children: /* @__PURE__ */ t(
37
+ m,
28
38
  {
29
39
  ...e,
30
40
  shouldShowHoverCard: !1,
31
- user: a,
41
+ user: n,
32
42
  avatarProps: e.popupAvatarProps,
33
43
  shortenLabelProps: e.popupShortenLabelProps || e.shortenLabelProps,
34
44
  renderFields: e.popupRenderFields,
@@ -38,25 +48,25 @@ function g(e) {
38
48
  showDid: e.popupShowDid || e.showDid
39
49
  }
40
50
  ) });
41
- return r === i.AvatarOnly ? /* @__PURE__ */ t(
42
- v,
51
+ return r === o.AvatarOnly ? /* @__PURE__ */ t(
52
+ A,
43
53
  {
44
54
  ...e,
45
- shouldShowHoverCard: n,
46
- renderCardContent: l,
47
- user: a
55
+ shouldShowHoverCard: u,
56
+ renderCardContent: s,
57
+ user: n
48
58
  }
49
- ) : /* @__PURE__ */ t(A, { containerRef: m, cardType: r, sx: e.sx, children: /* @__PURE__ */ t(
50
- f,
59
+ ) : /* @__PURE__ */ t(S, { containerRef: c, cardType: r, sx: e.sx, children: /* @__PURE__ */ t(
60
+ m,
51
61
  {
52
62
  ...e,
53
- shouldShowHoverCard: n,
54
- renderCardContent: l,
55
- user: a
63
+ shouldShowHoverCard: u,
64
+ renderCardContent: s,
65
+ user: n
56
66
  }
57
67
  ) });
58
68
  }
59
69
  export {
60
70
  L as createNameOnlyAvatar,
61
- g as default
71
+ B as default
62
72
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcblock/ux",
3
- "version": "3.0.33",
3
+ "version": "3.0.34",
4
4
  "description": "Common used react components for arcblock products",
5
5
  "keywords": [
6
6
  "react",
@@ -60,16 +60,16 @@
60
60
  "react": "^19.0.0",
61
61
  "react-router-dom": "^6.22.3"
62
62
  },
63
- "gitHead": "4b6fbddbcafd122684b82a0b452ca34fc6d1a6ab",
63
+ "gitHead": "e2822eb021fb9aebfcf80f71dd4da4ca76b2372b",
64
64
  "dependencies": {
65
- "@arcblock/bridge": "3.0.33",
65
+ "@arcblock/bridge": "3.0.34",
66
66
  "@arcblock/did": "^1.21.0",
67
67
  "@arcblock/did-motif": "^1.1.14",
68
- "@arcblock/icons": "3.0.33",
69
- "@arcblock/nft-display": "3.0.33",
70
- "@arcblock/react-hooks": "3.0.33",
68
+ "@arcblock/icons": "3.0.34",
69
+ "@arcblock/nft-display": "3.0.34",
70
+ "@arcblock/react-hooks": "3.0.34",
71
71
  "@blocklet/js-sdk": "^1.16.46",
72
- "@blocklet/theme": "3.0.33",
72
+ "@blocklet/theme": "3.0.34",
73
73
  "@fontsource/roboto": "~5.1.1",
74
74
  "@fontsource/ubuntu-mono": "^5.2.6",
75
75
  "@iconify-icons/logos": "^1.2.36",
@@ -23,6 +23,7 @@ import { DID_PREFIX } from '../Util/constant';
23
23
  * shape?: '' | 'rectangle' | 'square' | 'hexagon' | 'circle';
24
24
  * blockiesPadding?: true | false;
25
25
  * responsive?: false | true;
26
+ * useProxyFallback?: boolean;
26
27
  * } & Omit<import('../Img').ImgProps, 'size' | 'src'>} AvatarProps
27
28
  */
28
29
 
@@ -84,6 +85,7 @@ function Avatar({ ...rawProps }) {
84
85
  {...rest}
85
86
  // HACK: 这个 className 是传递给子元素的,所以下面的 sx 需要通过子元素选择器来写样式
86
87
  className={`avatar-img--${variant} ${rest?.className || ''}`}
88
+ useProxyFallback
87
89
  sx={{
88
90
  '& .avatar-img--rounded': {
89
91
  borderRadius: '4px',
@@ -159,6 +161,7 @@ Avatar.propTypes = {
159
161
  shape: PropTypes.oneOf(['', 'rectangle', 'square', 'hexagon', 'circle']),
160
162
  blockiesPadding: PropTypes.bool,
161
163
  responsive: PropTypes.bool,
164
+ useProxyFallback: PropTypes.bool,
162
165
  };
163
166
 
164
167
  /**
@@ -1,28 +1,5 @@
1
1
  import { Box, Typography } from '@mui/material';
2
2
  import Img from '../../Img';
3
- import { BLOCKLET_SERVICE_PATH_PREFIX } from '../../Util/constant';
4
-
5
- const getProxyImageUrl = (url: string) => {
6
- if (!url) return '';
7
-
8
- try {
9
- // 检查是否是一个有效的URL
10
- const urlObj = new URL(url);
11
-
12
- // 检查协议是否是https
13
- if (urlObj.protocol !== 'https:') {
14
- console.warn('Image URL must use HTTPS protocol:', url);
15
- return '';
16
- }
17
-
18
- // 返回代理URL
19
- return `${BLOCKLET_SERVICE_PATH_PREFIX}/proxy?url=${url}`;
20
- } catch (error) {
21
- // URL construction failed, indicating invalid URL format
22
- console.warn('Invalid image URL format:', url, error);
23
- return '';
24
- }
25
- };
26
3
 
27
4
  export type RequestAppInfo = {
28
5
  appLogo: string;
@@ -59,13 +36,7 @@ export default function AuthAppsInfo({
59
36
  justifyContent: 'center',
60
37
  }}>
61
38
  {/* FIXME: @zhanghan 增加 hover 的效果 */}
62
- <Img
63
- src={currentAppInfo.appLogo}
64
- alt="Server"
65
- width={48}
66
- height={48}
67
- fallback={getProxyImageUrl(currentAppInfo.appLogo)}
68
- />
39
+ <Img src={currentAppInfo.appLogo} alt="Server" width={48} height={48} useProxyFallback />
69
40
 
70
41
  <Box
71
42
  sx={{
@@ -86,13 +57,7 @@ export default function AuthAppsInfo({
86
57
  </Box>
87
58
 
88
59
  {/* FIXME: @zhanghan 增加 hover 的效果 */}
89
- <Img
90
- src={requestAppInfo.appLogo}
91
- alt={requestAppInfo.appName}
92
- width={48}
93
- height={48}
94
- fallback={getProxyImageUrl(requestAppInfo.appLogo)}
95
- />
60
+ <Img src={requestAppInfo.appLogo} alt={requestAppInfo.appName} width={48} height={48} useProxyFallback />
96
61
  </Box>
97
62
 
98
63
  <Typography
package/src/Img/index.jsx CHANGED
@@ -7,6 +7,29 @@ import { Icon } from '@iconify/react';
7
7
  import { Box } from '@mui/material';
8
8
  import noop from 'lodash/noop';
9
9
  import { mergeSx } from '../Util/style';
10
+ import { BLOCKLET_SERVICE_PATH_PREFIX } from '../Util/constant';
11
+
12
+ const getProxyImageUrl = (url) => {
13
+ if (!url) return '';
14
+
15
+ try {
16
+ // 检查是否是一个有效的URL
17
+ const urlObj = new URL(url);
18
+
19
+ // 检查协议是否是https
20
+ if (urlObj.protocol !== 'https:') {
21
+ console.warn('Image URL must use HTTPS protocol:', url);
22
+ return '';
23
+ }
24
+
25
+ // 返回代理URL
26
+ return `${BLOCKLET_SERVICE_PATH_PREFIX}/proxy?url=${encodeURIComponent(url)}`;
27
+ } catch (error) {
28
+ // URL construction failed, indicating invalid URL format
29
+ console.warn('Invalid image URL format:', url, error);
30
+ return '';
31
+ }
32
+ };
10
33
 
11
34
  /**
12
35
  * @typedef {Object} ImgExProps
@@ -22,6 +45,7 @@ import { mergeSx } from '../Util/style';
22
45
  * @property {boolean} [lazy=true]
23
46
  * @property {string} [placeholder]
24
47
  * @property {string} [fallback]
48
+ * @property {boolean} [useProxyFallback=false] - 是否使用代理 fallback, 用于解决 CSP 的问题
25
49
  * @property {string} [className='']
26
50
  * @property {function} [onError=() => {}]
27
51
  * @property {function} [onSuccess=() => {}]
@@ -52,6 +76,7 @@ function Img({
52
76
  size = 'cover',
53
77
  position = 'top center',
54
78
  src,
79
+ useProxyFallback = false, // 是否使用代理 fallback, 用于解决 CSP 的问题
55
80
  placeholder = null,
56
81
  fallback = null,
57
82
  style = null,
@@ -66,19 +91,29 @@ function Img({
66
91
  const [imgState, setImgState] = useState('init');
67
92
  const [fallbackError, setFallbackError] = useState(false);
68
93
 
94
+ const fallbackSrc = useMemo(() => {
95
+ if (fallback) {
96
+ return fallback;
97
+ }
98
+ if (useProxyFallback && src) {
99
+ return getProxyImageUrl(src);
100
+ }
101
+ return fallback;
102
+ }, [src, useProxyFallback, fallback]);
103
+
69
104
  const actualSrc = useMemo(() => {
70
105
  switch (imgState) {
71
106
  case 'init':
72
107
  case 'loading':
73
108
  return placeholder;
74
109
  case 'error':
75
- return fallbackError ? null : fallback;
110
+ return fallbackError ? null : fallbackSrc;
76
111
  case 'loaded':
77
112
  return src;
78
113
  default:
79
114
  return null;
80
115
  }
81
- }, [placeholder, fallback, src, imgState, fallbackError]);
116
+ }, [placeholder, fallbackSrc, src, imgState, fallbackError]);
82
117
 
83
118
  const actualRatio = width && height ? (100 * height) / width : ratio * 100;
84
119
 
@@ -112,9 +147,8 @@ function Img({
112
147
  setImgState('loaded');
113
148
  onSuccess();
114
149
  };
115
- img.onerror = (err) => {
150
+ img.onerror = () => {
116
151
  setImgState('error');
117
- onError(err);
118
152
  };
119
153
  }
120
154
 
@@ -125,18 +159,21 @@ function Img({
125
159
 
126
160
  // 处理 fallback 加载
127
161
  useEffect(() => {
128
- if (imgState === 'error' && fallback && !fallbackError) {
162
+ if (imgState === 'error' && fallbackSrc && !fallbackError) {
129
163
  const fallbackImg = new Image();
130
- fallbackImg.src = fallback;
164
+ fallbackImg.src = fallbackSrc;
131
165
  fallbackImg.onload = () => {
132
166
  // fallback 加载成功,保持在 error 状态但显示 fallback
133
167
  };
134
- fallbackImg.onerror = () => {
168
+ fallbackImg.onerror = (err) => {
135
169
  // fallback 也加载失败
136
170
  setFallbackError(true);
171
+ if (imgState === 'error') {
172
+ onError(err);
173
+ }
137
174
  };
138
175
  }
139
- }, [imgState, fallback, fallbackError]);
176
+ }, [imgState, fallbackSrc, fallbackError, onError]);
140
177
 
141
178
  return (
142
179
  // paddingTop 要求元素本身的宽度为 100%,所以只能加一个外层元素去限制宽度
@@ -183,7 +220,7 @@ function Img({
183
220
  rest.sx
184
221
  )}>
185
222
  <div className={`image ${className} ${classes.root}`} style={mergedStyle}>
186
- {(fallbackError || (!fallback && imgState === 'error')) && (
223
+ {(fallbackError || (!fallbackSrc && imgState === 'error')) && (
187
224
  <div className="image--state" title="Image load error">
188
225
  <Icon icon={WarningRoundedIcon} className="image--icon" />
189
226
  </div>
@@ -215,6 +252,7 @@ Img.propTypes = {
215
252
  className: PropTypes.string,
216
253
  onError: PropTypes.func,
217
254
  onSuccess: PropTypes.func,
255
+ useProxyFallback: PropTypes.bool,
218
256
  };
219
257
 
220
258
  export default Img;
@@ -51,6 +51,7 @@ export const renderAvatar = (
51
51
  size={avatarSize}
52
52
  did={user.did}
53
53
  variant="circle"
54
+ useProxyFallback
54
55
  style={{
55
56
  cursor: shouldShowHoverCard || onAvatarClick ? 'pointer' : 'default',
56
57
  }}
@@ -1,4 +1,4 @@
1
- import { useEffect, useRef, useState } from 'react';
1
+ import { useEffect, useMemo, useRef, useState } from 'react';
2
2
  import type { User } from './types';
3
3
  import { UserCardProps, CardType } from './types';
4
4
  import AvatarOnlyCard from './Cards/avatar-only';
@@ -55,9 +55,26 @@ function UserCard(props: UserCardProps) {
55
55
  };
56
56
  }, [props.did, props.user]);
57
57
 
58
+ // 补全 avatar 的 imageFilter 信息,以提高性能
59
+ const userInfo = useMemo(() => {
60
+ if (!user) {
61
+ return null;
62
+ }
63
+
64
+ const { avatar = '', ...rest } = user;
65
+ const avatarParam = avatar.split('?')[1];
66
+ if (avatar && !avatarParam) {
67
+ return {
68
+ ...rest,
69
+ avatar: `${avatar}?imageFilter=resize&w=48&h=48`,
70
+ };
71
+ }
72
+ return user;
73
+ }, [user]);
74
+
58
75
  // 如果不存在,则使用 did 渲染头像
59
- if (!user) {
60
- return <Avatar did={props.did} size={props.avatarSize} {...props.avatarProps} />;
76
+ if (!userInfo) {
77
+ return <Avatar did={props.did} size={props.avatarSize} useProxyFallback {...props.avatarProps} />;
61
78
  }
62
79
 
63
80
  // user 存在,则使用 user 渲染头像
@@ -68,7 +85,7 @@ function UserCard(props: UserCardProps) {
68
85
  <DetailedCard
69
86
  {...props}
70
87
  shouldShowHoverCard={false}
71
- user={user!}
88
+ user={userInfo!}
72
89
  avatarProps={props.popupAvatarProps}
73
90
  shortenLabelProps={props.popupShortenLabelProps || props.shortenLabelProps}
74
91
  renderFields={props.popupRenderFields}
@@ -88,7 +105,7 @@ function UserCard(props: UserCardProps) {
88
105
  {...props}
89
106
  shouldShowHoverCard={shouldShowHoverCard}
90
107
  renderCardContent={renderCardContent}
91
- user={user!}
108
+ user={userInfo!}
92
109
  />
93
110
  );
94
111
  }
@@ -100,7 +117,7 @@ function UserCard(props: UserCardProps) {
100
117
  {...props}
101
118
  shouldShowHoverCard={shouldShowHoverCard}
102
119
  renderCardContent={renderCardContent}
103
- user={user!}
120
+ user={userInfo!}
104
121
  />
105
122
  </CardContainer>
106
123
  );