Skip to content

Commit

Permalink
Merge branch 'next' into next-4
Browse files Browse the repository at this point in the history
  • Loading branch information
leventozen authored Jan 11, 2024
2 parents 8cc0e2d + 2304485 commit 69b3f6a
Show file tree
Hide file tree
Showing 11 changed files with 454 additions and 57 deletions.
5 changes: 5 additions & 0 deletions docs/design-system/colors.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ Baklava uses a list of defined color with some default values.
subtitle="Warning Color"
colors={{ '': 'var(--bl-color-warning)', '--highlight': 'var(--bl-color-warning-highlight)', '--contrast': 'var(--bl-color-warning-contrast)' }}
/>
<ColorItem
title="--bl-color-info"
subtitle="Info Color"
colors={{ '': 'var(--bl-color-info)', '--highlight': 'var(--bl-color-info-highlight)', '--contrast': 'var(--bl-color-info-contrast)' }}
/>
<ColorItem
title="--bl-color-neutral"
subtitle="Neutral Colors"
Expand Down
6 changes: 3 additions & 3 deletions src/components/alert/bl-alert.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

.alert {
--padding: var(--bl-size-m);
--main-color: var(--bl-color-primary);
--main-bg-color: var(--bl-color-primary-contrast);
--main-color: var(--bl-color-info);
--main-bg-color: var(--bl-color-info-contrast);

position: relative;
display: flex;
Expand All @@ -14,7 +14,7 @@
background-color: var(--main-bg-color);
color: var(--bl-color-neutral-darker);
box-shadow: inset 0 0 0 1px var(--main-color);
border-radius: var(--bl-border-radius-s);
border-radius: var(--bl-border-radius-l);
padding: calc(var(--padding) / 2) var(--padding);
padding-right: calc(var(--padding) / 2);
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/alert/bl-alert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export default class BlAlert extends LitElement {

const variant = slotElement.name === "action-secondary" ? "secondary" : "primary";
const buttonTypes: Record<AlertVariant, string> = {
info: "default",
info: "neutral",
warning: "neutral",
success: "success",
danger: "danger",
Expand Down
2 changes: 1 addition & 1 deletion src/components/notification/card/bl-notification-card.css
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,5 @@
}

.notification[variant="info"] .duration > .remaining {
background-color: var(--bl-color-primary);
background-color: var(--bl-color-info);
}
75 changes: 63 additions & 12 deletions src/components/select/bl-select.css
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,6 @@
display: none;
}

.remove-all::after {
content: "";
position: absolute;
left: 1.5rem;
bottom: 4px;
height: 1rem;
border-left: 1px solid var(--bl-color-neutral-lighter);
}

.selected .remove-all {
display: block;
}
Expand Down Expand Up @@ -193,7 +184,7 @@
display: flex;
align-items: center;
justify-content: center;
gap: var(--bl-size-2xs);
gap: var(--bl-size-4xs);
margin-left: var(--bl-size-2xs);
}

Expand All @@ -219,6 +210,15 @@
left: var(--left);
}

.popover-no-result {
display: flex;
flex-direction: column;
gap: var(--bl-size-2xs);
align-items: center;
justify-content: center;
height: 80px;
}

