Skip to content

Commit 2bd4b3a

Browse files
committed
chore: api feedback
1 parent b45d46f commit 2bd4b3a

File tree

5 files changed

+69
-40
lines changed

5 files changed

+69
-40
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
/src/cdk-experimental/** @jelbourn
8888
/src/cdk-experimental/dialog/** @jelbourn @josephperrott @crisbeto
8989
/src/cdk-experimental/scrolling/** @mmalerba
90+
/src/cdk-experimental/selection/** @amcdnl
9091

9192
# Docs examples & guides
9293
/guides/** @amcdnl @jelbourn

src/cdk-experimental/selection/selection-toggle.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import {takeUntil} from 'rxjs/operators';
2424
'(click)': '_onToggle()',
2525
'(contextmenu)': '_onToggle()',
2626
'(keydown.enter)': '_onToggle()',
27+
'(keydown.shift)': '_onShift()',
28+
'(blur)': '_onBlur()',
2729
}
2830
})
2931
export class CdkSelectionToggle<T> implements OnInit, OnDestroy {
@@ -106,4 +108,14 @@ export class CdkSelectionToggle<T> implements OnInit, OnDestroy {
106108
this._cd.markForCheck();
107109
}
108110

111+
/** Shift key was captured to set user selection. */
112+
_onShift() {
113+
this._selection.setTextSelection('none');
114+
}
115+
116+
/** Element was blurred, lets reset user selection. */
117+
_onBlur() {
118+
setTimeout(() => this._selection.setTextSelection('initial'), 200);
119+
}
120+
109121
}

src/cdk-experimental/selection/selection.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ default selections pass an array of the selections to this option like:
1212
with the `cdkSelectionToggle` directive with an argument of the item's value property.
1313

1414
```html
15-
<ul cdkSelection cdkSelectionStrategy="single">
15+
<ul cdkSelection cdkSelectionMode="single">
1616
<li *ngFor="let item of items">
1717
<button [cdkSelectionToggle]="item.value">
1818
{{item.label}}
@@ -21,15 +21,19 @@ with the `cdkSelectionToggle` directive with an argument of the item's value pro
2121
</ul>
2222
```
2323

24-
### Strategies
25-
The selection directive has 3 different strategies for selection:
24+
### Modes
25+
The selection directive has 2 different modes for selection:
2626

2727
- Single: Only one item can be selected at a time.
28-
- Multiple: Multiple items can be selected by clicking
29-
- Modifier Multiple: Multiple items can be select using keyboard modifiers such as shift or ctrl.
28+
- Multiple: Multiple items can be selected.
3029

31-
### Clearable
32-
The ability to clear a selection that has been made can be prevented using the `cdkSelectionClearable`.
30+
### Key Modifier
31+
When multi-selection mode is enabled anytime a user clicks a toggle element it will be selected.
32+
The `requireModifier` property will only allow multi-selection when using key modifiers. For example,
33+
CTRL/Command + Click would select multiples and SHIFT + Click would select a range.
34+
35+
### Deselectable
36+
The ability to deselect a selection that has been made can be prevented using the `cdkSelectionDeselectable`.
3337
This means that after a selection (or many selections) have been made users can deselect
3438
all but one of the selections. This concept can be related to radio buttons selection strategy.
3539

@@ -42,7 +46,7 @@ return a identifying attribute for the object.
4246
```TS
4347
@Component({
4448
template: `
45-
<ul cdkSelection cdkSelectionStrategy="multiple" [cdkSelectionTrackBy]=""trackBy>
49+
<ul cdkSelection cdkSelectionMode="multiple" [cdkSelectionTrackBy]=""trackBy>
4650
<li *ngFor="let item of items">
4751
<button [cdkSelectionToggle]="item">
4852
{{item.label}}

src/cdk-experimental/selection/selection.spec.ts

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ describe('CdkSelection', () => {
3232
});
3333

