@blocklet/pages-kit 0.6.18 → 0.6.19

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.
@@ -28,6 +28,7 @@ const component = __importStar(require("@blocklet/sdk/lib/component"));
28
28
  const dayjs = __importStar(require("../builtin/dayjs"));
29
29
  const stream = __importStar(require("../builtin/stream"));
30
30
  const utils = __importStar(require("../builtin/utils"));
31
+ const zod = __importStar(require("../builtin/zod"));
31
32
  exports.BuiltinModules = {
32
33
  React: {},
33
34
  ReactDOM: {},
@@ -68,4 +69,5 @@ exports.BuiltinModules = {
68
69
  '@blocklet/pages-kit/builtin/dayjs': dayjs,
69
70
  '@blocklet/pages-kit/builtin/utils': utils,
70
71
  '@blocklet/pages-kit/builtin/stream': stream,
72
+ '@blocklet/pages-kit/builtin/zod': zod,
71
73
  };
@@ -55,6 +55,7 @@ const session = __importStar(require("../builtin/session"));
55
55
  const stream = __importStar(require("../builtin/stream"));
56
56
  const uploader = __importStar(require("../builtin/uploader"));
57
57
  const utils = __importStar(require("../builtin/utils"));
58
+ const zod = __importStar(require("../builtin/zod"));
58
59
  const zustand = __importStar(require("../builtin/zustand"));
59
60
  const zustandMiddlewareImmer = __importStar(require("../builtin/zustand/middleware/immer"));
60
61
  const CustomComponentRenderer_1 = __importDefault(require("../components/CustomComponentRenderer"));
@@ -112,6 +113,7 @@ function injectGlobalComponents() {
112
113
  '@blocklet/pages-kit/builtin/async/image-preview': imagePreview,
113
114
  '@blocklet/pages-kit/builtin/async/ai-runtime': Promise.resolve().then(() => __importStar(require('../builtin/async/ai-runtime'))),
114
115
  '@blocklet/pages-kit/builtin/event-bus': eventBus,
116
+ '@blocklet/pages-kit/builtin/zod': zod,
115
117
  };
116
118
  // set global variable
117
119
  win[builtin_1.BuiltinModulesGlobalVariableName] = {
@@ -33,7 +33,10 @@ const blockletTheme = (0, Theme_1.createTheme)({
33
33
  },
34
34
  });
35
35
  function isGradient(color) {
36
- if (color?.trim()) {
36
+ if (typeof color !== 'string') {
37
+ return false;
38
+ }
39
+ if (color?.trim?.()) {
37
40
  try {
38
41
  gradient_parser_1.default.parse(color);
39
42
  return true;
@@ -61,6 +64,9 @@ function isColorString(color) {
61
64
  * 处理渐变的解析,并转换为rgba格式
62
65
  */
63
66
  function getSafeGradient(color) {
67
+ if (typeof color !== 'string') {
68
+ return '';
69
+ }
64
70
  try {
65
71
  const colorAst = gradient_parser_1.default.parse(color);
66
72
  const safeAst = colorAst.map((astItem) => {
@@ -119,7 +119,82 @@ export function ColorItem({ color, sx = {}, ...props }) {
119
119
  ...styleMap,
120
120
  }, ...props }));
121
121
  }
122
- export const ConfigColorDialog = function ConfigColorDialog({ ref, onSave, enableMuiPalette = true, }) {
122
+ // MUI Theme Tab Component
123
+ const MuiThemeTab = ({ value, onChange, }) => {
124
+ const { t } = useLocaleContext();
125
+ const muiPalette = useMuiColorPalette();
126
+ const mode = muiPalette?.theme?.palette?.mode;
127
+ const isDark = mode === 'dark';
128
+ const { groupedMuiColors } = muiPalette;
129
+ return (_jsxs(Box, { sx: { height: HEIGHT }, children: [_jsx(Alert, { severity: "info", sx: { mb: 1.5, mr: -1.5, py: 0, px: 1.5 }, children: t('maker.configColorMuiThemeInfo') }), Object.entries(groupedMuiColors).map(([palette, paletteColors]) => (_jsxs(Box, { sx: { pb: 1.5 }, children: [_jsx(Typography, { variant: "subtitle2", gutterBottom: true, sx: { textTransform: 'capitalize', mb: 0.5, lineHeight: 1 }, children: palette }), _jsx(Box, { sx: { display: 'flex', flexWrap: 'wrap', gap: 1 }, children: paletteColors.map((item) => {
130
+ let selectedColor = '';
131
+ if (value?.originalMuiKey === item.colorKey) {
132
+ if (item.colorValue === 'transparent') {
133
+ selectedColor = 'rgba(0,0,0,0.7)';
134
+ }
135
+ else if (tinycolor(item.colorValue).isDark()) {
136
+ selectedColor = 'rgba(255,255,255,0.8)';
137
+ }
138
+ else {
139
+ selectedColor = 'rgba(0,0,0,0.7)';
140
+ }
141
+ }
142
+ // 是否有另一种模式的颜色值
143
+ const hasAlternateColor = !!item.alternateColorValue;
144
+ return (_jsx(Tooltip, { title: `${item.colorKey}${hasAlternateColor ? t('maker.configColorMuiThemeWithAlternateColor') : ''}`, sx: {
145
+ zIndex: 99999,
146
+ }, children: _jsxs(Box, { onClick: () => {
147
+ onChange({
148
+ value: item.colorValue,
149
+ originalMuiKey: item.colorKey,
150
+ });
151
+ }, sx: {
152
+ width: 32,
153
+ height: 32,
154
+ border: value?.originalMuiKey === item.colorKey
155
+ ? `2px solid ${isDark ? 'rgba(255,255,255,0.8)' : 'rgba(0,0,0,0.7)'}`
156
+ : '1px solid #ccc',
157
+ borderRadius: 0.5,
158
+ cursor: 'pointer',
159
+ '&:hover': { opacity: 0.8 },
160
+ display: 'flex',
161
+ alignItems: 'center',
162
+ justifyContent: 'center',
163
+ position: 'relative',
164
+ overflow: 'hidden',
165
+ }, children: [_jsx(Box, { sx: {
166
+ position: 'absolute',
167
+ top: 0,
168
+ right: 0,
169
+ bottom: 0,
170
+ left: 0,
171
+ ...(item.colorValue === 'transparent'
172
+ ? { background: getTransparentBackground() }
173
+ : { backgroundColor: item.colorValue }),
174
+ } }), hasAlternateColor && _jsx(AlternateColorIndicator, { value: item.alternateColorValue }), value?.originalMuiKey === item.colorKey && (_jsx("i", { className: "i-mdi:check", style: {
175
+ color: selectedColor,
176
+ fontSize: '1.2rem',
177
+ position: 'relative',
178
+ zIndex: 2,
179
+ } }))] }) }, item.colorKey));
180
+ }) })] }, palette)))] }));
181
+ };
182
+ // Custom Color Tab Component
183
+ const CustomColorTab = ({ value, onChange, }) => {
184
+ const muiPalette = useMuiColorPalette();
185
+ const mode = muiPalette?.theme?.palette?.mode;
186
+ const isDark = mode === 'dark';
187
+ const colorValue = value?.value && typeof value.value === 'string' ? value.value : '';
188
+ return (_jsx(Box, { sx: { overflowY: 'auto', overflowX: 'hidden' }, children: _jsx(Suspense, { fallback: _jsx(Skeleton, { variant: "rectangular", width: WIDTH, height: HEIGHT }), children: _jsx(ColorPickerLib, { disableDarkMode: !isDark, disableLightMode: isDark, width: WIDTH,
189
+ // menu color picker height
190
+ height: WIDTH, value: colorValue, onChange: (colorValue) => {
191
+ onChange({
192
+ value: colorValue,
193
+ originalMuiKey: null,
194
+ });
195
+ }, hidePresets: true, hideAdvancedSliders: true, hideColorGuide: true, hideInputType: true }) }) }));
196
+ };
197
+ export const ConfigColorDialog = function ConfigColorDialog({ ref, onSave, enableMuiPalette = true, renderTabs, }) {
123
198
  const state = useReactive({
124
199
  value: '',
125
200
  originalMuiKey: null,
@@ -131,6 +206,35 @@ export const ConfigColorDialog = function ConfigColorDialog({ ref, onSave, enabl
131
206
  const muiPalette = useMuiColorPalette();
132
207
  const mode = muiPalette?.theme?.palette?.mode;
133
208
  const isDark = mode === 'dark';
209
+ // Create default tabs
210
+ const defaultTabs = enableMuiPalette
211
+ ? [
212
+ {
213
+ key: 'mui-theme',
214
+ label: t('maker.configColorMuiTheme') || 'Theme Color',
215
+ component: MuiThemeTab,
216
+ showPreview: true,
217
+ },
218
+ {
219
+ key: 'custom-color',
220
+ label: t('maker.configColorCustomColor') || 'Custom Color',
221
+ component: CustomColorTab,
222
+ showPreview: true,
223
+ },
224
+ ]
225
+ : [
226
+ {
227
+ key: 'custom-color',
228
+ label: t('maker.configColorCustomColor') || 'Custom Color',
229
+ component: CustomColorTab,
230
+ showPreview: true,
231
+ },
232
+ ];
233
+ // Use renderTabs function or fallback to default tabs
234
+ const allTabs = renderTabs ? renderTabs(defaultTabs) : defaultTabs;
235
+ // Get current active tab
236
+ const currentTab = allTabs[activeTab] || allTabs[0];
237
+ const CurrentTabComponent = currentTab?.component;
134
238
  const previewStyle = {};
135
239
  if (state.value) {
136
240
  if (isGradient(state.value)) {
@@ -147,7 +251,7 @@ export const ConfigColorDialog = function ConfigColorDialog({ ref, onSave, enabl
147
251
  const handleClose = useCallback(() => {
148
252
  setFalse();
149
253
  }, [setFalse]);
150
- const isActiveMuiTab = enableMuiPalette && activeTab === 0;
254
+ const isActiveMuiTab = currentTab?.key === 'mui-theme';
151
255
  useImperativeHandle(ref, () => {
152
256
  return {
153
257
  open({ value } = { value: '' }) {
@@ -156,16 +260,24 @@ export const ConfigColorDialog = function ConfigColorDialog({ ref, onSave, enabl
156
260
  state.originalMuiKey = value;
157
261
  const colorValue = muiPalette.getColorByMuiKey(value);
158
262
  state.value = getSafeGradient(colorValue || value);
159
- // 如果是 MUI 颜色键,再切换到 MUI Theme 标签
160
- setActiveTab(0);
263
+ // 如果是 MUI 颜色键,切换到 MUI Theme 标签
264
+ const muiTabIndex = allTabs.findIndex((tab) => tab.key === 'mui-theme');
265
+ if (muiTabIndex !== -1) {
266
+ setActiveTab(muiTabIndex);
267
+ }
268
+ }
269
+ else if (typeof value === 'object' && value !== null && 'value' in value) {
270
+ const outerData = value;
271
+ state.value = outerData.value;
272
+ state.originalMuiKey = null;
161
273
  }
162
274
  else {
163
275
  state.originalMuiKey = null;
164
276
  state.value = getSafeGradient(value);
165
277
  // 不自动切换标签,尊重用户上一次的选择
166
- // 只有在 MUI 不可用时才强制切换到自定义
278
+ // 只有在 MUI 不可用时才强制切换到第一个
167
279
  if (!enableMuiPalette) {
168
- setActiveTab(1);
280
+ setActiveTab(0);
169
281
  }
170
282
  }
171
283
  setTrue();
@@ -182,33 +294,17 @@ export const ConfigColorDialog = function ConfigColorDialog({ ref, onSave, enabl
182
294
  if (isActiveMuiTab) {
183
295
  const muiKey = muiPalette.getMuiKeyByColor(state.value);
184
296
  onSave({ value: muiKey || state.value }, handleClose);
185
- }
186
- else {
187
- // 在自定义色彩标签页时,保持原始值
188
- onSave({ value: state.value }, handleClose);
297
+ return;
189
298
  }
190
299
  }
191
- else {
192
- onSave({ value: state.value }, handleClose);
193
- }
300
+ onSave({ value: state.value }, handleClose);
194
301
  };
195
- // 直接从 hook 获取分组
196
- const { groupedMuiColors } = muiPalette;
197
302
  const rectWrapperBorder = `2px solid ${muiPalette?.theme?.palette?.divider}`;
198
- return (_jsxs(Dialog, { disableEnforceFocus: true, open: open, onClose: handleClose, children: [_jsxs(DialogTitle, { sx: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' }, children: [_jsx(Typography, { variant: "inherit", children: t('maker.configColor') }), enableMuiPalette && (_jsx(ButtonGroup, { size: "small", "aria-label": "color mode selector", children: [
199
- {
200
- label: t('maker.configColorMuiTheme') || 'Theme Color',
201
- value: 0,
202
- },
203
- {
204
- label: t('maker.configColorCustomColor') || 'Custom Color',
205
- value: 1,
206
- },
207
- ].map((item) => (_jsx(Button, { variant: activeTab === item.value ? 'contained' : 'outlined', onClick: () => setActiveTab(item.value), sx: {
303
+ return (_jsxs(Dialog, { disableEnforceFocus: true, open: open, onClose: handleClose, children: [_jsxs(DialogTitle, { sx: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' }, children: [_jsx(Typography, { variant: "inherit", children: t('maker.configColor') }), allTabs.length > 1 && (_jsx(ButtonGroup, { size: "small", "aria-label": "color mode selector", children: allTabs.map((tab, index) => (_jsx(Button, { variant: activeTab === index ? 'contained' : 'outlined', onClick: () => setActiveTab(index), sx: {
208
304
  fontWeight: 500,
209
305
  textTransform: 'none',
210
306
  minWidth: 'unset',
211
- }, children: item.label }))) }))] }), _jsxs(DialogContent, { sx: { width: 600, display: 'flex', flexDirection: 'row', gap: 2, overflowX: 'hidden' }, children: [_jsxs(Box, { sx: {
307
+ }, children: tab.label }, tab.key))) }))] }), _jsxs(DialogContent, { sx: { width: 600, display: 'flex', flexDirection: 'row', gap: 2, overflowX: 'hidden' }, children: [currentTab?.showPreview && (_jsxs(Box, { sx: {
212
308
  ...previewStyle,
213
309
  flex: '0 0 270px',
214
310
  borderRadius: 1,
@@ -241,71 +337,23 @@ export const ConfigColorDialog = function ConfigColorDialog({ ref, onSave, enabl
241
337
  } }), _jsx(ThemeModeLabel, { mode: !isDark ? 'dark' : 'light', position: "bottom-right" })] }));
242
338
  }
243
339
  return null;
244
- })() }))] }, "color-preview"), _jsx(Box, { sx: { flex: 1 }, children: isActiveMuiTab ? (
245
- // MUI 主题色面板
246
- _jsxs(Box, { sx: { height: HEIGHT }, children: [_jsx(Alert, { severity: "info", sx: { mb: 1.5, mr: -1.5, py: 0, px: 1.5 }, children: t('maker.configColorMuiThemeInfo') }), Object.entries(groupedMuiColors).map(([palette, paletteColors]) => (_jsxs(Box, { sx: { pb: 1.5 }, children: [_jsx(Typography, { variant: "subtitle2", gutterBottom: true, sx: { textTransform: 'capitalize', mb: 0.5, lineHeight: 1 }, children: palette }), _jsx(Box, { sx: { display: 'flex', flexWrap: 'wrap', gap: 1 }, children: paletteColors.map((item) => {
247
- let selectedColor = '';
248
- if (state.originalMuiKey === item.colorKey) {
249
- if (item.colorValue === 'transparent') {
250
- selectedColor = 'rgba(0,0,0,0.7)';
251
- }
252
- else if (tinycolor(item.colorValue).isDark()) {
253
- selectedColor = 'rgba(255,255,255,0.8)';
254
- }
255
- else {
256
- selectedColor = 'rgba(0,0,0,0.7)';
257
- }
258
- }
259
- // 是否有另一种模式的颜色值
260
- const hasAlternateColor = !!item.alternateColorValue;
261
- return (_jsx(Tooltip, { title: `${item.colorKey}${hasAlternateColor ? t('maker.configColorMuiThemeWithAlternateColor') : ''}`, sx: {
262
- zIndex: 99999,
263
- }, children: _jsxs(Box, { onClick: () => {
264
- state.value = item.colorValue;
265
- state.originalMuiKey = item.colorKey;
266
- }, sx: {
267
- width: 32,
268
- height: 32,
269
- border: state.originalMuiKey === item.colorKey
270
- ? `2px solid ${isDark ? 'rgba(255,255,255,0.8)' : 'rgba(0,0,0,0.7)'}`
271
- : '1px solid #ccc',
272
- borderRadius: 0.5,
273
- cursor: 'pointer',
274
- '&:hover': { opacity: 0.8 },
275
- display: 'flex',
276
- alignItems: 'center',
277
- justifyContent: 'center',
278
- position: 'relative',
279
- overflow: 'hidden',
280
- }, children: [_jsx(Box, { sx: {
281
- position: 'absolute',
282
- top: 0,
283
- right: 0,
284
- bottom: 0,
285
- left: 0,
286
- ...(item.colorValue === 'transparent'
287
- ? { background: getTransparentBackground() }
288
- : { backgroundColor: item.colorValue }),
289
- } }), hasAlternateColor && _jsx(AlternateColorIndicator, { value: item.alternateColorValue }), state.originalMuiKey === item.colorKey && (_jsx("i", { className: "i-mdi:check", style: {
290
- color: selectedColor,
291
- fontSize: '1.2rem',
292
- position: 'relative',
293
- zIndex: 2,
294
- } }))] }) }, item.colorKey));
295
- }) })] }, palette)))] })) : (
296
- // 自定义颜色选择器
297
- _jsx(Box, { sx: { overflowY: 'auto', overflowX: 'hidden' }, children: _jsx(Suspense, { fallback: _jsx(Skeleton, { variant: "rectangular", width: WIDTH, height: HEIGHT }), children: _jsx(ColorPickerLib, { disableDarkMode: !isDark, disableLightMode: isDark, width: WIDTH,
298
- // menu color picker height
299
- height: WIDTH, value: state.value, onChange: (value) => {
300
- state.value = value;
301
- state.originalMuiKey = null;
302
- }, hidePresets: true, hideAdvancedSliders: true, hideColorGuide: true, hideInputType: true }) }) })) })] }), _jsxs(DialogActions, { children: [_jsx(Button, { variant: "outlined", size: "small", onClick: handleClose, children: t('common.cancel') }), _jsx(Button, { variant: "contained", size: "small", onClick: handleSave, children: t('maker.save') })] })] }));
340
+ })() }))] }, "color-preview")), _jsx(Box, { sx: { flex: 1 }, children: CurrentTabComponent && (_jsx(CurrentTabComponent, { value: state, onChange: (value) => {
341
+ if (value && typeof value === 'object' && 'value' in value) {
342
+ state.value = value.value;
343
+ state.originalMuiKey = value.originalMuiKey || null;
344
+ }
345
+ else {
346
+ // Handle simple string values for backward compatibility
347
+ state.value = value || '';
348
+ state.originalMuiKey = null;
349
+ }
350
+ } })) })] }), _jsxs(DialogActions, { children: [_jsx(Button, { variant: "outlined", size: "small", onClick: handleClose, children: t('common.cancel') }), _jsx(Button, { variant: "contained", size: "small", onClick: handleSave, children: t('maker.save') })] })] }));
303
351
  };
