@blocklet/editor 2.2.17 → 2.2.18
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.
- package/lib/ext/PagesKitComponent/PagesKitComponentRenderer.d.ts +1 -0
- package/lib/ext/PagesKitComponent/PagesKitComponentRenderer.js +140 -34
- package/lib/ext/PagesKitComponent/utils.d.ts +0 -14
- package/lib/ext/PagesKitComponent/utils.js +1 -8
- package/package.json +5 -5
- package/lib/ext/PagesKitComponent/PropertyField.d.ts +0 -13
- package/lib/ext/PagesKitComponent/PropertyField.js +0 -154
|
@@ -1,31 +1,48 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
3
|
-
import { Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, IconButton,
|
|
3
|
+
import { Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, IconButton, Typography, Skeleton, styled, } from '@mui/material';
|
|
4
|
+
import isEmpty from 'lodash/isEmpty';
|
|
5
|
+
import { useLocalStorageState } from 'ahooks';
|
|
4
6
|
import { useEffect, useMemo, useState, lazy, Suspense } from 'react';
|
|
5
7
|
import SettingsOutlinedIcon from '@mui/icons-material/SettingsOutlined';
|
|
8
|
+
import SplitPane, { Pane } from 'split-pane-react';
|
|
9
|
+
import 'split-pane-react/esm/themes/default.css';
|
|
6
10
|
import { CustomComponentRenderer, customComponentStates } from '@blocklet/pages-kit/components';
|
|
7
11
|
// @ts-ignore
|
|
8
12
|
import { translations } from '@blocklet/pages-kit-runtime/locales';
|
|
9
13
|
import { LocaleProvider } from '@arcblock/ux/lib/Locale/context';
|
|
10
14
|
import mapValues from 'lodash/mapValues';
|
|
11
15
|
import { isBlockletRunning } from '../utils';
|
|
12
|
-
import { mode,
|
|
13
|
-
// isValidPropertyType,
|
|
14
|
-
getLocalizedValue, } from './utils';
|
|
15
|
-
// @FIXME: 需要移除这些无用的代码,现在使用 Pages Kit 提供的 ParametersConfig 组件
|
|
16
|
-
// import { PropertyField } from './PropertyField';
|
|
16
|
+
import { mode, getLocalizedValue } from './utils';
|
|
17
17
|
import { useContentLocale } from '../ContentLocale';
|
|
18
18
|
const ParametersConfigLazy = lazy(() => import('@blocklet/pages-kit-runtime/components').then((mod) => ({
|
|
19
19
|
// @ts-ignore
|
|
20
20
|
default: mod.ParametersConfig,
|
|
21
21
|
})));
|
|
22
|
+
const supportedLocales = window.blocklet?.languages?.map(({ code }) => code) || ['en', 'zh'];
|
|
23
|
+
const referLocaleKey = '$referLocale$';
|
|
24
|
+
/**
|
|
25
|
+
* 获取真实使用的语言代码
|
|
26
|
+
* 数据流: locale → 检查引用 → 返回实际语言
|
|
27
|
+
*
|
|
28
|
+
* 如果当前语言引用了其他语言(通过$referLocale$标记),则返回被引用的语言
|
|
29
|
+
* 否则返回当前语言自身
|
|
30
|
+
*
|
|
31
|
+
* 这样组件显示和数据编辑时,可以智能查找到实际存储内容的语言
|
|
32
|
+
*/
|
|
33
|
+
const getRealLocale = (pendingProperties, locale) => {
|
|
34
|
+
const result = pendingProperties?.[locale]?.[referLocaleKey] ?? locale;
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
22
37
|
export function PagesKitComponentRenderer({ id, name, properties, onPropertiesChange }) {
|
|
38
|
+
const [splitSizes, setSplitSizes] = useLocalStorageState('PagesKitComponentRendererDialogSplitSizes', {
|
|
39
|
+
defaultValue: ['auto', 300],
|
|
40
|
+
});
|
|
23
41
|
const locale = useContentLocale();
|
|
24
42
|
const [editor] = useLexicalComposerContext();
|
|
25
43
|
const isEditable = editor.isEditable();
|
|
26
44
|
const [loading, setLoading] = useState(true);
|
|
27
45
|
const [open, setOpen] = useState(false);
|
|
28
|
-
const upMd = useMediaQuery((theme) => theme.breakpoints.up('md'));
|
|
29
46
|
const [pendingProperties, setPendingProperties] = useState(properties || {});
|
|
30
47
|
const handleClick = () => {
|
|
31
48
|
setOpen(true);
|
|
@@ -42,6 +59,7 @@ export function PagesKitComponentRenderer({ id, name, properties, onPropertiesCh
|
|
|
42
59
|
useEffect(() => {
|
|
43
60
|
const load = async () => {
|
|
44
61
|
const state = customComponentStates().getState();
|
|
62
|
+
const realLocale = getRealLocale(pendingProperties, locale);
|
|
45
63
|
await state.loadComponents({
|
|
46
64
|
mode,
|
|
47
65
|
locale,
|
|
@@ -54,7 +72,7 @@ export function PagesKitComponentRenderer({ id, name, properties, onPropertiesCh
|
|
|
54
72
|
useCache: true,
|
|
55
73
|
// @ts-ignore
|
|
56
74
|
cacheDuration: 3600 * 2,
|
|
57
|
-
properties: Object.entries(pendingProperties?.[
|
|
75
|
+
properties: Object.entries(pendingProperties?.[realLocale] || {}).reduce((props, [key, value]) => {
|
|
58
76
|
props[key] = { value };
|
|
59
77
|
if (typeof value === 'object') {
|
|
60
78
|
props[key].value = JSON.stringify(value);
|
|
@@ -69,7 +87,7 @@ export function PagesKitComponentRenderer({ id, name, properties, onPropertiesCh
|
|
|
69
87
|
if (isBlockletRunning('pages-kit')) {
|
|
70
88
|
load();
|
|
71
89
|
}
|
|
72
|
-
}, [id, name, pendingProperties]);
|
|
90
|
+
}, [id, name, pendingProperties, locale]);
|
|
73
91
|
const componentStates = customComponentStates().getState()?.state?.components;
|
|
74
92
|
// 组装所有组件数据,使其能被 ParametersConfig 组件使用,不能去掉,否则无法渲染 EditorComponent
|
|
75
93
|
const allComponents = useMemo(() => {
|
|
@@ -80,46 +98,97 @@ export function PagesKitComponentRenderer({ id, name, properties, onPropertiesCh
|
|
|
80
98
|
}));
|
|
81
99
|
}, [componentStates]);
|
|
82
100
|
const component = useMemo(() => allComponents?.[id]?.data, [allComponents, id]);
|
|
83
|
-
const mergedPropertiesValues = useMemo(() =>
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
101
|
+
const mergedPropertiesValues = useMemo(() => {
|
|
102
|
+
const realLocale = getRealLocale(pendingProperties, locale);
|
|
103
|
+
return Object.fromEntries(Object.values(component?.properties ?? {}).map(({ data }) => {
|
|
104
|
+
return [
|
|
105
|
+
data.id,
|
|
106
|
+
{
|
|
107
|
+
value: pendingProperties?.[realLocale]?.[data.id] ??
|
|
108
|
+
getLocalizedValue({ key: 'defaultValue', locale: realLocale, data: data.locales }),
|
|
109
|
+
},
|
|
110
|
+
];
|
|
111
|
+
}));
|
|
112
|
+
}, [component, locale, pendingProperties]);
|
|
92
113
|
const componentRenderer = useMemo(() => (_jsx(CustomComponentRenderer, { instanceId: instanceId, componentId: id, locale: locale, dev: { mode }, properties: mergedPropertiesValues })), [instanceId, id, locale, mergedPropertiesValues, mode, component]);
|
|
93
114
|
if (loading || !component) {
|
|
94
115
|
return null;
|
|
95
116
|
}
|
|
96
|
-
return (_jsxs(Box, { sx: { position: 'relative', ...(isEditable && { mt: 2 }) }, children: [componentRenderer, isEditable && !!Object.keys(component?.properties ?? {}).length && (_jsxs(_Fragment, { children: [_jsx(IconButton, { sx: { position: 'absolute', right: 0, top: -
|
|
117
|
+
return (_jsxs(Box, { sx: { position: 'relative', ...(isEditable && { mt: 2 }) }, children: [componentRenderer, isEditable && !!Object.keys(component?.properties ?? {}).length && (_jsxs(_Fragment, { children: [_jsx(IconButton, { sx: { position: 'absolute', right: 0, top: -30, zIndex: 1200 }, onClick: handleClick, children: _jsx(SettingsOutlinedIcon, {}) }), open && (_jsxs(Dialog, { disableEnforceFocus: true, fullWidth: true, maxWidth: "lg", open: true, onClose: (event, reason) => {
|
|
97
118
|
const shouldClose = !['backdropClick', 'escapeKeyDown'].includes(reason);
|
|
98
119
|
if (shouldClose) {
|
|
99
120
|
handleCancel();
|
|
100
121
|
}
|
|
101
|
-
}, disableEscapeKeyDown: true, disableScrollLock: false,
|
|
102
|
-
|
|
122
|
+
}, disableEscapeKeyDown: true, disableScrollLock: false, sx: {
|
|
123
|
+
'&:has(.full-screen-container)': {
|
|
124
|
+
zIndex: '1200 !important',
|
|
125
|
+
},
|
|
126
|
+
}, children: [_jsx(DialogTitle, { children: _jsxs(Typography, { variant: "h6", children: [name, " "] }) }), _jsx(DialogContent, { id: "parameters-config-dialog", sx: {
|
|
127
|
+
zIndex: 1200,
|
|
103
128
|
overflow: 'hidden',
|
|
104
129
|
pr: 0,
|
|
105
130
|
position: 'relative',
|
|
106
131
|
'& [aria-label*="getMediaKitAbsoluteUrl"]': {
|
|
107
132
|
display: 'none',
|
|
108
133
|
},
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
134
|
+
height: '65vh',
|
|
135
|
+
'.full-screen-container': {
|
|
136
|
+
zIndex: '1300 !important',
|
|
137
|
+
},
|
|
138
|
+
}, children: _jsxs(StyledSplitPane, { split: "vertical", sizes: splitSizes, onChange: setSplitSizes, sashRender: SashRender, children: [_jsx(Pane, { minSize: 200, children: _jsx(Box, { sx: { flex: 1, mr: 1, overflow: 'auto', height: '100%' }, children: componentRenderer }) }), _jsx(Pane, { minSize: 200, maxSize: "70%", style: {
|
|
139
|
+
overflow: 'auto',
|
|
140
|
+
}, children: _jsx(Box, { sx: {
|
|
141
|
+
ml: 2,
|
|
142
|
+
pr: 2,
|
|
143
|
+
pb: 2,
|
|
144
|
+
}, children: _jsx(LocaleProvider, { translations: translations, fallbackLocale: "en", children: _jsx(Suspense, { fallback: _jsx(Skeleton, { variant: "rectangular", height: "65vh" }), children: _jsx(ParametersConfigLazy
|
|
112
145
|
// @ts-ignore
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
146
|
+
, {
|
|
147
|
+
// @ts-ignore
|
|
148
|
+
config: component, allComponents: allComponents, defaultLocale: "en", locale: locale, propertiesValue: mergedPropertiesValues,
|
|
149
|
+
/**
|
|
150
|
+
* 组件属性变更处理
|
|
151
|
+
* 数据流: 输入变更 → 解析引用 → 复制/更新内容 → 设置其他语言引用
|
|
152
|
+
*
|
|
153
|
+
* 1. 检查当前语言是否引用其他语言,若是则复制所有内容并移除引用标记
|
|
154
|
+
* 2. 更新当前语言的属性值
|
|
155
|
+
* 3. 对空语言或有引用标记的语言,自动添加引用到当前语言
|
|
156
|
+
*
|
|
157
|
+
* 这确保了语言切换时数据不会丢失,且多语言共享未翻译的内容
|
|
158
|
+
*/
|
|
159
|
+
onChange: ({ id: propertyId, value }) => {
|
|
160
|
+
setPendingProperties((prevProperties) => {
|
|
161
|
+
if (!locale || !propertyId || !value?.value)
|
|
162
|
+
return prevProperties;
|
|
163
|
+
// 创建新的属性对象
|
|
164
|
+
const updatedProperties = { ...prevProperties };
|
|
165
|
+
const realLocale = getRealLocale(updatedProperties, locale);
|
|
166
|
+
// 如果触发更新当前值,且存在引用,则将引用对象应用到自己身上
|
|
167
|
+
if (realLocale !== locale) {
|
|
168
|
+
// 将引用对象应用到自己身上
|
|
169
|
+
updatedProperties[locale] = {
|
|
170
|
+
...(updatedProperties[realLocale] || {}),
|
|
171
|
+
};
|
|
172
|
+
// 以防万一再尝试删除一次引用
|
|
173
|
+
delete updatedProperties[locale][referLocaleKey];
|
|
174
|
+
}
|
|
175
|
+
// 更新当前语言的值
|
|
176
|
+
updatedProperties[locale] = {
|
|
177
|
+
...(updatedProperties[locale] || {}),
|
|
178
|
+
[propertyId]: value?.value,
|
|
179
|
+
};
|
|
180
|
+
// 为其他所有支持的语言,如果为空,那么添加引用
|
|
181
|
+
supportedLocales.forEach((otherLocale) => {
|
|
182
|
+
if (otherLocale !== locale && isEmpty(updatedProperties[otherLocale])) {
|
|
183
|
+
// 如果其他语言不存在任何属性,则添加引用
|
|
184
|
+
updatedProperties[otherLocale] = {
|
|
185
|
+
[referLocaleKey]: locale,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
return updatedProperties;
|
|
190
|
+
});
|
|
191
|
+
} }) }) }) }) })] }) }), _jsxs(DialogActions, { children: [_jsx(Button, { color: "inherit", onClick: handleCancel, children: "Cancel" }), _jsx(Button, { color: "primary", variant: "contained", onClick: handleSave, children: "Save" })] })] }))] }))] }));
|
|
123
192
|
}
|
|
124
193
|
function hashCode(str) {
|
|
125
194
|
let hash = 0;
|
|
@@ -130,3 +199,40 @@ function hashCode(str) {
|
|
|
130
199
|
}
|
|
131
200
|
return Math.abs(hash).toString(36); // 转换为 36 进制,使 id 更短
|
|
132
201
|
}
|
|
202
|
+
const StyledSplitPane = styled(SplitPane) `
|
|
203
|
+
.react-split__sash {
|
|
204
|
+
z-index: 1000; // resolve the bug of uploader zIndex
|
|
205
|
+
}
|
|
206
|
+
`;
|
|
207
|
+
function SashRender() {
|
|
208
|
+
return _jsx(DragHandle, {});
|
|
209
|
+
}
|
|
210
|
+
const DragHandle = styled('div') `
|
|
211
|
+
position: relative;
|
|
212
|
+
height: 100%;
|
|
213
|
+
width: 5px;
|
|
214
|
+
background-color: #f0f0f0;
|
|
215
|
+
cursor: col-resize;
|
|
216
|
+
transition: background-color 0.1s ease;
|
|
217
|
+
|
|
218
|
+
&::after {
|
|
219
|
+
content: '';
|
|
220
|
+
position: absolute;
|
|
221
|
+
top: 50%;
|
|
222
|
+
left: 50%;
|
|
223
|
+
transform: translate(-50%, -50%);
|
|
224
|
+
width: 10px;
|
|
225
|
+
height: 20px;
|
|
226
|
+
background-color: #e3e3e3;
|
|
227
|
+
border-radius: 2px;
|
|
228
|
+
transition: background-color 0.1s ease;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
&:hover {
|
|
232
|
+
background-color: #e3e3e3;
|
|
233
|
+
|
|
234
|
+
&::after {
|
|
235
|
+
background-color: #808080;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
`;
|
|
@@ -1,25 +1,11 @@
|
|
|
1
1
|
export declare const mode: string;
|
|
2
|
-
export declare const propertyTypes: readonly ["string", "number", "boolean", "json", "url", "yaml", "color"];
|
|
3
|
-
export type PropertyType = (typeof propertyTypes)[number];
|
|
4
2
|
export type Properties = {
|
|
5
3
|
[locale: string]: {
|
|
6
4
|
[key: string]: any;
|
|
7
5
|
};
|
|
8
6
|
};
|
|
9
|
-
export declare const isValidPropertyType: (type: string | null | undefined) => boolean;
|
|
10
|
-
type Locales = {
|
|
11
|
-
[locale: string]: {
|
|
12
|
-
name?: string;
|
|
13
|
-
defaultValue?: any;
|
|
14
|
-
};
|
|
15
|
-
};
|
|
16
7
|
export declare const getLocalizedValue: ({ key, locale, data }: {
|
|
17
8
|
key: string;
|
|
18
9
|
locale: string;
|
|
19
10
|
data?: Properties | undefined;
|
|
20
11
|
}) => any;
|
|
21
|
-
export declare const getPropertyLabel: ({ locale, locales }: {
|
|
22
|
-
locale: string;
|
|
23
|
-
locales?: Locales | undefined;
|
|
24
|
-
}) => string;
|
|
25
|
-
export {};
|
|
@@ -1,16 +1,9 @@
|
|
|
1
1
|
export const mode = process.env.NODE_ENV === 'development' ? 'draft' : 'production';
|
|
2
|
-
export const propertyTypes = ['string', 'number', 'boolean', 'json', 'url', 'yaml', 'color'];
|
|
3
|
-
export const isValidPropertyType = (type) => {
|
|
4
|
-
return !type || propertyTypes.includes(type);
|
|
5
|
-
};
|
|
6
2
|
// 依次尝试取值
|
|
7
3
|
// - `data[locale][key]`
|
|
8
4
|
// - `data.en[key]`
|
|
9
5
|
// - 遍历所有 locale 取第一个有值的 `data[locale][key]`
|
|
10
6
|
export const getLocalizedValue = ({ key, locale, data }) => {
|
|
11
7
|
data = data || {};
|
|
12
|
-
return data[locale]?.[key]
|
|
13
|
-
};
|
|
14
|
-
export const getPropertyLabel = ({ locale, locales }) => {
|
|
15
|
-
return getLocalizedValue({ key: 'name', locale, data: locales });
|
|
8
|
+
return data[locale]?.[key] ?? data.en?.[key] ?? Object.values(data).find((x) => x?.[key])?.[key] ?? '';
|
|
16
9
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blocklet/editor",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.18",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
]
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@blocklet/code-editor": "^0.4.
|
|
27
|
+
"@blocklet/code-editor": "^0.4.255",
|
|
28
28
|
"@blocklet/embed": "^0.2.3",
|
|
29
29
|
"@blocklet/js-sdk": "^1.16.41",
|
|
30
|
-
"@blocklet/pages-kit": "^0.4.
|
|
31
|
-
"@blocklet/pages-kit-runtime": "^0.4.
|
|
30
|
+
"@blocklet/pages-kit": "^0.4.102",
|
|
31
|
+
"@blocklet/pages-kit-runtime": "^0.4.104",
|
|
32
32
|
"@excalidraw/excalidraw": "^0.14.2",
|
|
33
33
|
"@iconify/iconify": "^3.1.1",
|
|
34
34
|
"@iconify/icons-tabler": "^1.2.95",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"ufo": "^1.5.4",
|
|
68
68
|
"url-join": "^4.0.1",
|
|
69
69
|
"zustand": "^4.5.5",
|
|
70
|
-
"@blocklet/pdf": "^2.2.
|
|
70
|
+
"@blocklet/pdf": "^2.2.18"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
73
|
"@babel/core": "^7.25.2",
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { type PropertyType } from './utils';
|
|
2
|
-
interface PropertyFieldProps {
|
|
3
|
-
type?: PropertyType;
|
|
4
|
-
multiline?: boolean;
|
|
5
|
-
label: string;
|
|
6
|
-
value: any;
|
|
7
|
-
onChange: (value: any) => void;
|
|
8
|
-
}
|
|
9
|
-
export declare function UploaderButton({ onChange }: {
|
|
10
|
-
onChange?: Function;
|
|
11
|
-
}): import("react/jsx-runtime").JSX.Element;
|
|
12
|
-
export declare function PropertyField({ type, multiline, label, value, onChange, ...rest }: PropertyFieldProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
-
export {};
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Box, FormControlLabel, FormLabel, IconButton, InputAdornment, Stack, Switch, TextField } from '@mui/material';
|
|
3
|
-
import UploadIcon from '@mui/icons-material/Upload';
|
|
4
|
-
import { useRef } from 'react';
|
|
5
|
-
import { lazyRetry as lazy } from '@arcblock/ux/lib/Util';
|
|
6
|
-
import ColorPicker from '../../main/ui/ColorPicker';
|
|
7
|
-
const CodeEditor = lazy(() => import('@blocklet/code-editor').then((module) => ({
|
|
8
|
-
default: module.CodeEditor,
|
|
9
|
-
})));
|
|
10
|
-
function getVideoSize(url) {
|
|
11
|
-
return new Promise((resolve, reject) => {
|
|
12
|
-
const video = document.createElement('video');
|
|
13
|
-
video.src = url;
|
|
14
|
-
video.onloadedmetadata = () => {
|
|
15
|
-
const { videoWidth: naturalWidth, videoHeight: naturalHeight } = video;
|
|
16
|
-
resolve({ naturalWidth, naturalHeight });
|
|
17
|
-
};
|
|
18
|
-
video.onerror = (e) => reject(e);
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
function getImageSize(url) {
|
|
22
|
-
return new Promise((resolve, reject) => {
|
|
23
|
-
const img = new Image();
|
|
24
|
-
img.src = url;
|
|
25
|
-
img.onload = () => {
|
|
26
|
-
const { naturalWidth, naturalHeight } = img;
|
|
27
|
-
resolve({ naturalWidth, naturalHeight });
|
|
28
|
-
};
|
|
29
|
-
img.onerror = (e) => reject(e);
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
export function UploaderButton({ onChange }) {
|
|
33
|
-
const handleOpen = () => {
|
|
34
|
-
// @ts-ignore
|
|
35
|
-
const uploader = uploaderRef?.current?.getUploader();
|
|
36
|
-
uploader?.open();
|
|
37
|
-
if (onChange) {
|
|
38
|
-
// rewrite default emitter
|
|
39
|
-
uploader.onceUploadSuccess((...args) => {
|
|
40
|
-
onChange(...args);
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
return (_jsx(IconButton, { size: "small", onClick: handleOpen, children: _jsx(UploadIcon, {}) }, "uploader-trigger"));
|
|
45
|
-
}
|
|
46
|
-
export function PropertyField({ type, multiline, label, value, onChange, ...rest }) {
|
|
47
|
-
const codeEditorUploadCallback = useRef(null);
|
|
48
|
-
const handleOpen = () => {
|
|
49
|
-
// @ts-ignore
|
|
50
|
-
const uploader = uploaderRef?.current?.getUploader();
|
|
51
|
-
uploader?.open();
|
|
52
|
-
if (codeEditorUploadCallback.current) {
|
|
53
|
-
// rewrite default emitter
|
|
54
|
-
uploader.onceUploadSuccess(({ response }) => {
|
|
55
|
-
let fileName = response?.data?.filename || '';
|
|
56
|
-
if (fileName) {
|
|
57
|
-
fileName = `mediakit://${fileName}`;
|
|
58
|
-
}
|
|
59
|
-
codeEditorUploadCallback.current?.(fileName);
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
const handleChange = (v) => {
|
|
64
|
-
if (type === 'json') {
|
|
65
|
-
try {
|
|
66
|
-
onChange?.(JSON.parse(v));
|
|
67
|
-
}
|
|
68
|
-
catch (e) {
|
|
69
|
-
console.error(e);
|
|
70
|
-
onChange?.(v);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
onChange?.(v);
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
if (type === 'boolean') {
|
|
78
|
-
return (_jsx(FormControlLabel, { sx: { display: 'inline-flex', m: 0 }, label: label, labelPlacement: "start", control: _jsx(Switch, { checked: value === true, onChange: (_, checked) => handleChange(checked) }) }));
|
|
79
|
-
}
|
|
80
|
-
if (type === 'number') {
|
|
81
|
-
return (_jsx(TextField, { type: "number", size: "small", sx: { width: 1 }, label: label, value: value, onChange: (e) => handleChange(e.target.value), ...rest }));
|
|
82
|
-
}
|
|
83
|
-
if (type === 'url') {
|
|
84
|
-
return (_jsx(TextField, { sx: { width: 1 }, size: "small", label: label, value: value.url, onChange: (e) => handleChange(e.target.value), InputProps: {
|
|
85
|
-
endAdornment: (_jsx(InputAdornment, { position: "end", children: _jsx(UploaderButton, { onChange: async ({ response }) => {
|
|
86
|
-
const url = response?.data?.url || response?.data?.fileUrl;
|
|
87
|
-
let size;
|
|
88
|
-
if (url) {
|
|
89
|
-
size = await getImageSize(url)
|
|
90
|
-
.catch(() => getVideoSize(url))
|
|
91
|
-
.catch(() => undefined);
|
|
92
|
-
}
|
|
93
|
-
handleChange({ url, width: size?.naturalWidth, height: size?.naturalHeight });
|
|
94
|
-
} }) })),
|
|
95
|
-
}, ...rest }));
|
|
96
|
-
}
|
|
97
|
-
if (type === 'color') {
|
|
98
|
-
return (_jsx(TextField, { sx: { width: 1 }, size: "small", label: label, value: value, onChange: (e) => handleChange(e.target.value), InputProps: {
|
|
99
|
-
endAdornment: (_jsx(InputAdornment, { position: "end", sx: {
|
|
100
|
-
'.popup-item-color': {
|
|
101
|
-
width: 24,
|
|
102
|
-
height: 24,
|
|
103
|
-
borderRadius: '4px',
|
|
104
|
-
cursor: 'pointer',
|
|
105
|
-
backgroundColor: value || '#fff',
|
|
106
|
-
border: '1px solid rgba(0, 0, 0, 0.23)',
|
|
107
|
-
'&:hover': {
|
|
108
|
-
opacity: 0.8,
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
}, children: _jsx(ColorPicker, { color: value, onChange: handleChange, buttonClassName: "popup-item spaced popup-item-color" }) })),
|
|
112
|
-
}, ...rest }));
|
|
113
|
-
}
|
|
114
|
-
if (type === 'yaml' || type === 'json') {
|
|
115
|
-
let newValue = value;
|
|
116
|
-
if (type === 'json' && typeof value !== 'string') {
|
|
117
|
-
newValue = JSON.stringify(value, null, 2);
|
|
118
|
-
}
|
|
119
|
-
return (_jsxs(Stack, { sx: {
|
|
120
|
-
width: '100%',
|
|
121
|
-
position: 'relative',
|
|
122
|
-
pt: 1,
|
|
123
|
-
pb: '6px',
|
|
124
|
-
px: '1px',
|
|
125
|
-
minHeight: 50,
|
|
126
|
-
'.monaco-editor,.overflow-guard': { borderRadius: 1 },
|
|
127
|
-
}, children: [_jsx(FormLabel, { sx: {
|
|
128
|
-
position: 'absolute',
|
|
129
|
-
left: 0,
|
|
130
|
-
top: 0,
|
|
131
|
-
transform: 'translate(0px, -7px) scale(0.75)',
|
|
132
|
-
}, children: label }), _jsx(CodeEditor, { keyId: label, locale: "en", language: type === 'yaml' ? 'yaml' : 'json', value: newValue, onChange: (v) => {
|
|
133
|
-
return handleChange(v);
|
|
134
|
-
}, typeScriptNoValidation: false, onUpload: (callback) => {
|
|
135
|
-
codeEditorUploadCallback.current = callback;
|
|
136
|
-
handleOpen();
|
|
137
|
-
} }), _jsx(Box, { component: "fieldset", sx: {
|
|
138
|
-
pointerEvents: 'none',
|
|
139
|
-
position: 'absolute',
|
|
140
|
-
left: 0,
|
|
141
|
-
top: -5,
|
|
142
|
-
width: '100%',
|
|
143
|
-
height: '100%',
|
|
144
|
-
border: 1,
|
|
145
|
-
borderColor: 'rgba(0, 0, 0, 0.23)',
|
|
146
|
-
borderRadius: 1,
|
|
147
|
-
px: 1,
|
|
148
|
-
py: 0,
|
|
149
|
-
zIndex: 1,
|
|
150
|
-
m: 0,
|
|
151
|
-
} })] }));
|
|
152
|
-
}
|
|
153
|
-
return (_jsx(TextField, { sx: { width: 1 }, size: "small", label: label, value: value, onChange: (e) => handleChange(e.target.value), multiline: true, rows: 5, ...rest }));
|
|
154
|
-
}
|