3434
it('should select multiple', () => {
35-
testComponent.strategy = 'multiple';
35+
testComponent.mode = 'multiple';
3636
fixture.detectChanges();
3737

3838
testComponent.clickITem('item-1');
@@ -45,7 +45,8 @@ describe('CdkSelection', () => {
4545
});
4646

4747
it('should select one with modifier multipler', () => {
48-
testComponent.strategy = 'modifierMultiple';
48+
testComponent.mode = 'multiple';
49+
testComponent.modifier = true;
4950
fixture.detectChanges();
5051

5152
testComponent.clickITem('item-1');
@@ -58,7 +59,8 @@ describe('CdkSelection', () => {
5859
});
5960

6061
it('should select multiple with modifier multipler', () => {
61-
testComponent.strategy = 'modifierMultiple';
62+
testComponent.mode = 'multiple';
63+
testComponent.modifier = true;
6264
fixture.detectChanges();
6365

6466
testComponent.clickITem('item-1');
@@ -71,7 +73,8 @@ describe('CdkSelection', () => {
7173
});
7274

7375
it('should select multiple range with modifier multipler', () => {
74-
testComponent.strategy = 'modifierMultiple';
76+
testComponent.mode = 'multiple';
77+
testComponent.modifier = true;
7578
fixture.detectChanges();
7679

7780
testComponent.clickITem('item-0');
@@ -84,7 +87,7 @@ describe('CdkSelection', () => {
8487
});
8588

8689
it('should not clear single after selection', () => {
87-
testComponent.clearable = false;
90+
testComponent.deselectable = false;
8891
fixture.detectChanges();
8992

9093
testComponent.clickITem('item-1');
@@ -97,8 +100,8 @@ describe('CdkSelection', () => {
97100
});
98101

99102
it('should not clear multiple after selection', () => {
100-
testComponent.clearable = false;
101-
testComponent.strategy = 'multiple';
103+
testComponent.deselectable = false;
104+
testComponent.mode = 'multiple';
102105
fixture.detectChanges();
103106

104107
testComponent.clickITem('item-1');
@@ -111,8 +114,9 @@ describe('CdkSelection', () => {
111114
});
112115

113116
it('should not clear modifier multiple after selection', () => {
114-
testComponent.clearable = false;
115-
testComponent.strategy = 'modifierMultiple';
117+
testComponent.deselectable = false;
118+
testComponent.mode = 'multiple';
119+
testComponent.modifier = true;
116120
fixture.detectChanges();
117121

118122
testComponent.clickITem('item-1');
@@ -126,7 +130,7 @@ describe('CdkSelection', () => {
126130

127131
it('should not select more than max allow', () => {
128132
testComponent.max = 2;
129-
testComponent.strategy = 'multiple';
133+
testComponent.mode = 'multiple';
130134
fixture.detectChanges();
131135

132136
testComponent.clickITem('item-0');
@@ -162,9 +166,10 @@ describe('CdkSelection', () => {
162166
template: `
163167
<ul
164168
[cdkSelection]="selections"
165-
[cdkSelectionStrategy]="strategy"
169+
[cdkSelectionMode]="mode"
170+
[cdkSelectRequireModifier]="modifier"
166171
[cdkSelectionMaxSelections]="max"
167-
[cdkSelectionClearable]="clearable">
172+
[cdkSelectionDeselectable]="deselectable">
168173
<li *ngFor="let item of items; let i = index;">
169174
<button [cdkSelectionToggle]="item.value" [id]="'item-' + i" [disabled]="i === 3">
170175
{{item.label}}
@@ -185,8 +190,9 @@ class Selection {
185190
];
186191

187192
selections: string[] = [];
188-
clearable = true;
189-
strategy = 'single';
193+
deselectable = true;
194+
modifier = false;
195+
mode = 'single';
190196
max: number;
191197

192198
constructor(public elementRef: ElementRef) {}

src/cdk-experimental/selection/selection.ts

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,19 @@ export class CdkSelection<T> implements OnInit {
2525
* - Multiple: Multiple items can be selected.
2626
* - Modifier Multiple: Multiple items can be selected using modifier keys such as ctrl or shift.
2727
*/
28-
@Input('cdkSelectionStrategy') strategy: 'single' | 'multiple' | 'modifierMultiple' = 'single';
28+
@Input('cdkSelectionMode') mode: 'single' | 'multiple' = 'single';
29+
30+
/** When multi select is enabled, require a key modifier to select multiples. */
31+
@Input('cdkSelectRequireModifier') requireModifier: boolean = false;
2932

3033
/** Track by used for selection matching. */
3134
@Input('cdkSelectionTrackBy') trackBy: (model: T) => any;
3235

3336
/** Whether the selections can be cleared after selection. */
34-
@Input('cdkSelectionClearable')
35-
get clearable(): boolean { return this._clearable; }
36-
set clearable(val) { this._clearable = coerceBooleanProperty(val); }
37-
private _clearable: boolean = true;
37+
@Input('cdkSelectionDeselectable')
38+
get deselectable(): boolean { return this._deselectable; }
39+
set deselectable(val) { this._deselectable = coerceBooleanProperty(val); }
40+
private _deselectable: boolean = true;
3841

3942
/** The max number of selections that can be selected */
4043
@Input('cdkSelectionMaxSelections')
@@ -68,7 +71,7 @@ export class CdkSelection<T> implements OnInit {
6871

6972
ngOnInit() {
7073
this. _selectionModel = new SelectionModel<T>(
71-
this.getIsMultiple(),
74+
this.mode === 'multiple',
7275
this.selections,
7376
true,
7477
this.trackBy
@@ -95,19 +98,14 @@ export class CdkSelection<T> implements OnInit {
9598
}
9699
}
97100

98-
/** Returns whether the control is multi select or not. */
99-
getIsMultiple() {
100-
return this.strategy === 'multiple' || this.strategy === 'modifierMultiple';
101-
}
102-
103101
/** Toggle the selection of a item. */
104102
toggle(ctrl: any) {
105103
if (this.disabled) {
106104
return;
107105
}
108106

109107
if (Array.isArray(ctrl.model)) {
110-
if (this.getIsMultiple() &&
108+
if (this.mode === 'multiple' &&
111109
(this.maxSelections === undefined ||
112110
(ctrl.model.length + this._selectionModel.selected.length) < this.maxSelections)) {
113111
this._selectionModel.clear();
@@ -119,38 +117,46 @@ export class CdkSelection<T> implements OnInit {
119117
}
120118
}
121119

120+
/** Set the user selection for the element. */
121+
setTextSelection(type: string) {
122+
const elm = this._elementRef.nativeElement;
123+
elm.style.userSelect = type;
124+
elm.style.webkitUserSelect = type;
125+
elm.style.MozUserSelect = type;
126+
}
127+
122128
/** Update the selections given the arguments. */
123129
private _setSelections(ctrl: any) {
124130
const ctrls = this._getSortedSet();
125131
const index = this._getIndex(ctrls, ctrl);
126132
const { modifier, model } = ctrl;
127133
const selections = this._selectionModel.selected;
128134

129-
if (this.getIsMultiple() && modifier === 'shift') {
135+
if (this.mode === 'multiple' && modifier === 'shift') {
130136
if (index > -1) {
131137
this._selectRange(ctrls, this._previousSelectedIndex, index);
132138
}
133-
} else if (this.getIsMultiple()) {
139+
} else if (this.mode === 'multiple') {
134140
const isSelected = this._selectionModel.isSelected(model);
135-
if (this.strategy === 'modifierMultiple' && modifier !== 'meta') {
141+
if (this.requireModifier && modifier !== 'meta') {
136142
this._selectionModel.clear();
137-
if (!isSelected || !this.clearable) {
143+
if (!isSelected || !this.deselectable) {
138144
this._selectionModel.select(model);
139145
}
140146
} else {
141147
if (!isSelected) {
142148
if (this.maxSelections === undefined || selections.length < this.maxSelections) {
143149
this._selectionModel.select(model);
144150
}
145-
} else if (this.clearable || (!this.clearable && selections.length > 1)) {
151+
} else if (this.deselectable || (!this.deselectable && selections.length > 1)) {
146152
this._selectionModel.deselect(model);
147153
}
148154
}
149155
} else {
150156
const isSelected = this._selectionModel.isSelected(model);
151157
if (!isSelected) {
152158
this._selectionModel.select(model);
153-
} else if(this.clearable) {
159+
} else if(this.deselectable) {
154160
this._selectionModel.deselect(model);
155161
}
156162
}

0 commit comments

Comments
 (0)