@arcblock/ux 3.1.46 → 3.1.48

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.
@@ -6,34 +6,58 @@ export type PaperStyle = import('@mui/material').PaperProps & {
6
6
  minHeight?: number | string;
7
7
  };
8
8
  export type UxDialogProps = {
9
+ /**
10
+ * - The content of the dialog.
11
+ */
9
12
  /**
10
13
  * - The content of the dialog.
11
14
  */
12
15
  children: React.ReactNode;
16
+ /**
17
+ * - The title of the dialog.
18
+ */
13
19
  /**
14
20
  * - The title of the dialog.
15
21
  */
16
22
  title?: React.ReactNode;
23
+ /**
24
+ * - Content to be displayed before the dialog title.
25
+ */
17
26
  /**
18
27
  * - Content to be displayed before the dialog title.
19
28
  */
20
29
  prepend?: React.ReactNode;
30
+ /**
31
+ * - Content to be displayed in the top toolbar of the dialog.
32
+ */
21
33
  /**
22
34
  * - Content to be displayed in the top toolbar of the dialog.
23
35
  */
24
36
  toolbar?: React.ReactNode;
37
+ /**
38
+ * - Content to be displayed in the bottom actions toolbar of the dialog.
39
+ */
25
40
  /**
26
41
  * - Content to be displayed in the bottom actions toolbar of the dialog.
27
42
  */
28
43
  actions?: React.ReactNode;
44
+ /**
45
+ * - Whether or not to show the close button.
46
+ */
29
47
  /**
30
48
  * - Whether or not to show the close button.
31
49
  */
32
50
  showCloseButton?: boolean | undefined;
51
+ /**
52
+ * - The position of the actions toolbar.
53
+ */
33
54
  /**
34
55
  * - The position of the actions toolbar.
35
56
  */
36
57
  actionsPosition?: "left" | "right" | "center" | undefined;
58
+ /**
59
+ * - Props to be passed down to the dialog paper.
60
+ */
37
61
  /**
38
62
  * - Props to be passed down to the dialog paper.
39
63
  */
@@ -41,6 +65,9 @@ export type UxDialogProps = {
41
65
  slotProps?: {
42
66
  content: object;
43
67
  } | undefined;
68
+ /**
69
+ * - Callback function fired when the dialog is closed.
70
+ */
44
71
  /**
45
72
  * - Callback function fired when the dialog is closed.
46
73
  */
@@ -1,6 +1,9 @@
1
1
  import { default as PropTypes } from 'prop-types';
2
2
  export default Img;
3
3
  export type ImgExProps = {
4
+ /**
5
+ * - required
6
+ */
4
7
  /**
5
8
  * - required
6
9
  */
@@ -16,6 +19,9 @@ export type ImgExProps = {
16
19
  lazy?: boolean | undefined;
17
20
  placeholder?: string | undefined;
18
21
  fallback?: string | undefined;
22
+ /**
23
+ * - 是否使用代理 fallback, 用于解决 CSP 的问题
24
+ */
19
25
  /**
20
26
  * - 是否使用代理 fallback, 用于解决 CSP 的问题
21
27
  */
@@ -0,0 +1,5 @@
1
+ import { OrgTransferProps } from './type';
2
+ /**
3
+ * org transfer 弹框
4
+ */
5
+ export default function Index({ org, onSuccess, resourceId, buttonProps, buttonText, locale, dialogProps, children, }: OrgTransferProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,38 @@
1
+ import { jsxs as d, Fragment as g, jsx as i } from "react/jsx-runtime";
2
+ import { useRef as x, cloneElement as k } from "react";
3
+ import { Button as C } from "@mui/material";
4
+ import { useMemoizedFn as O } from "ahooks";
5
+ import h from "./selector.js";
6
+ import j from "./locales.js";
7
+ import { translate as F } from "../Locale/util.js";
8
+ function T({
9
+ org: e,
10
+ onSuccess: f,
11
+ resourceId: s,
12
+ buttonProps: n,
13
+ buttonText: l,
14
+ locale: t = "en",
15
+ dialogProps: c,
16
+ children: o
17
+ }) {
18
+ const a = O((u, p = {}) => F(j, u, t, "en", p)), r = x(null), m = () => {
19
+ r.current && r.current.open({ selectedOrg: e });
20
+ };
21
+ return /* @__PURE__ */ d(g, { children: [
22
+ o ? k(o, { ...n, onClick: m }) : /* @__PURE__ */ i(C, { ...n, onClick: m, children: l || a("transferOrg") }),
23
+ /* @__PURE__ */ i(
24
+ h,
25
+ {
26
+ locale: t,
27
+ org: e,
28
+ ref: r,
29
+ resourceId: s,
30
+ onSuccess: f,
31
+ dialogProps: c
32
+ }
33
+ )
34
+ ] });
35
+ }
36
+ export {
37
+ T as default
38
+ };
@@ -0,0 +1,25 @@
1
+ declare const _default: {
2
+ en: {
3
+ transferOrg: string;
4
+ cancel: string;
5
+ confirm: string;
6
+ tranferSuccess: string;
7
+ placeholder: string;
8
+ loading: string;
9
+ noResults: string;
10
+ resourceIdRequired: string;
11
+ organizationSameAsCurrent: string;
12
+ };
13
+ zh: {
14
+ transferOrg: string;
15
+ cancel: string;
16
+ confirm: string;
17
+ tranferSuccess: string;
18
+ placeholder: string;
19
+ loading: string;
20
+ noResults: string;
21
+ resourceIdRequired: string;
22
+ organizationSameAsCurrent: string;
23
+ };
24
+ };
25
+ export default _default;
@@ -0,0 +1,27 @@
1
+ const e = {
2
+ en: {
3
+ transferOrg: "Transfer to Other Organization",
4
+ cancel: "Cancel",
5
+ confirm: "Confirm",
6
+ tranferSuccess: "Transfer success",
7
+ placeholder: "Select an organization to transfer",
8
+ loading: "Loading...",
9
+ noResults: "No More",
10
+ resourceIdRequired: "Please select the resource to transfer",
11
+ organizationSameAsCurrent: "The selected organization is the same as the current organization, please select other organizations"
12
+ },
13
+ zh: {
14
+ transferOrg: "转移至其他组织",
15
+ cancel: "取消",
16
+ confirm: "确认",
17
+ tranferSuccess: "转移成功",
18
+ placeholder: "请选择要转移的组织",
19
+ loading: "加载中...",
20
+ noResults: "没有更多了",
21
+ resourceIdRequired: "请选择要转移的资源",
22
+ organizationSameAsCurrent: "选择的组织与当前组织相同,请选择其他组织"
23
+ }
24
+ };
25
+ export {
26
+ e as default
27
+ };
@@ -0,0 +1,2 @@
1
+ import { OrgTransferSelectorProps } from './type';
2
+ export default function OrgTransferSelector({ ref, org, onSuccess, resourceId, locale, dialogProps, }: OrgTransferSelectorProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,174 @@
1
+ import { jsx as n, jsxs as i, Fragment as O } from "react/jsx-runtime";
2
+ import { useState as F, useImperativeHandle as _, createElement as y } from "react";
3
+ import { useMemoizedFn as p, useReactive as q, useDebounce as G, useInfiniteScroll as H } from "ahooks";
4
+ import { Box as l, Typography as a, Autocomplete as N, CircularProgress as b, TextField as Q, Button as v } from "@mui/material";
5
+ import w from "../Toast/index.js";
6
+ import Z from "../Dialog/dialog.js";
7
+ import "../Dialog/confirm.js";
8
+ import "lodash/noop";
9
+ import { OrgQueryType as J, client as T } from "../Util/client.js";
10
+ import { formatAxiosError as K } from "../Util/index.js";
11
+ import { translate as U } from "../Locale/util.js";
12
+ import X from "./locales.js";
13
+ const I = 20;
14
+ function ce({
15
+ ref: C,
16
+ org: g,
17
+ onSuccess: S,
18
+ resourceId: f,
19
+ locale: E = "en",
20
+ dialogProps: k
21
+ }) {
22
+ const o = p((e, r = {}) => U(X, e, E, "en", r)), [h, c] = F(""), t = q({
23
+ open: !1,
24
+ selectedOrg: null
25
+ }), x = G(h, { wait: 500 }), { data: A, loadMore: W, loadingMore: d, loading: u, reload: z } = H(
26
+ async (e) => {
27
+ if (!t.open) return { list: [], total: 0 };
28
+ const m = { page: e ? Math.ceil(e.list.length / I) + 1 : 1, pageSize: I, search: x, type: J.OWNED }, R = await T.user.getOrgs(m), { orgs: j = [], paging: B } = R || {};
29
+ return { list: j, total: B?.total || 0 };
30
+ },
31
+ {
32
+ reloadDeps: [x],
33
+ isNoMore: (e) => e?.list.length ? e.list.length >= e?.total : !0,
34
+ onError: (e) => {
35
+ console.error("Get orgs failed", e);
36
+ },
37
+ manual: !0
38
+ // 手动触发,在对话框打开时再加载
39
+ }
40
+ ), s = p(() => {
41
+ t.open = !1, t.selectedOrg = null, c("");
42
+ }), M = p(async () => {
43
+ try {
44
+ if (!f)
45
+ throw new Error(o("resourceIdRequired"));
46
+ if (!t.selectedOrg)
47
+ throw new Error(o("placeholder"));
48
+ if (t.selectedOrg.id === g.id)
49
+ throw new Error(o("organizationSameAsCurrent"));
50
+ await T.user.migrateResourceToOrg({ form: g.id, to: t.selectedOrg.id, resourceId: f }), s(), S?.(t.selectedOrg), w.success(o("tranferSuccess"));
51
+ } catch (e) {
52
+ console.error("Resource transfer failed", e), w.error(K(e));
53
+ }
54
+ });
55
+ _(C, () => ({
56
+ open: (e = {}) => {
57
+ Object.assign(t, { open: !0, selectedOrg: null }, e), setTimeout(() => {
58
+ t.open && z();
59
+ }, 0);
60
+ },
61
+ close: s
62
+ }));
63
+ const D = A?.list || [], { placeholder: L = "", ...P } = k || {};
64
+ return /* @__PURE__ */ n(
65
+ Z,
66
+ {
67
+ title: o("transferOrg"),
68
+ fullWidth: !0,
69
+ maxWidth: "sm",
70
+ open: t.open,
71
+ onClose: s,
72
+ actions: /* @__PURE__ */ i(O, { children: [
73
+ /* @__PURE__ */ n(v, { onClick: s, color: "secondary", variant: "outlined", children: o("cancel") }),
74
+ /* @__PURE__ */ n(v, { onClick: M, color: "primary", variant: "contained", disabled: !t.selectedOrg, children: o("confirm") })
75
+ ] }),
76
+ ...P || {},
77
+ children: /* @__PURE__ */ i(l, { children: [
78
+ /* @__PURE__ */ n(a, { variant: "body2", color: "text.secondary", sx: { mb: 2 }, children: L || o("placeholder") }),
79
+ /* @__PURE__ */ n(
80
+ N,
81
+ {
82
+ options: D,
83
+ getOptionLabel: (e) => e?.name || "",
84
+ isOptionEqualToValue: (e, r) => e?.id === r?.id,
85
+ value: t.selectedOrg,
86
+ onChange: (e, r) => {
87
+ if (r?.isLoadingItem && !d) {
88
+ W();
89
+ return;
90
+ }
91
+ r?.isLoadingItem || (t.selectedOrg = r, r && c(""));
92
+ },
93
+ inputValue: t.selectedOrg ? t.selectedOrg.name : h,
94
+ onInputChange: (e, r, m) => {
95
+ m === "input" && (t.selectedOrg && (t.selectedOrg = null), c(r));
96
+ },
97
+ loading: u,
98
+ loadingText: o("loading"),
99
+ noOptionsText: o(u ? "loading" : "noResults"),
100
+ renderInput: (e) => /* @__PURE__ */ n(
101
+ Q,
102
+ {
103
+ ...e,
104
+ variant: "outlined",
105
+ fullWidth: !0,
106
+ InputProps: {
107
+ ...e.InputProps,
108
+ endAdornment: /* @__PURE__ */ i(O, { children: [
109
+ u && /* @__PURE__ */ n(b, { color: "inherit", size: 20 }),
110
+ e.InputProps.endAdornment
111
+ ] })
112
+ }
113
+ }
114
+ ),
115
+ renderOption: (e, r) => r.isLoadingItem ? /* @__PURE__ */ y(l, { component: "li", ...e, key: r.id }, /* @__PURE__ */ i(
116
+ l,
117
+ {
118
+ sx: {
119
+ display: "flex",
120
+ alignItems: "center",
121
+ justifyContent: "center",
122
+ flex: 1,
123
+ py: 1,
124
+ color: "primary.main",
125
+ cursor: "pointer"
126
+ },
127
+ children: [
128
+ d && /* @__PURE__ */ n(b, { size: 16, sx: { mr: 1 } }),
129
+ /* @__PURE__ */ n(a, { variant: "body2", sx: { fontStyle: d ? "italic" : "normal" }, children: r.name })
130
+ ]
131
+ }
132
+ )) : /* @__PURE__ */ y(l, { component: "li", ...e, key: r.id }, /* @__PURE__ */ i(l, { sx: { display: "flex", flexDirection: "column", flex: 1, minWidth: 0 }, children: [
133
+ /* @__PURE__ */ n(
134
+ a,
135
+ {
136
+ variant: "body1",
137
+ sx: {
138
+ overflow: "hidden",
139
+ textOverflow: "ellipsis",
140
+ whiteSpace: "nowrap"
141
+ },
142
+ children: r.name
143
+ }
144
+ ),
145
+ r.description && /* @__PURE__ */ n(
146
+ a,
147
+ {
148
+ variant: "body2",
149
+ color: "text.secondary",
150
+ sx: {
151
+ display: "-webkit-box",
152
+ WebkitLineClamp: 3,
153
+ WebkitBoxOrient: "vertical",
154
+ overflow: "hidden",
155
+ textOverflow: "ellipsis"
156
+ },
157
+ children: r.description
158
+ }
159
+ )
160
+ ] })),
161
+ sx: {
162
+ "& .MuiAutocomplete-listbox": {
163
+ maxHeight: 200
164
+ }
165
+ }
166
+ }
167
+ )
168
+ ] })
169
+ }
170
+ );
171
+ }
172
+ export {
173
+ ce as default
174
+ };
@@ -0,0 +1,28 @@
1
+ import { ComponentProps } from 'react';
2
+ import { ButtonProps } from '@mui/material';
3
+ import { default as Dialog } from '../Dialog';
4
+ export type Org = {
5
+ id: string;
6
+ name: string;
7
+ description?: string;
8
+ ownerDid: string;
9
+ metadata?: Record<string, any>;
10
+ };
11
+ type DialogProps = ComponentProps<typeof Dialog> & {
12
+ placeholder?: string;
13
+ };
14
+ export type OrgTransferSelectorProps = Omit<OrgTransferProps, 'children' | 'buttonProps' | 'buttonText'> & {
15
+ ref: React.RefObject<unknown | null>;
16
+ };
17
+ export interface OrgTransferProps {
18
+ resourceId: string;
19
+ onSuccess?: (org: Org) => void;
20
+ org?: Org;
21
+ children?: React.ReactNode;
22
+ buttonProps?: ButtonProps;
23
+ buttonText?: string;
24
+ dialogProps?: DialogProps;
25
+ locale?: string;
26
+ [key: string]: any;
27
+ }
28
+ export {};
@@ -0,0 +1 @@
1
+
@@ -1,6 +1,4 @@
1
- import { AxiosError } from 'axios';
2
1
  import { User } from './types';
3
- export declare const formatAxiosError: (err: AxiosError) => string;
4
2
  /**
5
3
  * 登录用户与当前用户(userDid)的关注关系
6
4
  */
@@ -1,67 +1,63 @@
1
- import { useState as y, useMemo as f, useEffect as d } from "react";
2
- import { useMemoizedFn as w } from "ahooks";
1
+ import { useState as y, useMemo as u, useEffect as F } from "react";
2
+ import { useMemoizedFn as f } from "ahooks";
3
3
  import U from "lodash/isNil";
4
- import { BlockletSDK as x } from "@blocklet/js-sdk";
5
- import u from "../Toast/index.js";
6
- const F = (r) => {
7
- const { response: t } = r;
8
- return t ? `Request failed: ${t.status} ${t.statusText}: ${JSON.stringify(t.data)}` : r.message;
9
- };
10
- function z({
11
- user: r,
12
- t,
13
- isMySelf: n,
4
+ import { BlockletSDK as D } from "@blocklet/js-sdk";
5
+ import a from "../Toast/index.js";
6
+ import { formatAxiosError as d } from "../Util/index.js";
7
+ function K({
8
+ user: e,
9
+ t: w,
10
+ isMySelf: l,
14
11
  visible: m
15
12
  }) {
16
- const [p, c] = y(!1), s = f(() => r?.did, [r]), i = f(() => Object.prototype.hasOwnProperty.call(r, "isFollowing") && !U(r.isFollowing), [r]), e = f(() => {
13
+ const [p, c] = y(!1), t = u(() => e?.did, [e]), n = u(() => Object.prototype.hasOwnProperty.call(e, "isFollowing") && !U(e.isFollowing), [e]), r = u(() => {
17
14
  let o = null;
18
15
  try {
19
- o = new x();
20
- } catch (l) {
21
- console.error("Failed to initialize BlockletSDK:", l), o = null;
16
+ o = new D();
17
+ } catch (s) {
18
+ console.error("Failed to initialize BlockletSDK:", s), o = null;
22
19
  }
23
20
  return o;
24
- }, []), a = w(async () => {
25
- if (!e) {
21
+ }, []), i = f(async () => {
22
+ if (!r) {
26
23
  c(!1);
27
24
  return;
28
25
  }
29
26
  try {
30
- if (n) {
27
+ if (l) {
31
28
  c(!0);
32
29
  return;
33
30
  }
34
- const o = await e.user.isFollowingUser({ userDid: s });
31
+ const o = await r.user.isFollowingUser({ userDid: t });
35
32
  c(o);
36
33
  } catch (o) {
37
34
  console.error(o);
38
35
  }
39
- }), g = w(async (o = s) => {
40
- if (!(!e || n && o === s))
36
+ }), h = f(async (o = t) => {
37
+ if (!(!r || l && o === t))
41
38
  try {
42
- await e.user.followUser({ userDid: o }), u.success(t("follow_success")), a();
43
- } catch (l) {
44
- console.error(l), u.error(F(l));
39
+ await r.user.followUser({ userDid: o }), a.success(w("follow_success")), i();
40
+ } catch (s) {
41
+ console.error(s), a.error(d(s));
45
42
  }
46
- }), h = w(async (o = s) => {
47
- if (!(!e || n && o === s))
43
+ }), g = f(async (o = t) => {
44
+ if (!(!r || l && o === t))
48
45
  try {
49
- await e.user.unfollowUser({ userDid: o }), u.success(t("unfollow_success")), a();
50
- } catch (l) {
51
- console.error(l), u.error(F(l));
46
+ await r.user.unfollowUser({ userDid: o }), a.success(w("unfollow_success")), i();
47
+ } catch (s) {
48
+ console.error(s), a.error(d(s));
52
49
  }
53
50
  });
54
- return d(() => {
55
- m && s && !n && e && !i && a();
56
- }, [a, s, n, e, i, m]), d(() => {
57
- i && c(r?.isFollowing || !1);
58
- }, [i, r]), {
51
+ return F(() => {
52
+ m && t && !l && r && !n && i();
53
+ }, [i, t, l, r, n, m]), F(() => {
54
+ n && c(e?.isFollowing || !1);
55
+ }, [n, e]), {
59
56
  followed: p,
60
- followUser: g,
61
- unfollowUser: h
57
+ followUser: h,
58
+ unfollowUser: g
62
59
  };
63
60
  }
64
61
  export {
65
- z as default,
66
- F as formatAxiosError
62
+ K as default
67
63
  };
@@ -0,0 +1,6 @@
1
+ import { BlockletSDK } from '@blocklet/js-sdk';
2
+ export declare enum OrgQueryType {
3
+ OWNED = "owned",
4
+ JOINED = "joined"
5
+ }
6
+ export declare const client: BlockletSDK;
@@ -0,0 +1,7 @@
1
+ import { BlockletSDK as n } from "@blocklet/js-sdk";
2
+ var t = /* @__PURE__ */ ((o) => (o.OWNED = "owned", o.JOINED = "joined", o))(t || {});
3
+ const r = new n();
4
+ export {
5
+ t as OrgQueryType,
6
+ r as client
7
+ };
@@ -26,15 +26,7 @@ export declare const LOGIN_PROVIDER: {
26
26
  TWITTER: string;
27
27
  };
28
28
  export declare const LOGIN_PROVIDER_NAME: {
29
- [LOGIN_PROVIDER.EMAIL]: string;
30
- [LOGIN_PROVIDER.AUTH0]: string;
31
- [LOGIN_PROVIDER.APPLE]: string;
32
- [LOGIN_PROVIDER.GITHUB]: string;
33
- [LOGIN_PROVIDER.GOOGLE]: string;
34
- [LOGIN_PROVIDER.WALLET]: string;
35
- [LOGIN_PROVIDER.NFT]: string;
36
- [LOGIN_PROVIDER.PASSKEY]: string;
37
- [LOGIN_PROVIDER.TWITTER]: string;
29
+ [x: string]: string;
38
30
  };
39
31
  export declare const OAUTH_PROVIDER: {
40
32
  email: string;
@@ -1,5 +1,6 @@
1
1
  import { mergeAllThemeOptions } from '@blocklet/theme';
2
2
  import { default as Cookies } from 'js-cookie';
3
+ import { AxiosError } from 'axios';
3
4
  import { $TSFixMe, Locale } from '../type';
4
5
  declare let dateTool: $TSFixMe | null;
5
6
  /** @deprecated for compatibility, please use `import { mergeAllThemeOptions } from '@blocklet/theme'` instead */
@@ -121,3 +122,4 @@ export declare const compareVersions: (version1: string, version2: string) => bo
121
122
  * 通过 server 的版本和 ux 的版本共同决定
122
123
  */
123
124
  export declare const isSupportFollow: () => boolean;
125
+ export declare const formatAxiosError: (err: AxiosError) => string;
package/lib/Util/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { lazy as j } from "react";
1
+ import { lazy as T } from "react";
2
2
  import l from "lodash/padStart";
3
- import { colors as w, getDIDMotifInfo as x } from "@arcblock/did-motif";
3
+ import { colors as w, getDIDMotifInfo as j } from "@arcblock/did-motif";
4
4
  import { mergeAllThemeOptions as Ke } from "@blocklet/theme";
5
5
  import I from "lodash/isNil";
6
6
  import E from "lodash/omitBy";
@@ -10,23 +10,23 @@ import O from "color-convert";
10
10
  import a from "dayjs";
11
11
  import "dayjs/locale/zh-cn";
12
12
  import U from "dayjs/plugin/utc";
13
- import F from "dayjs/plugin/timezone";
14
- import A from "dayjs/plugin/relativeTime";
15
- import P from "dayjs/plugin/updateLocale";
16
- import R from "dayjs/plugin/localizedFormat";
13
+ import A from "dayjs/plugin/timezone";
14
+ import F from "dayjs/plugin/relativeTime";
15
+ import R from "dayjs/plugin/updateLocale";
16
+ import P from "dayjs/plugin/localizedFormat";
17
17
  import W from "semver";
18
18
  import { DID_PREFIX as L, BLOCKLET_SERVICE_PATH_PREFIX as C } from "./constant.js";
19
19
  import b from "../package.json.js";
20
20
  import { getFederatedEnabled as M } from "./federated.js";
21
21
  let u = null;
22
- const _ = /^(\d{1,3}\.){3}\d{1,3}(:\d+)?$/, z = /* @__PURE__ */ new Set(["co", "com", "net", "org", "gov", "edu", "ac"]), N = /* @__PURE__ */ new Set(["uk", "au", "cn", "nz", "za", "in", "br", "mx", "fr", "it", "ca"]);
22
+ const _ = /^(\d{1,3}\.){3}\d{1,3}(:\d+)?$/, N = /* @__PURE__ */ new Set(["co", "com", "net", "org", "gov", "edu", "ac"]), z = /* @__PURE__ */ new Set(["uk", "au", "cn", "nz", "za", "in", "br", "mx", "fr", "it", "ca"]);
23
23
  function B(e) {
24
24
  if (!e)
25
25
  return !1;
26
26
  const t = e.split(".");
27
27
  if (t.length < 2) return !1;
28
28
  const o = t[t.length - 2], r = t[t.length - 1];
29
- return z.has(o) && N.has(r);
29
+ return N.has(o) && z.has(r);
30
30
  }
31
31
  function ye() {
32
32
  const { host: e } = window.location;
@@ -51,7 +51,7 @@ function Ie(e) {
51
51
  function be(e = {}) {
52
52
  return new URLSearchParams(e).toString();
53
53
  }
54
- function De(e = 1) {
54
+ function Se(e = 1) {
55
55
  let t = e;
56
56
  typeof t == "number" && (t = { expireInDays: t }), t.path === void 0 && (t.path = "/"), t.expireInDays || (t.expireInDays = 1);
57
57
  const o = {
@@ -64,7 +64,7 @@ function De(e = 1) {
64
64
  };
65
65
  return (typeof window > "u" || t.domain || t.returnDomain === !1) && t.returnDomain === !1 && delete o.domain, o;
66
66
  }
67
- const Se = (e) => e.color ? e.color : e.dark ? e.theme.palette.common.white : e.theme.palette.text.primary, Ve = (e) => e.background ? e.background : e.dark ? e.theme.palette.common.black : e.theme.palette.common.white;
67
+ const De = (e) => e.color ? e.color : e.dark ? e.theme.palette.common.white : e.theme.palette.text.primary, $e = (e) => e.background ? e.background : e.dark ? e.theme.palette.common.black : e.theme.palette.common.white;
68
68
  function ke(e, t, o = []) {
69
69
  const r = Object.assign({}, e), i = t.defaultProps || {};
70
70
  return Object.keys(i).forEach((n) => {
@@ -79,11 +79,11 @@ function ke(e, t, o = []) {
79
79
  typeof r[n] == "string" && r[n].indexOf("::prop::") === 0 && (r[n] = "");
80
80
  }), r;
81
81
  }
82
- function $e(e = 2017) {
82
+ function Ve(e = 2017) {
83
83
  const t = (/* @__PURE__ */ new Date()).getFullYear();
84
84
  return `${t}` == `${e}` ? `© ArcBlock ${t}` : `© ArcBlock ${e} - ${t}`;
85
85
  }
86
- const Te = () => typeof Intl == "object" && typeof Intl.DateTimeFormat == "function" && typeof Intl.DateTimeFormat().resolvedOptions == "function" ? Intl.DateTimeFormat().resolvedOptions().timeZone : "", je = (e) => {
86
+ const xe = () => typeof Intl == "object" && typeof Intl.DateTimeFormat == "function" && typeof Intl.DateTimeFormat().resolvedOptions == "function" ? Intl.DateTimeFormat().resolvedOptions().timeZone : "", Te = (e) => {
87
87
  let t = 0;
88
88
  for (let r = 0; r < e.length; r++)
89
89
  t = e.charCodeAt(r) + ((t << 5) - t);
@@ -93,7 +93,7 @@ const Te = () => typeof Intl == "object" && typeof Intl.DateTimeFormat == "funct
93
93
  o += `00${i.toString(16)}`.substr(-2);
94
94
  }
95
95
  return o;
96
- }, xe = (e) => {
96
+ }, je = (e) => {
97
97
  const t = Math.round(e / 1e3), o = Math.floor(t / 3600), r = Math.floor((t - o * 3600) / 60), i = t % 60;
98
98
  return `${l(o, 2, "0")}:${l(r, 2, "0")}:${l(i, 2, "0")}`;
99
99
  };
@@ -103,8 +103,8 @@ function X(e) {
103
103
  function Ee() {
104
104
  return u;
105
105
  }
106
- const D = (e) => (t, { locale: o, tz: r, isUtc: i } = {}) => {
107
- if (u === null && (a.extend(R), a.extend(U), a.extend(F), a.extend(P), a.extend(A), a.updateLocale("zh-cn", {
106
+ const S = (e) => (t, { locale: o, tz: r, isUtc: i } = {}) => {
107
+ if (u === null && (a.extend(P), a.extend(U), a.extend(A), a.extend(R), a.extend(F), a.updateLocale("zh-cn", {
108
108
  // copy with https://github.com/iamkun/dayjs/blob/dev/src/locale/zh-cn.js
109
109
  relativeTime: {
110
110
  future: "%s后",
@@ -127,7 +127,7 @@ const D = (e) => (t, { locale: o, tz: r, isUtc: i } = {}) => {
127
127
  return r && (n = n.tz(r)), i && (n = n.utc()), typeof o < "u" && (n = n.locale(o)), n.format(e);
128
128
  };
129
129
  function ve(e, { locale: t = "en", tz: o } = {}) {
130
- return D("ll")(e, { locale: t, tz: o });
130
+ return S("ll")(e, { locale: t, tz: o });
131
131
  }
132
132
  function Oe(e, {
133
133
  locale: t = "en",
@@ -135,9 +135,9 @@ function Oe(e, {
135
135
  isUtc: r = !1,
136
136
  format: i = "lll"
137
137
  } = {}) {
138
- return D(i)(e, { locale: t, tz: o, isUtc: r });
138
+ return S(i)(e, { locale: t, tz: o, isUtc: r });
139
139
  }
140
- function K() {
140
+ function J() {
141
141
  const e = window?.ABT_DEV || window.ABT;
142
142
  return e && typeof e.open == "function" ? e : null;
143
143
  }
@@ -150,7 +150,7 @@ function Ue({
150
150
  appInfo: n,
151
151
  memberAppInfo: f
152
152
  }) {
153
- const h = K();
153
+ const h = J();
154
154
  if (h)
155
155
  return h.open({
156
156
  action: t,
@@ -163,7 +163,7 @@ function Ue({
163
163
  ...f
164
164
  }
165
165
  }), { type: "extension" };
166
- const S = {
166
+ const D = {
167
167
  toolbar: "no",
168
168
  location: "no",
169
169
  status: "no",
@@ -173,19 +173,19 @@ function Ue({
173
173
  // iphone 8plus size
174
174
  width: 414,
175
175
  height: 736
176
- }, V = `${e}?action=${t}&locale=${o}&url=${encodeURIComponent(r)}`, c = Object.assign({}, S, i), k = (s) => s.innerWidth || s.document.documentElement.clientWidth || s.document.body.clientWidth;
176
+ }, $ = `${e}?action=${t}&locale=${o}&url=${encodeURIComponent(r)}`, c = Object.assign({}, D, i), k = (s) => s.innerWidth || s.document.documentElement.clientWidth || s.document.body.clientWidth;
177
177
  if (!("left" in c)) {
178
- const s = k(window.top || window), T = window.screenLeft || window.screenX;
179
- c.left = s + T - c.width;
178
+ const s = k(window.top || window), x = window.screenLeft || window.screenX;
179
+ c.left = s + x - c.width;
180
180
  }
181
181
  if (!("top" in c)) {
182
182
  const s = window.screenTop || window.screenY;
183
183
  c.top = s;
184
184
  }
185
- const $ = Object.keys(c).map((s) => `${s}=${c[s]}`).join(",");
186
- return window.open(V, "targetWindow", $), { type: "web" };
185
+ const V = Object.keys(c).map((s) => `${s}=${c[s]}`).join(",");
186
+ return window.open($, "targetWindow", V), { type: "web" };
187
187
  }
188
- const Fe = (e) => e && Number(e) >= 12 ? `${Number(e)}px` : "inherit", J = (e) => {
188
+ const Ae = (e) => e && Number(e) >= 12 ? `${Number(e)}px` : "inherit", K = (e) => {
189
189
  const t = e.replace(L, "");
190
190
  return !!/^(0x)?[0-9a-f]{40}$/i.test(t);
191
191
  }, Q = (e, t) => {
@@ -199,15 +199,15 @@ const Fe = (e) => e && Number(e) >= 12 ? `${Number(e)}px` : "inherit", J = (e) =
199
199
  } catch {
200
200
  return e;
201
201
  }
202
- }, Ae = (e, t = 48) => e && (e.indexOf(C) >= 0 ? Q(e, {
202
+ }, Fe = (e, t = 48) => e && (e.indexOf(C) >= 0 ? Q(e, {
203
203
  imageFilter: "resize",
204
204
  w: t,
205
205
  h: t
206
- }) : e), Pe = (e = 0) => new Promise((t) => {
206
+ }) : e), Re = (e = 0) => new Promise((t) => {
207
207
  setTimeout(() => {
208
208
  t();
209
209
  }, e);
210
- }), Re = (e) => /^https?:\/\//.test(e), p = "vid", g = "__visitor_id", Y = () => m.get(p) || localStorage.getItem(g), y = (e) => {
210
+ }), Pe = (e) => /^https?:\/\//.test(e), p = "vid", g = "__visitor_id", Y = () => m.get(p) || localStorage.getItem(g), y = (e) => {
211
211
  e === null ? m.remove(p, {
212
212
  sameSite: "None",
213
213
  secure: !0
@@ -245,14 +245,14 @@ const Fe = (e) => e && Number(e) >= 12 ? `${Number(e)}px` : "inherit", J = (e) =
245
245
  e && y(e);
246
246
  }
247
247
  }, Le = (e) => {
248
- if (J(e)) {
248
+ if (K(e)) {
249
249
  const t = Uint8Array.from(
250
250
  e.slice(2).match(/.{1,2}/g).map((o) => parseInt(o, 16))
251
251
  ).slice(0, 8).reduce((o, r) => o + r, 0) % w.length;
252
252
  return w[t];
253
253
  }
254
254
  try {
255
- return x(e)?.color;
255
+ return j(e)?.color;
256
256
  } catch {
257
257
  return null;
258
258
  }
@@ -262,7 +262,7 @@ const Fe = (e) => e && Number(e) >= 12 ? `${Number(e)}px` : "inherit", J = (e) =
262
262
  return e;
263
263
  let n;
264
264
  return t && (n = e[t]), (!n || typeof n != "string") && (n = e[r]), (!n || typeof n != "string") && (n = i), n;
265
- }, Me = (e) => j(
265
+ }, Me = (e) => T(
266
266
  () => v(
267
267
  async () => {
268
268
  try {
@@ -275,11 +275,11 @@ const Fe = (e) => e && Number(e) >= 12 ? `${Number(e)}px` : "inherit", J = (e) =
275
275
  { retries: 2 }
276
276
  )
277
277
  ), _e = (e) => E(e, I);
278
- function ze(e, t = 1) {
278
+ function Ne(e, t = 1) {
279
279
  const [o, r, i] = O.hex.rgb(e);
280
280
  return `rgba(${o}, ${r}, ${i}, ${t})`;
281
281
  }
282
- const G = () => window.blocklet?.serverVersion || window.env?.serverVersion || "", H = () => b.version, Z = () => (b.dependencies?.["@blocklet/js-sdk"]).replace(/^[\^~>=<]+/, ""), d = (e, t) => {
282
+ const q = () => window.blocklet?.serverVersion || window.env?.serverVersion || "", G = () => b.version, H = () => (b.dependencies?.["@blocklet/js-sdk"]).replace(/^[\^~>=<]+/, ""), d = (e, t) => {
283
283
  const o = (n) => {
284
284
  const f = n.match(/^(\d+\.\d+\.\d+(?:-[^-]+?-\d{8}))/);
285
285
  return f ? f[1] : n;
@@ -294,44 +294,48 @@ const G = () => window.blocklet?.serverVersion || window.env?.serverVersion || "
294
294
  } catch {
295
295
  return !1;
296
296
  }
297
- }, Ne = () => {
297
+ }, ze = () => {
298
298
  if (process.env.NODE_ENV === "development")
299
299
  return !0;
300
- const e = G(), t = H(), o = Z();
300
+ const e = q(), t = G(), o = H();
301
301
  if (!e || !t || !o)
302
302
  return !1;
303
303
  const r = d(t, "3.1.29"), i = d(e, "1.16.49-beta-20250822-070545-6d3344cc"), n = d(o, "1.16.49-beta-20250822-070545-6d3344cc");
304
304
  return r && i && n;
305
+ }, Be = (e) => {
306
+ const { response: t } = e;
307
+ return t ? `Request failed: ${t.status} ${t.statusText}: ${JSON.stringify(t.data)}` : e.message || "Unknown error occurred";
305
308
  };
306
309
  export {
307
310
  Q as appendParams,
308
311
  _e as cleanedObj,
309
312
  d as compareVersions,
310
313
  Ke as deepmergeAll,
311
- K as detectWalletExtension,
314
+ J as detectWalletExtension,
312
315
  We as ensureVisitorId,
316
+ Be as formatAxiosError,
313
317
  ve as formatToDate,
314
318
  Oe as formatToDatetime,
315
- xe as formatUptime,
316
- Ve as getBackground,
317
- Se as getColor,
318
- De as getCookieOptions,
319
- $e as getCopyright,
319
+ je as formatUptime,
320
+ $e as getBackground,
321
+ De as getColor,
322
+ Se as getCookieOptions,
323
+ Ve as getCopyright,
320
324
  Le as getDIDColor,
321
325
  Ee as getDateTool,
322
- Fe as getFontSize,
323
- Z as getJsSdkVersion,
324
- G as getServerVersion,
325
- Te as getTimezone,
326
+ Ae as getFontSize,
327
+ H as getJsSdkVersion,
328
+ q as getServerVersion,
329
+ xe as getTimezone,
326
330
  Ce as getTranslation,
327
- Ae as getUserAvatar,
328
- H as getUxPackageVersion,
331
+ Fe as getUserAvatar,
332
+ G as getUxPackageVersion,
329
333
  Y as getVisitorId,
330
- ze as hexToRgba,
331
- J as isEthereumDid,
332
- Ne as isSupportFollow,
334
+ Ne as hexToRgba,
335
+ K as isEthereumDid,
336
+ ze as isSupportFollow,
333
337
  B as isTwoSegmentTLD,
334
- Re as isUrl,
338
+ Pe as isUrl,
335
339
  Me as lazyRetry,
336
340
  ke as mergeProps,
337
341
  Ue as openWebWallet,
@@ -339,7 +343,7 @@ export {
339
343
  ye as resolveRootDomain,
340
344
  X as setDateTool,
341
345
  y as setVisitorId,
342
- Pe as sleep,
343
- je as str2color,
346
+ Re as sleep,
347
+ Te as str2color,
344
348
  be as stringifyQuery
345
349
  };
@@ -1,9 +1,9 @@
1
- const e = "3.1.46", s = { "@blocklet/js-sdk": "1.16.52-beta-20251005-235515-42ad5caf" }, t = {
1
+ const e = "3.1.48", s = { "@blocklet/js-sdk": "1.16.52" }, n = {
2
2
  version: e,
3
3
  dependencies: s
4
4
  };
5
5
  export {
6
- t as default,
6
+ n as default,
7
7
  s as dependencies,
8
8
  e as version
9
9
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcblock/ux",
3
- "version": "3.1.46",
3
+ "version": "3.1.48",
4
4
  "description": "Common used react components for arcblock products",
5
5
  "keywords": [
6
6
  "react",
@@ -68,16 +68,16 @@
68
68
  "react": "^19.0.0",
69
69
  "react-router-dom": "^6.22.3"
70
70
  },
71
- "gitHead": "2ced986bdd3c032e7b804790d3b9eced2eda7802",
71
+ "gitHead": "49a6dabae8a06667e517c6811f5f7939ff907ce1",
72
72
  "dependencies": {
73
- "@arcblock/bridge": "3.1.46",
73
+ "@arcblock/bridge": "3.1.48",
74
74
  "@arcblock/did": "^1.25.6",
75
75
  "@arcblock/did-motif": "^1.1.14",
76
- "@arcblock/icons": "3.1.46",
77
- "@arcblock/nft-display": "3.1.46",
78
- "@arcblock/react-hooks": "3.1.46",
79
- "@blocklet/js-sdk": "1.16.52-beta-20251005-235515-42ad5caf",
80
- "@blocklet/theme": "3.1.46",
76
+ "@arcblock/icons": "3.1.48",
77
+ "@arcblock/nft-display": "3.1.48",
78
+ "@arcblock/react-hooks": "3.1.48",
79
+ "@blocklet/js-sdk": "1.16.52",
80
+ "@blocklet/theme": "3.1.48",
81
81
  "@fontsource/roboto": "~5.1.1",
82
82
  "@fontsource/ubuntu-mono": "^5.2.6",
83
83
  "@iconify-icons/logos": "^1.2.36",
@@ -0,0 +1,53 @@
1
+ import { useRef, cloneElement } from 'react';
2
+ import { Button } from '@mui/material';
3
+ import { useMemoizedFn } from 'ahooks';
4
+ import OrgTransferSelector from './selector';
5
+ import { OrgTransferProps } from './type';
6
+ import translations from './locales';
7
+ import { translate } from '../Locale/util';
8
+
9
+ /**
10
+ * org transfer 弹框
11
+ */
12
+ export default function Index({
13
+ org,
14
+ onSuccess,
15
+ resourceId,
16
+ buttonProps,
17
+ buttonText,
18
+ locale = 'en',
19
+ dialogProps,
20
+ children,
21
+ }: OrgTransferProps) {
22
+ const t = useMemoizedFn((key, data = {}) => {
23
+ return translate(translations, key, locale, 'en', data);
24
+ });
25
+ const dialogRef = useRef(null);
26
+
27
+ const handleClick = () => {
28
+ if (dialogRef.current) {
29
+ (dialogRef.current as any).open({ selectedOrg: org });
30
+ }
31
+ };
32
+
33
+ return (
34
+ <>
35
+ {children ? (
36
+ cloneElement(children as React.ReactElement, { ...buttonProps, onClick: handleClick } as any)
37
+ ) : (
38
+ <Button {...buttonProps} onClick={handleClick}>
39
+ {buttonText || t('transferOrg')}
40
+ </Button>
41
+ )}
42
+
43
+ <OrgTransferSelector
44
+ locale={locale}
45
+ org={org}
46
+ ref={dialogRef}
47
+ resourceId={resourceId}
48
+ onSuccess={onSuccess}
49
+ dialogProps={dialogProps}
50
+ />
51
+ </>
52
+ );
53
+ }
@@ -0,0 +1,25 @@
1
+ export default {
2
+ en: {
3
+ transferOrg: 'Transfer to Other Organization',
4
+ cancel: 'Cancel',
5
+ confirm: 'Confirm',
6
+ tranferSuccess: 'Transfer success',
7
+ placeholder: 'Select an organization to transfer',
8
+ loading: 'Loading...',
9
+ noResults: 'No More',
10
+ resourceIdRequired: 'Please select the resource to transfer',
11
+ organizationSameAsCurrent:
12
+ 'The selected organization is the same as the current organization, please select other organizations',
13
+ },
14
+ zh: {
15
+ transferOrg: '转移至其他组织',
16
+ cancel: '取消',
17
+ confirm: '确认',
18
+ tranferSuccess: '转移成功',
19
+ placeholder: '请选择要转移的组织',
20
+ loading: '加载中...',
21
+ noResults: '没有更多了',
22
+ resourceIdRequired: '请选择要转移的资源',
23
+ organizationSameAsCurrent: '选择的组织与当前组织相同,请选择其他组织',
24
+ },
25
+ };
@@ -0,0 +1,249 @@
1
+ /**
2
+ * Org transfer selector
3
+ */
4
+ import { useImperativeHandle, useState } from 'react';
5
+ import { useReactive, useDebounce, useInfiniteScroll, useMemoizedFn } from 'ahooks';
6
+ import { Button, Typography, Box, Autocomplete, TextField, CircularProgress } from '@mui/material';
7
+ import { AxiosError } from 'axios';
8
+ import Toast from '../Toast';
9
+ import Dialog from '../Dialog';
10
+ import { Org, OrgTransferSelectorProps } from './type';
11
+ import { client, OrgQueryType } from '../Util/client';
12
+ import { formatAxiosError } from '../Util';
13
+ import { translate } from '../Locale/util';
14
+ import translations from './locales';
15
+
16
+ const PAGE_SIZE = 20;
17
+
18
+ export default function OrgTransferSelector({
19
+ ref,
20
+ org,
21
+ onSuccess,
22
+ resourceId,
23
+ locale = 'en',
24
+ dialogProps,
25
+ }: OrgTransferSelectorProps) {
26
+ const t = useMemoizedFn((key, data = {}) => {
27
+ return translate(translations, key, locale, 'en', data);
28
+ });
29
+ const [searchText, setSearchText] = useState('');
30
+
31
+ const state = useReactive<{
32
+ open: boolean;
33
+ selectedOrg: Org | null;
34
+ }>({
35
+ open: false,
36
+ selectedOrg: null,
37
+ });
38
+
39
+ const debouncedSearchText = useDebounce(searchText, { wait: 500 });
40
+
41
+ const { data, loadMore, loadingMore, loading, reload } = useInfiniteScroll(
42
+ async (d) => {
43
+ // 只有对话框打开时才发起请求
44
+ if (!state.open) return { list: [], total: 0 };
45
+
46
+ const page = d ? Math.ceil(d.list.length / PAGE_SIZE) + 1 : 1;
47
+ const params = { page, pageSize: PAGE_SIZE, search: debouncedSearchText, type: OrgQueryType.OWNED };
48
+ const response = await client.user.getOrgs(params);
49
+
50
+ const { orgs: resultOrgs = [], paging } = response || {};
51
+ return { list: resultOrgs, total: paging?.total || 0 };
52
+ },
53
+ {
54
+ reloadDeps: [debouncedSearchText],
55
+ isNoMore: (d) => {
56
+ if (!d?.list.length) return true;
57
+ return d.list.length >= d?.total;
58
+ },
59
+ onError: (error) => {
60
+ // eslint-disable-next-line no-console
61
+ console.error('Get orgs failed', error);
62
+ },
63
+ manual: true, // 手动触发,在对话框打开时再加载
64
+ }
65
+ );
66
+
67
+ const handleClose = useMemoizedFn(() => {
68
+ state.open = false;
69
+ state.selectedOrg = null;
70
+ setSearchText(''); // 关闭时重置搜索
71
+ });
72
+
73
+ const handleConfirm = useMemoizedFn(async () => {
74
+ try {
75
+ if (!resourceId) {
76
+ throw new Error(t('resourceIdRequired'));
77
+ }
78
+ if (!state.selectedOrg) {
79
+ throw new Error(t('placeholder'));
80
+ }
81
+ if (state.selectedOrg.id === org.id) {
82
+ throw new Error(t('organizationSameAsCurrent'));
83
+ }
84
+ await client.user.migrateResourceToOrg({ form: org.id, to: state.selectedOrg.id, resourceId });
85
+ handleClose();
86
+ onSuccess?.(state.selectedOrg);
87
+ Toast.success(t('tranferSuccess'));
88
+ } catch (error) {
89
+ console.error('Resource transfer failed', error);
90
+ Toast.error(formatAxiosError(error as AxiosError));
91
+ }
92
+ });
93
+
94
+ useImperativeHandle(ref, () => ({
95
+ open: (options = {}) => {
96
+ Object.assign(state, { open: true, selectedOrg: null }, options);
97
+ // 对话框打开时重新加载数据
98
+ setTimeout(() => {
99
+ if (state.open) {
100
+ reload();
101
+ }
102
+ }, 0);
103
+ },
104
+ close: handleClose,
105
+ }));
106
+
107
+ const organizations = data?.list || [];
108
+ // const hasMore = data ? data.list.length < data.total : false;
109
+
110
+ const { placeholder = '', ...rest } = dialogProps || {};
111
+ return (
112
+ <Dialog
113
+ title={t('transferOrg')}
114
+ fullWidth
115
+ maxWidth="sm"
116
+ open={state.open}
117
+ onClose={handleClose}
118
+ actions={
119
+ <>
120
+ <Button onClick={handleClose} color="secondary" variant="outlined">
121
+ {t('cancel')}
122
+ </Button>
123
+ <Button onClick={handleConfirm} color="primary" variant="contained" disabled={!state.selectedOrg}>
124
+ {t('confirm')}
125
+ </Button>
126
+ </>
127
+ }
128
+ {...(rest || {})}>
129
+ <Box>
130
+ <Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
131
+ {placeholder || t('placeholder')}
132
+ </Typography>
133
+
134
+ <Autocomplete
135
+ options={organizations}
136
+ getOptionLabel={(option) => option?.name || ''}
137
+ isOptionEqualToValue={(option, value) => option?.id === value?.id}
138
+ value={state.selectedOrg}
139
+ onChange={(_, newValue) => {
140
+ // 如果点击的是加载项,触发加载更多
141
+ if (newValue?.isLoadingItem && !loadingMore) {
142
+ loadMore();
143
+ return;
144
+ }
145
+ // 忽略加载项的选择
146
+ if (newValue?.isLoadingItem) {
147
+ return;
148
+ }
149
+ state.selectedOrg = newValue;
150
+ // 选择选项后清空搜索文本
151
+ if (newValue) {
152
+ setSearchText('');
153
+ }
154
+ }}
155
+ inputValue={state.selectedOrg ? state.selectedOrg.name : searchText}
156
+ onInputChange={(_, newInputValue, reason) => {
157
+ // 只有用户键盘输入时才更新搜索文本
158
+ if (reason === 'input') {
159
+ // 用户开始输入时,清除当前选中的组织,进入搜索模式
160
+ if (state.selectedOrg) {
161
+ state.selectedOrg = null;
162
+ }
163
+ setSearchText(newInputValue);
164
+ }
165
+ }}
166
+ loading={loading}
167
+ loadingText={t('loading')}
168
+ noOptionsText={loading ? t('loading') : t('noResults')}
169
+ renderInput={(params) => (
170
+ <TextField
171
+ {...params}
172
+ variant="outlined"
173
+ fullWidth
174
+ InputProps={{
175
+ ...params.InputProps,
176
+ endAdornment: (
177
+ <>
178
+ {loading && <CircularProgress color="inherit" size={20} />}
179
+ {params.InputProps.endAdornment}
180
+ </>
181
+ ),
182
+ }}
183
+ />
184
+ )}
185
+ renderOption={(props, option) => {
186
+ // 特殊处理加载项
187
+ if (option.isLoadingItem) {
188
+ return (
189
+ <Box component="li" {...props} key={option.id}>
190
+ <Box
191
+ sx={{
192
+ display: 'flex',
193
+ alignItems: 'center',
194
+ justifyContent: 'center',
195
+ flex: 1,
196
+ py: 1,
197
+ color: 'primary.main',
198
+ cursor: 'pointer',
199
+ }}>
200
+ {loadingMore && <CircularProgress size={16} sx={{ mr: 1 }} />}
201
+ <Typography variant="body2" sx={{ fontStyle: loadingMore ? 'italic' : 'normal' }}>
202
+ {option.name}
203
+ </Typography>
204
+ </Box>
205
+ </Box>
206
+ );
207
+ }
208
+
209
+ // 正常组织项的渲染
210
+ return (
211
+ <Box component="li" {...props} key={option.id}>
212
+ <Box sx={{ display: 'flex', flexDirection: 'column', flex: 1, minWidth: 0 }}>
213
+ <Typography
214
+ variant="body1"
215
+ sx={{
216
+ overflow: 'hidden',
217
+ textOverflow: 'ellipsis',
218
+ whiteSpace: 'nowrap',
219
+ }}>
220
+ {option.name}
221
+ </Typography>
222
+ {option.description && (
223
+ <Typography
224
+ variant="body2"
225
+ color="text.secondary"
226
+ sx={{
227
+ display: '-webkit-box',
228
+ WebkitLineClamp: 3,
229
+ WebkitBoxOrient: 'vertical',
230
+ overflow: 'hidden',
231
+ textOverflow: 'ellipsis',
232
+ }}>
233
+ {option.description}
234
+ </Typography>
235
+ )}
236
+ </Box>
237
+ </Box>
238
+ );
239
+ }}
240
+ sx={{
241
+ '& .MuiAutocomplete-listbox': {
242
+ maxHeight: 200,
243
+ },
244
+ }}
245
+ />
246
+ </Box>
247
+ </Dialog>
248
+ );
249
+ }
@@ -0,0 +1,31 @@
1
+ import type { ComponentProps } from 'react';
2
+ import { ButtonProps } from '@mui/material';
3
+ import Dialog from '../Dialog';
4
+
5
+ export type Org = {
6
+ id: string;
7
+ name: string;
8
+ description?: string;
9
+ ownerDid: string;
10
+ metadata?: Record<string, any>;
11
+ };
12
+
13
+ type DialogProps = ComponentProps<typeof Dialog> & {
14
+ placeholder?: string; // 搜索框的 placeholder
15
+ };
16
+
17
+ export type OrgTransferSelectorProps = Omit<OrgTransferProps, 'children' | 'buttonProps' | 'buttonText'> & {
18
+ ref: React.RefObject<unknown | null>;
19
+ };
20
+
21
+ export interface OrgTransferProps {
22
+ resourceId: string;
23
+ onSuccess?: (org: Org) => void;
24
+ org?: Org; // 当前所在的 Org
25
+ children?: React.ReactNode;
26
+ buttonProps?: ButtonProps;
27
+ buttonText?: string;
28
+ dialogProps?: DialogProps;
29
+ locale?: string;
30
+ [key: string]: any;
31
+ }
@@ -5,18 +5,9 @@ import isNil from 'lodash/isNil';
5
5
  import type { AxiosError } from 'axios';
6
6
  import { BlockletSDK } from '@blocklet/js-sdk';
7
7
  import Toast from '../Toast';
8
+ import { formatAxiosError } from '../Util';
8
9
  import type { User } from './types';
9
10
 
10
- export const formatAxiosError = (err: AxiosError) => {
11
- const { response } = err;
12
-
13
- if (response) {
14
- return `Request failed: ${response.status} ${response.statusText}: ${JSON.stringify(response.data)}`;
15
- }
16
-
17
- return err.message;
18
- };
19
-
20
11
  /**
21
12
  * 登录用户与当前用户(userDid)的关注关系
22
13
  */
@@ -0,0 +1,9 @@
1
+ import { BlockletSDK } from '@blocklet/js-sdk';
2
+
3
+ export enum OrgQueryType {
4
+ OWNED = 'owned',
5
+ JOINED = 'joined',
6
+ }
7
+
8
+ // eslint-disable-next-line import/prefer-default-export
9
+ export const client = new BlockletSDK();
package/src/Util/index.ts CHANGED
@@ -15,6 +15,7 @@ import timezone from 'dayjs/plugin/timezone';
15
15
  import relativeTime from 'dayjs/plugin/relativeTime';
16
16
  import updateLocale from 'dayjs/plugin/updateLocale';
17
17
  import localizedFormat from 'dayjs/plugin/localizedFormat';
18
+ import type { AxiosError } from 'axios';
18
19
  import semver from 'semver';
19
20
 
20
21
  import { DID_PREFIX, BLOCKLET_SERVICE_PATH_PREFIX } from './constant';
@@ -737,3 +738,13 @@ export const isSupportFollow = () => {
737
738
  const jsSdkVersionSupport = compareVersions(jsSdkVersion, '1.16.49-beta-20250822-070545-6d3344cc');
738
739
  return uxVersionSupport && serverVersionSupport && jsSdkVersionSupport;
739
740
  };
741
+
742
+ export const formatAxiosError = (err: AxiosError) => {
743
+ const { response } = err;
744
+
745
+ if (response) {
746
+ return `Request failed: ${response.status} ${response.statusText}: ${JSON.stringify(response.data)}`;
747
+ }
748
+
749
+ return err.message || 'Unknown error occurred';
750
+ };