fix: "解决冲突"

This commit is contained in:
YuanHongbo 2024-03-01 17:09:48 +08:00
commit 2c58e8f76f
178 changed files with 8211 additions and 777 deletions

View File

@ -1,10 +1,11 @@
import { defineConfig } from 'dumi';
import path from 'path';
console.log(path.join(__dirname, 'packages/hooks/src'));
export default defineConfig({
logo: '/logo.jpg',
favicons: ['/logo.jpg'],
history: { type: 'hash' },
themeConfig: {
name: 'Lambo',
socialLinks: {

4
global.d.ts vendored
View File

@ -1,4 +0,0 @@
declare module '@zhst/func';
declare module '@zhst/hooks';
declare module '@zhst/meta';
declare module '@zhst/request';

View File

@ -2,6 +2,12 @@ import { defineConfig } from 'father';
export default defineConfig({
// more father config: https://github.com/umijs/father/blob/master/docs/config.md
esm: { output: 'es' },
cjs: { output: 'lib' },
esm: {
output: 'es',
ignores: ['**/demo/*', 'src/**/demo/*']
},
cjs: {
output: 'lib',
ignores: ['**/demo/*', 'src/**/demo/*']
},
});

View File

@ -1,5 +1,18 @@
# @zhst/biz
## 0.6.0
### Minor Changes
- 新增业务组件 Tree、TreeTransfer、TreeTransferModal、BoxSelectTree
### Patch Changes
- Updated dependencies
- @zhst/hooks@0.7.0
- @zhst/func@0.7.0
- @zhst/meta@0.8.0
## 0.5.1
### Patch Changes

View File

@ -8,7 +8,7 @@
## 使用
```jsx
```js
import React from 'react';
import { Demo } from '@zhst/biz'

View File

@ -1,40 +0,0 @@
import React from 'react';
import type { ModalProps, DescriptionsProps, TabsProps, VideoViewRef, ImgViewRef } from '@zhst/meta';
import './index.less';
export declare const componentPrefix = "zhst-image";
export type TAB_TYPE = 'COMPATER' | 'NORMAL' | 'VIDEO';
export type MODEL_TYPE = 'VIDEO' | 'IMAGE';
export interface BigImageModalProps extends ModalProps {
visible: boolean;
activeTab?: TAB_TYPE;
attributeList: {
title: string;
children: Pick<DescriptionsProps, 'items'>;
};
tabs: {
data: Pick<TabsProps, 'items'> & {
key: TAB_TYPE;
};
};
dataSource: any;
imageData: any;
relatedData: any;
isRelated?: boolean;
footer?: React.ReactNode;
showCarousel?: boolean;
onTabChange?: (newVal?: TAB_TYPE, oldVal?: TAB_TYPE) => void;
onIndexChange?: (newVal?: number, oldVal?: number) => void;
transformPropFunc: (data: any) => void;
}
interface BigModalRef {
tab: TAB_TYPE;
setTab: (tab: TAB_TYPE) => void;
modalRef: ModalProps;
activeKey: string;
setActiveKey: (val: string) => void;
videoPlayerRef: VideoViewRef;
combineImageRef: any;
bigImagePreviewRef: ImgViewRef;
}
declare const BigImageModal: React.FC<BigImageModalProps, BigModalRef>;
export default BigImageModal;

View File

@ -1,13 +0,0 @@
import * as React from 'react';
import './index.less';
declare const Navigation: React.FC<{
show?: boolean;
onClick?: React.MouseEventHandler<HTMLElement>;
prev?: boolean;
next?: boolean;
disabled?: boolean;
className?: string;
color?: string;
hoverColor?: string;
}>;
export default Navigation;

View File

@ -1,7 +1,6 @@
import * as React from 'react';
import classnames from 'classnames';
import { Button } from 'antd';
import { Icon } from '@zhst/meta';
import { Icon, Button } from '@zhst/meta';
import "./index.less";
var componentName = "zhst-image__nav";
var Navigation = function Navigation(props) {

View File

@ -1,3 +0,0 @@
import React from 'react';
declare const _default: () => React.JSX.Element;
export default _default;

View File

@ -1,5 +1,5 @@
import React from 'react';
import { Button } from 'antd';
import { Button } from '@zhst/meta';
import { useThrottleFn } from '@zhst/hooks';
export default (function () {
var _useThrottleFn = useThrottleFn(function () {

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,5 @@
export { default as Demo } from './Demo';
export { default as BigImageModal } from './BigImageModal';
export { default as BoxSelectTree } from './boxSelectTree';
export { default as Tree } from './tree';
export { default as TreeTransfer } from './treeTransfer';
export { default as TreeTransferModal } from './treeTransferModal';

View File

@ -1,2 +1,5 @@
export { default as Demo } from "./Demo";
export { default as BigImageModal } from "./BigImageModal";
export { default as BigImageModal } from "./BigImageModal";
export { default as BoxSelectTree } from "./boxSelectTree";
export { default as Tree } from "./tree";
export { default as TreeTransfer } from "./treeTransfer";
export { default as TreeTransferModal } from "./treeTransferModal";

View File

@ -2,8 +2,8 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" ==
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
//@ts-nocheck
import channel from "./ws";
var startChannel = function startChannel(topic, req, callback) {

View File

@ -3,8 +3,8 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
// @ts-nocheck
import { v4 as uuidv4 } from 'uuid';
import { has } from '@zhst/func';

View File

@ -1,40 +0,0 @@
import React from 'react';
import type { ModalProps, DescriptionsProps, TabsProps, VideoViewRef, ImgViewRef } from '@zhst/meta';
import './index.less';
export declare const componentPrefix = "zhst-image";
export type TAB_TYPE = 'COMPATER' | 'NORMAL' | 'VIDEO';
export type MODEL_TYPE = 'VIDEO' | 'IMAGE';
export interface BigImageModalProps extends ModalProps {
visible: boolean;
activeTab?: TAB_TYPE;
attributeList: {
title: string;
children: Pick<DescriptionsProps, 'items'>;
};
tabs: {
data: Pick<TabsProps, 'items'> & {
key: TAB_TYPE;
};
};
dataSource: any;
imageData: any;
relatedData: any;
isRelated?: boolean;
footer?: React.ReactNode;
showCarousel?: boolean;
onTabChange?: (newVal?: TAB_TYPE, oldVal?: TAB_TYPE) => void;
onIndexChange?: (newVal?: number, oldVal?: number) => void;
transformPropFunc: (data: any) => void;
}
interface BigModalRef {
tab: TAB_TYPE;
setTab: (tab: TAB_TYPE) => void;
modalRef: ModalProps;
activeKey: string;
setActiveKey: (val: string) => void;
videoPlayerRef: VideoViewRef;
combineImageRef: any;
bigImagePreviewRef: ImgViewRef;
}
declare const BigImageModal: React.FC<BigImageModalProps, BigModalRef>;
export default BigImageModal;

View File

@ -1,13 +0,0 @@
import * as React from 'react';
import './index.less';
declare const Navigation: React.FC<{
show?: boolean;
onClick?: React.MouseEventHandler<HTMLElement>;
prev?: boolean;
next?: boolean;
disabled?: boolean;
className?: string;
color?: string;
hoverColor?: string;
}>;
export default Navigation;

View File

@ -34,7 +34,6 @@ __export(navigation_exports, {
module.exports = __toCommonJS(navigation_exports);
var React = __toESM(require("react"));
var import_classnames = __toESM(require("classnames"));
var import_antd = require("antd");
var import_meta = require("@zhst/meta");
var import_index = require("./index.less");
var componentName = `zhst-image__nav`;
@ -52,7 +51,7 @@ var Navigation = (props) => {
className
)
},
/* @__PURE__ */ React.createElement(import_antd.Button, { type: "text", disabled, onClick }, /* @__PURE__ */ React.createElement(import_meta.Icon, { size: 28, color, icon: prev ? "icon-qiehuanzuo" : "icon-qiehuanyou" }))
/* @__PURE__ */ React.createElement(import_meta.Button, { type: "text", disabled, onClick }, /* @__PURE__ */ React.createElement(import_meta.Icon, { size: 28, color, icon: prev ? "icon-qiehuanzuo" : "icon-qiehuanyou" }))
);
};
var navigation_default = Navigation;

View File

@ -1,3 +0,0 @@
import React from 'react';
declare const _default: () => React.JSX.Element;
export default _default;

View File

@ -33,9 +33,9 @@ __export(Demo_exports, {
});
module.exports = __toCommonJS(Demo_exports);
var import_react = __toESM(require("react"));
var import_antd = require("antd");
var import_meta = require("@zhst/meta");
var import_hooks = require("@zhst/hooks");
var Demo_default = () => {
const { run } = (0, import_hooks.useThrottleFn)(() => console.log("123"));
return /* @__PURE__ */ import_react.default.createElement(import_antd.Button, { onClick: () => run() }, "测试");
return /* @__PURE__ */ import_react.default.createElement(import_meta.Button, { onClick: () => run() }, "测试");
};

View File

@ -53,7 +53,7 @@ var turf = __toESM(require("@turf/turf"));
var import_useTaskState = require("../useTaskState");
var import_Tree = __toESM(require("@common/components/CameraTree/Tree"));
var import_request = __toESM(require("../../utils/request"));
var import_antd = require("antd");
var import_meta = require("@zhst/meta");
var import_utils = require("@common/components/CameraTree/utils");
var import_func = require("@zhst/func");
var defaultFaceThreshold = 0.68;
@ -85,10 +85,10 @@ var operateTrackById = async (smartTrackId, operationType) => {
url: "/singer.SmartTrackService/OperationSmartTrack",
data
});
import_antd.message.success("操作成功");
import_meta.message.success("操作成功");
} catch (err) {
console.error(err);
import_antd.message.success("操作失败");
import_meta.message.success("操作失败");
}
};
var deleteTrackById = async (smartTrackId) => {
@ -239,7 +239,7 @@ var ModifyTrackCameras = async (value) => {
}
});
} catch (err) {
import_antd.message.error(err);
import_meta.message.error(err);
}
};
var setIntelligentTrackCircleInfo = async (smartTrackId, circleCenter) => {
@ -256,7 +256,7 @@ var setIntelligentTrackCircleInfo = async (smartTrackId, circleCenter) => {
}
});
} catch (err) {
import_antd.message.error(err);
import_meta.message.error(err);
}
};
var getTackCameraInfo = async (value) => {

View File

@ -1,2 +1,5 @@
export { default as Demo } from './Demo';
export { default as BigImageModal } from './BigImageModal';
export { default as BoxSelectTree } from './boxSelectTree';
export { default as Tree } from './tree';
export { default as TreeTransfer } from './treeTransfer';
export { default as TreeTransferModal } from './treeTransferModal';

View File

@ -30,13 +30,22 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
var src_exports = {};
__export(src_exports, {
BigImageModal: () => import_BigImageModal.default,
Demo: () => import_Demo.default
BoxSelectTree: () => import_boxSelectTree.default,
Tree: () => import_tree.default,
TreeTransfer: () => import_treeTransfer.default,
TreeTransferModal: () => import_treeTransferModal.default
});
module.exports = __toCommonJS(src_exports);
var import_Demo = __toESM(require("./Demo"));
var import_BigImageModal = __toESM(require("./BigImageModal"));
var import_boxSelectTree = __toESM(require("./boxSelectTree"));
var import_tree = __toESM(require("./tree"));
var import_treeTransfer = __toESM(require("./treeTransfer"));
var import_treeTransferModal = __toESM(require("./treeTransferModal"));
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
BigImageModal,
Demo
BoxSelectTree,
Tree,
TreeTransfer,
TreeTransferModal
});

