refactor: table cell text overflow that show ellipsis (#125)

* fix: table column text overflow auto hidden

* refactor: table column text overflow auto hidden

* refactor: table column text overflow auto hidden

* fix: popover text overflow handle

Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
SemmyWong 2021-12-04 15:36:59 +08:00 committed by GitHub
parent 5dfa57581a
commit 62796f136c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 77 additions and 105 deletions

View File

@ -333,7 +333,6 @@ export function useDesignable(path?: any) {
// console.log('useDesignable', { schema, schemaPath, currentSchema });
const options = useContext(SchemaOptionsContext);
let DesignableBar = get(options.components, currentSchema['x-designable-bar']);
debugger;
if (!designable) {
DesignableBar = () => null;
}

View File

@ -0,0 +1,3 @@
.ant-popover-inner-content {
max-width: 500px;
}

View File

@ -1,3 +1,4 @@
import './index.less';
export * from './components/router-config';
export * from './components/admin-layout';
export * from './components/auth-layout';

View File

@ -0,0 +1,9 @@
.input-ellipsis {
display: inline-block;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
width: 100%;
vertical-align: middle;
margin-right: 10;
}

View File

@ -1,4 +1,4 @@
import React, { createContext, useContext } from 'react';
import React, { createContext, useContext, useEffect, useState } from 'react';
import { isArr, isValid } from '@formily/shared';
import { observer, useField } from '@formily/react';
import { InputProps } from 'antd/lib/input';
@ -6,21 +6,16 @@ import { InputNumberProps } from 'antd/lib/input-number';
import { SelectProps } from 'antd/lib/select';
import { TreeSelectProps } from 'antd/lib/tree-select';
import { CascaderProps } from 'antd/lib/cascader';
import {
DatePickerProps,
RangePickerProps as DateRangePickerProps,
} from 'antd/lib/date-picker';
import { DatePickerProps, RangePickerProps as DateRangePickerProps } from 'antd/lib/date-picker';
import { TimePickerProps, TimeRangePickerProps } from 'antd/lib/time-picker';
import { Tag, Space, Popover } from 'antd';
import cls from 'classnames';
import {
formatMomentValue,
usePrefixCls,
} from '@formily/antd/esm/__builtins__';
import { formatMomentValue, usePrefixCls } from '@formily/antd/esm/__builtins__';
import { FullscreenOutlined } from '@ant-design/icons';
import moment from 'moment';
import { useCompile } from '../../hooks/useCompile';
import { Field } from '@formily/core';
import './index.less';
const PlaceholderContext = createContext<string>('');
@ -31,14 +26,27 @@ const usePlaceholder = (value?: any) => {
return isValid(value) && value !== '' ? value : placeholder;
};
const Input: React.FC<InputProps> = (props) => {
const Input: React.FC<InputProps & { ellipsis: any }> = (props) => {
const prefixCls = usePrefixCls('description-input', props);
const domRef = React.useRef<HTMLInputElement>(null);
const compile = useCompile();
const [ellipsis, setEllipsis] = useState(false);
const content = compile(usePlaceholder(props.value));
const ellipsisContent = (
<Popover content={usePlaceholder(props.value)} style={{ width: 100 }}>
<div className={'input-ellipsis'}>{content}</div>
</Popover>
);
useEffect(() => {
if (props.ellipsis && domRef.current?.scrollWidth > domRef.current?.clientWidth) {
setEllipsis(true);
}
}, []);
return (
<div className={cls(prefixCls, props.className)} style={props.style}>
{props.addonBefore}
{props.prefix}
{compile(usePlaceholder(props.value))}
<div ref={domRef}>{ellipsis ? ellipsisContent : content}</div>
{props.suffix}
{props.addonAfter}
</div>
@ -79,34 +87,32 @@ const InputNumber: React.FC<InputProps & InputNumberProps> = (props) => {
const TextArea: React.FC<any> = (props) => {
const prefixCls = usePrefixCls('description-textarea', props);
const ellipsis = props.ellipsis === true ? {} : props.ellipsis;
const content = props.ellipsis ? (
<div>
<Popover content={usePlaceholder(props.value)}>
<div
style={{
display: 'inline-block',
textOverflow: 'ellipsis',
overflow: 'hidden',
whiteSpace: 'nowrap',
width: 100,
verticalAlign: 'middle',
marginRight: 10,
...ellipsis,
}}
>
{usePlaceholder(props.text || props.value)}
</div>
</Popover>
</div>
) : (
usePlaceholder(props.value)
const domRef = React.useRef<HTMLInputElement>(null);
const [ellipsis, setEllipsis] = useState(false);
const ellipsisProp = props.ellipsis === true ? {} : props.ellipsis;
const content = usePlaceholder(props.value);
const ellipsisContent = (
<Popover content={usePlaceholder(props.value)}>
<div
className={'input-ellipsis'}
style={{
...ellipsisProp,
}}
>
{usePlaceholder(props.text || props.value)}
</div>
</Popover>
);
useEffect(() => {
if (props.ellipsis && domRef.current?.scrollWidth > domRef.current?.clientWidth) {
setEllipsis(true);
}
}, []);
return (
<div className={cls(prefixCls, props.className)} style={props.style}>
{props.addonBefore}
{props.prefix}
{content}
<div ref={domRef}>{ellipsis ? ellipsisContent : content}</div>
{props.suffix}
{props.addonAfter}
</div>
@ -116,11 +122,7 @@ const TextArea: React.FC<any> = (props) => {
const Select: React.FC<SelectProps<any>> = observer((props) => {
const field = useField<Field>();
const prefixCls = usePrefixCls('description-select', props);
const dataSource: any[] = field?.dataSource?.length
? field.dataSource
: props?.options?.length
? props.options
: [];
const dataSource: any[] = field?.dataSource?.length ? field.dataSource : props?.options?.length ? props.options : [];
const placeholder = usePlaceholder();
const getSelected = () => {
const value = props.value;
@ -128,9 +130,7 @@ const Select: React.FC<SelectProps<any>> = observer((props) => {
if (props.labelInValue) {
return isArr(value) ? value : [];
} else {
return isArr(value)
? value.map((val) => ({ label: val, value: val }))
: [];
return isArr(value) ? value.map((val) => ({ label: val, value: val })) : [];
}
} else {
if (props.labelInValue) {
@ -145,8 +145,7 @@ const Select: React.FC<SelectProps<any>> = observer((props) => {
const selected = getSelected();
if (!selected.length) return <Tag>{placeholder}</Tag>;
return selected.map(({ value, label }, key) => {
const text =
dataSource?.find((item) => item.value == value)?.label || label;
const text = dataSource?.find((item) => item.value == value)?.label || label;
return <Tag key={key}>{text || placeholder}</Tag>;
});
};
@ -160,11 +159,7 @@ const Select: React.FC<SelectProps<any>> = observer((props) => {
const ObjectSelect: React.FC<SelectProps<any>> = observer((props) => {
const field = useField<Field>();
const prefixCls = usePrefixCls('description-select', props);
const dataSource: any[] = field?.dataSource?.length
? field.dataSource
: props?.options?.length
? props.options
: [];
const dataSource: any[] = field?.dataSource?.length ? field.dataSource : props?.options?.length ? props.options : [];
const placeholder = usePlaceholder();
const getSelected = () => {
const value = props.value;
@ -172,9 +167,7 @@ const ObjectSelect: React.FC<SelectProps<any>> = observer((props) => {
if (props.labelInValue) {
return isArr(value) ? value : [];
} else {
return isArr(value)
? value.map((val) => ({ label: val, value: val }))
: [];
return isArr(value) ? value.map((val) => ({ label: val, value: val })) : [];
}
} else {
if (props.labelInValue) {
@ -189,8 +182,7 @@ const ObjectSelect: React.FC<SelectProps<any>> = observer((props) => {
const selected = getSelected();
if (!selected.length) return <Tag>{placeholder}</Tag>;
return selected.map(({ value, label }, key) => {
const text =
dataSource?.find((item) => item.value == value)?.label || label;
const text = dataSource?.find((item) => item.value == value)?.label || label;
return <Tag key={key}>{text || placeholder}</Tag>;
});
};
@ -205,20 +197,14 @@ const TreeSelect: React.FC<TreeSelectProps<any>> = observer((props) => {
const field = useField<Field>();
const placeholder = usePlaceholder();
const prefixCls = usePrefixCls('description-tree-select', props);
const dataSource = field?.dataSource?.length
? field.dataSource
: props?.options?.length
? props.options
: [];
const dataSource = field?.dataSource?.length ? field.dataSource : props?.options?.length ? props.options : [];
const getSelected = () => {
const value = props.value;
if (props.multiple) {
if (props.labelInValue) {
return isArr(value) ? value : [];
} else {
return isArr(value)
? value.map((val) => ({ label: val, value: val }))
: [];
return isArr(value) ? value.map((val) => ({ label: val, value: val })) : [];
}
} else {
if (props.labelInValue) {
@ -245,11 +231,7 @@ const TreeSelect: React.FC<TreeSelectProps<any>> = observer((props) => {
const selected = getSelected();
if (!selected?.length) return <Tag>{placeholder}</Tag>;
return selected.map(({ value, label }, key) => {
return (
<Tag key={key}>
{findLabel(value, dataSource) || label || placeholder}
</Tag>
);
return <Tag key={key}>{findLabel(value, dataSource) || label || placeholder}</Tag>;
});
};
return (
@ -263,11 +245,7 @@ const Cascader: React.FC<CascaderProps> = observer((props) => {
const field = useField<Field>();
const placeholder = usePlaceholder();
const prefixCls = usePrefixCls('description-cascader', props);
const dataSource: any[] = field?.dataSource?.length
? field.dataSource
: props?.options?.length
? props.options
: [];
const dataSource: any[] = field?.dataSource?.length ? field.dataSource : props?.options?.length ? props.options : [];
const getSelected = () => {
return isArr(props.value) ? props.value : [];
};
@ -316,11 +294,7 @@ const DatePicker: React.FC<DatePickerProps> = (props: any) => {
};
const getLabels = () => {
const d = moment(props.value);
const labels = formatMomentValue(
d.isValid() ? d : null,
getDefaultFormat(),
placeholder,
);
const labels = formatMomentValue(d.isValid() ? d : null, getDefaultFormat(), placeholder);
return isArr(labels) ? labels.join('~') : labels;
};
return <div className={cls(prefixCls, props.className)}>{getLabels()}</div>;

View File

@ -1,12 +1,6 @@
import React, { useContext, useMemo, useState } from 'react';
import { ISchema, SchemaField } from '..';
import {
createForm,
onFieldChange,
onFieldReact,
onFormValuesChange,
onFormReset,
} from '@formily/core';
import { createForm, onFieldChange, onFieldReact, onFormValuesChange, onFormReset } from '@formily/core';
import {
FormProvider,
FormConsumer,
@ -19,14 +13,7 @@ import {
} from '@formily/react';
import { Field } from '@formily/core/esm/models/Field';
import { Form } from '@formily/core/esm/models/Form';
import {
Input,
FormItem,
FormLayout,
FormButtonGroup,
Submit,
Space,
} from '@formily/antd';
import { Input, FormItem, FormLayout, FormButtonGroup, Submit, Space } from '@formily/antd';
import { CloseCircleOutlined } from '@ant-design/icons';
import { get } from 'lodash';
import { isValid, uid } from '@formily/shared';
@ -75,9 +62,7 @@ export const FilterItem = (props) => {
}
const operationValue = Object.keys(nested).shift();
console.log('toValues', { operationValue });
const operation = operations.find(
(operation) => operation.value === operationValue,
);
const operation = operations.find((operation) => operation.value === operationValue);
console.log('toValues', { operation });
if (!operation) {
return {
@ -121,8 +106,7 @@ export const FilterItem = (props) => {
effects: (form) => {
onFieldChange('column', (field: Field, form: Form) => {
const column = (field.value || {}) as ISchema;
const operations =
column?.['x-component-props']?.['operations'] || [];
const operations = column?.['x-component-props']?.['operations'] || [];
field.query('operation').take((f: Field) => {
f.setDataSource(operations);
f.value = get(operations, [0]);
@ -149,7 +133,6 @@ export const FilterItem = (props) => {
return;
}
const fieldName = Object.keys(column.properties).shift();
debugger;
if (operation?.noValue) {
onChange({
[fieldName]: {
@ -174,9 +157,7 @@ export const FilterItem = (props) => {
[],
);
const columnEnum: any = [...columns.values()].map((column) =>
column.toJSON(),
);
const columnEnum: any = [...columns.values()].map((column) => column.toJSON());
return (
<FormProvider form={form}>

View File

@ -20,7 +20,7 @@ export const TableCell = observer((props: any) => {
const componentProps = merge(uiSchema?.['x-component-props'] || {}, schema?.['x-component-props'] || {}, {
arrayMerge: (t, s) => s,
});
console.log('Table.Cell', collectionField?.interface, componentProps);
console.log('Table.Cell', collectionField?.interface, componentProps, uiSchema);
return (
<div className={`field-interface-${collectionField?.interface}`}>
<RecursionField
@ -38,7 +38,7 @@ export const TableCell = observer((props: any) => {
feedbackLayout: 'popover',
},
'x-decorator': 'FormilyFormItem',
'x-component-props': componentProps,
'x-component-props': { ...componentProps },
properties: {
...schema?.properties,
},

View File

@ -1,5 +1,5 @@
import { DndContext } from '@dnd-kit/core';
import React, { useState } from 'react';
import { DndContext } from '@dnd-kit/core';
import { Table as AntdTable } from 'antd';
import { findIndex } from 'lodash';
import cls from 'classnames';

View File

@ -22,6 +22,10 @@ export const useTableColumns = () => {
const columnSchemas = schema.reduceProperties((columns, current) => {
if (isColumn(current)) {
if (!current['x-component-props']) {
current['x-component-props'] = {};
}
current['x-component-props']['ellipsis'] = true;
if (current['x-hidden']) {
return columns;
}
@ -45,6 +49,7 @@ export const useTableColumns = () => {
),
dataIndex: column.name,
...columnProps,
ellipsis: true,
render: (_: any, record: any) => {
const index = findIndex(field.value, (item) => item[rowKey] === record[rowKey]);
return (