Skip to content

Commit

Permalink
feat(core/select): show info if no matches found and fix selection bug (
Browse files Browse the repository at this point in the history
  • Loading branch information
nuke-ellington committed Apr 21, 2023
1 parent bbafc1d commit 6be3a47
Show file tree
Hide file tree
Showing 12 changed files with 101 additions and 45 deletions.
4 changes: 2 additions & 2 deletions packages/angular/src/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1348,14 +1348,14 @@ export declare interface IxPill extends Components.IxPill {}


@ProxyCmp({
inputs: ['allowClear', 'disabled', 'editable', 'hideListHeader', 'i18nPlaceholder', 'i18nPlaceholderEditable', 'i18nSelectListHeader', 'mode', 'readonly', 'selectedIndices']
inputs: ['allowClear', 'disabled', 'editable', 'hideListHeader', 'i18nNoMatches', 'i18nPlaceholder', 'i18nPlaceholderEditable', 'i18nSelectListHeader', 'mode', 'readonly', 'selectedIndices']
})
@Component({
selector: 'ix-select',
changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['allowClear', 'disabled', 'editable', 'hideListHeader', 'i18nPlaceholder', 'i18nPlaceholderEditable', 'i18nSelectListHeader', 'mode', 'readonly', 'selectedIndices'],
inputs: ['allowClear', 'disabled', 'editable', 'hideListHeader', 'i18nNoMatches', 'i18nPlaceholder', 'i18nPlaceholderEditable', 'i18nSelectListHeader', 'mode', 'readonly', 'selectedIndices'],
})
export class IxSelect {
protected el: HTMLElement;
Expand Down
24 changes: 23 additions & 1 deletion packages/core/component-doc.json
Original file line number Diff line number Diff line change
Expand Up @@ -7059,6 +7059,28 @@
"optional": false,
"required": false
},
{
"name": "i18nNoMatches",
"type": "string",
"mutable": false,
"attr": "i-1-8n-no-matches",
"reflectToAttr": false,
"docs": "Hint inside of dropdown if no items where found with current filter text",
"docsTags": [
{
"name": "since",
"text": "1.5.0"
}
],
"default": "'No matches'",
"values": [
{
"type": "string"
}
],
"optional": false,
"required": false
},
{
"name": "i18nPlaceholder",
"type": "string",
Expand Down Expand Up @@ -7155,7 +7177,7 @@
"mutable": true,
"attr": "selected-indices",
"reflectToAttr": false,
"docs": "Indices of selected items",
"docs": "Indices of selected items\nThis corresponds to the value property of ix-select-items and therefor not neccessarily the indices of the items in the list.",
"docsTags": [],
"default": "[]",
"values": [
Expand Down
14 changes: 12 additions & 2 deletions packages/core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1222,6 +1222,11 @@ export namespace Components {
* @
*/
"hideListHeader": boolean;
/**
* Hint inside of dropdown if no items where found with current filter text
* @since 1.5.0
*/
"i18nNoMatches": string;
/**
* Input field placeholder
*/
Expand All @@ -1243,7 +1248,7 @@ export namespace Components {
*/
"readonly": boolean;
/**
* Indices of selected items
* Indices of selected items This corresponds to the value property of ix-select-items and therefor not neccessarily the indices of the items in the list.
*/
"selectedIndices": string | string[];
}
Expand Down Expand Up @@ -3661,6 +3666,11 @@ declare namespace LocalJSX {
* @
*/
"hideListHeader"?: boolean;
/**
* Hint inside of dropdown if no items where found with current filter text
* @since 1.5.0
*/
"i18nNoMatches"?: string;
/**
* Input field placeholder
*/
Expand Down Expand Up @@ -3690,7 +3700,7 @@ declare namespace LocalJSX {
*/
"readonly"?: boolean;
/**
* Indices of selected items
* Indices of selected items This corresponds to the value property of ix-select-items and therefor not neccessarily the indices of the items in the list.
*/
"selectedIndices"?: string | string[];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

:host {
display: block;
min-width: 10rem;

&.icon-only {
min-width: 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export class DropdownItem {
disabled: this.disabled,
}}
onClick={() => this.emitItemClick()}
tabindex={0}
>
{this.checked ? (
<ix-icon class="checkmark" name="single-check" size="16"></ix-icon>
Expand Down
5 changes: 4 additions & 1 deletion packages/core/src/components/dropdown/dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,10 @@ export class Dropdown {
}

if (this.placement.includes('auto') || isSubmenu) {
positionConfig.middleware.push(flip());
positionConfig.middleware.push(
flip({ fallbackStrategy: 'initialPlacement' })
);
positionConfig.placement = 'bottom-start';
} else {
positionConfig.placement = this.placement as
| BasePlacement
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/components/pagination/pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ export class Pagination {
<span class="item-count">
{this.i18nItems}
<ix-select
hideListHeader
i18nPlaceholder=""
i18nSelectListHeader=""
selected-indices={this.itemCount}
Expand Down
6 changes: 0 additions & 6 deletions packages/core/src/components/select-item/select-item.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,4 @@

:host {
display: block;

ix-dropdown-item {
button {
margin-left: 1rem;
}
}
}
1 change: 0 additions & 1 deletion packages/core/src/components/select-item/select-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ export class SelectItem {
<Host>
<ix-dropdown-item
checked={this.selected}
hover={this.hover}
label={this.label ? this.label : this.value}
onItemClick={(e) => this.onItemClick(e)}
></ix-dropdown-item>
Expand Down
84 changes: 54 additions & 30 deletions packages/core/src/components/select/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export class Select {

/**
* Indices of selected items
* This corresponds to the value property of ix-select-items and therefor not neccessarily the indices of the items in the list.
*/
@Prop({ mutable: true }) selectedIndices: string | string[] = [];

Expand Down Expand Up @@ -74,6 +75,13 @@ export class Select {
*/
@Prop() i18nSelectListHeader = 'Please select an option';

/**
* Hint inside of dropdown if no items where found with current filter text
*
* @since 1.5.0
*/
@Prop() i18nNoMatches = 'No matches';

/**
* Hide list header
*
Expand Down Expand Up @@ -128,6 +136,10 @@ export class Select {
return this.mode === 'multiple';
}

get isEveryDropdownItemHidden() {
return this.items.every((item) => item.classList.contains('d-none'));
}

@Watch('selectedIndices')
watchSelectedIndices(newId: string | string[]) {
if (!newId) {
Expand All @@ -149,17 +161,6 @@ export class Select {
this.emitItemClick(newId);
}

@Watch('inputFilterText')
watchInputText(newValue: string) {
if (!this.editable) {
return;
}

if (this.itemExists(newValue)) {
return;
}
}

private emitItemClick(newId: string) {
if (this.isMultipleMode && Array.isArray(this.selectedIndices)) {
if (this.selectedIndices.includes(newId)) {
Expand All @@ -180,11 +181,11 @@ export class Select {
return;
}

const test = document.createElement('ix-select-item');
test.value = value;
test.label = value;
const newItem = document.createElement('ix-select-item');
newItem.value = value;
newItem.label = value;

this.addItemRef.appendChild(test);
this.addItemRef.appendChild(newItem);

this.clearInput();
this.emitItemClick(value);
Expand Down Expand Up @@ -239,16 +240,17 @@ export class Select {

private dropdownVisibilityChanged(event: CustomEvent<boolean>) {
this.dropdownShow = event.detail;
this.hasFocus = event.detail;

if (event.detail) {
this.inputRef.focus();
this.inputRef.select();

this.navigationItem = this.items[0];
this.setHoverEffectForNavigatedSelectItem();
this.removeHiddenFromItems();
this.isDropdownEmpty = this.isEveryDropdownItemHidden;
} else {
this.navigationItem = undefined;
}
this.hasFocus = event.detail;
}

@Listen('keydown', {
Expand Down Expand Up @@ -294,6 +296,11 @@ export class Select {
event.stopPropagation();
event.preventDefault();

const focusItem = this.items.find(
(item) => document.activeElement === item.querySelector('button')
);
this.navigationItem = focusItem;

const selectItems = this.items.filter(
(i) => !i.classList.contains('d-none')
);
Expand All @@ -310,13 +317,12 @@ export class Select {
}

private setHoverEffectForNavigatedSelectItem() {
this.items.forEach((item: HTMLIxSelectItemElement) => {
item.hover = item === this.navigationItem;
});
this.navigationItem?.querySelector('button').focus();
}

private filterItemsWithTypeahead() {
this.inputFilterText = this.inputRef.value;

if (this.inputFilterText) {
this.items.forEach((item) => {
item.classList.remove('d-none');
Expand All @@ -329,9 +335,8 @@ export class Select {
} else {
this.removeHiddenFromItems();
}
this.isDropdownEmpty = this.items.every((item) =>
item.classList.contains('d-none')
);

this.isDropdownEmpty = this.isEveryDropdownItemHidden;
}

private removeHiddenFromItems() {
Expand All @@ -353,6 +358,22 @@ export class Select {
this.dropdownShow = false;
}

private onInputBlur(e) {
if (this.editable) {
return;
}

if (this.isSingleMode) {
if (this.dropdownShow && this.isDropdownEmpty) {
this.dropdownShow = false;
}
}

if (!this.dropdownShow && this.mode !== 'multiple') {
e.target['value'] = this.value;
}
}

private placeholderValue() {
if (this.editable) {
return this.i18nPlaceholderEditable;
Expand Down Expand Up @@ -411,6 +432,7 @@ export class Select {
placeholder={this.placeholderValue()}
value={this.inputValue}
ref={(ref) => (this.inputRef = ref)}
onBlur={(e) => this.onInputBlur(e)}
onInput={() => this.filterItemsWithTypeahead()}
/>
{this.allowClear &&
Expand Down Expand Up @@ -446,25 +468,22 @@ export class Select {
ref={(ref) => (this.dropdownRef = ref)}
show={this.dropdownShow}
class={{
'd-none':
this.disabled ||
this.readonly ||
(this.isDropdownEmpty && !this.editable),
'd-none': this.disabled || this.readonly,
}}
anchor={this.dropdownAnchor}
trigger={this.dropdownWrapperRef}
onShowChanged={(e) => this.dropdownVisibilityChanged(e)}
placement="auto-start"
overwriteDropdownStyle={async () => {
return {
width: `${this.hostElement.clientWidth}px`,
minWidth: `${this.hostElement.clientWidth}px`,
};
}}
>
<div
class={{
'select-list-header': true,
hidden: this.hideListHeader === true,
hidden: this.hideListHeader || this.isDropdownEmpty,
}}
title={this.i18nSelectListHeader}
>
Expand All @@ -490,6 +509,11 @@ export class Select {
}}
></ix-dropdown-item>
)}
{this.isDropdownEmpty && !this.editable ? (
<div class="select-list-header">{this.i18nNoMatches}</div>
) : (
''
)}
</ix-dropdown>
</Host>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ regressionTest.describe('basic', () => {

await page.waitForSelector('.dropdown.show');

expect(await page.screenshot({ fullPage: true })).toMatchSnapshot();
expect(await page.screenshot({ fullPage: true })).toMatchSnapshot({
maxDiffPixelRatio: 0.01,
});
});
});
1 change: 1 addition & 0 deletions packages/vue/src/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,7 @@ export const IxSelect = /*@__PURE__*/ defineContainer<JSX.IxSelect>('ix-select',
'i18nPlaceholder',
'i18nPlaceholderEditable',
'i18nSelectListHeader',
'i18nNoMatches',
'hideListHeader',
'itemSelectionChange',
'addItem'
Expand Down

0 comments on commit 6be3a47

Please sign in to comment.