Skip to content

Commit

Permalink
feat: #265 added search input for select component
Browse files Browse the repository at this point in the history
  • Loading branch information
musa.akkaya committed Dec 7, 2022
1 parent 5386778 commit 7b86ab6
Show file tree
Hide file tree
Showing 4 changed files with 347 additions and 7 deletions.
61 changes: 58 additions & 3 deletions src/components/select/bl-select.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
--disabled-color: var(--bl-color-tertiary);
--z-index: 1;
--menu-height: 250px;
--search-container-padding: var(--bl-size-m) var(--bl-size-m) 0;
--search-icon-size: var(--bl-size-xl);
}

:host([size='large']) .select-wrapper {
Expand Down Expand Up @@ -168,11 +170,8 @@
background-color: var(--background-color);
font: var(--bl-font-title-3-regular);
border-radius: var(--bl-border-radius-s);
padding: var(--menu-padding);
outline: none;
box-sizing: border-box;
max-height: var(--menu-height);
overflow-y: auto;
display: none;
flex-direction: column;
z-index: var(--z-index);
Expand Down Expand Up @@ -249,3 +248,59 @@ label {
.select-open .invalid-text {
visibility: hidden;
}

.search-container {
padding: var(--search-container-padding);
}

.search-container .search-wrapper{
position: relative;
}

.search-container .search-wrapper .search-input{
width: 100%;

--bl-input-padding-horizontal: 2rem 0 var(--bl-size-xs);
}

:where(.search-container .search-wrapper .search-input:focus) + .search-icon {
--icon-color: var(--bl-color-primary);
}

.search-container .search-wrapper .search-icon {
position: absolute;
right: var(--bl-size-3xs);
width: var(--search-icon-size);
height: var(--search-icon-size);
top: 50%;
display: flex;
align-items: center;
justify-content: center;
transform: translateY(-50%);
}

.search-container .search-wrapper .search-icon .loading {
animation: loading-spinner 1s infinite linear;

--icon-color: var(--bl-color-primary);
}

.options-container{
padding: var(--menu-padding);
max-height: var(--menu-height);
overflow-y: auto;
}

.options-container .not-found {
padding: var(--bl-size-m) 0;
}

@keyframes loading-spinner {
0% {
transform: rotate(0deg);
}

100% {
transform: rotate(360deg);
}
}
39 changes: 37 additions & 2 deletions src/components/select/bl-select.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,21 @@ import { userEvent } from '@storybook/testing-library';
helpText: {
control: 'text'
},
searchBar: {
control: 'boolean'
},
searchFilterable: {
control: 'boolean'
},
searchBarPlaceholder: {
control: 'text'
},
searchNotFoundText: {
control: 'text'
},
searchBarLoadingState: {
control: 'boolean'
},
}}
/>

Expand All @@ -61,7 +76,13 @@ export const SelectTemplate = (args) => html`<bl-select
size='${ifDefined(args.size)}'
help-text='${ifDefined(args.helpText)}'
invalid-text='${ifDefined(args.customInvalidText)}'
placeholder='${ifDefined(args.placeholder)}'>
placeholder='${ifDefined(args.placeholder)}'
?search-bar='${ifDefined(args.searchBar)}'
?search-filterable='${ifDefined(args.searchFilterable)}'
search-bar-placeholder='${ifDefined(args.searchBarPlaceholder)}'
search-not-found-text='${ifDefined(args.searchNotFoundText)}'
?search-bar-loading-state='${ifDefined(args.searchBarLoadingState)}'
>
<bl-select-option value="tr">Turkey</bl-select-option>
<bl-select-option value="nl">Netherlands</bl-select-option>
</bl-select>`
Expand All @@ -76,7 +97,13 @@ export const SelectOptionsSelectedTemplate = (args) => html`<bl-select
size='${ifDefined(args.size)}'
help-text='${ifDefined(args.helpText)}'
invalid-text='${ifDefined(args.customInvalidText)}'
placeholder='${ifDefined(args.placeholder)}'>
placeholder='${ifDefined(args.placeholder)}'
?search-bar='${ifDefined(args.searchBar)}'
?search-filterable='${ifDefined(args.searchFilterable)}'
search-bar-placeholder='${ifDefined(args.searchBarPlaceholder)}'
search-not-found-text='${ifDefined(args.searchNotFoundText)}'
?search-bar-loading-state='${ifDefined(args.searchBarLoadingState)}'
>
<bl-select-option value="tr">Turkey</bl-select-option>
<bl-select-option value="nl" selected>Netherlands</bl-select-option>
</bl-select>`
Expand Down Expand Up @@ -184,6 +211,14 @@ Select have 3 size options: `small`, `medium` and `large`. `medium` size is defa
</Story>
</Canvas>