.select-open .popover {
display: flex;
border: solid 1px var(--border-focus-color);
Expand Down Expand Up @@ -263,8 +263,8 @@ legend span {
visibility: visible;
}

:where(.selected) .label,
:host(:not([placeholder]).select-open) .label {
:host([placeholder]) :where(.select-open, .selected) .label,
:host(:not([placeholder])) .selected .label {
display: none;
}

Expand Down Expand Up @@ -361,3 +361,54 @@ legend span {
bottom: 0;
border-bottom: 1px solid var(--bl-color-neutral-lighter);
}

.search-bar-input {
font: var(--bl-font-title-3-regular);
font-size: var(--font-size);
color: var(--text-color);
border: none;
outline: none;
background-color: transparent;
width: 100%;
height: 100%;
padding: 0;
margin: 0;
box-sizing: border-box;
}

.search-bar-input::placeholder {
color: var(--placeholder-color);
}

.search-bar-input:focus-visible {
outline: none;
}

.search-loading-icon {
animation: spin 1s linear infinite;
}

.action-divider {
display: none;
}

.select-wrapper .action-divider {
display: block;
height: 1rem;
width: 1px;
background-color: var(--bl-color-neutral-lighter);
}

@keyframes spin {
from {
transform: rotate(0deg);
}

to {
transform: rotate(360deg);
}
}

.actions bl-icon {
padding: 4px;
}
33 changes: 33 additions & 0 deletions src/components/select/bl-select.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ export const SelectTemplate = (args) => html`<bl-select
?success=${args.success}
?view-select-all=${args.viewSelectAll}
select-all-text=${ifDefined(args.selectAllText)}
?search-bar=${args.searchBar}
?search-bar-loading-state=${args.searchBarLoadingState}
search-bar-placeholder=${ifDefined(args.searchBarPlaceholder)}
size=${ifDefined(args.size)}
help-text=${ifDefined(args.helpText)}
invalid-text=${ifDefined(args.customInvalidText)}
Expand Down Expand Up @@ -192,6 +195,14 @@ The Select component features a 'Select All' option in the Multiple Select, whic
</Story>
</Canvas>

Select all is designed to operate on filtered results as well, selecting only those options that meet the filter.

<Canvas>
<Story name="Searchable with Select All" args={{ searchBar: true, searchBarPlaceholder: 'Search your options', multiple: true, viewSelectAll: true }}>
{SelectTemplate.bind({})}
</Story>
</Canvas>

## Clear Button

The select component includes a clear button. Clear button can be displayed by passing `clearable` attribute to the Select component.
Expand Down Expand Up @@ -249,6 +260,28 @@ Select component can be disabled by using `disabled` attribute.
</Story>
</Canvas>

## Searchable

<bl-badge icon="document">[ADR](https://github.com/Trendyol/baklava/issues/265#issuecomment-1845414216)</bl-badge>

Select component can be searchable by using `search-bar` attribute.

Display a loading icon in place of the search icon with using `search-bar-loading-state` attribute, seamlessly integrating it with your API endpoint to provide a smooth user experience during data retrieval.

<Canvas>
<Story name="Searchable" args={{ searchBar: true, searchBarPlaceholder: 'Search your options' }}>
{SelectTemplate.bind({})}
</Story>

<Story name="Searchable with Multiple Option" args={{ searchBar: true, searchBarPlaceholder: 'Search your options', multiple: true, viewSelectAll: true }}>
{SelectTemplate.bind({})}
</Story>

<Story name="Searchable with Loading State" args={{ searchBar: true, searchBarPlaceholder: 'Search your options', multiple: true, searchBarLoadingState: true }}>
{SelectTemplate.bind({})}
</Story>
</Canvas>

## `bl-select` Event

Select component fires `bl-select` event once selection changes. This event has a payload in the type of
Expand Down
143 changes: 140 additions & 3 deletions src/components/select/bl-select.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ describe("bl-select", () => {

expect(removeAll).to.exist;
expect(event).to.exist;
expect(event.detail).to.eql([]);
expect(event.detail).to.eql(null);
expect(el.options.length).to.equal(2);
expect(el.selectedOptions.length).to.equal(0);
expect(el.value).to.null;
Expand Down Expand Up @@ -246,7 +246,7 @@ describe("bl-select", () => {
const event = await oneEvent(el, "bl-select");

expect(event).to.exist;
expect(event.detail.length).to.equal(1);
expect(event.detail).to.exist;
expect(el.selectedOptions.length).to.equal(1);
});
it("should remove selected item if it is already selected", async () => {
Expand Down Expand Up @@ -280,6 +280,119 @@ describe("bl-select", () => {
expect(selectOption).is.not.exist;
});

it("should show search input if search-bar attribute is given", async () => {
const el = await fixture<BlSelect>(html`<bl-select search-bar>
<bl-select-option value="tr">Turkey</bl-select-option>
<bl-select-option value="en">United States of America</bl-select-option>
</bl-select>`);

const searchInput = el.shadowRoot?.querySelector<HTMLInputElement>("fieldset input");

expect(searchInput).to.exist;
});

it("should search 'Turkey' when 'turkey' is typed", async () => {
const el = await fixture<BlSelect>(html`<bl-select search-bar>
<bl-select-option value="tr">Turkey</bl-select-option>
<bl-select-option value="en">United States of America</bl-select-option>
</bl-select>`);

const searchInput = el.shadowRoot?.querySelector<HTMLInputElement>("fieldset input");

searchInput?.focus();

await sendKeys({
type: "turkey",
});

el.options.forEach(option => {
if (option.innerText === "Turkey") {
expect(option.hidden).to.be.false;
} else {
expect(option.hidden).to.be.true;
}
});
});

it("should show loading icon when the search loading state is true", async () => {
const el = await fixture<BlSelect>(html`<bl-select search-bar>
<bl-select-option value="tr">Turkey</bl-select-option>
<bl-select-option value="en">United States of America</bl-select-option>
</bl-select>`);

const searchInput = el.shadowRoot?.querySelector<HTMLInputElement>("fieldset input");

searchInput?.focus();

const loadingIcon = el.shadowRoot?.querySelector<HTMLInputElement>("fieldset bl-icon");

await sendKeys({
type: "turkey",
});

expect(loadingIcon).to.exist;
});

it("should be displayed a 'no result' message if the searched term does not match with any option", async () => {
const el = await fixture<BlSelect>(html`<bl-select search-bar>
<bl-select-option value="tr">Turkey</bl-select-option>
<bl-select-option value="en">United States of America</bl-select-option>
</bl-select>`);

const searchInput = el.shadowRoot?.querySelector<HTMLInputElement>("fieldset input");

searchInput?.focus();

await sendKeys({
type: "netherlands",
});

const noResultContainer = el.shadowRoot?.querySelector<HTMLInputElement>(".popover .popover-no-result");
const noResultMessage = el.shadowRoot?.querySelector<HTMLInputElement>(".popover .popover-no-result span")?.innerText;


el.options.forEach(option => {
expect(option.hidden).to.be.true;
});

expect(noResultContainer).to.exist;
expect(noResultMessage).to.equal("No Data Found");
});

it("should be cleared the search input if the user click on the clear search button", async () => {
const el = await fixture<BlSelect>(html`<bl-select search-bar>
<bl-select-option value="tr">Turkey</bl-select-option>
<bl-select-option value="en">United States of America</bl-select-option>
</bl-select>`);

const searchInput = el.shadowRoot?.querySelector<HTMLInputElement>("fieldset input");

searchInput?.focus();

await sendKeys({
type: "netherlands",
});

const clearSearchButton = el.shadowRoot?.querySelector<BlButton>(".popover .popover-no-result bl-button");

clearSearchButton?.click();

setTimeout(() => expect(searchInput?.value).to.equal(""));
});

it("should focus if one or more option selected already", async () => {
const el = await fixture<BlSelect>(html`<bl-select search-bar>
<bl-select-option value="tr">Turkey</bl-select-option>
<bl-select-option value="en">United States of America</bl-select-option>
</bl-select>`);

const dropdownIcon = el.shadowRoot?.querySelector<HTMLDivElement>(".dropdown-icon");

dropdownIcon?.click();

await(()=> expect(document.activeElement).to.equal(el));
});

describe("additional selection counter", () => {
let el: BlSelect;

Expand Down Expand Up @@ -649,5 +762,29 @@ describe("bl-select", () => {
expect(selectAll.indeterminate).to.be.false;
expect(selectAll.checked).to.be.false;
});
});
});

describe("events", () => {
it("should fire search event when 'turkey' is typed", async () => {
const el = await fixture<BlSelect>(html`<bl-select search-bar>
<bl-select-option value="tr">Turkey</bl-select-option>
<bl-select-option value="en">United States of America</bl-select-option>
</bl-select>`);

const searchInput = el.shadowRoot?.querySelector<HTMLInputElement>("fieldset input");

if (searchInput) {
searchInput.focus();

searchInput.value = "turkey";
}

setTimeout(() => searchInput?.dispatchEvent(new Event("input")));

const event = await oneEvent(el, "bl-search");

expect(event).to.exist;
expect(event.detail).to.equal("turkey");
});
});
});
Loading

0 comments on commit 69b3f6a

Please sign in to comment.