@cqsjjb/jjb-react-admin-component 3.3.1-beta.5 → 3.3.1-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,116 +0,0 @@
1
- import MD5 from 'spark-md5';
2
- import React, { useEffect, useRef, useState, forwardRef, useImperativeHandle } from 'react';
3
- import Cropper from 'react-cropper';
4
- import 'cropperjs/dist/cropper.css';
5
- import { Empty } from 'antd';
6
- import { tools } from '@cqsjjb/jjb-common-lib';
7
- import { isHttpUrl } from '../tools/index.js';
8
- const ImageCropper = /*#__PURE__*/forwardRef((props, ref) => {
9
- const {
10
- width = 400,
11
- height = 400,
12
- aspect = 16 / 9,
13
- locked = false,
14
- resource
15
- } = props;
16
- const cropRef = useRef(null);
17
- const [src, setSrc] = useState(undefined);
18
-
19
- // 更新 src
20
- const onUpdateSrc = () => {
21
- if (resource instanceof File) {
22
- tools.getFileToBase64(resource).then(setSrc);
23
- } else if (/^data:image\/(png|jpg|jpeg);base64/.test(resource) || isHttpUrl(resource)) {
24
- setSrc(resource);
25
- }
26
- };
27
-
28
- // 初始化或资源变化时更新
29
- useEffect(() => {
30
- onUpdateSrc();
31
- }, [resource]);
32
-
33
- // 暴露给父组件的方法
34
- useImperativeHandle(ref, () => ({
35
- toDataURL: (quality = 1) => {
36
- const md5 = new MD5();
37
- try {
38
- const base64 = cropRef.current.cropper.getCroppedCanvas().toDataURL('image/png', quality);
39
- md5.appendBinary(base64);
40
- return {
41
- md5: md5.end(),
42
- base64
43
- };
44
- } catch (e) {
45
- return null;
46
- }
47
- },
48
- toDataFile: () => {
49
- try {
50
- const {
51
- md5,
52
- base64
53
- } = ref.current.toDataURL();
54
- return {
55
- md5,
56
- file: tools.getBase64ToFile(base64, `${tools.createOnlyKey()}.png`)
57
- };
58
- } catch (e) {
59
- return {
60
- file: null,
61
- md5: null
62
- };
63
- }
64
- },
65
- toBlobURL: () => {
66
- try {
67
- return window.URL.createObjectURL(ref.current.toDataFile().file);
68
- } catch (e) {
69
- return null;
70
- }
71
- },
72
- toDataImageText: () => {
73
- try {
74
- return `<img alt="img" src="${ref.current.toDataURL().base64}"/>`;
75
- } catch (e) {
76
- return null;
77
- }
78
- },
79
- toDataImageInstance: () => {
80
- return new Promise(resolve => {
81
- const image = new Image();
82
- image.src = ref.current.toDataURL().base64;
83
- image.onload = () => resolve({
84
- src: image.src,
85
- width: image.width,
86
- height: image.height,
87
- instance: image
88
- });
89
- });
90
- }
91
- }));
92
- return /*#__PURE__*/React.createElement("div", {
93
- style: {
94
- width,
95
- height,
96
- position: 'relative'
97
- }
98
- }, src ? /*#__PURE__*/React.createElement(Cropper, {
99
- ref: cropRef,
100
- src: src,
101
- style: {
102
- width,
103
- height
104
- },
105
- aspectRatio: aspect,
106
- cropBoxResizable: !locked
107
- }) : /*#__PURE__*/React.createElement(Empty, {
108
- image: Empty.PRESENTED_IMAGE_SIMPLE,
109
- style: {
110
- margin: 0,
111
- paddingTop: (height - 70) / 2 - 40
112
- },
113
- description: "\u672A\u5BFC\u5165\u56FE\u7247\u8D44\u6E90\uFF0C\u65E0\u6CD5\u88C1\u526A"
114
- }));
115
- });
116
- export default ImageCropper;
@@ -1,310 +0,0 @@
1
- import MD5 from 'spark-md5';
2
- import React, { useState, useRef, useCallback } from 'react';
3
- import { tools } from '@cqsjjb/jjb-common-lib';
4
- import { Button, Col, Image as ImageFunc, Modal, Row, message } from 'antd';
5
- import { PlusOutlined, EyeOutlined, DeleteOutlined, SyncOutlined, ScissorOutlined } from '@ant-design/icons';
6
- import ImageCropper from '../ImageCropper';
7
- import './index.less';
8
- import { getToken, getViewAsp, getAppKey, isHttpUrl } from '../tools/index.js';
9
- const {
10
- toObject,
11
- isPromise,
12
- isFunction,
13
- parseObject
14
- } = tools;
15
- const prefixCls = window.process?.env?.app?.antd['ant-prefix'] || 'ant';
16
- const FILE_TYPE = ['image/png', 'image/jpg', 'image/jpeg'];
17
- const FILE_TYPE_POWER = [...FILE_TYPE, 'image/svg+xml'];
18
- const ImageUploader = props => {
19
- const [loading, setLoading] = useState(false);
20
- const [preview, setPreview] = useState(false);
21
- const [visible, setVisible] = useState(false);
22
- const [resource, setResource] = useState(undefined);
23
- const cropperRef = useRef(null);
24
- const fileInputRef = useRef(null);
25
- const algorithm = (() => {
26
- const value = document.documentElement.style.getPropertyValue('--saas-algorithm');
27
- return value ? value === '#FFF' ? 'default' : 'dark' : 'default';
28
- })();
29
- const onLoadFile = useCallback(file => {
30
- const md5 = new MD5();
31
- const {
32
- svg = false
33
- } = props;
34
- return new Promise(resolve => {
35
- const reader = new FileReader();
36
- reader.onload = e => {
37
- md5.appendBinary(e.target.result);
38
- const isImage = (svg ? FILE_TYPE_POWER : FILE_TYPE).includes(file.type);
39
- if (isImage) {
40
- const image = new Image();
41
- const base64 = e.target.result;
42
- image.src = base64;
43
- image.onload = () => {
44
- resolve({
45
- file,
46
- base64,
47
- md5: md5.end(),
48
- size: file.size,
49
- type: file.type,
50
- name: file.name,
51
- width: image.width,
52
- height: image.height
53
- });
54
- };
55
- } else {
56
- resolve({
57
- file,
58
- md5: md5.end(),
59
- size: file.size,
60
- type: file.type,
61
- name: file.name,
62
- width: 0,
63
- height: 0,
64
- base64: undefined
65
- });
66
- }
67
- };
68
- reader.readAsDataURL(file);
69
- });
70
- }, [props]);
71
- const onCompression = useCallback(data => {
72
- const {
73
- compressionConfig
74
- } = props;
75
- return new Promise(resolve => {
76
- const URL = window.URL || window.webkitURL;
77
- const {
78
- quality = 0.8
79
- } = toObject(compressionConfig);
80
- const img = new Image();
81
- const canvas = document.createElement('canvas');
82
- const context = canvas.getContext('2d');
83
- onLoadFile(data.file).then(res => {
84
- img.width = res.width;
85
- img.height = res.height;
86
- img.src = URL.createObjectURL(data.file);
87
- img.onload = () => {
88
- img.onload = null;
89
- canvas.width = img.width;
90
- canvas.height = img.height;
91
- context.drawImage(img, 0, 0, img.width, img.height);
92
- canvas.toBlob(blob => {
93
- const newFile = new File([blob], data.name, {
94
- type: blob.type
95
- });
96
- resolve({
97
- ...data,
98
- file: newFile,
99
- size: newFile.size
100
- });
101
- }, 'image/png', quality);
102
- };
103
- });
104
- });
105
- }, [onLoadFile, props]);
106
- const onUploadHttp = useCallback(transfer => {
107
- const {
108
- API_HOST
109
- } = window.process.env.app;
110
- const {
111
- data = {},
112
- action,
113
- headers: $headers = {},
114
- needToken = true,
115
- customRequest,
116
- fieldName = 'file',
117
- onChange
118
- } = props;
119
- const requestURL = isHttpUrl(action) ? action : `${API_HOST}${action}`;
120
- const xhr = new XMLHttpRequest();
121
- const form = new FormData();
122
- const headers = toObject($headers);
123
- headers.appKey = getAppKey();
124
- if (needToken) {
125
- headers.token = getToken();
126
- }
127
- transfer.md5 && form.append('md5', transfer.md5);
128
- setLoading(true);
129
- xhr.open('POST', requestURL);
130
- Object.keys(headers).forEach(key => xhr.setRequestHeader(key, headers[key]));
131
- xhr.onreadystatechange = () => {
132
- if (xhr.readyState === 4 && xhr.status === 200) {
133
- setLoading(false);
134
- const res = parseObject(xhr.responseText);
135
- if (isFunction(customRequest)) {
136
- const fn = customRequest(res);
137
- if (isPromise(fn)) {
138
- fn.then(value => onChange && onChange(value));
139
- }
140
- } else {
141
- const {
142
- success,
143
- errMessage
144
- } = res;
145
- if (success) {
146
- const result = toObject(res.data);
147
- if (typeof onChange === 'undefined') {
148
- console.warn('ImageUploader警告:缺少必要的onChange回调,可能无法正确显示图片!');
149
- }
150
- onChange && onChange({
151
- fileId: result.fileId,
152
- fileUrl: result.fileUrl
153
- });
154
- message.success('上传成功!');
155
- } else {
156
- message.error(errMessage || '未知错误,上传失败,请检查!');
157
- }
158
- }
159
- }
160
- };
161
- form.append(fieldName, transfer.file);
162
- Object.keys(data).forEach(key => form.append(key, data[key]));
163
- xhr.send(form);
164
- }, [props]);
165
- const onUpload = useCallback(e => {
166
- const target = e.target;
167
- const files = target.files;
168
- const file = files[0];
169
- const {
170
- wh = '50*50',
171
- svg = false,
172
- size = 5120,
173
- cropper = false,
174
- compression = false
175
- } = props;
176
- onLoadFile(file).then(load => {
177
- const [w, h] = getViewAsp(wh);
178
- const fileSize = load.size;
179
- const fileType = load.type;
180
- if (!(svg ? FILE_TYPE_POWER : FILE_TYPE).includes(fileType)) {
181
- message.error(`文件格式错误,不是图片类型,支持.PNG、.JPG、.JPEG${svg ? '、.SVG' : ''}`);
182
- target.value = null;
183
- return;
184
- }
185
- if (fileSize / 1024 > size) {
186
- message.error(`图片大小超过最大值(${size}KB),请重新选择`);
187
- target.value = null;
188
- return;
189
- }
190
- if (cropper) {
191
- setResource(load.file);
192
- setVisible(true);
193
- } else {
194
- if (load.width < w || load.height < h) {
195
- message.error(`图片尺寸不能小于${w}x${h}`);
196
- target.value = null;
197
- return;
198
- }
199
- if (compression && fileSize / 1024 > 200) {
200
- onCompression(load).then(res => onUploadHttp(res));
201
- target.value = null;
202
- return;
203
- }
204
- onUploadHttp(load);
205
- }
206
- target.value = null;
207
- });
208
- }, [props, onLoadFile, onCompression, onUploadHttp]);
209
- const {
210
- tip = '点击上传',
211
- svg = false,
212
- value,
213
- disabled = false,
214
- width = 120,
215
- height = 120,
216
- preview: _preview = true,
217
- cropper = false,
218
- borderStyle = 'dashed',
219
- borderColor = '#d9d9d9',
220
- borderWidth = 1,
221
- borderRadius = 2,
222
- backgroundColor = '#fafafa',
223
- cropperConfig: $cropperConfig = {},
224
- onChange
225
- } = props;
226
- const cropperConfig = toObject($cropperConfig);
227
- return /*#__PURE__*/React.createElement("div", {
228
- style: {
229
- width,
230
- height,
231
- borderStyle,
232
- borderWidth,
233
- borderColor,
234
- borderRadius,
235
- backgroundColor
236
- },
237
- className: `${prefixCls}_image-file-uploader_ ${prefixCls}_image-file-uploader-${algorithm}_`
238
- }, value ? /*#__PURE__*/React.createElement("div", {
239
- className: `${prefixCls}_image-file-uploader-preview_`
240
- }, value && /*#__PURE__*/React.createElement(ImageFunc, {
241
- src: toObject(value).fileUrl,
242
- preview: !disabled ? {
243
- visible: preview,
244
- onVisibleChange: () => setPreview(false)
245
- } : true
246
- }), !disabled && /*#__PURE__*/React.createElement("div", {
247
- className: `${prefixCls}_image-file-uploader-preview-control_`
248
- }, _preview && /*#__PURE__*/React.createElement(EyeOutlined, {
249
- title: "\u9884\u89C8",
250
- onClick: () => setPreview(true)
251
- }), /*#__PURE__*/React.createElement(DeleteOutlined, {
252
- title: "\u5220\u9664",
253
- onClick: () => onChange && onChange(undefined)
254
- }))) : /*#__PURE__*/React.createElement("label", {
255
- className: `${prefixCls}_image-file-uploader-select_`
256
- }, loading ? /*#__PURE__*/React.createElement(SyncOutlined, {
257
- spin: true
258
- }) : /*#__PURE__*/React.createElement(PlusOutlined, null), /*#__PURE__*/React.createElement("div", {
259
- style: {
260
- maxWidth: width
261
- },
262
- className: `${prefixCls}_image-file-uploader-select-tip_`
263
- }, loading ? '上传中...' : tip), !loading && !disabled && /*#__PURE__*/React.createElement("input", {
264
- ref: fileInputRef,
265
- type: "file",
266
- style: {
267
- display: 'none'
268
- },
269
- accept: `image/png,image/jpg,image/jpeg${svg ? ',image/svg+xml' : ''}`,
270
- onChange: onUpload
271
- })), cropper && visible && !svg && /*#__PURE__*/React.createElement(Modal, {
272
- open: true,
273
- title: "\u56FE\u7247\u88C1\u526A",
274
- width: (cropperConfig.width || 400) + 48,
275
- footer: /*#__PURE__*/React.createElement(Row, {
276
- align: "middle",
277
- justify: "space-between"
278
- }, /*#__PURE__*/React.createElement(Col, {
279
- style: {
280
- color: 'red'
281
- }
282
- }, "\u5F53\u524D\u88C1\u526A\u7684\u7EB5\u6A2A\u6BD4\uFF1A16 / ", cropperConfig.aspect ? Math.floor(16 / cropperConfig.aspect) : 9), /*#__PURE__*/React.createElement(Col, null, /*#__PURE__*/React.createElement(Button, {
283
- type: "primary",
284
- icon: /*#__PURE__*/React.createElement(ScissorOutlined, null),
285
- onClick: () => {
286
- onUploadHttp(cropperRef.current.toDataFile());
287
- setTimeout(() => setVisible(false), 300);
288
- }
289
- }, "\u786E\u5B9A"))),
290
- maskClosable: false,
291
- destroyOnClose: false,
292
- onCancel: () => setVisible(false)
293
- }, /*#__PURE__*/React.createElement(ImageCropper, {
294
- ref: cropperRef,
295
- width: cropperConfig.width || 400,
296
- height: cropperConfig.height || 400,
297
- locked: cropperConfig.locked,
298
- aspect: cropperConfig.aspect,
299
- resource: resource
300
- })));
301
- };
302
- export default ImageUploader;
303
- export const getValueProps = value => ({
304
- value: value ? {
305
- fileUrl: value
306
- } : undefined
307
- });
308
- export const getValueFromEvent = file => {
309
- return file?.fileUrl;
310
- };
@@ -1,211 +0,0 @@
1
- function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
- import React, { useState, useEffect, useCallback, useImperativeHandle, forwardRef } from 'react';
3
- import { Table, Row, Col, Form } from 'antd';
4
- import { isEqual } from 'lodash';
5
- import SearchForm from '@cqsjjb/jjb-react-admin-component/SearchForm';
6
- import ProTable from '@cqsjjb/jjb-react-admin-component/Table';
7
-
8
- /**
9
- * @component ListDataContainer
10
- * @description 通用列表数据容器组件,提供搜索表单、数据表格、分页等功能的完整列表页面解决方案
11
- *
12
- * @props {Array} columns - 表格列配置,遵循Ant Design Table组件的columns规范
13
- * @props {Function} fetchDataApi - 数据获取API函数,接收分页和搜索参数,返回包含list和total的对象
14
- * @props {Array} searchFormConfig - 搜索表单配置数组
15
- * @param {React.Component} searchFormConfig[].field - 表单项组件(如ControlWrapper.Select)
16
- * @param {string} searchFormConfig[].name - 表单项字段名
17
- * @param {string} searchFormConfig[].label - 表单项标签
18
- * @param {Object} searchFormConfig[].fieldProps - 传递给字段组件的属性
19
- * @param {Object} searchFormConfig[].itemProps - 传递给Form.Item的属性
20
- * @param {React.ReactNode} searchFormConfig[].content - 字段组件的子元素(如Select.Option列表)
21
- * @param {boolean} searchFormConfig[].required - 是否必填
22
- * @props {string} rowKey - 表格行键值,默认为'id'
23
- * @props {Object} initialPagination - 初始分页配置,包含current、pageSize等分页属性
24
- * @props {Object} tableProps - 传递给Table组件的属性
25
- * @props {boolean} proTable - 是否使用ProTable组件,默认为false
26
- * @example
27
- * // 基础用法
28
- * <ListDataContainer
29
- * columns={tableColumns}
30
- * fetchDataApi={getCourseList}
31
- * searchFormConfig={[
32
- * {
33
- * field: Select,
34
- * name: 'status',
35
- * label: '状态',
36
- * }
37
- * {
38
- * field: Input,
39
- * name: 'name',
40
- * label: '名称',
41
- * required: true,
42
- * }
43
- * ]}
44
- * />
45
- *
46
- */
47
-
48
- const SELECT_COMPONENTS = ['Select', 'TreeSelect', 'Cascader', 'DatePicker', 'TimePicker', 'Checkbox', 'Radio', 'Switch', 'Slider', 'Upload'];
49
- const INPUT_COMPONENTS = ['Input', 'InputNumber'];
50
- const ListDataContainer = /*#__PURE__*/forwardRef(({
51
- columns,
52
- fetchDataApi,
53
- searchFormConfig = [],
54
- rowKey = 'id',
55
- initialPagination = {
56
- pageIndex: 1,
57
- pageSize: 10,
58
- showSizeChanger: true,
59
- showQuickJumper: true
60
- },
61
- tableProps = {},
62
- proTable = false
63
- }, ref) => {
64
- const [form] = Form.useForm();
65
- const [tableData, setTableData] = useState([]);
66
- const [loading, setLoading] = useState(false);
67
- const [pagination, setPagination] = useState(initialPagination);
68
- const [totalCount, setTotalCount] = useState(0);
69
- const getComponentName = Component => {
70
- return Component.displayName || Component.constructor.name;
71
- };
72
-
73
- /**
74
- * 数据加载与刷新方法
75
- * @param {Object} [overrideParams={}] - 可选,用于覆盖内部参数的键值对
76
- * 若传入,会覆盖同名的表单参数和分页参数(如page、pageSize或搜索字段)
77
- */
78
- const loadDataSource = useCallback(async (overrideParams = {}) => {
79
- if (!fetchDataApi) return;
80
- setLoading(true);
81
- try {
82
- // 1. 获取组件内部的表单参数
83
- const formValues = await form.validateFields();
84
-
85
- // 2. 构造基础参数:分页参数 + 表单参数
86
- const baseParams = {
87
- pageIndex: pagination.pageIndex,
88
- pageSize: pagination.pageSize,
89
- ...formValues
90
- };
91
-
92
- // 3. 用外部传入的参数覆盖基础参数(同名参数以外部为准)
93
- const requestParams = {
94
- ...baseParams,
95
- ...overrideParams
96
- };
97
-
98
- // 4. 发起请求
99
- const response = await fetchDataApi(requestParams);
100
- setTableData(response.data || []);
101
- setTotalCount(response.totalCount || 0);
102
- } catch (error) {
103
- console.error('列表数据请求失败:', error);
104
- setTableData([]);
105
- setTotalCount(0);
106
- } finally {
107
- setLoading(false);
108
- }
109
- }, [fetchDataApi, pagination, form]);
110
-
111
- // 暴露刷新方法给父组件
112
- useImperativeHandle(ref, () => ({
113
- // 外部调用时可传入覆盖参数
114
- loadDataSource: (overrideParams = {}) => loadDataSource(overrideParams)
115
- }));
116
- const handleFinish = values => {
117
- // 搜索时重置到第一页,并用表单值覆盖(values会合并到baseParams中)
118
- setPagination(prev => ({
119
- ...prev,
120
- pageIndex: 1
121
- }));
122
- loadDataSource({
123
- ...values,
124
- pageIndex: 1
125
- });
126
- };
127
- const handleReset = () => {
128
- // 清空表单
129
- form.setFieldsValue(searchFormConfig.reduce((obj, item) => {
130
- obj[item.name] = undefined;
131
- return obj;
132
- }, {}));
133
- // 重置分页并使用内部默认参数查询
134
- setPagination(initialPagination);
135
- loadDataSource();
136
- };
137
- const handlePaginationChange = newPagination => {
138
- console.warn("ssssssssssss", newPagination);
139
- // 更新分页后,用新分页参数查询
140
- setPagination({
141
- ...newPagination,
142
- pageIndex: newPagination.current
143
- });
144
- loadDataSource({
145
- pageIndex: newPagination.current,
146
- pageSize: newPagination.pageSize
147
- });
148
- };
149
- useEffect(() => {
150
- loadDataSource();
151
- }, []);
152
- const generateFormItems = () => {
153
- return searchFormConfig.map((item, index) => {
154
- const {
155
- field: FieldComponent,
156
- name,
157
- label,
158
- required,
159
- fieldProps = {},
160
- itemProps = {},
161
- content,
162
- ...restProps
163
- } = item;
164
- return /*#__PURE__*/React.createElement(Form.Item, _extends({
165
- key: `search-item-${name}-${index}`,
166
- name: name,
167
- label: label
168
- }, required ? {
169
- required: true,
170
- rules: [{
171
- required: true,
172
- message: `${SELECT_COMPONENTS.includes(getComponentName(FieldComponent)) ? '请选择' : '请输入'}${label}`
173
- }]
174
- } : {}, itemProps, restProps), /*#__PURE__*/React.createElement(FieldComponent, _extends({
175
- allowClear: true,
176
- placeholder: `${SELECT_COMPONENTS.includes(getComponentName(FieldComponent)) ? '请选择' : '请输入'}${label}`
177
- }, fieldProps), content || null));
178
- }).filter(Boolean);
179
- };
180
- const TableComponent = proTable ? ProTable : Table;
181
- return /*#__PURE__*/React.createElement(Row, {
182
- gutter: [16, 24]
183
- }, /*#__PURE__*/React.createElement(Col, {
184
- span: 24
185
- }, /*#__PURE__*/React.createElement(SearchForm, {
186
- expand: true,
187
- form: form,
188
- loading: loading,
189
- formLine: generateFormItems(),
190
- onReset: handleReset,
191
- onFinish: handleFinish
192
- })), /*#__PURE__*/React.createElement(Col, {
193
- span: 24
194
- }, /*#__PURE__*/React.createElement(TableComponent, _extends({
195
- columns: columns,
196
- dataSource: tableData,
197
- rowKey: rowKey,
198
- loading: loading,
199
- pagination: {
200
- ...pagination,
201
- current: pagination.pageIndex,
202
- total: totalCount
203
- },
204
- onChange: handlePaginationChange,
205
- scroll: {
206
- x: 'max-content'
207
- },
208
- bordered: true
209
- }, tableProps))));
210
- });
211
- export default ListDataContainer;
@@ -1,42 +0,0 @@
1
- import React, { useEffect, useState, useMemo } from 'react';
2
- const MEDIA_QUERY_LIST = {
3
- MAX_WIDTH_479: '(max-width: 479px)',
4
- MIN_WIDTH_480_AND_MAX_WIDTH_599: '(min-width: 480px) and (max-width: 599px)',
5
- MIN_WIDTH_600_AND_MAX_WIDTH_899: '(min-width: 600px) and (max-width: 899px)',
6
- MIN_WIDTH_900_AND_MAX_WIDTH_1199: '(min-width: 900px) and (max-width: 1199px)',
7
- MIN_WIDTH_1200_AND_MAX_WIDTH_1439: '(min-width: 1200px) and (max-width: 1439px)',
8
- MIN_WIDTH_1440: '(min-width: 1440px)'
9
- };
10
- export default function MediaQuery({
11
- children,
12
- disabled
13
- }) {
14
- const [media, setMedia] = useState(undefined);
15
- const mediaQueries = useMemo(() => {
16
- if (disabled) return {};
17
- return Object.fromEntries(Object.entries(MEDIA_QUERY_LIST).map(([key, query]) => [key, window.matchMedia(query)]));
18
- }, [disabled]);
19
- useEffect(() => {
20
- if (disabled) return;
21
- const handleChange = () => {
22
- for (const [key, mql] of Object.entries(mediaQueries)) {
23
- if (mql.matches) {
24
- setMedia(key);
25
- return;
26
- }
27
- }
28
- setMedia(undefined);
29
- };
30
- Object.values(mediaQueries).forEach(mql => mql.addEventListener('change', handleChange));
31
-
32
- // 初始化
33
- handleChange();
34
- return () => {
35
- Object.values(mediaQueries).forEach(mql => mql.removeEventListener('change', handleChange));
36
- };
37
- }, [mediaQueries, disabled]);
38
- return /*#__PURE__*/React.createElement(React.Fragment, null, (Array.isArray(children) ? children : [children]).map((item, index) => /*#__PURE__*/React.isValidElement(item) ? /*#__PURE__*/React.cloneElement(item, {
39
- key: index,
40
- 'data-media-query': media
41
- }) : item));
42
- }