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:
parent
5dfa57581a
commit
62796f136c
@ -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;
|
||||
}
|
||||
|
3
packages/client/src/index.less
Normal file
3
packages/client/src/index.less
Normal file
@ -0,0 +1,3 @@
|
||||
.ant-popover-inner-content {
|
||||
max-width: 500px;
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
import './index.less';
|
||||
export * from './components/router-config';
|
||||
export * from './components/admin-layout';
|
||||
export * from './components/auth-layout';
|
||||
|
9
packages/client/src/schemas/display/index.less
Normal file
9
packages/client/src/schemas/display/index.less
Normal 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;
|
||||
}
|
@ -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>;
|
||||
|
@ -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}>
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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';
|
||||
|
@ -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 (
|
||||
|
Loading…
Reference in New Issue
Block a user