Skip to content

Commit

Permalink
feat(core/select): hide clear button on disabled and readonly (#1574)
Browse files Browse the repository at this point in the history
Co-authored-by: Lukas Maurer <[email protected]>
  • Loading branch information
matthiashader and nuke-ellington authored Dec 3, 2024
1 parent 5ca2446 commit 57586a7
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 25 deletions.
5 changes: 5 additions & 0 deletions .changeset/good-mayflies-accept.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@siemens/ix': patch
---

Hide clear button in ix-select for disabled and readonly states.
61 changes: 36 additions & 25 deletions packages/core/src/components/select/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ export class Select implements IxInputFieldComponent<string | string[]> {
@Event() ixBlur!: EventEmitter<void>;

@State() dropdownShow = false;
@State() selectedLabels: string[] = [];
@State() selectedLabels: (string | undefined)[] = [];
@State() isDropdownEmpty = false;
@State() navigationItem?: DropdownItemWrapper;
@State() inputFilterText = '';
Expand Down Expand Up @@ -302,7 +302,7 @@ export class Select implements IxInputFieldComponent<string | string[]> {

@Watch('dropdownShow')
watchDropdownShow(show: boolean) {
if (show) {
if (show && this.dropdownRef) {
this.arrowFocusController = new ArrowFocusController(
this.visibleNonShadowItems,
this.dropdownRef,
Expand Down Expand Up @@ -356,7 +356,7 @@ export class Select implements IxInputFieldComponent<string | string[]> {
}

private focusDropdownItem(index: number) {
this.navigationItem = null;
this.navigationItem = undefined;

if (index < this.visibleNonShadowItems.length) {
const nestedDropdownItem =
Expand Down Expand Up @@ -402,7 +402,7 @@ export class Select implements IxInputFieldComponent<string | string[]> {
newItem.value = value;
newItem.label = value;

this.customItemsContainerRef.appendChild(newItem);
this.customItemsContainerRef?.appendChild(newItem);

this.clearInput();
this.itemClick(value);
Expand Down Expand Up @@ -452,7 +452,7 @@ export class Select implements IxInputFieldComponent<string | string[]> {
this.selectedLabels = this.selectedItems.map((item) => item.label);

if (this.selectedLabels?.length && this.isSingleMode) {
this.inputValue = this.selectedLabels[0];
this.inputValue = this.selectedLabels[0] ?? '';
} else {
this.inputValue = '';
}
Expand All @@ -468,7 +468,7 @@ export class Select implements IxInputFieldComponent<string | string[]> {
}

if (!value) {
this.itemSelectionChange.emit(null);
this.itemSelectionChange.emit([]);
} else {
this.itemSelectionChange.emit(Array.isArray(value) ? value : [value]);
}
Expand Down Expand Up @@ -505,7 +505,7 @@ export class Select implements IxInputFieldComponent<string | string[]> {
this.cleanupResources();
}

private itemExists(item: string) {
private itemExists(item: string | undefined) {
return this.items.find((i) => i.label === item);
}

Expand All @@ -519,7 +519,7 @@ export class Select implements IxInputFieldComponent<string | string[]> {
this.removeHiddenFromItems();
this.isDropdownEmpty = this.isEveryDropdownItemHidden;
} else {
this.navigationItem = null;
this.navigationItem = undefined;
this.updateSelection();
this.inputFilterText = '';
}
Expand Down Expand Up @@ -551,15 +551,17 @@ export class Select implements IxInputFieldComponent<string | string[]> {
return;
}

const trimmedInput = this.inputFilterText.trim();
const itemLabel = (el as HTMLIxSelectItemElement)?.label;

if (
!this.itemExists(this.inputFilterText.trim()) &&
!this.itemExists((el as HTMLIxSelectItemElement)?.label)
this.editable &&
!this.itemExists(trimmedInput) &&
!this.itemExists(itemLabel)
) {
if (this.editable) {
const defaultPrevented = this.emitAddItem(this.inputFilterText.trim());
if (defaultPrevented) {
return;
}
const defaultPrevented = this.emitAddItem(trimmedInput);
if (defaultPrevented) {
return;
}
}

Expand Down Expand Up @@ -622,16 +624,14 @@ export class Select implements IxInputFieldComponent<string | string[]> {

if (
this.isAddItemVisible() &&
this.addItemRef.contains(
this.addItemRef?.contains(
await this.navigationItem.getDropdownItemElement()
)
) {
if (moveUp) {
this.applyFocusTo(this.visibleItems.pop());
} else {
if (this.visibleItems.length) {
this.applyFocusTo(this.visibleItems.shift());
}
} else if (this.visibleItems.length) {
this.applyFocusTo(this.visibleItems.shift());
}
return;
}
Expand Down Expand Up @@ -687,7 +687,7 @@ export class Select implements IxInputFieldComponent<string | string[]> {
}

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

if (this.isSingleMode && this.inputFilterText === this.selectedLabels[0]) {
return;
Expand All @@ -697,7 +697,9 @@ export class Select implements IxInputFieldComponent<string | string[]> {
this.items.forEach((item) => {
item.classList.remove('d-none');
if (
!item.label.toLowerCase().includes(this.inputFilterText.toLowerCase())
!item.label
?.toLowerCase()
.includes(this.inputFilterText.toLowerCase())
) {
item.classList.add('d-none');
}
Expand Down Expand Up @@ -801,15 +803,22 @@ export class Select implements IxInputFieldComponent<string | string[]> {
*/
@Method()
getNativeInputElement(): Promise<HTMLInputElement> {
return Promise.resolve(this.inputRef);
if (this.inputRef) {
return Promise.resolve(this.inputRef);
} else {
return Promise.reject(new Error('Input element not found'));
}
}

/**
* Focuses the input field
*/
@Method()
async focusInput(): Promise<void> {
return (await this.getNativeInputElement()).focus();
const inputElement = await this.getNativeInputElement();
if (inputElement) {
inputElement.focus();
}
}

render() {
Expand Down Expand Up @@ -880,12 +889,14 @@ export class Select implements IxInputFieldComponent<string | string[]> {
ref={(ref) => (this.inputRef = ref)}
onBlur={(e) => this.onInputBlur(e)}
onFocus={() => {
this.navigationItem = null;
this.navigationItem = undefined;
}}
onInput={() => this.filterItemsWithTypeahead()}
onKeyDown={(e) => this.onKeyDown(e)}
/>
{this.allowClear &&
!this.disabled &&
!this.readonly &&
(this.selectedLabels?.length || this.inputFilterText) ? (
<ix-icon-button
class="clear"
Expand Down
22 changes: 22 additions & 0 deletions packages/core/src/components/select/test/select.ct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,28 @@ test('type in a novel item name and click outside', async ({ mount, page }) => {
expect(inputValue).toBe('Item 2');
});

test('check if clear button visible in disabled', async ({ mount, page }) => {
await mount(`
<ix-select value="2" allow-clear>
<ix-select-item value="1" label="Item 1">Test</ix-select-item>
<ix-select-item value="2" label="Item 2">Test</ix-select-item>
<ix-select-item value="3" label="Item 3">Test</ix-select-item>
</ix-select>
`);

const selectElement = page.locator('ix-select');
await expect(selectElement).toHaveClass(/hydrated/);

const clearButton = page.locator('ix-icon-button.clear.btn-icon-16');
await expect(clearButton).toBeVisible();

await selectElement.evaluate(
(select: HTMLIxSelectElement) => (select.disabled = true)
);

await expect(clearButton).not.toBeAttached();
});

test('type in a novel item name in multiple mode, click outside', async ({
mount,
page,
Expand Down
56 changes: 56 additions & 0 deletions packages/storybook-docs/src/stories/select.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* SPDX-FileCopyrightText: 2024 Siemens AG
*
* SPDX-License-Identifier: MIT
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import type { Components } from '@siemens/ix/components';
import type { ArgTypes, Meta, StoryObj } from '@storybook/web-components';
import { genericRender, makeArgTypes } from './utils/generic-render';
import { html } from 'lit';

type Element = Components.IxSelect;

const meta = {
title: 'Example/Select',
tags: [],
render: (args) => genericRender('ix-select', args),
argTypes: makeArgTypes<Partial<ArgTypes<Element>>>('ix-select'),
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/design/r2nqdNNXXZtPmWuVjIlM1Q/iX-Components---Brand-Dark?node-id=42365-175539&m=dev',
},
},
} satisfies Meta<Element>;

export default meta;
type Story = StoryObj<Element>;

export const Default: Story = {
args: {},
};

export const editableSelect: Story = {
render: ({ value, editable, allowClear, disabled }) => {
return html` <ix-select
value=${value}
?editable=${editable}
?allow-clear=${allowClear}
disabled=${disabled}
>
<ix-select-item label="Item 1" value="1"></ix-select-item>
<ix-select-item label="Item 2" value="2"></ix-select-item>
<ix-select-item label="Item 3" value="3"></ix-select-item>
<ix-select-item label="Item 4" value="4"></ix-select-item>
</ix-select>`;
},
args: {
value: 'Administrator',
editable: true,
allowClear: true,
disabled: false,
},
};

0 comments on commit 57586a7

Please sign in to comment.