304
- export function ColorPicker({ value, onChange, style = {}, sx = {} }) {
352
+ export function ColorPicker({ value, onChange, style = {}, sx = {}, renderTabs }) {
305
353
  const refDialog = useRef(null);
306
354
  return (_jsxs(_Fragment, { children: [_jsx(ColorItem, { color: value || '', style: { width: '1rem', height: '1rem', padding: 0, marginRight: '0.25rem', ...style }, sx: { ...sx }, onClick: () => {
307
355
  refDialog.current?.open({ value });
308
- } }), _jsx(ConfigColorDialog, { ref: refDialog, onSave: ({ value }, close) => {
356
+ } }), _jsx(ConfigColorDialog, { ref: refDialog, renderTabs: renderTabs, onSave: ({ value }, close) => {
309
357
  onChange(value);
310
358
  close();
311
359
  } })] }));
@@ -0,0 +1,54 @@
1
+ import * as z4 from 'zod/v4';
2
+ // Re-export all zod/v4 types for compatibility
3
+ export * from 'zod/v4';
4
+ export const pagesKitRegistry = z4.registry();
5
+ // Define upload schema with metadata
6
+ export const uploadSchema = z4
7
+ .object({
8
+ url: z4.string().nullable(),
9
+ mediaKitUrl: z4.string().nullable(),
10
+ width: z4.number().nullable(),
11
+ height: z4.number().nullable(),
12
+ })
13
+ .register(pagesKitRegistry, {
14
+ id: 'pages_kit_upload',
15
+ type: 'upload',
16
+ locales: {
17
+ en: {
18
+ name: 'Media Upload',
19
+ description: 'Media upload component with URL, media kit URL and dimensions',
20
+ defaultValue: {
21
+ url: 'https://example.com/image.jpg',
22
+ mediaKitUrl: 'https://mediakit.example.com/image.jpg',
23
+ width: 1920,
24
+ height: 1080,
25
+ },
26
+ },
27
+ zh: {
28
+ name: '媒体上传',
29
+ description: '支持URL、媒体工具包URL和尺寸的媒体上传组件',
30
+ defaultValue: {
31
+ url: 'https://example.com/image.jpg',
32
+ mediaKitUrl: 'https://mediakit.example.com/image.jpg',
33
+ width: 1920,
34
+ height: 1080,
35
+ },
36
+ },
37
+ },
38
+ examples: [
39
+ {
40
+ url: 'https://example.com/image.jpg',
41
+ mediaKitUrl: 'https://mediakit.example.com/image.jpg',
42
+ width: 1920,
43
+ height: 1080,
44
+ },
45
+ ],
46
+ });
47
+ // Create factory functions for custom types
48
+ const upload = () => uploadSchema;
49
+ // Export enhanced zod with custom types
50
+ export const z = {
51
+ ...z4,
52
+ upload, // Factory function, consistent with z.string(), z.object()
53
+ };
54
+ export default z;