## Select Search bar

<Canvas>
<Story name="Select Search Bar" args={{ label: 'Choose country', searchBar: true }}>
{SelectTemplate.bind({})}
</Story>
</Canvas>

## Reference

<ArgsTable of="bl-select" />
132 changes: 131 additions & 1 deletion src/components/select/bl-select.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,15 @@ describe('bl-select', () => {
</div>
</div>
<div class="popover">
<slot></slot>
<div class="options-container">
<slot>
</slot>
<div class="not-found">
<slot name="search-not-found">
Not Found
</slot>
</div>
</div>
</div>
</div>
`
Expand Down Expand Up @@ -207,4 +215,126 @@ describe('bl-select', () => {
expect(selectOption).is.not.exist;
});
});

it('should show search bar when searchBar is true', async () => {
const el = await fixture<BlSelect>(html`<bl-select multiple search-bar>
<bl-select-option value="1">Option 1</bl-select-option>
<bl-select-option value="2" selected>Option 2</bl-select-option>
</bl-select>`);

assert.shadowDom.equal(
el,
`<div
class="select-wrapper selected"
tabindex="-1"
>
<div class="select-input">
<ul class="selected-options">
<li>
Option 2
</li>
</ul>
<div class="actions">
<bl-button
class="remove-all"
icon="close"
kind="neutral"
size="small"
variant="tertiary"
>
</bl-button>
<bl-icon
class="dropdown-icon open"
name="arrow_up"
>
</bl-icon>
<bl-icon
class="closed dropdown-icon"
name="arrow_down"
>
</bl-icon>
</div>
</div>
<div class="popover">
<div class="search-container">
<div class="search-wrapper">
<bl-input
class="search-input"
placeholder=""
>
</bl-input>
<div class="search-icon">
<bl-icon name="search">
</bl-icon>
</div>
</div>
</div>
<div class="options-container">
<slot>
</slot>
</div>
</div>
</div>`
)
});

it('should show loading state', async () => {
const el = await fixture<BlSelect>(html`<bl-select multiple search-bar search-bar-loading-state>
<bl-select-option value="1">Option 1</bl-select-option>
<bl-select-option value="2" selected>Option 2</bl-select-option>
</bl-select>`);

const blIconLoading = el.shadowRoot?.querySelector('bl-icon.loading');
expect(blIconLoading).to.exist;
});


it('should search input text 2 and show clear button when clear event', async () => {
const el = await fixture<BlSelect>(html`<bl-select multiple search-bar>
<bl-select-option value="1">Option 1</bl-select-option>
<bl-select-option value="2" selected>Option 2</bl-select-option>
</bl-select>`);

const searchInput = el.shadowRoot?.querySelector('bl-input.search-input');
setTimeout(() => searchInput?.dispatchEvent(new CustomEvent('bl-input', {detail: "2"})));

await oneEvent(searchInput!, 'bl-input');
const blButtonClear = el.shadowRoot?.querySelector('bl-button.search-input-clear');
const optionItems = el.options.filter(item => item.style.display === "block")

expect(optionItems.length).to.equal(1);
expect(blButtonClear).to.exist;



setTimeout(() => blButtonClear?.dispatchEvent(new Event('click', {})))
const ev = await oneEvent(blButtonClear!, 'click');
expect(ev).to.exist;
});

it('should search input text when show notFound', async () => {
const el = await fixture<BlSelect>(html`<bl-select multiple search-bar search-not-found-text="searchNotFoundText">
<bl-select-option value="1">Option 1</bl-select-option>
<bl-select-option value="2" selected>Option 2</bl-select-option>
</bl-select>`);

const searchInput = el.shadowRoot?.querySelector('bl-input.search-input');
setTimeout(() => searchInput?.dispatchEvent(new CustomEvent('bl-input', {detail: "customEvent"})));

await oneEvent(searchInput!, 'bl-input');

const notFoundText = el.shadowRoot?.querySelector(".not-found")
expect(notFoundText).to.exist;
expect(notFoundText?.textContent?.trim()).to.equal('searchNotFoundText')
});

it('should open select menu with search attribute when detect input focus', async () => {
const el = await fixture<BlSelect>(html`<bl-select multiple search-bar search-not-found-text="searchNotFoundText">
<bl-select-option value="1">Option 1</bl-select-option>
<bl-select-option value="2" selected>Option 2</bl-select-option>
</bl-select>`);

const selectInput = <HTMLDivElement>el.shadowRoot?.querySelector('.select-input');
selectInput?.click();
});
});
Loading

0 comments on commit 7b86ab6

Please sign in to comment.