Skip to content

Commit 3108b90

Browse files
feat: fluid state for dropdown (#3008)
Signed-off-by: Akshat Patel <[email protected]> Co-authored-by: Akshat Patel <[email protected]>
1 parent 3bda789 commit 3108b90

File tree

2 files changed

+66
-27
lines changed

2 files changed

+66
-27
lines changed

src/dropdown/dropdown.component.ts

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ import { hasScrollableParents } from "carbon-components-angular/utils";
6969
<div
7070
class="cds--list-box"
7171
[ngClass]="{
72-
'cds--dropdown': type !== 'multi',
72+
'cds--dropdown': type !== 'multi' && !(skeleton && fluid),
7373
'cds--multiselect': type === 'multi',
7474
'cds--multi-select--selected': type === 'multi' && getSelectedCount() > 0,
7575
'cds--dropdown--light': theme === 'light',
@@ -83,8 +83,11 @@ import { hasScrollableParents } from "carbon-components-angular/utils";
8383
'cds--dropdown--sm cds--list-box--sm': size === 'sm',
8484
'cds--dropdown--md cds--list-box--md': size === 'md',
8585
'cds--dropdown--lg cds--list-box--lg': size === 'lg',
86-
'cds--list-box--expanded': !menuIsClosed
87-
}">
86+
'cds--list-box--expanded': !menuIsClosed,
87+
'cds--list-box--invalid': invalid
88+
}"
89+
[attr.data-invalid]="invalid ? true : null">
90+
<div *ngIf="skeleton && fluid" class="cds--list-box__label"></div>
8891
<button
8992
#dropdownButton
9093
[id]="id"
@@ -96,7 +99,8 @@ import { hasScrollableParents } from "carbon-components-angular/utils";
9699
[attr.aria-readonly]="readonly"
97100
aria-haspopup="listbox"
98101
(click)="disabled || readonly ? $event.stopPropagation() : toggleMenu()"
99-
(blur)="onBlur()"
102+
(focus)="fluid ? handleFocus($event) : null"
103+
(blur)="fluid ? handleFocus($event) : onBlur()"
100104
[attr.disabled]="disabled ? true : null">
101105
<div
102106
(click)="clearSelected()"
@@ -125,18 +129,6 @@ import { hasScrollableParents } from "carbon-components-angular/utils";
125129
[ngTemplateOutletContext]="getRenderTemplateContext()"
126130
[ngTemplateOutlet]="displayValue">
127131
</ng-template>
128-
<svg
129-
*ngIf="invalid"
130-
class="cds--dropdown__invalid-icon"
131-
cdsIcon="warning--filled"
132-
size="16">
133-
</svg>
134-
<svg
135-
*ngIf="!invalid && warn"
136-
cdsIcon="warning--alt--filled"
137-
size="16"
138-
class="cds--list-box__invalid-icon cds--list-box__invalid-icon--warning">
139-
</svg>
140132
<span class="cds--list-box__menu-icon">
141133
<svg
142134
*ngIf="!skeleton"
@@ -147,6 +139,18 @@ import { hasScrollableParents } from "carbon-components-angular/utils";
147139
</svg>
148140
</span>
149141
</button>
142+
<svg
143+
*ngIf="invalid"
144+
class="cds--list-box__invalid-icon"
145+
cdsIcon="warning--filled"
146+
size="16">
147+
</svg>
148+
<svg
149+
*ngIf="!invalid && warn"
150+
cdsIcon="warning--alt--filled"
151+
size="16"
152+
class="cds--list-box__invalid-icon cds--list-box__invalid-icon--warning">
153+
</svg>
150154
<div
151155
#dropdownMenu
152156
[ngClass]="{
@@ -155,8 +159,9 @@ import { hasScrollableParents } from "carbon-components-angular/utils";
155159
<ng-content *ngIf="!menuIsClosed"></ng-content>
156160
</div>
157161
</div>
162+
<hr *ngIf="fluid" class="cds--list-box__divider" />
158163
<div
159-
*ngIf="helperText && !invalid && !warn && !skeleton"
164+
*ngIf="helperText && !invalid && !warn && !skeleton && !fluid"
160165
class="cds--form__helper-text"
161166
[ngClass]="{
162167
'cds--form__helper-text--disabled': disabled
@@ -183,6 +188,25 @@ import { hasScrollableParents } from "carbon-components-angular/utils";
183188
})
184189
export class Dropdown implements OnInit, AfterContentInit, AfterViewInit, OnDestroy, ControlValueAccessor {
185190
static dropdownCount = 0;
191+
@HostBinding("class.cds--list-box__wrapper--fluid--invalid") get fluidInvalidClass() {
192+
return this.invalid && this.fluid;
193+
}
194+
195+
@HostBinding("class.cds--list-box__wrapper--fluid--focus") get fluidFocusClass() {
196+
return this.fluid && this._isFocused && this.menuIsClosed;
197+
}
198+
199+
protected get writtenValue() {
200+
return this._writtenValue;
201+
}
202+
203+
protected set writtenValue(val: any[]) {
204+
if (val && val.length === 0) {
205+
this.clearSelected();
206+
}
207+
this._writtenValue = val;
208+
}
209+
186210
@Input() id = `dropdown-${Dropdown.dropdownCount++}`;
187211
/**
188212
* Label for the dropdown.
@@ -319,6 +343,13 @@ export class Dropdown implements OnInit, AfterContentInit, AfterViewInit, OnDest
319343
@ViewChild("dropdownMenu", { static: true }) dropdownMenu;
320344

321345
@HostBinding("class.cds--dropdown__wrapper") hostClass = true;
346+
347+
@HostBinding("class.cds--list-box__wrapper") hostWrapperClass = true;
348+
/**
349+
* Experimental: enable fluid state
350+
*/
351+
@HostBinding("class.cds--list-box__wrapper--fluid") @Input() fluid = false;
352+
322353
/**
323354
* Set to `true` if the dropdown is closed (not expanded).
324355
*/
@@ -340,17 +371,10 @@ export class Dropdown implements OnInit, AfterContentInit, AfterViewInit, OnDest
340371

341372
protected onTouchedCallback: () => void = this._noop;
342373

374+
protected _isFocused = false;
375+
343376
// primarily used to capture and propagate input to `writeValue` before the content is available
344377
private _writtenValue: any = [];
345-
protected get writtenValue() {
346-
return this._writtenValue;
347-
}
348-
protected set writtenValue(val: any[]) {
349-
if (val && val.length === 0) {
350-
this.clearSelected();
351-
}
352-
this._writtenValue = val;
353-
}
354378

355379
/**
356380
* Creates an instance of Dropdown.
@@ -801,6 +825,13 @@ export class Dropdown implements OnInit, AfterContentInit, AfterViewInit, OnDest
801825
return value instanceof TemplateRef;
802826
}
803827

828+
handleFocus(event: FocusEvent) {
829+
this._isFocused = event.type === "focus";
830+
if (event.type === "blur") {
831+
this.onBlur();
832+
}
833+
}
834+
804835
/**
805836
* Controls when it's needed to apply the selection feedback
806837
*/

src/dropdown/dropdown.stories.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ export default {
6565
appendInline: false,
6666
dropUp: false,
6767
size: "md",
68-
theme: "dark"
68+
theme: "dark",
69+
fluid: false
6970
},
7071
argTypes: {
7172
type: {
@@ -103,6 +104,7 @@ const Template = (args) => ({
103104
placeholder="Select"
104105
[disabled]="disabled"
105106
[readonly]="readonly"
107+
[fluid]="fluid"
106108
(selected)="selected($event)"
107109
(onClose)="onClose($event)">
108110
<cds-dropdown-list [items]="items"></cds-dropdown-list>
@@ -111,6 +113,11 @@ const Template = (args) => ({
111113
});
112114
export const Basic = Template.bind({});
113115

116+
export const Fluid = Template.bind({});
117+
Fluid.args = {
118+
fluid: true
119+
};
120+
114121
const MultiTemplate = (args) => ({
115122
props: args,
116123
template: `
@@ -131,6 +138,7 @@ const MultiTemplate = (args) => ({
131138
placeholder="Select"
132139
[disabled]="disabled"
133140
[readonly]="readonly"
141+
[fluid]="fluid"
134142
(selected)="selected($event)"
135143
(onClose)="onClose($event)">
136144
<cds-dropdown-list [items]="items"></cds-dropdown-list>

0 commit comments

Comments
 (0)