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