Skip to content

feat: 新增ProFormSelect 组件 #246

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Sep 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .npmrc
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
shamefully-hoist=true
strict-peer-dependencies=false
strict-peer-dependencies=false
shared-workspace-lockfile=true
7 changes: 7 additions & 0 deletions packages/pro-field/env.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1,8 @@
/// <reference types="vite/client" />

// declare module '*.vue' {
// import { DefineComponent } from 'vue';
// // eslint-disable-next-line @typescript-eslint/ban-types
// const component: DefineComponent<{}, {}, any>;
// export default component;
// }
12 changes: 6 additions & 6 deletions packages/pro-field/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,26 @@
"dependencies": {
"@ant-design/icons-vue": "^6.1.0",
"@types/lodash-es": "^4.17.6",
"ant-design-vue": "^3.2.11",
"ant-design-vue": "^3.2.12",
"dayjs": "^1.11.5",
"vue": "^3.2.38",
"vue": "^3.2.39",
"vue-router": "^4.1.5"
},
"devDependencies": {
"@ant-design-vue/pro-utils": "workspace:^0.0.0",
"@shared/vite-plugin-less-copy": "workspace:^0.0.0",
"@rollup/plugin-typescript": "^8.4.0",
"@rushstack/eslint-patch": "^1.1.4",
"@rollup/plugin-typescript": "^8.5.0",
"@rushstack/eslint-patch": "^1.2.0",
"@types/jsdom": "^16.2.15",
"@types/node": "^16.11.56",
"@types/node": "^16.11.59",
"@vitejs/plugin-vue": "^2.3.4",
"@vitejs/plugin-vue-jsx": "^1.3.10",
"@vue/eslint-config-prettier": "^7.0.0",
"@vue/eslint-config-typescript": "^10.0.0",
"@vue/test-utils": "^2.0.2",
"@vue/tsconfig": "^0.1.3",
"consola": "^2.15.3",
"eslint": "^8.23.0",
"eslint": "^8.23.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^8.7.1",
"jsdom": "^19.0.0",
Expand Down
53 changes: 53 additions & 0 deletions packages/pro-field/src/components/Password/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { ref, defineComponent, type App, DefineComponent, Plugin } from 'vue';
import { Space, InputPassword } from 'ant-design-vue';
import { EyeInvisibleOutlined, EyeOutlined } from '@ant-design/icons-vue';
import { passwordTextProps, type PasswordTextProps } from './types';

const FieldPassword = defineComponent({
name: 'FieldPassword',
inheritAttrs: false,
props: passwordTextProps,
slots: ['render', 'renderFormItem'],
setup(props, { slots }) {
return () => {
const { mode, text, fieldProps } = props;
const render = props.render ?? slots.render;
const renderFormItem = props.renderFormItem ?? slots?.renderFormItem;

const visible = ref(props.visible);

if (mode === 'read') {
let dom = <>-</>;
if (text) {
dom = (
<Space>
<span>{visible.value ? text : '* * * * *'}</span>
<a onClick={() => (visible.value = !visible.value)}>
{visible.value ? <EyeOutlined /> : <EyeInvisibleOutlined />}
</a>
</Space>
);
}
if (render) {
return render(text, { mode, fieldProps }, dom);
}
return dom;
}
if (mode === 'edit' || mode === 'update') {
const renderDom = <InputPassword allowClear {...props.fieldProps} />;
if (renderFormItem) {
return renderFormItem(text, { mode, fieldProps }, renderDom);
}
return renderDom;
}
return null;
};
},
});

FieldPassword.install = (app: App) => {
app.component(FieldPassword.name, FieldPassword);
return app;
};

export default FieldPassword as DefineComponent<PasswordTextProps> & Plugin;
15 changes: 15 additions & 0 deletions packages/pro-field/src/components/Password/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { PropType, ExtractPropTypes } from 'vue';
import { proFieldFC } from '../typings';

export const passwordTextProps = {
...proFieldFC,
/**
* 是否显示密码
*/
visible: {
type: Boolean as PropType<boolean>,
default: false,
},
};

export type PasswordTextProps = Partial<ExtractPropTypes<typeof passwordTextProps>>;
60 changes: 60 additions & 0 deletions packages/pro-field/src/components/Select/SearchSelect/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { defineComponent } from 'vue';
import { Select } from 'ant-design-vue';
import { searchSelectProps } from './types';
import { getSlot } from '@ant-design-vue/pro-utils';

export const slots = [
'notFoundContent',
'suffixIcon',
'itemIcon',
'removeIcon',
'clearIcon',
'dropdownRender',
'option',
'placeholder',
'tagRender',
'maxTagPlaceholder',
'optionLabel',
];

const SearchSelect = defineComponent({
props: searchSelectProps,
slots,
setup(props, { slots }) {
const notFoundContent = getSlot(slots, props, 'notFoundContent');
const suffixIcon = getSlot(slots, props, 'suffixIcon');
const itemIcon = getSlot(slots, props, 'itemIcon');
const removeIcon = getSlot(slots, props, 'removeIcon');
const clearIcon = getSlot(slots, props, 'clearIcon');
const dropdownRender = getSlot(slots, props, 'dropdownRender');
const option = getSlot(slots, props, 'option');
const placeholder = getSlot(slots, props, 'placeholder');
const tagRender = getSlot(slots, props, 'tagRender');
const maxTagPlaceholder = getSlot(slots, props, 'maxTagPlaceholder');
const optionLabel = getSlot(slots, props, 'optionLabel');

return () => {
return (
<Select
{...props}
v-slots={{
notFoundContent,
suffixIcon,
itemIcon,
removeIcon,
clearIcon,
dropdownRender,
option,
placeholder,
tagRender,
maxTagPlaceholder,
optionLabel,
}}
allowClear
/>
);
};
},
});

export default SearchSelect;
14 changes: 14 additions & 0 deletions packages/pro-field/src/components/Select/SearchSelect/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { ExtractPropTypes, PropType } from 'vue';
import { selectProps, type DefaultOptionType } from 'ant-design-vue/es/select';
import type { VueNode } from '@ant-design-vue/pro-utils';

const omitSelectProps = selectProps();

export const searchSelectProps = {
...omitSelectProps,
option: {
type: Function as PropType<(props: DefaultOptionType) => VueNode>,
},
};

export type SearchSelectProps = Partial<ExtractPropTypes<typeof searchSelectProps>>;
55 changes: 55 additions & 0 deletions packages/pro-field/src/components/Select/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { defineComponent, type App, DefineComponent, Plugin, PropType, ExtractPropTypes } from 'vue';
import type { SelectProps } from 'ant-design-vue';
import SearchSelect from './SearchSelect';
import type { SearchSelectProps } from './SearchSelect/types';
import { proFieldFC } from '../typings';

export const fieldSelectProps = {
...proFieldFC,
fieldProps: {
type: Object as PropType<SelectProps & { option: SearchSelectProps['option'] }>,
},
};
export type FieldSelectProps = Partial<ExtractPropTypes<typeof fieldSelectProps>>;

const FieldSelect = defineComponent({
props: fieldSelectProps,
setup(props) {
const children = () => {
if (props.mode === 'read') {
const dom = <>{props.text}</>;
if (props.render) {
return props.render(props.text, { mode: props.mode, fieldProps: props.fieldProps }, dom) || null;
}
return dom;
}
if (props.mode === 'edit' || props.mode === 'update') {
const renderDom = () => {
return (
<SearchSelect
style={{
minWidth: 100,
}}
{...props.fieldProps}
/>
);
};
const dom = renderDom();
if (props.renderFormItem) {
return props.renderFormItem(props.text, { mode: props.mode, fieldProps: props.fieldProps }, dom) || null;
}
return dom;
}
return null;
};

return () => children();
},
});

FieldSelect.install = (app: App) => {
app.component(FieldSelect.name, FieldSelect);
return app;
};

export default FieldSelect as DefineComponent<FieldSelectProps> & Plugin;
41 changes: 13 additions & 28 deletions packages/pro-field/src/components/Text/index.tsx
Original file line number Diff line number Diff line change
@@ -1,52 +1,37 @@
import { defineComponent, type App, type Plugin, type DefineComponent, ref } from 'vue';
import { defineComponent, type App, type Plugin, type DefineComponent } from 'vue';
import { Input } from 'ant-design-vue';
import { textFieldPorps, type TextFieldPorps } from './types';

import 'ant-design-vue/es/input/style/index.less';

type NameType = string | number;

const FieldText = defineComponent({
name: 'FieldText',
inheritAttrs: false,
props: textFieldPorps,
slots: ['render', 'renderFormItem'],
setup(props, { slots }) {
const render = props.render ?? slots?.render;
const renderFormItem = props.renderFormItem ?? slots?.renderFormItem;
const inputValue = ref((props.formItemProps?.model || {})[props.formItemProps?.name as NameType]);
return () => {
if (props.mode === 'read') {
const { type, mode, text, emptyText, fieldProps } = props;
const render = props.render ?? slots?.render;
const renderFormItem = props.renderFormItem ?? slots?.renderFormItem;
if (mode === 'read') {
const dom = (
<>
{props.fieldProps?.prefix}
{props.text ?? (props.emptyText || '-')}
{props.fieldProps?.suffix}
{fieldProps?.prefix}
{text ?? (emptyText || '-')}
{fieldProps?.suffix}
</>
);
if (render) {
return render(props.text, { mode: props.mode, fieldProps: props.fieldProps }, dom) ?? props.emptyText;
return render(text, { mode, fieldProps }, dom) ?? emptyText;
}
return dom;
}
if (props.mode === 'edit' || props.mode === 'update') {
const dom = (
<Input
type={props.type}
allowClear
{...props.fieldProps}
value={inputValue.value}
onChange={(e) => {
const value = e.target.value;
inputValue.value = value;
}}
/>
);

if (mode === 'edit' || mode === 'update') {
const renderDom = <Input type={type} allowClear {...fieldProps} />;
if (renderFormItem) {
return renderFormItem(props.text, { mode: props.mode, fieldProps: props.fieldProps }, dom);
return renderFormItem(text, { mode, fieldProps }, renderDom);
}
return dom;
return renderDom;
}
return null;
};
Expand Down
13 changes: 6 additions & 7 deletions packages/pro-field/src/components/typings.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import type { InputProps } from 'ant-design-vue/es/input/inputProps';
import type { PropType, ExtractPropTypes } from 'vue';
import type { ProFieldFCMode, VueNode } from '@ant-design-vue/pro-utils';
import type { FormItemProps, FormProps } from 'ant-design-vue';

export type NameType = string | number;

// BaseProFieldProps
export const baseProFieldFC = {
/** 值的类型 */
text: {
type: String as PropType<VueNode>,
type: [String, Array] as PropType<VueNode>,
},
fieldProps: {
type: Object as PropType<InputProps>,
type: Object as PropType<any>,
},
/** 模式类型 */
mode: {
Expand Down Expand Up @@ -41,12 +42,10 @@ export const baseProFieldFC = {

export const proRenderFieldPropsType = {
render: {
type: Function as PropType<
(text: any, props: Omit<ProFieldFCRenderProps, 'value' | 'onChange'>, dom: VueNode) => VueNode
>,
type: Function as PropType<(text: VueNode, props: ProFieldFCRenderProps, dom: VueNode) => VueNode>,
},
renderFormItem: {
type: Function as PropType<(text: any, props: ProFieldFCRenderProps, dom: VueNode) => VueNode>,
type: Function as PropType<(text: VueNode, props: ProFieldFCRenderProps, dom: VueNode) => VueNode>,
},
};

Expand Down
Loading