@arcblock/ux 3.0.15 → 3.0.17

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.
@@ -9,6 +9,7 @@ interface TabsProps extends Omit<MuiTabsProps, 'variant' | 'onChange'> {
9
9
  onChange: (value: string) => void;
10
10
  variant?: 'card' | 'line' | MuiTabsProps['variant'];
11
11
  iconPosition?: TabProps['iconPosition'];
12
+ enableTabClick?: boolean;
12
13
  }
13
- export default function Tabs({ tabs, current, onChange, variant, iconPosition, ...rest }: TabsProps): import("react/jsx-runtime").JSX.Element;
14
+ export default function Tabs({ tabs, current, onChange, variant, iconPosition, enableTabClick, ...rest }: TabsProps): import("react/jsx-runtime").JSX.Element;
14
15
  export {};
package/lib/Tabs/index.js CHANGED
@@ -1,25 +1,32 @@
1
- import { jsx as l } from "react/jsx-runtime";
2
- import { Tabs as u, Tab as c } from "@mui/material";
3
- import { styled as p } from "../Theme/index.js";
4
- const d = "index", s = {
5
- tabs: `${d}-tabs`,
6
- tab: `${d}-tab`
7
- }, m = p(u)(({ theme: e }) => ({
8
- [`& .${s.tabs}`]: {},
9
- [`& .${s.tab}`]: {
1
+ import { jsx as r } from "react/jsx-runtime";
2
+ import { Tabs as c, Tab as d } from "@mui/material";
3
+ import { styled as m } from "../Theme/index.js";
4
+ const b = "index", u = {
5
+ tabs: `${b}-tabs`,
6
+ tab: `${b}-tab`
7
+ }, v = m(c)(({ theme: t }) => ({
8
+ [`& .${u.tabs}`]: {},
9
+ [`& .${u.tab}`]: {
10
10
  fontSize: "0.875rem",
11
- [e.breakpoints.up("md")]: {
11
+ [t.breakpoints.up("md")]: {
12
12
  fontSize: "1rem"
13
13
  }
14
14
  }
15
15
  }));
16
- function v({ tabs: e, current: t, onChange: r, iconPosition: n = void 0, ...o }) {
17
- return /* @__PURE__ */ l(
18
- u,
16
+ function f({
17
+ tabs: t,
18
+ current: n,
19
+ onChange: e,
20
+ iconPosition: s = void 0,
21
+ enableTabClick: l = !1,
22
+ ...o
23
+ }) {
24
+ return /* @__PURE__ */ r(
25
+ c,
19
26
  {
20
27
  scrollButtons: "auto",
21
- value: t,
22
- onChange: (a, i) => r(i),
28
+ value: n,
29
+ onChange: (a, i) => !l && e(i),
23
30
  ...o,
24
31
  variant: "scrollable",
25
32
  sx: {
@@ -63,27 +70,35 @@ function v({ tabs: e, current: t, onChange: r, iconPosition: n = void 0, ...o })
63
70
  },
64
71
  ...o.sx
65
72
  },
66
- children: e.map((a) => /* @__PURE__ */ l(
67
- c,
73
+ children: t.map((a) => /* @__PURE__ */ r(
74
+ d,
68
75
  {
69
- className: s.tab,
76
+ className: u.tab,
70
77
  value: a.value,
71
78
  label: a.label,
72
79
  icon: a.icon,
73
- iconPosition: n
80
+ iconPosition: s,
81
+ onClick: () => l && e(a.value)
74
82
  },
75
83
  a.value
76
84
  ))
77
85
  }
78
86
  );
79
87
  }
80
- function f({ tabs: e, current: t, onChange: r, iconPosition: n = void 0, ...o }) {
81
- return /* @__PURE__ */ l(
82
- u,
88
+ function y({
89
+ tabs: t,
90
+ current: n,
91
+ onChange: e,
92
+ iconPosition: s = void 0,
93
+ enableTabClick: l = !1,
94
+ ...o
95
+ }) {
96
+ return /* @__PURE__ */ r(
97
+ c,
83
98
  {
84
99
  scrollButtons: "auto",
85
- value: t,
86
- onChange: (a, i) => r(i),
100
+ value: n,
101
+ onChange: (a, i) => !l && e(i),
87
102
  ...o,
88
103
  variant: "scrollable",
89
104
  sx: {
@@ -132,14 +147,15 @@ function f({ tabs: e, current: t, onChange: r, iconPosition: n = void 0, ...o })
132
147
  },
133
148
  ...o.sx
134
149
  },
135
- children: e.map((a) => /* @__PURE__ */ l(
136
- c,
150
+ children: t.map((a) => /* @__PURE__ */ r(
151
+ d,
137
152
  {
138
- className: s.tab,
153
+ className: u.tab,
139
154
  value: a.value,
140
155
  label: a.label,
141
156
  icon: a.icon,
142
- iconPosition: n
157
+ iconPosition: s,
158
+ onClick: () => l && e(a.value)
143
159
  },
144
160
  a.value
145
161
  ))
@@ -147,31 +163,53 @@ function f({ tabs: e, current: t, onChange: r, iconPosition: n = void 0, ...o })
147
163
  );
148
164
  }
149
165
  function T({
150
- tabs: e,
151
- current: t,
152
- onChange: r,
153
- variant: n = void 0,
154
- iconPosition: o = void 0,
166
+ tabs: t,
167
+ current: n,
168
+ onChange: e,
169
+ variant: s = void 0,
170
+ iconPosition: l = void 0,
171
+ enableTabClick: o = !1,
155
172
  ...a
156
173
  }) {
157
- return n === "card" ? /* @__PURE__ */ l(v, { ...a, tabs: e, current: t, onChange: r, iconPosition: o }) : n === "line" ? /* @__PURE__ */ l(f, { ...a, tabs: e, current: t, onChange: r, iconPosition: o }) : /* @__PURE__ */ l(
158
- m,
174
+ return s === "card" ? /* @__PURE__ */ r(
175
+ f,
176
+ {
177
+ ...a,
178
+ tabs: t,
179
+ current: n,
180
+ enableTabClick: o,
181
+ onChange: e,
182
+ iconPosition: l
183
+ }
184
+ ) : s === "line" ? /* @__PURE__ */ r(
185
+ y,
186
+ {
187
+ ...a,
188
+ tabs: t,
189
+ current: n,
190
+ enableTabClick: o,
191
+ onChange: e,
192
+ iconPosition: l
193
+ }
194
+ ) : /* @__PURE__ */ r(
195
+ v,
159
196
  {
160
197
  scrollButtons: "auto",
161
198
  variant: "scrollable",
162
- value: t,
163
- onChange: (i, b) => r(b),
199
+ value: n,
200
+ onChange: (i, p) => !o && e(p),
164
201
  indicatorColor: "primary",
165
202
  ...a,
166
- className: [s.tabs, a.className || ""].join(" "),
167
- children: e.map((i) => /* @__PURE__ */ l(
168
- c,
203
+ className: [u.tabs, a.className || ""].join(" "),
204
+ children: t.map((i) => /* @__PURE__ */ r(
205
+ d,
169
206
  {
170
- className: s.tab,
207
+ className: u.tab,
171
208
  value: i.value,
172
209
  label: i.label,
173
210
  icon: i.icon,
174
- iconPosition: o
211
+ iconPosition: l,
212
+ onClick: () => o && e(i.value)
175
213
  },
176
214
  i.value
177
215
  ))
@@ -1,49 +1,51 @@
1
- import { jsx as i, jsxs as R } from "react/jsx-runtime";
2
- import { createContext as _, use as B, useState as L, useRef as j, useMemo as h, useCallback as C, useEffect as k } from "react";
3
- import { useTheme as y, StyledEngineProvider as D, ThemeProvider as K, CssBaseline as U, GlobalStyles as V } from "@mui/material";
4
- import v from "lodash/set";
5
- import { BLOCKLET_THEME_PREFER_KEY as b, isValidThemeMode as W, getDefaultThemePrefer as w } from "@blocklet/theme";
1
+ import { jsx as m, jsxs as j } from "react/jsx-runtime";
2
+ import { createContext as F, use as G, useState as E, useRef as H, useMemo as f, useCallback as x, useEffect as h } from "react";
3
+ import { useTheme as M, StyledEngineProvider as I, ThemeProvider as N, CssBaseline as O, GlobalStyles as U } from "@mui/material";
4
+ import { deepmerge as A } from "@mui/utils";
5
+ import y from "lodash/set";
6
+ import { useDebounceFn as K } from "ahooks";
7
+ import { getBlockletThemeOptions as V, BLOCKLET_THEME_PREFER_KEY as b, isValidThemeMode as W, getDefaultThemePrefer as $ } from "@blocklet/theme";
6
8
  import { useLocationState as q } from "../hooks/use-location-state.js";
7
- import { createTheme as g, lazyCreateDefaultTheme as z, isUxTheme as A, isTheme as F } from "./theme.js";
8
- const G = g(), $ = _({});
9
- function H() {
10
- return B($);
9
+ import { createTheme as T, lazyCreateDefaultTheme as z, isUxTheme as Y, isTheme as J } from "./theme.js";
10
+ const Q = T(), P = F({});
11
+ function X() {
12
+ return G(P);
11
13
  }
12
- const x = (l) => l ? l === "system" ? w({ theme: { prefer: "system" } }) : l : w();
13
- function I({ className: l = void 0 }) {
14
- const e = y();
15
- if (e.palette.mode === "dark") {
16
- const s = "transparent", n = e.palette.grey[300], o = (l || "").trim().split(/\s+/).filter(Boolean).map((c) => c.startsWith(".") ? c : `.${c}`).join(" "), r = o ? `${o}::-webkit-scrollbar, ${o} *::-webkit-scrollbar` : "*::-webkit-scrollbar", a = o ? `${o}::-webkit-scrollbar-track, ${o} *::-webkit-scrollbar-track` : "*::-webkit-scrollbar-track", m = o ? `${o}::-webkit-scrollbar-thumb, ${o} *::-webkit-scrollbar-thumb` : "*::-webkit-scrollbar-thumb", d = o ? `${o}, ${o} *` : "*";
17
- return /* @__PURE__ */ i(
18
- V,
14
+ const B = (l) => l ? l === "system" ? $({ theme: { prefer: "system" } }) : l : $();
15
+ function Z({ className: l = void 0 }) {
16
+ const t = M();
17
+ if (t.palette.mode === "dark") {
18
+ const r = "transparent", a = t.palette.grey[300], o = (l || "").trim().split(/\s+/).filter(Boolean).map((u) => u.startsWith(".") ? u : `.${u}`).join(" "), s = o ? `${o}::-webkit-scrollbar, ${o} *::-webkit-scrollbar` : "*::-webkit-scrollbar", i = o ? `${o}::-webkit-scrollbar-track, ${o} *::-webkit-scrollbar-track` : "*::-webkit-scrollbar-track", c = o ? `${o}::-webkit-scrollbar-thumb, ${o} *::-webkit-scrollbar-thumb` : "*::-webkit-scrollbar-thumb", g = o ? `${o}, ${o} *` : "*";
19
+ return /* @__PURE__ */ m(
20
+ U,
19
21
  {
20
22
  styles: {
21
23
  // Chrome, Safari, Edge
22
24
  "@supports selector(::-webkit-scrollbar)": {
23
- [r]: {
25
+ [s]: {
24
26
  width: "12px",
25
27
  height: "12px"
26
28
  },
27
- [a]: {
28
- background: s
29
+ [i]: {
30
+ background: r
29
31
  },
30
- [m]: {
31
- background: n,
32
+ [c]: {
33
+ background: a,
32
34
  borderRadius: "6px",
33
35
  border: "2px solid",
34
- borderColor: s,
36
+ borderColor: r,
35
37
  backgroundClip: "padding-box",
36
38
  "&:hover": {
37
- background: e.palette.grey[400],
39
+ background: t.palette.grey[400],
38
40
  backgroundClip: "padding-box"
39
41
  }
40
42
  }
41
43
  },
42
44
  // Firefox
43
45
  "@supports not selector(::-webkit-scrollbar)": {
44
- [d]: {
46
+ [g]: {
45
47
  scrollbarWidth: "auto",
46
- scrollbarColor: `${n} ${s}`
48
+ scrollbarColor: `${a} ${r}`
47
49
  }
48
50
  }
49
51
  }
@@ -52,83 +54,97 @@ function I({ className: l = void 0 }) {
52
54
  }
53
55
  return null;
54
56
  }
55
- function E({
57
+ function _({
56
58
  children: l = null,
57
- theme: e = G,
58
- injectFirst: s = !0,
59
- darkSchemeClass: n = ""
59
+ theme: t = Q,
60
+ injectFirst: r = !0,
61
+ darkSchemeClass: a = ""
60
62
  }) {
61
- const o = h(() => typeof e == "function" || F(e) ? e : g(e), [e]);
63
+ const o = f(() => typeof t == "function" || J(t) ? t : T(t), [t]);
62
64
  return (
63
65
  // injectFirst 会影响 makeStyles 自定义样式和 mui styles 覆盖问题
64
- /* @__PURE__ */ i(D, { injectFirst: s, children: /* @__PURE__ */ R(K, { theme: o, children: [
65
- /* @__PURE__ */ i(U, {}),
66
- /* @__PURE__ */ i(I, { className: n }),
66
+ /* @__PURE__ */ m(I, { injectFirst: r, children: /* @__PURE__ */ j(N, { theme: o, children: [
67
+ /* @__PURE__ */ m(O, {}),
68
+ /* @__PURE__ */ m(Z, { className: a }),
67
69
  l
68
70
  ] }) })
69
71
  );
70
72
  }
71
- function N({
73
+ function ee({
72
74
  children: l = null,
73
- theme: e = void 0,
74
- prefer: s = void 0,
75
- disableBlockletTheme: n = !1,
75
+ theme: t = void 0,
76
+ prefer: r = void 0,
77
+ disableBlockletTheme: a = !1,
76
78
  ...o
77
79
  }) {
78
- const [r, a] = L(() => x(s)), m = y(), d = q(), c = j(null), p = h(() => {
79
- let t = {};
80
- const u = z(r);
81
- if (e)
82
- if (typeof e == "function") {
83
- const M = u();
84
- A(m) ? t = { ...e(m, { mode: r }) } : t = { ...e(M, { mode: r }) };
80
+ const [s, i] = E(() => B(r)), [c, g] = E(null), u = M(), k = q(), d = H(null), { run: w } = K(
81
+ (e) => {
82
+ g(e);
83
+ },
84
+ {
85
+ wait: 200
86
+ }
87
+ ), C = f(() => {
88
+ let e = {};
89
+ if (t) {
90
+ const R = z(s);
91
+ if (typeof t == "function") {
92
+ const D = R();
93
+ Y(u) ? e = { ...t(u, { mode: s }) } : e = { ...t(D, { mode: s }) };
85
94
  } else
86
- t = { ...e };
87
- return v(t, "palette.mode", r), v(t, "mode", r), t;
88
- }, [r, e, m]), f = h(() => g({ ...p, disableBlockletTheme: n }), [p, n]), T = C(() => {
89
- const t = r === "light" ? "dark" : "light";
90
- a(t), sessionStorage.removeItem(b), localStorage.setItem(b, t);
91
- }, [r, a]), S = C(
92
- (t) => {
93
- r !== t && (a(t), sessionStorage.removeItem(b), localStorage.setItem(b, t));
95
+ e = { ...t };
96
+ }
97
+ let n = s;
98
+ return c && (n = c.mode || "light", e = A(e, V(n, c))), y(e, "palette.mode", n), y(e, "mode", n), e;
99
+ }, [s, t, u, c]), p = f(() => T({ ...C, disableBlockletTheme: !!c || a }), [C, a, c]), S = x(() => {
100
+ const e = s === "light" ? "dark" : "light";
101
+ i(e), sessionStorage.removeItem(b), localStorage.setItem(b, e);
102
+ }, [s, i]), v = x(
103
+ (e) => {
104
+ s !== e && (i(e), sessionStorage.removeItem(b), localStorage.setItem(b, e));
94
105
  },
95
- [r, a]
96
- ), P = h(
106
+ [s, i]
107
+ ), L = f(
97
108
  () => ({
98
- mode: r,
99
- toggleMode: T,
100
- changeMode: S,
101
- prefer: s
109
+ mode: s,
110
+ toggleMode: S,
111
+ changeMode: v,
112
+ prefer: r
102
113
  }),
103
- [r, s, T, S]
114
+ [s, r, S, v]
104
115
  );
105
- return k(() => {
106
- a(x(s));
107
- }, [s, a, d.search]), k(() => {
108
- const t = new URLSearchParams(d.search).get("theme");
109
- W(t) && sessionStorage.setItem(b, t);
110
- }, [d.search]), k(() => {
111
- c.current || (c.current = document.querySelector('meta[name="theme-color"]'));
112
- const t = f.palette.background.default;
113
- if (c.current)
114
- c.current.setAttribute("content", t);
116
+ return h(() => {
117
+ i(B(r));
118
+ }, [r, i, k.search]), h(() => {
119
+ const e = new URLSearchParams(k.search).get("theme");
120
+ W(e) && sessionStorage.setItem(b, e);
121
+ }, [k.search]), h(() => {
122
+ d.current || (d.current = document.querySelector('meta[name="theme-color"]'));
123
+ const e = p.palette.background.default;
124
+ if (d.current)
125
+ d.current.setAttribute("content", e);
115
126
  else {
116
- const u = document.createElement("meta");
117
- u.name = "theme-color", u.content = t, document.head.appendChild(u), c.current = u;
127
+ const n = document.createElement("meta");
128
+ n.name = "theme-color", n.content = e, document.head.appendChild(n), d.current = n;
118
129
  }
119
- }, [f.palette.background.default]), /* @__PURE__ */ i($, { value: P, children: /* @__PURE__ */ i(E, { theme: f, ...o, children: l }) });
130
+ }, [p.palette.background.default]), h(() => {
131
+ const e = (n) => {
132
+ n.origin === window.origin && n.data.type === "THEME_BUILDER_CONFIG_CHANGED" && w(n.data.payload);
133
+ };
134
+ return window.addEventListener("message", e), () => window.removeEventListener("message", e);
135
+ }, [w]), /* @__PURE__ */ m(P, { value: L, children: /* @__PURE__ */ m(_, { theme: p, ...o, children: l }) });
120
136
  }
121
- function te({
137
+ function me({
122
138
  children: l = null,
123
- prefer: e = void 0,
124
- enableColorScheme: s = !1,
125
- ...n
139
+ prefer: t = void 0,
140
+ enableColorScheme: r = !1,
141
+ ...a
126
142
  }) {
127
- const { toggleMode: o } = H();
128
- return s || e || !o ? /* @__PURE__ */ i(N, { prefer: e, ...n, children: l }) : /* @__PURE__ */ i(E, { ...n, children: l });
143
+ const { toggleMode: o } = X();
144
+ return r || t || !o ? /* @__PURE__ */ m(ee, { prefer: t, ...a, children: l }) : /* @__PURE__ */ m(_, { ...a, children: l });
129
145
  }
130
146
  export {
131
- $ as ColorSchemeContext,
132
- te as default,
133
- H as useColorScheme
147
+ P as ColorSchemeContext,
148
+ me as default,
149
+ X as useColorScheme
134
150
  };
@@ -60,7 +60,6 @@ const m = ({ palette: e, components: t, overrides: o, ...r }) => ({
60
60
  },
61
61
  ...r
62
62
  }), v = {
63
- // @ts-expect-error
64
63
  themeName: "ArcBlock",
65
64
  pageWidth: "md",
66
65
  disableBlockletTheme: !1,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcblock/ux",
3
- "version": "3.0.15",
3
+ "version": "3.0.17",
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": "56670fd3ff4223fcdaaf1b38eb2e993217344328",
63
+ "gitHead": "4c0ab1335d46f38cc05e804c6ae099dfd6fa9ad8",
64
64
  "dependencies": {
65
- "@arcblock/bridge": "3.0.15",
65
+ "@arcblock/bridge": "3.0.17",
66
66
  "@arcblock/did": "^1.20.15",
67
67
  "@arcblock/did-motif": "^1.1.14",
68
- "@arcblock/icons": "3.0.15",
69
- "@arcblock/nft-display": "3.0.15",
70
- "@arcblock/react-hooks": "3.0.15",
68
+ "@arcblock/icons": "3.0.17",
69
+ "@arcblock/nft-display": "3.0.17",
70
+ "@arcblock/react-hooks": "3.0.17",
71
71
  "@blocklet/js-sdk": "^1.16.45",
72
- "@blocklet/theme": "3.0.15",
72
+ "@blocklet/theme": "3.0.17",
73
73
  "@fontsource/roboto": "~5.1.1",
74
74
  "@fontsource/ubuntu-mono": "^5.2.6",
75
75
  "@iconify-icons/logos": "^1.2.36",
@@ -25,14 +25,22 @@ interface CardTabsProps extends Omit<MuiTabsProps, 'onChange'> {
25
25
  current: any;
26
26
  onChange: (value: string) => void;
27
27
  iconPosition?: TabProps['iconPosition'];
28
+ enableTabClick?: boolean;
28
29
  }
29
30
 
30
- function CardTabs({ tabs, current, onChange, iconPosition = undefined, ...rest }: CardTabsProps) {
31
+ function CardTabs({
32
+ tabs,
33
+ current,
34
+ onChange,
35
+ iconPosition = undefined,
36
+ enableTabClick = false,
37
+ ...rest
38
+ }: CardTabsProps) {
31
39
  return (
32
40
  <MuiTabs
33
41
  scrollButtons="auto"
34
42
  value={current}
35
- onChange={(_, newValue) => onChange(newValue)}
43
+ onChange={(_, newValue) => !enableTabClick && onChange(newValue)}
36
44
  {...rest}
37
45
  variant="scrollable"
38
46
  sx={{
@@ -84,6 +92,7 @@ function CardTabs({ tabs, current, onChange, iconPosition = undefined, ...rest }
84
92
  label={x.label}
85
93
  icon={x.icon}
86
94
  iconPosition={iconPosition}
95
+ onClick={() => enableTabClick && onChange(x.value)}
87
96
  />
88
97
  ))}
89
98
  </MuiTabs>
@@ -95,14 +104,22 @@ interface LineTabsProps extends Omit<MuiTabsProps, 'onChange'> {
95
104
  current: any;
96
105
  onChange: (value: string) => void;
97
106
  iconPosition?: TabProps['iconPosition'];
107
+ enableTabClick?: boolean;
98
108
  }
99
109
 
100
- function LineTabs({ tabs, current, onChange, iconPosition = undefined, ...rest }: LineTabsProps) {
110
+ function LineTabs({
111
+ tabs,
112
+ current,
113
+ onChange,
114
+ iconPosition = undefined,
115
+ enableTabClick = false,
116
+ ...rest
117
+ }: LineTabsProps) {
101
118
  return (
102
119
  <MuiTabs
103
120
  scrollButtons="auto"
104
121
  value={current}
105
- onChange={(_, newValue) => onChange(newValue)}
122
+ onChange={(_, newValue) => !enableTabClick && onChange(newValue)}
106
123
  {...rest}
107
124
  variant="scrollable"
108
125
  sx={{
@@ -162,6 +179,7 @@ function LineTabs({ tabs, current, onChange, iconPosition = undefined, ...rest }
162
179
  label={x.label}
163
180
  icon={x.icon}
164
181
  iconPosition={iconPosition}
182
+ onClick={() => enableTabClick && onChange(x.value)}
165
183
  />
166
184
  ))}
167
185
  </MuiTabs>
@@ -174,6 +192,7 @@ interface TabsProps extends Omit<MuiTabsProps, 'variant' | 'onChange'> {
174
192
  onChange: (value: string) => void;
175
193
  variant?: 'card' | 'line' | MuiTabsProps['variant'];
176
194
  iconPosition?: TabProps['iconPosition'];
195
+ enableTabClick?: boolean; // 是否启用点击切换 tab,默认不启用,启用后,当前 tab 处于活跃状态下点击 tab 也会触发 onChange 事件,
177
196
  }
178
197
 
179
198
  export default function Tabs({
@@ -182,14 +201,33 @@ export default function Tabs({
182
201
  onChange,
183
202
  variant = undefined,
184
203
  iconPosition = undefined,
204
+ enableTabClick = false,
185
205
  ...rest
186
206
  }: TabsProps) {
187
207
  if (variant === 'card') {
188
- return <CardTabs {...rest} tabs={tabs} current={current} onChange={onChange} iconPosition={iconPosition} />;
208
+ return (
209
+ <CardTabs
210
+ {...rest}
211
+ tabs={tabs}
212
+ current={current}
213
+ enableTabClick={enableTabClick}
214
+ onChange={onChange}
215
+ iconPosition={iconPosition}
216
+ />
217
+ );
189
218
  }
190
219
 
191
220
  if (variant === 'line') {
192
- return <LineTabs {...rest} tabs={tabs} current={current} onChange={onChange} iconPosition={iconPosition} />;
221
+ return (
222
+ <LineTabs
223
+ {...rest}
224
+ tabs={tabs}
225
+ current={current}
226
+ enableTabClick={enableTabClick}
227
+ onChange={onChange}
228
+ iconPosition={iconPosition}
229
+ />
230
+ );
193
231
  }
194
232
 
195
233
  return (
@@ -197,7 +235,7 @@ export default function Tabs({
197
235
  scrollButtons="auto"
198
236
  variant="scrollable"
199
237
  value={current}
200
- onChange={(_, newValue) => onChange(newValue)}
238
+ onChange={(_, newValue) => !enableTabClick && onChange(newValue)}
201
239
  indicatorColor="primary"
202
240
  {...rest}
203
241
  className={[classes.tabs, rest.className || ''].join(' ')}>
@@ -209,6 +247,7 @@ export default function Tabs({
209
247
  label={x.label}
210
248
  icon={x.icon}
211
249
  iconPosition={iconPosition}
250
+ onClick={() => enableTabClick && onChange(x.value)}
212
251
  />
213
252
  ))}
214
253
  </StyledMuiTabs>
@@ -9,8 +9,16 @@ import {
9
9
  useTheme,
10
10
  CssBaseline,
11
11
  } from '@mui/material';
12
+ import { deepmerge } from '@mui/utils';
12
13
  import set from 'lodash/set';
13
- import { BLOCKLET_THEME_PREFER_KEY, getDefaultThemePrefer, isValidThemeMode } from '@blocklet/theme';
14
+ import { useDebounceFn } from 'ahooks';
15
+ import {
16
+ BLOCKLET_THEME_PREFER_KEY,
17
+ getDefaultThemePrefer,
18
+ isValidThemeMode,
19
+ getBlockletThemeOptions,
20
+ type BlockletThemeMeta,
21
+ } from '@blocklet/theme';
14
22
 
15
23
  import { useLocationState } from '../hooks/use-location-state';
16
24
  import { createTheme, isTheme, isUxTheme, lazyCreateDefaultTheme, type UxThemeOptions } from './theme';
@@ -164,15 +172,27 @@ function ColorSchemeProvider({
164
172
  ...rest
165
173
  }: ThemeProviderProps) {
166
174
  const [mode, setMode] = useState<PaletteMode>(() => resolveMode(prefer));
175
+ const [themeBuilderConfig, setThemeBuilderConfig] = useState<BlockletThemeMeta | null>(null);
167
176
  const parentTheme = useTheme();
168
177
  const location = useLocationState();
169
178
  const metaThemeColorRef = useRef<HTMLMetaElement | null>(null);
170
179
 
180
+ // 使用防抖函数包装 setThemeBuilderConfig,避免过于频繁的主题修改
181
+ const { run: debouncedSetThemeBuilderConfig } = useDebounceFn(
182
+ (config: BlockletThemeMeta | null) => {
183
+ setThemeBuilderConfig(config);
184
+ },
185
+ {
186
+ wait: 200,
187
+ }
188
+ );
189
+
171
190
  const _themeInput = useMemo(() => {
172
191
  let result: UxThemeOptions = {};
173
- const createBaseTheme = lazyCreateDefaultTheme(mode);
174
192
 
175
193
  if (themeInput) {
194
+ const createBaseTheme = lazyCreateDefaultTheme(mode);
195
+
176
196
  if (typeof themeInput === 'function') {
177
197
  const baseTheme = createBaseTheme();
178
198
 
@@ -186,15 +206,22 @@ function ColorSchemeProvider({
186
206
  }
187
207
  }
188
208
 
189
- set(result, 'palette.mode', mode);
190
- set(result, 'mode', mode);
209
+ // 接受 ThemeBuilder 配置
210
+ let _mode = mode;
211
+ if (themeBuilderConfig) {
212
+ _mode = themeBuilderConfig.mode || 'light';
213
+ result = deepmerge(result, getBlockletThemeOptions(_mode, themeBuilderConfig));
214
+ }
215
+
216
+ set(result, 'palette.mode', _mode);
217
+ set(result, 'mode', _mode);
191
218
 
192
219
  return result;
193
- }, [mode, themeInput, parentTheme]);
220
+ }, [mode, themeInput, parentTheme, themeBuilderConfig]);
194
221
 
195
222
  const theme = useMemo(() => {
196
- return createTheme({ ..._themeInput, disableBlockletTheme });
197
- }, [_themeInput, disableBlockletTheme]);
223
+ return createTheme({ ..._themeInput, disableBlockletTheme: !!themeBuilderConfig || disableBlockletTheme });
224
+ }, [_themeInput, disableBlockletTheme, themeBuilderConfig]);
198
225
 
199
226
  // 切换明/暗模式
200
227
  const toggleMode = useCallback(() => {
@@ -258,6 +285,22 @@ function ColorSchemeProvider({
258
285
  }
259
286
  }, [theme.palette.background.default]);
260
287
 
288
+ // 监听来自 ThemeBuilder 的消息,支持 Blocklet 实时预览
289
+ useEffect(() => {
290
+ const handleMessage = (event: MessageEvent) => {
291
+ // 必须同源
292
+ if (event.origin !== window.origin) return;
293
+
294
+ if (event.data.type === 'THEME_BUILDER_CONFIG_CHANGED') {
295
+ debouncedSetThemeBuilderConfig(event.data.payload);
296
+ }
297
+ };
298
+
299
+ window.addEventListener('message', handleMessage);
300
+
301
+ return () => window.removeEventListener('message', handleMessage);
302
+ }, [debouncedSetThemeBuilderConfig]);
303
+
261
304
  return (
262
305
  <ColorSchemeContext value={colorSchemeValue}>
263
306
  <BaseThemeProvider theme={theme} {...rest}>
@@ -33,7 +33,6 @@ export function isTheme(obj: any): obj is Theme {
33
33
 
34
34
  /** 是否是 UX Theme 对象 */
35
35
  export function isUxTheme(obj: any): obj is Theme {
36
- // @ts-expect-error
37
36
  return isTheme(obj) && obj.__isUxTheme__ === true;
38
37
  }
39
38
 
@@ -119,7 +118,6 @@ export function lazyCreateDefaultTheme(mode: PaletteMode) {
119
118
  }
120
119
 
121
120
  // 主要处理 overrides
122
- // @ts-expect-error
123
121
  const normalizeUserThemeOptions = ({ palette, components, overrides, ...rest }: UxThemeOptions) => {
124
122
  const result: UxThemeOptions = {
125
123
  palette,
@@ -134,7 +132,6 @@ const normalizeUserThemeOptions = ({ palette, components, overrides, ...rest }:
134
132
  };
135
133
 
136
134
  const defaultUxThemeOptions: UxThemeOptions = {
137
- // @ts-expect-error
138
135
  themeName: 'ArcBlock',
139
136
  pageWidth: 'md',
140
137
  disableBlockletTheme: false,
@@ -170,7 +167,6 @@ export const create = (...args: Array<UxThemeOptions | ((baseTheme: Theme) => Ux
170
167
  deepmerge(acc, normalizeUserThemeOptions(typeof curr === 'function' ? curr(createBaseTheme()) : curr)),
171
168
  normalizeUserThemeOptions(defaultUxThemeOptions)
172
169
  );
173
- // @ts-expect-error
174
170
  const prefer = userThemeOptions.mode || userThemeOptions.palette?.mode || defaultPrefer;
175
171
  const blockletThemeOptions = getBlockletThemeOptions(prefer);
176
172
  const defaultThemeOptions = createDefaultThemeOptions(prefer);
@@ -192,7 +188,6 @@ export const create = (...args: Array<UxThemeOptions | ((baseTheme: Theme) => Ux
192
188
 
193
189
  // 创建主题
194
190
  const theme = _createTheme(mergedThemeOptions);
195
- // @ts-expect-error
196
191
  theme.__isUxTheme__ = true;
197
192
 
198
193
  // 异步加载字体