diff --git a/packages/amis-ui/scss/components/form/_selection.scss b/packages/amis-ui/scss/components/form/_selection.scss index 6541f0d86..c710face5 100644 --- a/packages/amis-ui/scss/components/form/_selection.scss +++ b/packages/amis-ui/scss/components/form/_selection.scss @@ -270,11 +270,13 @@ display: flex; flex-direction: row; min-height: 100%; + flex-wrap: wrap; &-col { position: relative; flex-grow: 1; min-width: 150px; + width: 0; } &-col:not(:last-child) { @@ -287,6 +289,10 @@ color: var(--text--muted-color); } + &-checkAll { + width: 100%; + } + &-item { display: flex; // height: var(--Form-input-height); @@ -326,6 +332,9 @@ &-itemLabel { flex-grow: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; span { margin-left: px2rem(10px); diff --git a/packages/amis-ui/src/components/AssociatedSelection.tsx b/packages/amis-ui/src/components/AssociatedSelection.tsx index 574c0f864..181d3bb1f 100644 --- a/packages/amis-ui/src/components/AssociatedSelection.tsx +++ b/packages/amis-ui/src/components/AssociatedSelection.tsx @@ -126,7 +126,9 @@ export class AssociatedSelection extends BaseSelection< labelField, virtualThreshold, itemHeight, - loadingConfig + loadingConfig, + checkAll, + checkAllLabel } = this.props; const selectdOption = BaseSelection.resolveSelected( @@ -214,6 +216,8 @@ export class AssociatedSelection extends BaseSelection< virtualThreshold={virtualThreshold} itemHeight={itemHeight} loadingConfig={loadingConfig} + checkAllLabel={checkAllLabel} + checkAll={checkAll} /> ) : rightMode === 'chained' ? ( ) : ( ) ) : ( diff --git a/packages/amis-ui/src/components/ChainedSelection.tsx b/packages/amis-ui/src/components/ChainedSelection.tsx index 5d129ed32..307defc9c 100644 --- a/packages/amis-ui/src/components/ChainedSelection.tsx +++ b/packages/amis-ui/src/components/ChainedSelection.tsx @@ -166,6 +166,54 @@ export class ChainedSelection extends BaseSelection< return this.renderItem(option, index, depth, id, styles); } + renderCheckAll() { + const { + multiple, + checkAll, + checkAllLabel, + classnames: cx, + translate: __, + labelClassName, + itemClassName + } = this.props; + + if (!multiple || !checkAll) { + return null; + } + const availableOptions = this.getAvailableOptions(); + + const valueArray = this.valueArray; + + const checkedAll = availableOptions.every( + option => valueArray.indexOf(option) > -1 + ); + const checkedPartial = availableOptions.some( + option => valueArray.indexOf(option) > -1 + ); + + return ( +
+ + +
+ {__(checkAllLabel)} +
+
+ ); + } + render() { const { value, @@ -330,7 +378,10 @@ export class ChainedSelection extends BaseSelection< return (
{body && body.length ? ( - body + <> + {this.renderCheckAll()} + {body} + ) : (
{__(placeholder)} diff --git a/packages/amis-ui/src/components/GroupedSelection.tsx b/packages/amis-ui/src/components/GroupedSelection.tsx index a8e61be6f..636574547 100644 --- a/packages/amis-ui/src/components/GroupedSelection.tsx +++ b/packages/amis-ui/src/components/GroupedSelection.tsx @@ -168,6 +168,50 @@ export class GroupedSelection extends BaseSelection { ); } + renderCheckAll() { + const { + multiple, + checkAll, + checkAllLabel, + classnames: cx, + translate: __, + labelClassName, + itemClassName + } = this.props; + + if (!multiple || !checkAll) { + return null; + } + const availableOptions = this.getAvailableOptions(); + + const valueArray = this.valueArray; + + const checkedAll = availableOptions.every( + option => valueArray.indexOf(option) > -1 + ); + const checkedPartial = availableOptions.some( + option => valueArray.indexOf(option) > -1 + ); + + return ( +
+ + +
+ {__(checkAllLabel)} +
+
+ ); + } + render() { const { value, @@ -206,6 +250,7 @@ export class GroupedSelection extends BaseSelection { height={height} itemCount={flattendOptions.length} itemSize={itemHeight} + prefix={this.renderCheckAll()} renderItem={({ index, style @@ -227,7 +272,10 @@ export class GroupedSelection extends BaseSelection { )} ) : ( - options.map((option, key) => this.renderOption(option, key)) + <> + {this.renderCheckAll()} + {options.map((option, key) => this.renderOption(option, key))} + ); } diff --git a/packages/amis-ui/src/components/Selection.tsx b/packages/amis-ui/src/components/Selection.tsx index a425fe610..b6f11e0f7 100644 --- a/packages/amis-ui/src/components/Selection.tsx +++ b/packages/amis-ui/src/components/Selection.tsx @@ -14,7 +14,8 @@ import { themeable, ThemeProps, autobind, - findTree + findTree, + flattenTree } from 'amis-core'; import Checkbox from './Checkbox'; import {Option, Options} from './Select'; @@ -41,6 +42,8 @@ export interface BaseSelectionProps extends ThemeProps, LocaleProps { disabled?: boolean; onClick?: (e: React.MouseEvent) => void; placeholderRender?: (props: any) => JSX.Element | null; + checkAll?: boolean; + checkAllLabel?: string; } export interface ItemRenderStates { @@ -153,13 +156,22 @@ export class BaseSelection< onChange && onChange(multiple ? newValue : newValue[0]); } + getAvailableOptions() { + const {options} = this.props; + const flattendOptions = flattenTree(options, item => + item.children ? null : item + ).filter(a => a && !a.disabled); + + return flattendOptions as Option[]; + } + @autobind toggleAll() { const {value, onChange, option2value, options} = this.props; let valueArray: Array