@blocklet/ui-react 3.1.27 → 3.1.28

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,39 +1,32 @@
1
- import { jsx as r, jsxs as m, Fragment as v } from "react/jsx-runtime";
2
- import { useState as N } from "react";
1
+ import { jsx as r, jsxs as m, Fragment as N } from "react/jsx-runtime";
2
+ import { useState as $ } from "react";
3
3
  import l from "prop-types";
4
- import { useCreation as $ } from "ahooks";
4
+ import { useCreation as M } from "ahooks";
5
5
  import j from "lodash/isInteger";
6
6
  import I from "lodash/isString";
7
7
  import { styled as z } from "@arcblock/ux/lib/Theme";
8
8
  import c from "clsx";
9
- import { ExpandMore as M } from "@mui/icons-material";
10
- import C from "../Icon/index.js";
9
+ import { ExpandMore as C } from "@mui/icons-material";
10
+ import P from "../Icon/index.js";
11
11
  import A from "../hooks/use-mobile.js";
12
- import { splitNavColumns as E } from "../utils.js";
13
- function F({ links: e = [], flowLayout: d = !1, columns: u, ...x }) {
14
- const [g, b] = N(-1), w = A({ key: "md" }), h = e.some((t) => t.items?.length), k = !w && h && j(u) && u > 1, p = ({ label: t, link: o, icon: i, render: a, props: n }) => {
12
+ import { splitNavColumns as E, isMailProtocol as F } from "../utils.js";
13
+ function R({ links: e = [], flowLayout: d = !1, columns: u, ...k }) {
14
+ const [g, b] = $(-1), w = A({ key: "md" }), h = e.some((t) => t.items?.length), x = !w && h && j(u) && u > 1, p = ({ label: t, link: o, icon: i, render: a, props: n }) => {
15
15
  let s = t;
16
16
  if (a)
17
17
  s = a({ label: t, link: o, props: n });
18
18
  else if (o && I(o)) {
19
- const f = o.startsWith("http") || o.startsWith("//");
20
- s = /* @__PURE__ */ r(
21
- "a",
22
- {
23
- href: o,
24
- "aria-label": `Footer link for ${t}`,
25
- target: f ? "_blank" : "_self",
26
- rel: f ? "noreferrer noopener" : void 0,
27
- ...n,
28
- children: t
29
- }
30
- );
31
- }
32
- return /* @__PURE__ */ m(v, { children: [
33
- i && /* @__PURE__ */ r(C, { icon: i, size: 20, sx: { mr: 0.5 } }),
19
+ const f = o.startsWith("http") || o.startsWith("//"), v = F(o) ? {} : {
20
+ target: f ? "_blank" : "_self",
21
+ rel: f ? "noreferrer noopener" : void 0
22
+ };
23
+ s = /* @__PURE__ */ r("a", { href: o, "aria-label": `Footer link for ${t}`, ...v, ...n, children: t });
24
+ }
25
+ return /* @__PURE__ */ m(N, { children: [
26
+ i && /* @__PURE__ */ r(P, { icon: i, size: 20, sx: { mr: 0.5 } }),
34
27
  s
35
28
  ] });
36
- }, y = $(() => e?.length ? d ? e.map((t, o) => /* @__PURE__ */ r("span", { className: "footer-links-item", children: p(t) }, o)) : k ? E(e, { columns: u }).map((t, o) => /* @__PURE__ */ r("div", { className: "footer-links-column", children: t.filter((i) => i.group).map((i, a) => {
29
+ }, y = M(() => e?.length ? d ? e.map((t, o) => /* @__PURE__ */ r("span", { className: "footer-links-item", children: p(t) }, o)) : x ? E(e, { columns: u }).map((t, o) => /* @__PURE__ */ r("div", { className: "footer-links-column", children: t.filter((i) => i.group).map((i, a) => {
37
30
  const { items: n } = i;
38
31
  return /* @__PURE__ */ m("div", { className: "footer-links-group", children: [
39
32
  /* @__PURE__ */ r("span", { className: "footer-links-item", children: p(i) }),
@@ -59,7 +52,7 @@ function F({ links: e = [], flowLayout: d = !1, columns: u, ...x }) {
59
52
  /* @__PURE__ */ m("span", { className: "footer-links-item", children: [
60
53
  p(t),
61
54
  !!i?.length && /* @__PURE__ */ r("span", { className: "footer-links-group-expand-icon", children: /* @__PURE__ */ r(
62
- M,
55
+ C,
63
56
  {
64
57
  style: {
65
58
  transform: `rotate(${a ? 180 : 0}deg)`
@@ -72,21 +65,21 @@ function F({ links: e = [], flowLayout: d = !1, columns: u, ...x }) {
72
65
  },
73
66
  o
74
67
  );
75
- }) : null, [e, d, k, g]);
68
+ }) : null, [e, d, x, g]);
76
69
  return e?.length ? /* @__PURE__ */ r(
77
- R,
70
+ S,
78
71
  {
79
- ...x,
80
- className: c(x.className, {
72
+ ...k,
73
+ className: c(k.className, {
81
74
  "footer-links--grouped": h,
82
75
  "footer-links--flow": d,
83
- "footer-links--columns": k
76
+ "footer-links--columns": x
84
77
  }),
85
78
  children: /* @__PURE__ */ r("div", { className: "footer-links-inner", children: y })
86
79
  }
87
80
  ) : null;
88
81
  }
89
- F.propTypes = {
82
+ R.propTypes = {
90
83
  links: l.arrayOf(
91
84
  l.shape({
92
85
  label: l.string,
@@ -100,7 +93,7 @@ F.propTypes = {
100
93
  // 列布局
101
94
  columns: l.number.isRequired
102
95
  };
103
- const R = z("div")`
96
+ const S = z("div")`
104
97
  overflow: hidden;
105
98
  color: ${({ theme: e }) => e.palette.text.secondary};
106
99
  .footer-links-inner {
@@ -251,5 +244,5 @@ const R = z("div")`
251
244
  }
252
245
  `;
253
246
  export {
254
- F as default
247
+ R as default
255
248
  };
package/lib/blocklets.js CHANGED
@@ -1,48 +1,50 @@
1
- import { mapRecursive as s, filterRecursive as a, isUrl as f } from "./utils.js";
2
- const g = window?.blocklet?.groupPrefix || window?.blocklet?.prefix || "/", i = (o) => {
3
- const r = { ...o }, e = o?.background;
4
- return typeof e == "string" ? r.background = { header: e, footer: e, default: e } : e && typeof e == "object" && (r.background = {
5
- header: e.header || e.default,
6
- footer: e.footer || e.default,
7
- default: e.default
1
+ import { mapRecursive as s, filterRecursive as a, isUrl as f, isMailProtocol as i } from "./utils.js";
2
+ const p = window?.blocklet?.groupPrefix || window?.blocklet?.prefix || "/", c = (e) => {
3
+ const r = { ...e }, t = e?.background;
4
+ return typeof t == "string" ? r.background = { header: t, footer: t, default: t } : t && typeof t == "object" && (r.background = {
5
+ header: t.header || t.default,
6
+ footer: t.footer || t.default,
7
+ default: t.default
8
8
  }), r;
9
- }, c = (o, r = "en") => {
10
- if (typeof o == "string") {
11
- if (f(o)) {
12
- const t = new URL(o);
13
- return t.searchParams.set("locale", r), t.href;
9
+ }, u = (e, r = "en") => {
10
+ if (typeof e == "string") {
11
+ if (f(e)) {
12
+ const o = new URL(e);
13
+ return o.searchParams.set("locale", r), o.href;
14
14
  }
15
- const e = new URL(o, window.location.origin);
16
- return e.searchParams.set("locale", r), e.pathname + e.search;
15
+ if (i(e))
16
+ return e;
17
+ const t = new URL(e, window.location.origin);
18
+ return t.searchParams.set("locale", r), t.pathname + t.search;
17
19
  }
18
- return typeof o == "object" ? o[r] || o?.en || o?.zh : o;
19
- }, p = (o, r = "en") => {
20
- if (!o?.length)
21
- return o;
22
- const e = (t, n) => t && typeof t == "object" ? t[n] || t?.en || t?.zh : t;
20
+ return typeof e == "object" ? e[r] || e?.en || e?.zh : e;
21
+ }, b = (e, r = "en") => {
22
+ if (!e?.length)
23
+ return e;
24
+ const t = (o, n) => o && typeof o == "object" ? o[n] || o?.en || o?.zh : o;
23
25
  return s(
24
- o,
25
- (t) => ({
26
- ...t,
27
- title: e(t.title, r),
28
- description: e(t.description, r),
26
+ e,
27
+ (o) => ({
28
+ ...o,
29
+ title: t(o.title, r),
30
+ description: t(o.description, r),
29
31
  // 仅对叶结点进行处理
30
- link: t.items?.length ? t.link : c(t.link, r),
31
- _rawLink: t.link
32
+ link: o.items?.length ? o.link : u(o.link, r),
33
+ _rawLink: o.link
32
34
  }),
33
35
  "items"
34
36
  );
35
- }, u = (o) => s(
36
- o,
37
+ }, l = (e) => s(
38
+ e,
37
39
  (r) => r.role ? {
38
40
  ...r,
39
41
  role: Array.isArray(r.role) ? r.role : [r.role]
40
42
  } : r,
41
43
  "items"
42
- ), l = (o) => {
43
- if (!o?.length)
44
+ ), d = (e) => {
45
+ if (!e?.length)
44
46
  return null;
45
- const r = u(o), e = {
47
+ const r = l(e), t = {
46
48
  header: [],
47
49
  footer: [],
48
50
  // 对应 footer social media
@@ -55,32 +57,32 @@ const g = window?.blocklet?.groupPrefix || window?.blocklet?.prefix || "/", i =
55
57
  sessionManager: [],
56
58
  userCenter: []
57
59
  };
58
- return r.forEach((t) => {
59
- t.section ? Array.isArray(t.section) ? t.section.forEach((n) => {
60
- e[n]?.push(t);
61
- }) : typeof t.section == "string" && e[t.section]?.push(t) : e.header.push(t);
62
- }), e;
63
- }, b = (o) => {
64
- if (!o)
60
+ return r.forEach((o) => {
61
+ o.section ? Array.isArray(o.section) ? o.section.forEach((n) => {
62
+ t[n]?.push(o);
63
+ }) : typeof o.section == "string" && t[o.section]?.push(o) : t.header.push(o);
64
+ }), t;
65
+ }, y = (e) => {
66
+ if (!e)
65
67
  return null;
66
- const r = { ...o };
67
- return r.theme = i(r.theme), r.navigation = l(d(r.navigation)), r;
68
- }, d = (o = []) => a(o, (r, e) => !!r.link || e.filteredChildren?.length, "items"), y = (o, r) => a(
69
- o,
70
- (e, t) => {
71
- const n = !e.role || r && (e.role.includes(r) || e.role.includes("guest"));
72
- return t.isLeaf ? n : n && t.filteredChildren?.length;
68
+ const r = { ...e };
69
+ return r.theme = c(r.theme), r.navigation = d(h(r.navigation)), r;
70
+ }, h = (e = []) => a(e, (r, t) => !!r.link || t.filteredChildren?.length, "items"), w = (e, r) => a(
71
+ e,
72
+ (t, o) => {
73
+ const n = !t.role || r && (t.role.includes(r) || t.role.includes("guest"));
74
+ return o.isLeaf ? n : n && o.filteredChildren?.length;
73
75
  },
74
76
  "items"
75
77
  );
76
78
  export {
77
- y as filterNavByRole,
78
- d as filterValidNavItems,
79
- b as formatBlockletInfo,
80
- u as formatNavigation,
81
- i as formatTheme,
82
- c as getLink,
83
- p as getLocalizedNavigation,
84
- l as parseNavigation,
85
- g as publicPath
79
+ w as filterNavByRole,
80
+ h as filterValidNavItems,
81
+ y as formatBlockletInfo,
82
+ l as formatNavigation,
83
+ c as formatTheme,
84
+ u as getLink,
85
+ b as getLocalizedNavigation,
86
+ d as parseNavigation,
87
+ p as publicPath
86
88
  };
package/lib/utils.d.ts CHANGED
@@ -3,6 +3,7 @@ export function flatRecursive(array: any, childrenKey?: string): any[];
3
3
  export function countRecursive(array: any, childrenKey?: string): number;
4
4
  export function filterRecursive(array: any, predicate: any, childrenKey?: string): any;
5
5
  export function isUrl(str: any): boolean;
6
+ export function isMailProtocol(str: any): boolean;
6
7
  export function isIconifyString(str: any): boolean;
7
8
  export function matchPath(path: any): any;
8
9
  export function matchPaths(paths?: any[]): number;
package/lib/utils.js CHANGED
@@ -1,61 +1,62 @@
1
1
  import H from "semver";
2
- const d = (n, r, e = "children") => n.map((t) => Array.isArray(t[e]) ? r({
2
+ const d = (e, r, n = "children") => e.map((t) => Array.isArray(t[n]) ? r({
3
3
  ...t,
4
- [e]: d(t[e], r, e)
5
- }) : r(t)), C = (n, r = "children") => {
6
- const e = [];
7
- return d(n, (t) => e.push(t), r), e;
8
- }, S = (n, r = "children") => {
9
- let e = 0;
10
- return d(n, () => e++, r), e;
11
- }, R = (n, r, e = "children") => n.map((t) => ({ ...t })).filter((t) => {
12
- const s = t[e];
4
+ [n]: d(t[n], r, n)
5
+ }) : r(t)), C = (e, r = "children") => {
6
+ const n = [];
7
+ return d(e, (t) => n.push(t), r), n;
8
+ }, P = (e, r = "children") => {
9
+ let n = 0;
10
+ return d(e, () => n++, r), n;
11
+ }, R = (e, r, n = "children") => e.map((t) => ({ ...t })).filter((t) => {
12
+ const s = t[n];
13
13
  if (Array.isArray(s)) {
14
- const o = R(s, r, e);
15
- t[e] = o?.length ? o : void 0;
14
+ const o = R(s, r, n);
15
+ t[n] = o?.length ? o : void 0;
16
16
  }
17
- const c = { filteredChildren: t[e], isLeaf: !s?.length };
17
+ const c = { filteredChildren: t[n], isLeaf: !s?.length };
18
18
  return r(t, c);
19
- }), x = (n) => /^https?:\/\//.test(n), P = (n) => /^[\w-]+:[\w-]+$/.test(n), V = (n) => {
20
- if (!n || !n?.startsWith("/"))
19
+ }), S = (e) => /^https?:\/\//.test(e), x = (e) => /^mailto:/i.test(e.trim()), W = (e) => /^[\w-]+:[\w-]+$/.test(e), V = (e) => {
20
+ if (!e || !e?.startsWith("/"))
21
21
  return !1;
22
- const r = (s) => s.endsWith("/") ? s : `${s}/`, e = r(window.location.pathname), t = r(new URL(n, window.location.origin).pathname);
23
- return e.startsWith(t);
24
- }, W = (n = []) => {
25
- const r = n.map((t, s) => ({ path: t, index: s })).filter((t) => V(t.path));
22
+ const r = (s) => s.endsWith("/") ? s : `${s}/`, n = r(window.location.pathname), t = r(new URL(e, window.location.origin).pathname);
23
+ return n.startsWith(t);
24
+ }, k = (e = []) => {
25
+ const r = e.map((t, s) => ({ path: t, index: s })).filter((t) => V(t.path));
26
26
  return r?.length ? r.slice(1).reduce((t, s) => t.path.length >= s.path.length ? t : s, r[0]).index : -1;
27
- }, k = (n, r = {}) => {
28
- const { columns: e = 1, breakInside: t = !1, groupHeight: s = 48, itemHeight: c = 24, childrenKey: o = "items" } = r, p = n.reduce((u, g) => u + s + (g[o]?.length || 0) * c, 0), l = Math.ceil(p / e), h = [[]];
27
+ }, v = (e, r = {}) => {
28
+ const { columns: n = 1, breakInside: t = !1, groupHeight: s = 48, itemHeight: c = 24, childrenKey: o = "items" } = r, p = e.reduce((u, g) => u + s + (g[o]?.length || 0) * c, 0), h = Math.ceil(p / n), l = [[]];
29
29
  let i = 0, a = 0;
30
- const m = l * 0.2, f = (u) => a > l - m && i < e - 1 && a + u > l + m;
31
- return n.forEach((u) => {
30
+ const m = h * 0.2, f = (u) => a > h - m && i < n - 1 && a + u > h + m;
31
+ return e.forEach((u) => {
32
32
  const g = s + (u[o]?.length || 0) * c;
33
- t && f(s) && (i++, a = 0, h[i] = []), !t && a > 0 && f(g) && (i++, a = 0, h[i] = []), h[i].push({
33
+ t && f(s) && (i++, a = 0, l[i] = []), !t && a > 0 && f(g) && (i++, a = 0, l[i] = []), l[i].push({
34
34
  ...u,
35
35
  group: !0
36
36
  }), a += s, u[o] && u[o].forEach((w) => {
37
- t && f(c) && (i++, a = 0, h[i] = []), h[i].push({
37
+ t && f(c) && (i++, a = 0, l[i] = []), l[i].push({
38
38
  ...w,
39
39
  group: !1
40
40
  }), a += c;
41
41
  });
42
- }), h;
43
- }, v = (n, r) => {
44
- const e = (c) => {
42
+ }), l;
43
+ }, E = (e, r) => {
44
+ const n = (c) => {
45
45
  const o = c.match(/^(\d+\.\d+\.\d+(?:-[^-]+?-\d{8}))/);
46
46
  return o ? o[1] : c;
47
- }, t = e(n), s = e(r);
48
- return t === s && n !== r ? !1 : H.gte(t, s);
47
+ }, t = n(e), s = n(r);
48
+ return t === s && e !== r ? !1 : H.gte(t, s);
49
49
  };
50
50
  export {
51
- v as compareVersions,
52
- S as countRecursive,
51
+ E as compareVersions,
52
+ P as countRecursive,
53
53
  R as filterRecursive,
54
54
  C as flatRecursive,
55
- P as isIconifyString,
56
- x as isUrl,
55
+ W as isIconifyString,
56
+ x as isMailProtocol,
57
+ S as isUrl,
57
58
  d as mapRecursive,
58
59
  V as matchPath,
59
- W as matchPaths,
60
- k as splitNavColumns
60
+ k as matchPaths,
61
+ v as splitNavColumns
61
62
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blocklet/ui-react",
3
- "version": "3.1.27",
3
+ "version": "3.1.28",
4
4
  "description": "Some useful front-end web components that can be used in Blocklets.",
5
5
  "keywords": [
6
6
  "react",
@@ -35,9 +35,9 @@
35
35
  "dependencies": {
36
36
  "@abtnode/constant": "^1.16.48",
37
37
  "@abtnode/util": "^1.16.48",
38
- "@arcblock/bridge": "3.1.27",
39
- "@arcblock/icons": "3.1.27",
40
- "@arcblock/react-hooks": "3.1.27",
38
+ "@arcblock/bridge": "3.1.28",
39
+ "@arcblock/icons": "3.1.28",
40
+ "@arcblock/react-hooks": "3.1.28",
41
41
  "@arcblock/ws": "^1.21.3",
42
42
  "@blocklet/constant": "^1.16.48",
43
43
  "@blocklet/did-space-react": "^1.1.16",
@@ -84,7 +84,7 @@
84
84
  "access": "public"
85
85
  },
86
86
  "devDependencies": {
87
- "@arcblock/did-connect-react": "3.1.27",
87
+ "@arcblock/did-connect-react": "3.1.28",
88
88
  "@types/dompurify": "^3.2.0",
89
89
  "@types/ua-parser-js": "^0.7.39",
90
90
  "@types/validator": "^13.15.2",
@@ -92,5 +92,5 @@
92
92
  "jest": "^29.7.0",
93
93
  "unbuild": "^2.0.0"
94
94
  },
95
- "gitHead": "9cbf9135aa96ce8d13481db7b21f755d009d2f9f"
95
+ "gitHead": "8a62be8796c0ab9129b24a08ecc051d1ac23e0de"
96
96
  }
@@ -9,7 +9,7 @@ import clsx from 'clsx';
9
9
  import { ExpandMore as ExpandMoreIcon } from '@mui/icons-material';
10
10
  import Icon from '../Icon';
11
11
  import useMobile from '../hooks/use-mobile';
12
- import { splitNavColumns } from '../utils';
12
+ import { splitNavColumns, isMailProtocol } from '../utils';
13
13
 
14
14
  /**
15
15
  * footer 中的 links (支持分组, 最多支持 2 级)
@@ -28,14 +28,17 @@ export default function Links({ links = [], flowLayout = false, columns, ...rest
28
28
  result = render({ label, link, props });
29
29
  } else if (link && isString(link)) {
30
30
  const isExternal = link.startsWith('http') || link.startsWith('//');
31
+ const isMail = isMailProtocol(link);
32
+
33
+ const otherProps = isMail
34
+ ? {}
35
+ : {
36
+ target: isExternal ? '_blank' : '_self',
37
+ rel: isExternal ? 'noreferrer noopener' : undefined,
38
+ };
31
39
 
32
40
  result = (
33
- <a
34
- href={link}
35
- aria-label={`Footer link for ${label}`}
36
- target={isExternal ? '_blank' : '_self'}
37
- rel={isExternal ? 'noreferrer noopener' : undefined}
38
- {...props}>
41
+ <a href={link} aria-label={`Footer link for ${label}`} {...otherProps} {...props}>
39
42
  {label}
40
43
  </a>
41
44
  );
package/src/blocklets.js CHANGED
@@ -1,4 +1,4 @@
1
- import { mapRecursive, filterRecursive, isUrl } from './utils';
1
+ import { mapRecursive, filterRecursive, isUrl, isMailProtocol } from './utils';
2
2
 
3
3
  export const publicPath = window?.blocklet?.groupPrefix || window?.blocklet?.prefix || '/';
4
4
 
@@ -28,6 +28,10 @@ export const getLink = (link, locale = 'en') => {
28
28
  url.searchParams.set('locale', locale);
29
29
  return url.href;
30
30
  }
31
+ // 如果是 mailto 协议, 直接返回
32
+ if (isMailProtocol(link)) {
33
+ return link;
34
+ }
31
35
  const url = new URL(link, window.location.origin);
32
36
  url.searchParams.set('locale', locale);
33
37
  return url.pathname + url.search;
package/src/utils.js CHANGED
@@ -47,6 +47,11 @@ export const isUrl = (str) => {
47
47
  return /^https?:\/\//.test(str);
48
48
  };
49
49
 
50
+ // 链接是否是 mailto 协议
51
+ export const isMailProtocol = (str) => {
52
+ return /^mailto:/i.test(str.trim());
53
+ };
54
+
50
55
  /**
51
56
  * @description 检测是否是 Iconify 格式的字符串
52
57
  * @deprecated