From 62796f136c2eea5459b8fa075057baacf5e7198a Mon Sep 17 00:00:00 2001 From: SemmyWong <67748948+semmywong@users.noreply.github.com> Date: Sat, 4 Dec 2021 15:36:59 +0800 Subject: [PATCH] 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 --- .../src/components/schema-renderer/index.tsx | 1 - packages/client/src/index.less | 3 + packages/client/src/index.tsx | 1 + .../client/src/schemas/display/index.less | 9 ++ packages/client/src/schemas/display/index.tsx | 128 +++++++----------- .../client/src/schemas/filter/FilterItem.tsx | 29 +--- .../client/src/schemas/table/TableCell.tsx | 4 +- .../client/src/schemas/table/TableMain.tsx | 2 +- .../schemas/table/hooks/useTableColumns.tsx | 5 + 9 files changed, 77 insertions(+), 105 deletions(-) create mode 100644 packages/client/src/index.less create mode 100644 packages/client/src/schemas/display/index.less diff --git a/packages/client/src/components/schema-renderer/index.tsx b/packages/client/src/components/schema-renderer/index.tsx index 8d3cd42c8..c42b47382 100644 --- a/packages/client/src/components/schema-renderer/index.tsx +++ b/packages/client/src/components/schema-renderer/index.tsx @@ -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; } diff --git a/packages/client/src/index.less b/packages/client/src/index.less new file mode 100644 index 000000000..1bf113cc4 --- /dev/null +++ b/packages/client/src/index.less @@ -0,0 +1,3 @@ +.ant-popover-inner-content { + max-width: 500px; +} diff --git a/packages/client/src/index.tsx b/packages/client/src/index.tsx index 1b48a9301..6adbb1431 100644 --- a/packages/client/src/index.tsx +++ b/packages/client/src/index.tsx @@ -1,3 +1,4 @@ +import './index.less'; export * from './components/router-config'; export * from './components/admin-layout'; export * from './components/auth-layout'; diff --git a/packages/client/src/schemas/display/index.less b/packages/client/src/schemas/display/index.less new file mode 100644 index 000000000..324f8b8d7 --- /dev/null +++ b/packages/client/src/schemas/display/index.less @@ -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; +} diff --git a/packages/client/src/schemas/display/index.tsx b/packages/client/src/schemas/display/index.tsx index 8c0ce52fe..56630f1ab 100644 --- a/packages/client/src/schemas/display/index.tsx +++ b/packages/client/src/schemas/display/index.tsx @@ -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(''); @@ -31,14 +26,27 @@ const usePlaceholder = (value?: any) => { return isValid(value) && value !== '' ? value : placeholder; }; -const Input: React.FC = (props) => { +const Input: React.FC = (props) => { const prefixCls = usePrefixCls('description-input', props); + const domRef = React.useRef(null); const compile = useCompile(); + const [ellipsis, setEllipsis] = useState(false); + const content = compile(usePlaceholder(props.value)); + const ellipsisContent = ( + +
{content}
+
+ ); + useEffect(() => { + if (props.ellipsis && domRef.current?.scrollWidth > domRef.current?.clientWidth) { + setEllipsis(true); + } + }, []); return (
{props.addonBefore} {props.prefix} - {compile(usePlaceholder(props.value))} +
{ellipsis ? ellipsisContent : content}
{props.suffix} {props.addonAfter}
@@ -79,34 +87,32 @@ const InputNumber: React.FC = (props) => { const TextArea: React.FC = (props) => { const prefixCls = usePrefixCls('description-textarea', props); - const ellipsis = props.ellipsis === true ? {} : props.ellipsis; - const content = props.ellipsis ? ( -
- -
- {usePlaceholder(props.text || props.value)} -
-
-
- ) : ( - usePlaceholder(props.value) + const domRef = React.useRef(null); + const [ellipsis, setEllipsis] = useState(false); + const ellipsisProp = props.ellipsis === true ? {} : props.ellipsis; + const content = usePlaceholder(props.value); + const ellipsisContent = ( + +
+ {usePlaceholder(props.text || props.value)} +
+
); + useEffect(() => { + if (props.ellipsis && domRef.current?.scrollWidth > domRef.current?.clientWidth) { + setEllipsis(true); + } + }, []); return (
{props.addonBefore} {props.prefix} - {content} +
{ellipsis ? ellipsisContent : content}
{props.suffix} {props.addonAfter}
@@ -116,11 +122,7 @@ const TextArea: React.FC = (props) => { const Select: React.FC> = observer((props) => { const field = useField(); 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> = 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> = observer((props) => { const selected = getSelected(); if (!selected.length) return {placeholder}; 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 {text || placeholder}; }); }; @@ -160,11 +159,7 @@ const Select: React.FC> = observer((props) => { const ObjectSelect: React.FC> = observer((props) => { const field = useField(); 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> = 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> = observer((props) => { const selected = getSelected(); if (!selected.length) return {placeholder}; 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 {text || placeholder}; }); }; @@ -205,20 +197,14 @@ const TreeSelect: React.FC> = observer((props) => { const field = useField(); 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> = observer((props) => { const selected = getSelected(); if (!selected?.length) return {placeholder}; return selected.map(({ value, label }, key) => { - return ( - - {findLabel(value, dataSource) || label || placeholder} - - ); + return {findLabel(value, dataSource) || label || placeholder}; }); }; return ( @@ -263,11 +245,7 @@ const Cascader: React.FC = observer((props) => { const field = useField(); 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 = (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
{getLabels()}
; diff --git a/packages/client/src/schemas/filter/FilterItem.tsx b/packages/client/src/schemas/filter/FilterItem.tsx index bf0dc894f..9f43eed68 100644 --- a/packages/client/src/schemas/filter/FilterItem.tsx +++ b/packages/client/src/schemas/filter/FilterItem.tsx @@ -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 ( diff --git a/packages/client/src/schemas/table/TableCell.tsx b/packages/client/src/schemas/table/TableCell.tsx index ed47ab34b..fcdb8bbca 100644 --- a/packages/client/src/schemas/table/TableCell.tsx +++ b/packages/client/src/schemas/table/TableCell.tsx @@ -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 (
{ feedbackLayout: 'popover', }, 'x-decorator': 'FormilyFormItem', - 'x-component-props': componentProps, + 'x-component-props': { ...componentProps }, properties: { ...schema?.properties, }, diff --git a/packages/client/src/schemas/table/TableMain.tsx b/packages/client/src/schemas/table/TableMain.tsx index 589089971..4a2948225 100644 --- a/packages/client/src/schemas/table/TableMain.tsx +++ b/packages/client/src/schemas/table/TableMain.tsx @@ -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'; diff --git a/packages/client/src/schemas/table/hooks/useTableColumns.tsx b/packages/client/src/schemas/table/hooks/useTableColumns.tsx index 6067afb9c..5101bb623 100644 --- a/packages/client/src/schemas/table/hooks/useTableColumns.tsx +++ b/packages/client/src/schemas/table/hooks/useTableColumns.tsx @@ -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 (