View File

@ -1,6 +1,6 @@
{
"name": "@zhst/biz",
"version": "0.5.1",
"version": "0.6.0",
"description": "业务库",
"keywords": [
"business",
@ -20,7 +20,7 @@
"typings": "es/index.d.ts",
"exports": {
".": {
"import": "./src/index.ts"
"import": "./es/index.js"
}
},
"files": [
@ -38,6 +38,8 @@
"@types/zhst": "workspace:^"
},
"dependencies": {
"@ant-design/icons": "^5.2.6",
"@ant-design/pro-components": "^2.6.49",
"@zhst/func": "workspace:^",
"@zhst/hooks": "workspace:^",
"@zhst/meta": "workspace:^",

View File

@ -1,5 +1,5 @@
---
group: 数据展示
group: 进阶组件
category: Components
subtitle: 大图预览组件
title: BigImagePreview 大图预览组件

View File

@ -0,0 +1,93 @@
import React, { FC } from 'react';
import { InputProps, Tabs, TabsProps, TreeDataNode, TreeProps } from 'antd'
import BoxPanel from './components/boxPanel';
import { ModalFormProps } from '@ant-design/pro-components';
export interface BoxSelectTreeProps {
boxDataSource: TreeDataNode[]
data: TreeDataNode[]
onSearch?: (e: any) => void // 搜索
onItemSelect?: TreeProps['onSelect']
onItemCheck?: TreeProps['onCheck']
onTabChange?: (e: any) => void
onBoxBatchDelete?: (data?: any) => void
onBoxDelete?: (data?: any) => void
onCreateSubmit?: ModalFormProps['onFinish']
tabsProps?: TabsProps
searchInputProps?: InputProps
treeProps?: TreeProps
}
const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
const {
data,
boxDataSource = [],
onTabChange,
onSearch,
onItemCheck,
onItemSelect,
onBoxBatchDelete,
onBoxDelete,
onCreateSubmit,
tabsProps,
searchInputProps,
treeProps
} = props
const onChange = (key: string) => {
onTabChange?.(key)
};
const items: TabsProps['items'] = [
{
key: '1',
label: <div style={{ textAlign:'center', width: '160px' }} ></div>,
children: (
<BoxPanel
searchInputProps={searchInputProps}
boxDataSource={boxDataSource}
treeProps={treeProps}
data={data}
onCreateSubmit={onCreateSubmit}
onBoxBatchDelete={onBoxBatchDelete}
onBoxDelete={onBoxDelete}
onSearch={onSearch}
onItemCheck={onItemCheck}
onItemSelect={onItemSelect}
/>
)
},
{
key: '2',
label: <div style={{ textAlign:'center', width: '160px' }} ></div>,
children: (
<BoxPanel
boxDataSource={boxDataSource}
searchInputProps={searchInputProps}
treeProps={treeProps}
data={data}
onBoxBatchDelete={onBoxBatchDelete}
onCreateSubmit={onCreateSubmit}
onBoxDelete={onBoxDelete}
onSearch={onSearch}
onItemCheck={onItemCheck}
onItemSelect={onItemSelect}
/>
)
},
];
return (
<Tabs
defaultActiveKey="1"
centered
items={items}
onChange={onChange}
tabBarGutter={0}
indicator={{ size: (origin) => origin, align: 'center' }}
{...tabsProps}
/>
);
};
export default BoxSelectTree;

View File

@ -0,0 +1,175 @@
import React, { FC, useState, useRef } from 'react';
import{ Button, Divider, Input, Space, TreeDataNode } from 'antd'
import { ModalForm, ModalFormProps, ProFormInstance, ProFormText } from '@ant-design/pro-components'
import { DiffOutlined, SwitcherOutlined } from '@ant-design/icons'
import type { TreeProps, InputProps } from 'antd';
import TreeTransferModal from '../../../treeTransferModal'
import BoxTree from '../../../tree';
import './index.less'
export interface BoxGroupPanelProps {
searchInputProps?: InputProps
treeProps?: TreeProps
data: TreeDataNode[]
boxDataSource: TreeDataNode[]
handleImport?: () => void
onSearch?: (e: any) => void
onItemCheck?: TreeProps['onCheck']
onItemSelect?: TreeProps['onSelect']
onBoxBatchDelete?: (data?: any) => void
onBoxDelete?: (data?: any) => void
onCreateSubmit?: ModalFormProps['onFinish']
}
const BoxGroupPanel: FC<BoxGroupPanelProps> = (props) => {
const {
searchInputProps,
data = [],
onSearch,
treeProps,
onItemCheck,
onItemSelect,
onCreateSubmit,
onBoxBatchDelete,
onBoxDelete,
boxDataSource
} = props
const [isTreeCheckable, setIsTreeCheckable] = useState(false)
const [targetItems, setTargetItems] = useState<TreeDataNode[]>([]);
const [boxChoiceOpen, setBoxChoiceOpen] = useState(false)
const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
const createFormRef = useRef<
ProFormInstance<{
name: string;
company?: string;
useMode?: string;
}>
>()
/**
*
* @param _data
*/
const handleCheckable = () => {
setIsTreeCheckable(pre => !pre)
}
const onTreeCheck: TreeProps['onCheck'] = (keys: any, info) => {
let _targetItems: TreeDataNode[] = []
setCheckedKeys(keys)
info.checkedNodes.forEach(o => {
o.isLeaf && _targetItems.push(o)
})
setTargetItems(_targetItems)
}
/**
*
* @param key
* @param param1
*/
const onItemDelete = (key: any, { keys }: any) => {
setCheckedKeys(pre => {
const newKeys = pre.filter(_key => !keys.includes(_key))
return newKeys
})
setTargetItems(pre => pre.filter(o => o.key !== key))
}
const onOk = (data: any) => {
console.log('data', data)
}
const onReset = () => {
setCheckedKeys([])
setTargetItems([])
}
return (
<div style={{ padding: '0 16px' }}>
<TreeTransferModal
open={boxChoiceOpen}
onCancel={() => setBoxChoiceOpen(false)}
onRadioChange={(val) => console.log('radio', val)} // 顶部 radio 事件
dataSource={boxDataSource} // 数据源
targetItems={targetItems} // 右侧选中项
checkedKeys={checkedKeys} // 左侧选中
onReset={onReset} // 重置按钮事件
onOk={onOk} // 确定按钮事件
onTreeCheck={onTreeCheck} // 树check选中事件
onItemDelete={onItemDelete} // 右侧点击删除事件
/>
<Space size={12} direction='vertical'>
<Space>
<Input size='middle' onChange={(e) => onSearch?.(e)} placeholder='请输入盒子名称' {...searchInputProps} />
<Button style={{ width: '80px' }} type='primary' ></Button>
</Space>
<Space align='center'>
<ModalForm
width={'600px'}
formRef={createFormRef}
title="新建组"
modalProps={{ destroyOnClose: true }}
layout='horizontal'
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
trigger={<Button type='link' ></Button>}
submitter={{
searchConfig: {
submitText: '确定',
resetText: '取消',
},
}}
onFinish={onCreateSubmit}
>
<ProFormText
rules={[
{
required: true,
},
]}
width="md"
name="name"
label="盒子组名称"
placeholder="请输入盒子名称"
/>
<ProFormText
width="md"
name="boxList"
label="盒子选择"
placeholder="已选择0个盒子"
fieldProps={{
readOnly: true,
suffix: (
<Space>
<a onClick={() => {
createFormRef.current?.setFieldValue('boxList', null)
}} ></a>
<a onClick={() => setBoxChoiceOpen(true)}></a>
</Space>
)
}}
/>
</ModalForm>
<Divider type="vertical" />
{/* @ts-ignore */}
<Button danger type='link' disabled={treeProps?.checkedKeys?.length <= 0} onClick={onBoxBatchDelete} ></Button>
<Divider type="vertical" />
<Button type="link" onClick={() => handleCheckable()} icon={isTreeCheckable ? <DiffOutlined /> : <SwitcherOutlined />} />
<Button type="link" onClick={() => handleCheckable()} icon={isTreeCheckable ? <DiffOutlined /> : <SwitcherOutlined />} />
</Space>
<Divider style={{ margin: 0 }} />
<BoxTree
treeCheckable={isTreeCheckable}
data={data}
onItemSelect={onItemSelect}
onItemCheck={onItemCheck}
onItemDelete={onBoxDelete}
{...treeProps}
/>
</Space>
</div>
)
}
export default BoxGroupPanel

View File

@ -0,0 +1,72 @@
import React, { useState } from 'react';
import { BoxSelectTree } from '@zhst/biz';
import { treeData, boxDataSource } from './mock'
import { Select, TreeProps, Modal, Checkbox } from 'antd';
const { Option } = Select
const demo = () => {
const [searchType, setSearchType] = useState('1')
const [searchVal, setSearchVal] = useState('')
const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
const [modal, contextHolder] = Modal.useModal();
const onTreeCheck: TreeProps['onCheck'] = (keys: any) => {
setCheckedKeys(keys)
}
const onBoxBatchDelete = () => {
console.log('盒子批量删除', checkedKeys)
modal.warning({
content: (
<div>
<p></p>
<Checkbox></Checkbox>
</div>
),
cancelText: '取消',
okText: '确定',
onOk() {},
onCancel() {}
})
}
return (
<div style={{ border: '1px solid #ccc', width: '320px' }}>
{contextHolder}
<BoxSelectTree
data={treeData}
boxDataSource={boxDataSource}
onSearch={e => console.log('搜索', e)}
onCreateSubmit={async () => { return true }}
onItemCheck={onTreeCheck}
onItemSelect={e => console.log('onItemSelect', e)}
onTabChange={e => console.log('tabChange', e)}
onBoxDelete={data => console.log('盒子删除', data)}
onBoxBatchDelete={onBoxBatchDelete}
searchInputProps={{
addonBefore: (
<Select
value={searchType}
onChange={_type => {
setSearchType(_type)
setSearchVal('')
}}
style={{ width: '72px' }}
>
<Option value="1"></Option>
<Option value="2"></Option>
</Select>
),
onChange: e => setSearchVal(e.target.value),
value: searchVal
}}
treeProps={{
checkedKeys
}}
/>
</div>
);
};
export default demo;

View File

@ -0,0 +1,69 @@
import { TreeDataNode } from "antd";
export const treeData: TreeDataNode[] = [
{
title: '全部盒子',
key: '0-0',
children: [
{
title: '盒子组1',
key: '0-0-0',
children: [
{
title: '摄像头1',
key: '0-0-0-0',
},
{
title: '摄像头2',
key: '0-0-0-1',
},
],
},
{
title: '盒子组2',
key: '0-0-1',
children: [
{
title: '摄像头4',
key: '0-0-1-0'
}
],
},
],
},
];
export const boxDataSource: TreeDataNode[] = [
{
key: '0-0',
title: '分组0-0',
isLeaf: false,
checkable: false,
},
{
key: '0-1',
title: '分组0-1',
isLeaf: false,
children: [
{ key: '0-1-0', title: '分组0-1-0', isLeaf: true, checkable: false },
{ key: '0-1-1', title: '分组0-1-1', isLeaf: true, checkable: false },
{ key: '0-1-2', title: '分组0-1-2', isLeaf: true, checkable: false },
{
key: '0-1-3',
title: '分组0-1-3',
isLeaf: false,
children: [
{ key: '0-1-3-1', title: '分组0-1-3-1', isLeaf: true },
{ key: '0-1-3-2', title: '分组0-1-3-2', isLeaf: true },
{ key: '0-1-3-3', title: '分组0-1-3-3', isLeaf: true },
],
},
],
},
{ key: '0-2', title: '分组0-2', isLeaf: false, checkable: false, },
{ key: '0-3', title: '分组0-3', isLeaf: false, checkable: false, },
{ key: '0-4', title: '分组0-4', isLeaf: false, checkable: false, },
{ key: '0-5', title: '分组0-4', isLeaf: false, checkable: false, },
{ key: '0-6', title: '分组0-4', isLeaf: false, checkable: false, },
];

View File

@ -0,0 +1,26 @@
---
category: Components
title: BoxSelectTree 盒子树
demo:
cols: 2
group:
title: 进阶组件
order: 2
---
盒子树
## 代码演示
<code src="./demo/basic.tsx">基本用法</code>
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| data | 数据源 | Array[] | [] | - |
| onSearch | 搜索监听 | function: (e) => void | - | - |
| onItemSelect | 树当前选中(单选) | function: (e) => void | - | - |
| onItemCheck | 树选择(支持多选) | function: (e) => void | - | - |
| tabsProps | Tabs组件的Props | antd的Tabs组件 | - | - |
| searchInputProps | 搜索框的Props | antd的Input组件 | - | - |
| onTabChange | tab切换监听 | function: (e) => void | - | - |

View File

@ -0,0 +1,3 @@
import BoxSelectTree from './boxSelectTree';
export default BoxSelectTree;

View File

@ -0,0 +1,34 @@
import { TreeDataNode } from "antd";
export const treeData: TreeDataNode[] = [
{
title: '全部盒子',
key: '0-0',
children: [
{
title: '盒子组1',
key: '0-0-0',
children: [
{
title: '摄像头1',
key: '0-0-0-0',
},
{
title: '摄像头2',
key: '0-0-0-1',
},
],
},
{
title: '盒子组2',
key: '0-0-1',
children: [
{
title: '摄像头4',
key: '0-0-1-0'
}
],
},
],
},
];

View File

@ -1,4 +1,7 @@
export { default as Demo } from './Demo';
export { default as BigImageModal } from './BigImageModal'
export { default as BoxSelectTree } from './boxSelectTree'
export { default as Tree } from './tree'
export { default as TreeTransfer } from './treeTransfer'
export { default as TreeTransferModal } from './treeTransferModal'
export { default as WarningRecordCard } from './WarningRecordCard'
export type {IRecord, WarningRecordCardProps} from './WarningRecordCard'

View File

@ -0,0 +1,76 @@
import React, { FC } from 'react';
import { Tree, Badge, TreeDataNode, Space, TreeProps } from 'antd';
import { CloseOutlined, EditOutlined, SettingOutlined } from '@ant-design/icons'
import { ModalForm, ProFormText } from '@ant-design/pro-components';
import './index.less'
const componentName = 'zhst-biz-tree'
export interface BoxTreeProps extends TreeProps {
data: TreeDataNode[]
treeCheckable?: boolean
showItemOption?: boolean
treeProps?: TreeProps
onItemCheck?: TreeProps['onCheck']
onItemSelect?: TreeProps['onSelect']
onItemSetting?: (_data: any) => void
onItemDelete?: (_data: any) => void
onRenameFinish?: (_data: any, _nodeData: any) => Promise<any>
}
const boxTree: FC<BoxTreeProps> = (props) => {
const { onItemSelect, onItemCheck, onItemSetting, onItemDelete, data = [], showItemOption = true, treeCheckable = false, onRenameFinish } = props
return (
<Tree
checkable={treeCheckable}
blockNode
onSelect={onItemSelect}
onCheck={onItemCheck}
treeData={data}
titleRender={(_nodeData) => {
return (
<div className={`${componentName}-item-render`}>
{!_nodeData.children && <Badge style={{ marginRight: '6px' }} status="success" />}
{_nodeData.title as any}
{showItemOption && <Space className={`${componentName}-item-render_right`} style={{ float:'right' }} >
<ModalForm
title="重命名"
width={600}
modalProps={{ destroyOnClose: true }}
layout='horizontal'
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
trigger={<EditOutlined />}
submitter={{
searchConfig: {
submitText: '确定',
resetText: '取消',
},
}}
onFinish={async (value) => onRenameFinish?.(value, _nodeData)}
>
<ProFormText
rules={[
{
required: true,
},
]}
width="md"
name="name"
label="盒子名称"
placeholder="请输入盒子名称"
/>
</ModalForm>
<SettingOutlined onClick={() => onItemSetting?.(_nodeData)} />
<CloseOutlined onClick={() => onItemDelete?.(_nodeData)} />
</Space>}
</div>
)
}}
{...props}
/>
);
};
export default boxTree;

View File

@ -0,0 +1,20 @@
import React from 'react';
import { Tree } from '@zhst/biz';
import { treeData } from './mock'
const demo = () => {
return (
<div style={{ width: '320px' }}>
<Tree
data={treeData}
onItemCheck={e => console.log('多选框', e)}
onItemSelect={e => console.log('当前选中', e)}
onItemDelete={(e) => console.log('删除', e)}
onItemSetting={e => console.log('配置', e)}
onRenameFinish={async (data, pData) => console.log('重命名表单提交', data, pData)}
/>
</div>
);
};
export default demo;

View File

@ -0,0 +1,30 @@
import React from 'react';
import { Tree } from '@zhst/biz';
import { Tooltip } from 'antd';
import { treeData } from './mock'
const demo = () => {
return (
<div style={{ width: '320px' }}>
<Tree
data={treeData}
titleRender={(_nodeData) => {
const { title } = _nodeData as any
return (
<div>
{title}
<div style={{ float: 'right' }} >
<Tooltip placement="right" title={'存在0个'}>
<a >0</a>
</Tooltip>
</div>
</div>
)
}
}
/>
</div>
);
};
export default demo;

View File

@ -0,0 +1,34 @@
import { TreeDataNode } from "antd";
export const treeData: TreeDataNode[] = [
{
title: '全部盒子',
key: '0-0',
children: [
{
title: '盒子组1',
key: '0-0-0',
children: [
{
title: '摄像头1',
key: '0-0-0-0',
},
{
title: '摄像头2',
key: '0-0-0-1',
},
],
},
{
title: '盒子组2',
key: '0-0-1',
children: [
{
title: '摄像头4',
key: '0-0-1-0'
}
],
},
],
},
];

View File

@ -0,0 +1,16 @@
import React from 'react';
import { Tree } from '@zhst/biz';
import { treeData } from './mock'
const demo = () => {
return (
<div style={{ width: '320px' }}>
<Tree
data={treeData}
showItemOption={false}
/>
</div>
);
};
export default demo;

View File

@ -0,0 +1,9 @@
.zhst-biz-tree-item-render {
&_right {
display: none;
}
&:hover &_right {
display: inline-flex;
}
}

View File

@ -0,0 +1,21 @@
---
category: Components
title: Tree 树
demo:
cols: 2
group:
title: 数据展示
order: 2
---
## 代码演示
<code src="./demo/basic.tsx">基本用法</code>
<code src="./demo/customTitleRender.tsx">自定义渲染界面</code>
<code src="./demo/noOption.tsx">不展示配置项</code>
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| data | 数据源 | Array[] | [] | - |

View File

@ -0,0 +1,3 @@
import BoxTree from './boxTree';
export default BoxTree;

View File

@ -0,0 +1,124 @@
import React, { useState } from 'react';
import { Button, Card, Flex, Input, Tree } from 'antd';
import theme from 'antd/es/theme'
import { TransferProps, TreeDataNode, TreeProps } from 'antd';
import './index.less'
import { DeleteOutlined, DoubleRightOutlined, SearchOutlined } from '@ant-design/icons';
import { getAllRootKeyById } from './treeTransferHelper';
const componentName = 'zhst-biz-treeTransfer'
export interface TreeTransferProps {
dataSource: TreeDataNode[]
treeProps?: TreeProps
targetItems: TreeDataNode[];
checkedKeys: string[];
onTreeSelect?: TreeProps['onSelect']
onTreeCheck?: TreeProps['onCheck']
onItemDelete?: (key: string, info?: { root: TreeDataNode[], keys: string[] }) => void
onChange?: TransferProps['onChange'];
onOk?: (data: any) => void;
onReset?: () => void;
}
const { useToken } = theme
const TreeTransfer: React.FC<TreeTransferProps> = ({
dataSource,
treeProps,
targetItems = [],
checkedKeys = [],
onTreeCheck,
onTreeSelect,
onItemDelete,
onOk,
onReset
}) => {
const { token } = useToken()
const [keyWords, setKeyWords ] = useState('')
function findNodesWithKeyword(_keyWords: string, _treeData: TreeDataNode[]) {
// @ts-ignore
function dfs(node: any) {
return node.filter((item: { title: string | string[]; }) => item.title.includes(_keyWords))
}
const data = dfs(_treeData)
return data || [];
}
return (
<Flex gap={20} className={componentName} align='center' justify='center'>
<div className={`${componentName}-left`}>
<Card
className={`${componentName}-left_card`}
title={<div style={{ textAlign: 'center' }} ></div>}
bodyStyle={{ padding: 12 }}
>
<Input prefix={<SearchOutlined />} onChange={e => setKeyWords(e.target.value)} placeholder='请输入设备名称' />
<Tree
style={{ marginTop: '6px' }}
height={420}
blockNode
checkable
checkedKeys={checkedKeys}
treeData={findNodesWithKeyword(keyWords, dataSource)}
onCheck={(keys, info) => onTreeCheck?.(keys, info)}
onSelect={(keys, info) => onTreeSelect?.(keys, info)}
{...treeProps}
/>
</Card>
</div>
<DoubleRightOutlined/>
<div className={`${componentName}-right`}>
<Card
className={`${componentName}-right_card`}
title={<div style={{ textAlign: 'center' }}></div>}
bodyStyle={{ padding: 0 }}
>
<div
className={`${componentName}-right_card__items`}
>
{targetItems.map(item => (
<div
className={`${componentName}-right_card__items___item`}
key={item.key}
onMouseEnter={(e: any) => {
e.target.style.backgroundColor = token.colorPrimaryBg
e.target.style.color = token.colorPrimary
}}
onMouseLeave={(e: any) => {
e.target.style.color = token.colorText
e.target.style.backgroundColor = null
}}
>
{item.title as any}
<div style={{ float: 'right' }}>
<DeleteOutlined onClick={() => {
const { root, keys } = getAllRootKeyById(item.key as string, dataSource)
onItemDelete?.(item.key as string, { root, keys })
}} />
</div>
</div>
))}
</div>
<Flex
className={`${componentName}-right_card__btns`}
>
<Button style={{ marginRight: 8, width: '50%' }} disabled={targetItems.length <= 0} onClick={onReset}></Button>
<Button
style={{ width: '50%' }}
type='primary'
onClick={() => onOk?.(targetItems)}
></Button>
</Flex>
</Card>
</div>
</Flex>
);
}
export default TreeTransfer

View File

@ -0,0 +1,56 @@
import React, { useState } from 'react';
import { TreeTransfer } from '@zhst/biz';
import { TreeDataNode } from 'antd';
import { TreeProps } from 'antd/lib';
import { boxDataSource } from './mock'
const App: React.FC = () => {
const [targetItems, setTargetItems] = useState<TreeDataNode[]>([]);
const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
const onTreeCheck: TreeProps['onCheck'] = (keys: any, info) => {
let _targetItems: TreeDataNode[] = []
setCheckedKeys(keys)
info.checkedNodes.forEach(o => {
o.isLeaf && _targetItems.push(o)
})
setTargetItems(_targetItems)
}
/**
*
* @param key
* @param param1
*/
const onItemDelete = (key: any, { keys }: any) => {
setCheckedKeys(pre => {
const newKeys = pre.filter(_key => !keys.includes(_key))
console.log('newKeys', newKeys, keys)
return newKeys
})
setTargetItems(pre => pre.filter(o => o.key !== key))
}
const onOk = (data: any) => {
console.log('data', data)
}
const onReset = () => {
setCheckedKeys([])
setTargetItems([])
}
return (
<TreeTransfer
dataSource={boxDataSource}
targetItems={targetItems}
checkedKeys={checkedKeys}
onTreeCheck={onTreeCheck}
onItemDelete={onItemDelete}
onOk={onOk}
onReset={onReset}
/>
)
};
export default App;

View File

@ -0,0 +1,35 @@
import { TreeDataNode } from "antd";
export const boxDataSource: TreeDataNode[] = [
{
key: '0-0',
title: '分组0-0',
isLeaf: false,
checkable: false,
},
{
key: '0-1',
title: '分组0-1',
isLeaf: false,
children: [
{ key: '0-1-0', title: '分组0-1-0', isLeaf: true, checkable: false },
{ key: '0-1-1', title: '分组0-1-1', isLeaf: true, checkable: false },
{ key: '0-1-2', title: '分组0-1-2', isLeaf: true, checkable: false },
{
key: '0-1-3',
title: '分组0-1-3',
isLeaf: false,
children: [
{ key: '0-1-3-1', title: '分组0-1-3-1', isLeaf: true },
{ key: '0-1-3-2', title: '分组0-1-3-2', isLeaf: true },
{ key: '0-1-3-3', title: '分组0-1-3-3', isLeaf: true },
],
},
],
},
{ key: '0-2', title: '分组0-2', isLeaf: false, checkable: false, },
{ key: '0-3', title: '分组0-3', isLeaf: false, checkable: false, },
{ key: '0-4', title: '分组0-4', isLeaf: false, checkable: false, },
{ key: '0-5', title: '分组0-4', isLeaf: false, checkable: false, },
{ key: '0-6', title: '分组0-4', isLeaf: false, checkable: false, },
];

View File

@ -0,0 +1,127 @@
import React, { useState } from 'react';
import { TreeTransfer } from '@zhst/biz';
import { Button, Modal, Radio, TreeDataNode } from 'antd';
import { TreeProps } from 'antd/lib';
const treeData: TreeDataNode[] = [
{
key: '0-0',
title: '分组0-0',
isLeaf: false,
checkable: false,
},
{
key: '0-1',
title: '分组0-1',
isLeaf: false,
children: [
{ key: '0-1-0', title: '分组0-1-0', isLeaf: true, checkable: false },
{ key: '0-1-1', title: '分组0-1-1', isLeaf: true, checkable: false },
{ key: '0-1-2', title: '分组0-1-2', isLeaf: true, checkable: false },
{
key: '0-1-3',
title: '分组0-1-3',
isLeaf: false,
children: [
{ key: '0-1-3-1', title: '分组0-1-3-1', isLeaf: true },
{ key: '0-1-3-2', title: '分组0-1-3-2', isLeaf: true },
{ key: '0-1-3-3', title: '分组0-1-3-3', isLeaf: true },
],
},
],
},
{ key: '0-2', title: '分组0-2', isLeaf: false, checkable: false, },
{ key: '0-3', title: '分组0-3', isLeaf: false, checkable: false, },
{ key: '0-4', title: '分组0-4', isLeaf: false, checkable: false, },
{ key: '0-5', title: '分组0-4', isLeaf: false, checkable: false, },
{ key: '0-6', title: '分组0-4', isLeaf: false, checkable: false, },
];
const App: React.FC = () => {
const [targetItems, setTargetItems] = useState<TreeDataNode[]>([]);
const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
const [type, setType] = useState('box')
const [open, setOpen] = useState(false)
const onTreeCheck: TreeProps['onCheck'] = (keys: any, info) => {
let _targetItems: TreeDataNode[] = []
setCheckedKeys(keys)
info.checkedNodes.forEach(o => {
o.isLeaf && _targetItems.push(o)
})
setTargetItems(_targetItems)
}
/**
*
* @param key
* @param param1
*/
const onItemDelete = (key: any, { keys }: any) => {
setCheckedKeys(pre => {
const newKeys = pre.filter(_key => !keys.includes(_key))
console.log('newKeys', newKeys, keys)
return newKeys
})
setTargetItems(pre => pre.filter(o => o.key !== key))
}
const onOk = (data: any) => {
console.log('data', data)
}
const onReset = () => {
setCheckedKeys([])
setTargetItems([])
}
return (
<div>
<Button type="primary" onClick={() => setOpen(true)} ></Button>
<Modal
open={open}
destroyOnClose
title="统计点位"
width="948px"
onCancel={() => setOpen(false)}
footer={null}
>
<div>
<Radio.Group
onChange={e => setType(e.target.value)}
style={{ marginLeft: '24px', padding: '20px 0' }}
value={type}
>
<Radio value={'box'}></Radio>
<Radio value={'boxGroup'}></Radio>
</Radio.Group>
{type === 'box' ?
(
<TreeTransfer
dataSource={treeData}
targetItems={targetItems}
checkedKeys={checkedKeys}
onTreeCheck={onTreeCheck}
onItemDelete={onItemDelete}
onOk={onOk}
onReset={onReset}
/>
) : (
<TreeTransfer
dataSource={treeData}
targetItems={targetItems}
checkedKeys={checkedKeys}
onTreeCheck={onTreeCheck}
onItemDelete={onItemDelete}
onOk={onOk}
onReset={onReset}
/>
)}
<p style={{ textAlign: 'right' }} >{targetItems.length}</p>
</div>
</Modal>
</div>
)
};
export default App;

View File

@ -0,0 +1,43 @@
.zhst-biz-treeTransfer {
&-left {
&_card {
width: 500px;
height: 522px;
background-color: #FCFCFC;
}
}
&-right {
&_card {
width: 300px;
height: 522px;
background-color: #FCFCFC;
&__items {
padding: 8px 4px;
overflow: scroll;
&::-webkit-scrollbar {
display: none;
}
&___item {
margin: 0;
padding: 4px 12px;
cursor: pointer;
}
}
&__btns {
width: 100%;
padding: 8px;
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
box-sizing: border-box;
border-top: 1px solid #f0f0f0;
}
}
}
}

View File

@ -0,0 +1,18 @@
---
category: Components
title: TreeTransfer 树穿梭框
group:
title: 数据展示
order: 2
---
盒子树
## 代码演示
<code src="./demo/basic.tsx">基本用法</code>
<code src="./demo/withModal.tsx">和Modal组合使用</code>
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| data | 数据源 | Array[] | [] | - |

View File

@ -0,0 +1,3 @@
import TreeTransfer from "./TreeTransfer";
export default TreeTransfer

View File

@ -0,0 +1,62 @@
export const isChecked = (selectedKeys: React.Key[], eventKey: React.Key) =>
selectedKeys.includes(eventKey);
function isObject(value: any) {
return value !== null && typeof value === 'object' && !Array.isArray(value);
}
/**
*
* @param objects
* @param element
* @returns
*/
export const findParentByChild = (objects: any[], propertyValue: string | number, propertyKey: string = 'key') => {
for (let i = 0; i < objects.length; i++) {
const obj = objects[i];
if (obj[propertyKey] === propertyValue) {
return obj
} else if (typeof obj === 'object') {
const found = findParentByChild(Object.values(obj), propertyValue);
if (found) {
return obj
}
}
}
return null; // 如果找不到包含具有指定属性的子对象的父对象,返回 null
}
export const getAllRootKeyById = (val: string | number, list: any[], key: string = 'key') => {
let keys: any[] = []
const findParentByChild = (propertyValue: string | number, objects: any[], propertyKey: string) => {
for (let i = 0; i < objects.length; i++) {
const obj = objects[i];
if (obj[propertyKey] === propertyValue) {
console.log('obj', obj)
return obj
} else if (typeof obj === 'object') {
const found = findParentByChild(propertyValue, Object.values(obj), propertyKey);
if (found) {
if (isObject(found)) {
keys.push(found.key)
}
return obj
}
}
}
return null; // 如果找不到包含具有指定属性的子对象的父对象,返回 null
}
const data = findParentByChild(val, list, key)
data.key && keys.push(data.key)
return {
root: data,
keys
}
}

View File

@ -0,0 +1,91 @@
import React, { FC, useState } from 'react';
import TreeTransfer from '../treeTransfer';
import { Modal, ModalProps, Radio, RadioGroupProps, TransferProps, TreeDataNode } from 'antd';
import { TreeProps } from 'antd/lib';
export interface TreeTransferModalProps {
dataSource: TreeDataNode[]
treeProps?: TreeProps
targetItems: TreeDataNode[];
checkedKeys: string[];
onTreeSelect?: TreeProps['onSelect']
onTreeCheck?: TreeProps['onCheck']
onItemDelete?: (key: string, info?: { root: TreeDataNode[], keys: string[] }) => void
onChange?: TransferProps['onChange'];
onOk?: (data: any) => void;
onReset?: () => void;
open?: boolean
onCancel?: ModalProps['onCancel']
onRadioChange?: RadioGroupProps['onChange']
modalProps?: ModalProps
}
const TreeTransferModal: FC<TreeTransferModalProps> = (props) => {
const {
open,
dataSource = [],
checkedKeys,
onItemDelete,
onOk,
onCancel,
onReset,
onRadioChange,
onTreeCheck,
targetItems,
modalProps,
} = props
const [type, setType] = useState('box')
return (
<Modal
open={open}
destroyOnClose
title="统计点位"
width="948px"
footer={null}
onCancel={onCancel}
{...modalProps}
>
<div>
<Radio.Group
onChange={e => {
setType(e.target.value)
onRadioChange?.(e)
}}
style={{ marginLeft: '24px', padding: '20px 0' }}
value={type}
>
<Radio value={'box'}></Radio>
<Radio value={'boxGroup'}></Radio>
</Radio.Group>
{type === 'box' ?
(
<TreeTransfer
dataSource={dataSource}
targetItems={targetItems}
checkedKeys={checkedKeys}
onTreeCheck={onTreeCheck}
onItemDelete={onItemDelete}
onOk={onOk}
onReset={onReset}
/>
) : (
<TreeTransfer
dataSource={dataSource}
targetItems={targetItems}
checkedKeys={checkedKeys}
onTreeCheck={onTreeCheck}
onItemDelete={onItemDelete}
onOk={onOk}
onReset={onReset}
/>
)}
<p style={{ textAlign: 'right' }} >{targetItems.length}</p>
</div>
</Modal>
)
};
export default TreeTransferModal;

View File

@ -0,0 +1,63 @@
import React, { useState } from 'react';
import { TreeTransferModal } from '@zhst/biz';
import { Button, TreeDataNode } from 'antd';
import { TreeProps } from 'antd/lib';
import { boxDataSource } from './mock'
const App: React.FC = () => {
const [targetItems, setTargetItems] = useState<TreeDataNode[]>([]);
const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
const [open, setOpen] = useState(false)
const onTreeCheck: TreeProps['onCheck'] = (keys: any, info) => {
let _targetItems: TreeDataNode[] = []
setCheckedKeys(keys)
info.checkedNodes.forEach(o => {
o.isLeaf && _targetItems.push(o)
})
setTargetItems(_targetItems)
}
/**
*
* @param key
* @param param1
*/
const onItemDelete = (key: any, { keys }: any) => {
setCheckedKeys(pre => {
const newKeys = pre.filter(_key => !keys.includes(_key))
console.log('newKeys', newKeys, keys)
return newKeys
})
setTargetItems(pre => pre.filter(o => o.key !== key))
}
const onOk = (data: any) => {
console.log('data', data)
}
const onReset = () => {
setCheckedKeys([])
setTargetItems([])
}
return (
<div>
<Button type="primary" onClick={() => setOpen(true)} ></Button>
<TreeTransferModal
open={open}
onCancel={() => setOpen(false)}
onRadioChange={() => setOpen(false)} // 顶部 radio 事件
dataSource={boxDataSource} // 数据源
targetItems={targetItems} // 右侧选中项
checkedKeys={checkedKeys} // 左侧选中
onReset={onReset} // 重置按钮事件
onOk={onOk} // 确定按钮事件
onTreeCheck={onTreeCheck} // 树check选中事件
onItemDelete={onItemDelete} // 右侧点击删除事件
/>
</div>
)
};
export default App;

View File

@ -0,0 +1,35 @@
import { TreeDataNode } from "antd";
export const boxDataSource: TreeDataNode[] = [
{
key: '0-0',
title: '分组0-0',
isLeaf: false,
checkable: false,
},
{
key: '0-1',
title: '分组0-1',
isLeaf: false,
children: [
{ key: '0-1-0', title: '分组0-1-0', isLeaf: true, checkable: false },
{ key: '0-1-1', title: '分组0-1-1', isLeaf: true, checkable: false },
{ key: '0-1-2', title: '分组0-1-2', isLeaf: true, checkable: false },
{
key: '0-1-3',
title: '分组0-1-3',
isLeaf: false,
children: [
{ key: '0-1-3-1', title: '分组0-1-3-1', isLeaf: true },
{ key: '0-1-3-2', title: '分组0-1-3-2', isLeaf: true },
{ key: '0-1-3-3', title: '分组0-1-3-3', isLeaf: true },
],
},
],
},
{ key: '0-2', title: '分组0-2', isLeaf: false, checkable: false, },
{ key: '0-3', title: '分组0-3', isLeaf: false, checkable: false, },
{ key: '0-4', title: '分组0-4', isLeaf: false, checkable: false, },
{ key: '0-5', title: '分组0-4', isLeaf: false, checkable: false, },
{ key: '0-6', title: '分组0-4', isLeaf: false, checkable: false, },
];

View File

@ -0,0 +1,17 @@
---
category: Components
title: TreeTransferModal 树穿梭框弹框
group:
title: 数据展示
order: 2
---
树穿梭框弹框
## 代码演示
<code src="./demo/basic.tsx">基本用法</code>
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| data | 数据源 | Array[] | [] | - |

View File

@ -0,0 +1,3 @@
import TreeTransferModal from './TreeTransferModal'
export default TreeTransferModal

View File

@ -4,4 +4,5 @@ export default defineConfig({
// more father config: https://github.com/umijs/father/blob/master/docs/config.md
esm: { output: 'es' },
cjs: { output: 'lib' },
// umd: { output: 'dist' }
});

View File

@ -1,5 +1,16 @@
# @zhst/utils
## 0.7.0
### Minor Changes
- 新增业务组件 Tree、TreeTransfer、TreeTransferModal、BoxSelectTree
### Patch Changes
- Updated dependencies
- @zhst/request@0.7.0
## 0.6.0
### Minor Changes

1
packages/func/dist/func.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -7,7 +7,4 @@ export * from "./number";
export * from "./time";
export * from "./utils";
export * from "./camera";
export * from "./math";
export var a = function a(data) {
console.log('data', data);
};
export * from "./math";

View File

@ -1,6 +1,6 @@
{
"name": "@zhst/func",
"version": "0.6.0",
"version": "0.7.0",
"description": "函数合集",
"keywords": [
"hooks"

View File

@ -8,7 +8,3 @@ export * from './time'
export * from './utils'
export * from './camera'
export * from './math'
export const a = (data: string) => {
console.log('data', data)
}

View File

@ -4,4 +4,5 @@ export default defineConfig({
// more father config: https://github.com/umijs/father/blob/master/docs/config.md
esm: { output: 'es' },
cjs: { output: 'lib' },
// umd: { output: 'dist' }
});

View File

@ -1,5 +1,16 @@
# @zhst/hooks
## 0.7.0
### Minor Changes
- 新增业务组件 Tree、TreeTransfer、TreeTransferModal、BoxSelectTree
### Patch Changes
- Updated dependencies
- @zhst/func@0.7.0
## 0.6.0
### Minor Changes

View File

@ -48,4 +48,4 @@ export var useActivateState = function useActivateState() {
});
return isActive;
};
export default useActivateWrapper;
export default useActivateWrapper;

View File

@ -1,6 +1,6 @@
{
"name": "@zhst/hooks",
"version": "0.6.0",
"version": "0.7.0",
"description": "hooks合集",
"keywords": [
"hooks"

View File

@ -1,7 +0,0 @@
import { defineConfig } from 'father';
export default defineConfig({
// more father config: https://github.com/umijs/father/blob/master/docs/config.md
esm: { output: 'es' },
cjs: { output: 'lib' },
});

View File

@ -1,140 +0,0 @@
# @zhst/biz
## 0.5.1
### Patch Changes
- Updated dependencies
- @zhst/hooks@0.6.0
- @zhst/func@0.6.0
- @zhst/meta@0.7.0
- @zhst/biz@0.5.1
## 0.5.0
### Minor Changes
- feat: 初版发布
### Patch Changes
- Updated dependencies
- @zhst/hooks@0.5.0
- @zhst/func@0.5.0
- @zhst/meta@0.6.0
- @zhst/biz@0.5.0
## 0.4.2
### Patch Changes
- Updated dependencies
- @zhst/meta@0.5.2
- @zhst/biz@0.4.2
## 0.4.1
### Patch Changes
- feat: 初始化
- Updated dependencies
- @zhst/hooks@0.4.1
- @zhst/func@0.4.1
- @zhst/meta@0.5.1
- @zhst/biz@0.4.1
## 0.4.0
### Minor Changes
- fix: 修改 pkg
### Patch Changes
- Updated dependencies
- @zhst/hooks@0.4.0
- @zhst/func@0.4.0
- @zhst/meta@0.5.0
- @zhst/biz@0.4.0
## 0.3.6
### Patch Changes
- Updated dependencies
- @zhst/meta@0.4.4
- @zhst/biz@0.3.6
## 0.3.5
### Patch Changes
- Updated dependencies
- @zhst/meta@0.4.3
- @zhst/biz@0.3.5
## 0.3.4
### Patch Changes
- Updated dependencies
- @zhst/meta@0.4.2
- @zhst/biz@0.3.4
## 0.3.3
### Patch Changes
- Updated dependencies
- @zhst/func@0.3.1
- @zhst/biz@0.3.3
- @zhst/hooks@0.3.1
- @zhst/meta@0.4.1
## 0.3.2
### Patch Changes
- Updated dependencies
- @zhst/meta@0.4.0
- @zhst/biz@0.3.2
## 0.3.1
### Patch Changes
- Updated dependencies
- @zhst/meta@0.3.1
- @zhst/biz@0.3.1
## 0.3.0
### Minor Changes
- feat: 初始化项目包
### Patch Changes
- Updated dependencies
- @zhst/hooks@0.3.0
- @zhst/func@0.3.0
- @zhst/meta@0.3.0
- @zhst/biz@0.3.0
## 0.2.4
### Patch Changes
- feat: 新增 meta 包
- Updated dependencies
- @zhst/func@0.2.4
- @zhst/hooks@0.2.4
- @zhst/meta@0.2.4
## 0.2.3
### Patch Changes
- fix: 调试包 link
- Updated dependencies
- @zhst/hooks@0.2.3

View File

@ -1,20 +0,0 @@
:::warning{title=待开始}
目前项目正在如火如荼的筹备中...
:::
## 介绍
物料库,每一个物料都是单独存在的个体,不需要任何依赖,就能形成一个页面,甚至一个项目
## 安装
> pnpm install @zhst/material
## 使用
```jsx
import React from 'react';
import { Demo } from '@zhst/material'
export default () => <Demo />
```

View File

@ -1,3 +0,0 @@
import React from 'react';
declare const _default: () => React.JSX.Element;
export default _default;

View File

@ -1,4 +0,0 @@
import React from 'react';
export default (function () {
return /*#__PURE__*/React.createElement("div", null, "hi");
});

View File

@ -1 +0,0 @@
export { default as Demo } from './Demo';

View File

@ -1 +0,0 @@
export { default as Demo } from "./Demo";

View File

@ -1,3 +0,0 @@
import React from 'react';
declare const _default: () => React.JSX.Element;
export default _default;

View File

@ -1,38 +0,0 @@
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/Demo/index.tsx
var Demo_exports = {};
__export(Demo_exports, {
default: () => Demo_default
});
module.exports = __toCommonJS(Demo_exports);
var import_react = __toESM(require("react"));
var Demo_default = () => {
return /* @__PURE__ */ import_react.default.createElement("div", null, "hi");
};

View File

@ -1 +0,0 @@
export { default as Demo } from './Demo';

View File

@ -1,39 +0,0 @@
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.tsx
var src_exports = {};
__export(src_exports, {
Demo: () => import_Demo.default
});
module.exports = __toCommonJS(src_exports);
var import_Demo = __toESM(require("./Demo"));
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Demo
});

View File

@ -1,39 +0,0 @@
{
"name": "@zhst/material",
"version": "0.5.1",
"description": "物料库",
"keywords": [
"business",
"biz",
"zhst",
"material"
],
"license": "ISC",
"author": "dev",
"sideEffects": [
"dist/*",
"es/**/style/*",
"lib/**/style/*",
"*.less"
],
"main": "lib/index.js",
"module": "es/index.js",
"typings": "es/index.d.ts",
"files": [
"es",
"lib"
],
"scripts": {
"build": "father build"
},
"publishConfig": {
"access": "public",
"registry": "http://10.0.0.77:4874"
},
"dependencies": {
"@zhst/hooks": "workspace:^",
"@zhst/meta": "workspace:^",
"@zhst/func": "workspace:^",
"@zhst/biz": "workspace:^"
}
}

View File

@ -1,8 +0,0 @@
import React from 'react'
export default () => {
return (
<div>hi</div>
)
}

View File

@ -1,8 +0,0 @@
---
nav:
title: 元组件
title: 版本更新日志
order: 99
---
<embed src="../../CHANGELOG.md" ></embed>

View File

@ -1 +0,0 @@
export { default as Demo } from './Demo';

View File

@ -1,5 +1,18 @@
# @zhst/utils
## 0.8.0
### Minor Changes
- 新增业务组件 Tree、TreeTransfer、TreeTransferModal、BoxSelectTree
### Patch Changes
- Updated dependencies
- @zhst/hooks@0.7.0
- @zhst/func@0.7.0
- @zhst/meta@0.8.0
## 0.7.0
### Minor Changes

View File

@ -16,17 +16,7 @@ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
import React, { useEffect, useState, useCallback, useRef, useImperativeHandle } from 'react';
import classNames from 'classnames';
import { useLatest } from '@zhst/hooks';
import { get, pick, isNull, generateImg, dataURLToBlob,
// @ts-ignore
getOdRect,
// @ts-ignore
getExtendRect,
// @ts-ignore
getTransformRect,
// @ts-ignore
getRotateImg, getTransforms, addEventListenerWrapper, getFileByRect
// @ts-ignore
} from '@zhst/func';
import { get, pick, isNull, generateImg, dataURLToBlob, getOdRect, getExtendRect, getTransformRect, getRotateImg, getTransforms, addEventListenerWrapper, getFileByRect } from '@zhst/func';
import Align from 'rc-align';
import { Button, Empty } from '..';
import Icon from "../iconfont";

View File

@ -1,6 +1,7 @@
import React from 'react';
import classNames from 'classnames';
import { Button, Tooltip } from 'antd';
// @ts-ignore
import { Button, Tooltip } from "../../..";
import Icon from "../../../iconfont";
import "./index.less";
var componentName = "zhst-image__btn-group";

View File

@ -14,9 +14,7 @@ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';
import { noop, get, addEventListenerWrapper, dataURLToBlob, nextTick, toRealNumber, getTransforms, formatDurationTime
// @ts-ignore
} from '@zhst/func';
import { noop, get, addEventListenerWrapper, dataURLToBlob, nextTick, toRealNumber, getTransforms, formatDurationTime } from '@zhst/func';
import Align from 'rc-align';
import { useLatest, useUpdateEffect, useFullscreen, useUnmount } from '@zhst/hooks';
import classNames from 'classnames';

View File

@ -19,7 +19,6 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
import React, { Component } from 'react';
import flvjs from 'flv.js';
// @ts-ignore
import { isEqual } from '@zhst/func';
export var FLV_EVENT = flvjs.Events;
var VideoPlayer = /*#__PURE__*/function (_Component) {

View File

@ -41,4 +41,6 @@ export { default as Card } from "./card";
export { default as Skeleton } from "./skeleton";
export { default as Tooltip } from "./tooltip";
export { default as Tour } from "./tour";
export { default as Segmented } from "./segmented";
export { default as Segmented } from "./segmented";
export { default as App } from "./app";
export { default as notification } from "./notification";

View File

@ -1,6 +1,6 @@
{
"name": "@zhst/meta",
"version": "0.7.0",
"version": "0.8.0",
"description": "原子组件",
"keywords": [
"meta",
@ -67,7 +67,7 @@
"@types/tar": "^6.1.10",
"@types/throttle-debounce": "^5.0.2",
"@types/warning": "^3.0.3",
"@types/zhst": "workspace:^",
"@zhst/types": "workspace:^",
"@typescript-eslint/eslint-plugin": "^6.17.0",
"@typescript-eslint/parser": "^6.17.0",
"react": "^18.2.0",

View File

@ -7,18 +7,13 @@ import {
isNull,
generateImg,
dataURLToBlob,
// @ts-ignore
getOdRect,
// @ts-ignore
getExtendRect,
// @ts-ignore
getTransformRect,
// @ts-ignore
getRotateImg,
getTransforms,
addEventListenerWrapper,
getFileByRect
// @ts-ignore
} from '@zhst/func';
import Align from 'rc-align';
import { Button, Empty } from '..';

View File

@ -1,6 +1,7 @@
import React, { MouseEvent } from 'react';
import classNames from 'classnames';
import { Button, Tooltip, TooltipProps } from 'antd';
// @ts-ignore
import { Button, Tooltip, TooltipProps } from '../../..';
import Icon from '../../../iconfont';
import './index.less';
@ -38,7 +39,7 @@ export const BtnGroup: React.FC<BtnGroupProps> = (props) => {
>
<Button
type="text"
onClick={(e) => {
onClick={(e: React.MouseEvent<HTMLElement, globalThis.MouseEvent>) => {
onClick(key, e);
}}
>

View File

@ -1,6 +1,6 @@
import React, { useRef } from 'react';
import { Button, Space } from 'antd'
import { Button, Space } from '@zhst/meta'
import { BigImagePreview } from '@zhst/meta'

View File

@ -8,7 +8,6 @@ import {
toRealNumber,
getTransforms,
formatDurationTime
// @ts-ignore
} from '@zhst/func';
import Align from 'rc-align';
import { Rect, IScreenshotButtonProp, AlignType } from '@zhst/types'

View File

@ -1,6 +1,5 @@
import React, { Component, CSSProperties } from 'react';
import flvjs from 'flv.js';
// @ts-ignore
import { isEqual } from '@zhst/func';
export const FLV_EVENT = flvjs.Events;

View File

@ -0,0 +1,87 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders components/app/demo/basic.tsx extend context correctly 1`] = `
<div
class="ant-app"
>
<div
class="ant-space ant-space-horizontal ant-space-align-center ant-space-gap-row-small ant-space-gap-col-small"
>
<div
class="ant-space-item"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Open message
</span>
</button>
</div>
<div
class="ant-space-item"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Open modal
</span>
</button>
</div>
<div
class="ant-space-item"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Open notification
</span>
</button>
</div>
</div>
</div>
`;
exports[`renders components/app/demo/basic.tsx extend context correctly 2`] = `[]`;
exports[`renders components/app/demo/config.tsx extend context correctly 1`] = `
<div
class="ant-app"
>
<div
class="ant-space ant-space-horizontal ant-space-align-center ant-space-gap-row-small ant-space-gap-col-small"
>
<div
class="ant-space-item"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Message for only one
</span>
</button>
</div>
<div
class="ant-space-item"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Notification for bottomLeft
</span>
</button>
</div>
</div>
</div>
`;
exports[`renders components/app/demo/config.tsx extend context correctly 2`] = `[]`;

View File

@ -0,0 +1,83 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders components/app/demo/basic.tsx correctly 1`] = `
<div
class="ant-app"
>
<div
class="ant-space ant-space-horizontal ant-space-align-center ant-space-gap-row-small ant-space-gap-col-small"
>
<div
class="ant-space-item"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Open message
</span>
</button>
</div>
<div
class="ant-space-item"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Open modal
</span>
</button>
</div>
<div
class="ant-space-item"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Open notification
</span>
</button>
</div>
</div>
</div>
`;
exports[`renders components/app/demo/config.tsx correctly 1`] = `
<div
class="ant-app"
>
<div
class="ant-space ant-space-horizontal ant-space-align-center ant-space-gap-row-small ant-space-gap-col-small"
>
<div
class="ant-space-item"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Message for only one
</span>
</button>
</div>
<div
class="ant-space-item"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Notification for bottomLeft
</span>
</button>
</div>
</div>
</div>
`;

View File

@ -0,0 +1,17 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`App rtl render component should be rendered correctly in RTL direction 1`] = `
<div
class="ant-app"
/>
`;
exports[`App single 1`] = `
<div
class="ant-app"
>
<div>
Hello World
</div>
</div>
`;

View File

@ -0,0 +1,3 @@
import { extendTest } from '../../../tests/shared/demoTest';
extendTest('app');

View File

@ -0,0 +1,3 @@
import demoTest from '../../../tests/shared/demoTest';
demoTest('app');

View File

@ -0,0 +1,5 @@
import { imageDemoTest } from '../../../tests/shared/imageTest';
describe('app', () => {
imageDemoTest('app');
});

View File

@ -0,0 +1,236 @@
import React, { useEffect } from 'react';
import { SmileOutlined } from '@ant-design/icons';
import type { NotificationConfig } from 'antd/es/notification/interface';
import App from '..';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { render, waitFakeTimer } from '../../../tests/utils';
import type { AppConfig } from '../context';
import { AppConfigContext } from '../context';
describe('App', () => {
mountTest(App);
rtlTest(App);
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.clearAllTimers();
jest.useRealTimers();
});
it('single', () => {
// Sub page
const MyPage: React.FC = () => {
const { message } = App.useApp();
React.useEffect(() => {
message.success('Good!');
}, [message]);
return <div>Hello World</div>;
};
// Entry component
const MyApp: React.FC = () => (
<App>
<MyPage />
</App>
);
const { getByText, container } = render(<MyApp />);
expect(getByText('Hello World')).toBeTruthy();
expect(container.firstChild).toMatchSnapshot();
});
it('should work as message and notification config configured in app', async () => {
let consumedConfig: AppConfig | undefined;
const Consumer = () => {
const { message, notification } = App.useApp();
consumedConfig = React.useContext(AppConfigContext);
useEffect(() => {
message.success('Message 1');
message.success('Message 2');
notification.success({ message: 'Notification 1' });
notification.success({ message: 'Notification 2' });
notification.success({ message: 'Notification 3' });
}, [message, notification]);
return <div />;
};
const Wrapper = () => (
<App message={{ maxCount: 1 }} notification={{ maxCount: 2 }}>
<Consumer />
</App>
);
render(<Wrapper />);
await waitFakeTimer();
expect(consumedConfig?.message).toStrictEqual({ maxCount: 1 });
expect(consumedConfig?.notification).toStrictEqual({ maxCount: 2 });
expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(1);
expect(document.querySelectorAll('.ant-notification-notice')).toHaveLength(2);
});
it('should be a merged config configured in nested app', async () => {
let offsetConsumedConfig: AppConfig | undefined;
let maxCountConsumedConfig: AppConfig | undefined;
const OffsetConsumer = () => {
offsetConsumedConfig = React.useContext(AppConfigContext);
return <div />;
};
const MaxCountConsumer = () => {
maxCountConsumedConfig = React.useContext(AppConfigContext);
return <div />;
};
const Wrapper = () => (
<App message={{ maxCount: 1 }} notification={{ maxCount: 2 }}>
<App message={{ top: 32 }} notification={{ top: 96 }}>
<OffsetConsumer />
</App>
<MaxCountConsumer />
</App>
);
render(<Wrapper />);
expect(offsetConsumedConfig?.message).toStrictEqual({ maxCount: 1, top: 32 });
expect(offsetConsumedConfig?.notification).toStrictEqual({ maxCount: 2, top: 96 });
expect(maxCountConsumedConfig?.message).toStrictEqual({ maxCount: 1 });
expect(maxCountConsumedConfig?.notification).toStrictEqual({ maxCount: 2 });
});
it('should respect config from props in priority', async () => {
let config: AppConfig | undefined;
const Consumer = () => {
config = React.useContext(AppConfigContext);
return <div />;
};
const Wrapper = () => (
<App message={{ maxCount: 10, top: 20 }} notification={{ maxCount: 30, bottom: 40 }}>
<App message={{ maxCount: 11 }} notification={{ bottom: 41 }}>
<Consumer />
</App>
</App>
);
render(<Wrapper />);
expect(config?.message).toStrictEqual({ maxCount: 11, top: 20 });
expect(config?.notification).toStrictEqual({ maxCount: 30, bottom: 41 });
});
it('should respect notification placement config from props in priority', async () => {
let consumedConfig: AppConfig | undefined;
const Consumer = () => {
const { notification } = App.useApp();
consumedConfig = React.useContext(AppConfigContext);
useEffect(() => {
notification.success({ message: 'Notification 1' });
notification.success({ message: 'Notification 2' });
notification.success({ message: 'Notification 3' });
}, [notification]);
return <div />;
};
const config: NotificationConfig = {
placement: 'bottomLeft',
top: 100,
bottom: 50,
};
const Wrapper = () => (
<App notification={config}>
<Consumer />
</App>
);
render(<Wrapper />);
await waitFakeTimer();
expect(consumedConfig?.notification).toStrictEqual(config);
expect(document.querySelector('.ant-notification-topRight')).not.toBeInTheDocument();
expect(document.querySelector('.ant-notification-bottomLeft')).toHaveStyle({
top: '',
left: '0px',
bottom: '50px',
});
});
it('support className', () => {
const { container } = render(
<App className="test-class">
<div>test</div>
</App>,
);
expect(container.querySelector<HTMLDivElement>('.ant-app')).toHaveClass('test-class');
});
it('support style', () => {
const { container } = render(
<App style={{ color: 'blue' }}>
<div>test</div>
</App>,
);
expect(container.querySelector<HTMLDivElement>('.ant-app')).toHaveStyle('color: blue;');
});
// https://github.com/ant-design/ant-design/issues/41197#issuecomment-1465803061
describe('restIcon style', () => {
beforeEach(() => {
Array.from(document.querySelectorAll('style')).forEach((style) => {
style.parentNode?.removeChild(style);
});
});
it('should work by default', () => {
const { container } = render(
<App>
<SmileOutlined />
</App>,
);
expect(container.querySelector('.anticon')).toBeTruthy();
const dynamicStyles = Array.from(document.querySelectorAll('style[data-css-hash]'));
expect(
dynamicStyles.some((style) => {
const { innerHTML } = style;
return innerHTML.startsWith('.anticon');
}),
).toBeTruthy();
});
});
describe('component', () => {
it('replace', () => {
const { container } = render(
<App component="section">
<p />
</App>,
);
expect(container.querySelector('section.ant-app')).toBeTruthy();
});
it('to false', () => {
const warnSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
const { container } = render(
<App component={false}>
<p />
</App>,
);
expect(warnSpy).not.toHaveBeenCalled();
expect(container.querySelector('.ant-app')).toBeFalsy();
warnSpy.mockRestore();
});
});
});

Some files were not shown because too many files have changed in this diff Show More