From 43b520877e45915bb51a01357ede04846a751f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aykut=20Sara=C3=A7?= Date: Fri, 27 Oct 2023 15:50:10 +0300 Subject: [PATCH 01/18] chore(react): refactor generate-react-exports (#725) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Simplifies the logic of `generate-react-exports.js` as types are inferred, removing the need of generics * Simplifies the React export making it more readable ```tsx /** * @tag bl-textarea * @summary Baklava Textarea component */ export const BlTextarea = React.lazy(() => customElements.whenDefined("bl-textarea").then(() => ({ default: createComponent({ react: React, displayName: "BlTextarea", tagName: "bl-textarea", elementClass: customElements.get("bl-textarea") as Constructor, events: { onBlInput: "bl-input" as EventName, onBlChange: "bl-change" as EventName, onBlInvalid: "bl-invalid" as EventName, }, }), })) ); ``` --------- Co-authored-by: Aykut Saraç --- .prettierrc.json | 1 + package-lock.json | 20 +++++++++++- package.json | 2 +- scripts/generate-react-exports.js | 53 ++++++++++++++++--------------- tsconfig.json | 3 +- 5 files changed, 49 insertions(+), 30 deletions(-) diff --git a/.prettierrc.json b/.prettierrc.json index be05741f..5799269f 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -8,6 +8,7 @@ "trailingComma": "es5", "useTabs": false, "importOrder": [ + "^react", "^lit", "", "^[./]", diff --git a/package-lock.json b/package-lock.json index f8469438..8e910f4e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2376,6 +2376,19 @@ "node": ">=8" } }, + "node_modules/@commitlint/load/node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/@commitlint/message": { "version": "16.2.1", "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-16.2.1.tgz", @@ -24629,7 +24642,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==", "dev": true, - "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -27600,6 +27612,12 @@ "requires": { "has-flag": "^4.0.0" } + }, + "typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true } } }, diff --git a/package.json b/package.json index ec978e51..ce549dad 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "serve": "node scripts/build.js --serve", "storybook:dev": "storybook dev -p 1994", "lint": "npm-run-all -s lint:*", - "lint:tsc": "tsc --noEmit", + "lint:tsc": "tsc --noEmit --project ./tsconfig.json", "lint:eslint": "eslint src", "lint:style": "stylelint src/**/*.css", "lint:prettier": "prettier --check src", diff --git a/scripts/generate-react-exports.js b/scripts/generate-react-exports.js index 474c6f00..cdeff8de 100644 --- a/scripts/generate-react-exports.js +++ b/scripts/generate-react-exports.js @@ -3,7 +3,7 @@ import { pascalCase } from "pascal-case"; import path from "path"; import { format } from "prettier"; import { fileURLToPath } from "url"; - +import prettierConfig from "../.prettierrc.json" assert { type: "json" }; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -24,43 +24,41 @@ const baklavaReactFileParts = []; for (const module of customElementsModules) { const { declarations, path } = module; - const componentDeclaration = declarations.find(declaration => declaration.customElement === true); - const { events, name: componentName, tagName: fileName, jsDoc } = componentDeclaration; + const component = declarations.find(declaration => declaration.customElement === true); + const { name: componentName, tagName: fileName } = component; - const eventNames = - events?.reduce((acc, curr) => { - acc[getReactEventName(curr.name)] = curr.name; - return acc; - }, {}) || {}; + const eventNames = (component.events || []).map(event => { + const reactEvent = getReactEventName(event.name); + const reactEventName = `${componentName}${reactEvent.split("onBl")[1]}`; + return `${reactEvent}: '${event.name}' as EventName<${reactEventName}>`; + }).join(',\n'); - const eventTypes = - events?.map(event => { - const eventName = getReactEventName(event.name); - const eventType = cleanGenericTypes(componentDeclaration.typeParameters, event.type.text); - const predefinedEventName = `${componentName}${eventName.split("onBl")[1]}`; + component.events?.forEach(event => { + const eventName = getReactEventName(event.name); + const eventType = cleanGenericTypes(component.typeParameters, event.type.text); + const predefinedEventName = `${componentName}${eventName.split("onBl")[1]}`; - eventStatements.push(`export declare type ${predefinedEventName} = ${eventType};`); - return `${eventName}: EventName<${predefinedEventName}>`; - }) || []; + eventStatements.push(`export declare type ${predefinedEventName} = ${eventType};`); + }); const importPath = path.replace(/^src\//, "").replace(/\.ts$/, ""); - const typeName = componentName + "Type"; - const formattedEventTypes = eventTypes.length ? `, {${eventTypes.join(", ")}}` : ""; - const componentType = `${typeName}${formattedEventTypes}`; - importStatements.push(`import type ${typeName} from "./${importPath}";`); - exportStatements.push(`export declare type ${componentName} = ${typeName}`); + importStatements.push(`export type ${componentName} = import("./${importPath}").default;`); + + const jsDoc = component.jsDoc || ""; const source = ` - ${jsDoc || ""} + ${jsDoc} export const ${componentName} = React.lazy(() => customElements.whenDefined('${fileName}').then(() => ({ - default: createComponent<${componentType}>({ + default: createComponent({ react: React, displayName: "${componentName}", tagName: "${fileName}", - elementClass: customElements.get("${fileName}"), - events: ${JSON.stringify(eventNames)}, + elementClass: customElements.get("${fileName}") as Constructor<${componentName}>, + events: { + ${eventNames} + }, }) })) ); @@ -76,16 +74,19 @@ function getReactEventName(baklavaEventName) { } function writeBaklavaReactFile(fileContentParts) { + const constructorType = `type Constructor = { new (): T };`; + const content = [ `/* eslint-disable @typescript-eslint/ban-ts-comment */`, `// @ts-nocheck`, ...importStatements, ...eventStatements, + constructorType, ...exportStatements, ...fileContentParts, ].join("\n\n"); - const formattedContent = format(content, { parser: "typescript" }); + const formattedContent = format(content, Object.assign(prettierConfig, { parser: "typescript" })); const outputPath = `${__dirname}/../src/baklava-react.ts`; fs.writeFileSync(outputPath, formattedContent); } diff --git a/tsconfig.json b/tsconfig.json index 46fc7bd2..9709a126 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -34,6 +34,5 @@ } ] }, - "include": ["./src/**/*.ts", "./src/**/*/*.test.ts"], - "exclude": [] + "include": ["src"], } From fd32b93fb37165f7f972c186c3848252e7bb2f4d Mon Sep 17 00:00:00 2001 From: Buse Selvi <106681486+buseselvi@users.noreply.github.com> Date: Thu, 2 Nov 2023 14:45:48 +0200 Subject: [PATCH 02/18] feat(icon): new icons added (#735) - camera_off - sound_off - photo_off - microphone - microphone_off - right_sided_arrow - left_sided_arrow icons added. --- src/components/icon/icon-list.ts | 7 +++++++ src/components/icon/icons/camera_off.svg | 4 ++++ src/components/icon/icons/left_sided_arrow.svg | 3 +++ src/components/icon/icons/microphone.svg | 3 +++ src/components/icon/icons/microphone_off.svg | 12 ++++++++++++ src/components/icon/icons/photo_off.svg | 3 +++ src/components/icon/icons/right_sided_arrow.svg | 3 +++ src/components/icon/icons/sound_off.svg | 4 ++++ 8 files changed, 39 insertions(+) create mode 100644 src/components/icon/icons/camera_off.svg create mode 100644 src/components/icon/icons/left_sided_arrow.svg create mode 100644 src/components/icon/icons/microphone.svg create mode 100644 src/components/icon/icons/microphone_off.svg create mode 100644 src/components/icon/icons/photo_off.svg create mode 100644 src/components/icon/icons/right_sided_arrow.svg create mode 100644 src/components/icon/icons/sound_off.svg diff --git a/src/components/icon/icon-list.ts b/src/components/icon/icon-list.ts index 88e09f87..8ea7f109 100644 --- a/src/components/icon/icon-list.ts +++ b/src/components/icon/icon-list.ts @@ -23,6 +23,7 @@ const icons = [ "burger", "calendar", "camera", + "camera_off", "campaign", "change", "change_fill", @@ -93,6 +94,7 @@ const icons = [ "info", "instagram", "label", + "left_sided_arrow", "light_bulb", "like", "link", @@ -117,6 +119,8 @@ const icons = [ "metric_decrease", "metric_increase", "metric_minus", + "microphone", + "microphone_off", "minus", "minus_fill", "mobile", @@ -149,6 +153,7 @@ const icons = [ "phone", "phone_settings", "photo", + "photo_off", "pie_chart", "pie_chart_report", "pin", @@ -167,6 +172,7 @@ const icons = [ "qr", "report", "review", + "right_sided_arrow", "rocket", "rotate", "sad", @@ -184,6 +190,7 @@ const icons = [ "shopping_bag_discount", "shopping_bag_return", "sorting", + "sound_off", "sound_on", "split_money", "star", diff --git a/src/components/icon/icons/camera_off.svg b/src/components/icon/icons/camera_off.svg new file mode 100644 index 00000000..1768dc69 --- /dev/null +++ b/src/components/icon/icons/camera_off.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/components/icon/icons/left_sided_arrow.svg b/src/components/icon/icons/left_sided_arrow.svg new file mode 100644 index 00000000..e3708fdb --- /dev/null +++ b/src/components/icon/icons/left_sided_arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/icon/icons/microphone.svg b/src/components/icon/icons/microphone.svg new file mode 100644 index 00000000..eb80e100 --- /dev/null +++ b/src/components/icon/icons/microphone.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/icon/icons/microphone_off.svg b/src/components/icon/icons/microphone_off.svg new file mode 100644 index 00000000..1d478ac0 --- /dev/null +++ b/src/components/icon/icons/microphone_off.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/components/icon/icons/photo_off.svg b/src/components/icon/icons/photo_off.svg new file mode 100644 index 00000000..05f6b28d --- /dev/null +++ b/src/components/icon/icons/photo_off.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/icon/icons/right_sided_arrow.svg b/src/components/icon/icons/right_sided_arrow.svg new file mode 100644 index 00000000..6fff9796 --- /dev/null +++ b/src/components/icon/icons/right_sided_arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/icon/icons/sound_off.svg b/src/components/icon/icons/sound_off.svg new file mode 100644 index 00000000..1305ab92 --- /dev/null +++ b/src/components/icon/icons/sound_off.svg @@ -0,0 +1,4 @@ + + + + From 43d6b0d50112de8ea4437bcd2b9bae6115fda593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aykut=20Sara=C3=A7?= Date: Thu, 23 Nov 2023 15:47:58 +0300 Subject: [PATCH 03/18] fix(select): select check additional count event loop (#743) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes select causing the window to be frozen on choosing x amount of options. This is caused by running `_checkAdditionalItemCount` within updated for each update instead of listening for selected options only. Co-authored-by: Aykut Saraç --- src/components/select/bl-select.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/select/bl-select.ts b/src/components/select/bl-select.ts index d96b09a0..3beac77b 100644 --- a/src/components/select/bl-select.ts +++ b/src/components/select/bl-select.ts @@ -488,7 +488,9 @@ export default class BlSelect extends Form this.value = null; } - this._checkAdditionalItemCount(); + if (_changedProperties.has("_selectedOptions")) { + this._checkAdditionalItemCount(); + } } /** From cb12aa687a9c86afdefd1ef6fdaa93a5ad7a8190 Mon Sep 17 00:00:00 2001 From: Ogun Babacan Date: Thu, 30 Nov 2023 17:06:16 +0300 Subject: [PATCH 04/18] feat: notification component (#741) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #141 --------- Signed-off-by: Ogun Babacan Co-authored-by: Aykut Saraç --- commitlint.config.cjs | 55 +- src/baklava.ts | 2 + src/components/alert/bl-alert.test.ts | 17 +- src/components/alert/bl-alert.ts | 6 +- src/components/dialog/bl-dialog.mdx | 8 + src/components/dialog/bl-dialog.test.ts | 6 +- src/components/dialog/bl-dialog.ts | 12 +- .../notification/bl-notification.css | 106 +++ .../notification/bl-notification.mdx | 111 +++ .../notification/bl-notification.stories.ts | 418 +++++++++++ .../notification/bl-notification.test.ts | 694 ++++++++++++++++++ .../notification/bl-notification.ts | 254 +++++++ .../card/bl-notification-card.css | 57 ++ .../card/bl-notification-card.test.ts | 192 +++++ .../notification/card/bl-notification-card.ts | 192 +++++ src/components/tooltip/bl-tooltip.test.ts | 14 +- src/utilities/elements.ts | 8 + 17 files changed, 2104 insertions(+), 48 deletions(-) create mode 100644 src/components/notification/bl-notification.css create mode 100644 src/components/notification/bl-notification.mdx create mode 100644 src/components/notification/bl-notification.stories.ts create mode 100644 src/components/notification/bl-notification.test.ts create mode 100644 src/components/notification/bl-notification.ts create mode 100644 src/components/notification/card/bl-notification-card.css create mode 100644 src/components/notification/card/bl-notification-card.test.ts create mode 100644 src/components/notification/card/bl-notification-card.ts create mode 100644 src/utilities/elements.ts diff --git a/commitlint.config.cjs b/commitlint.config.cjs index f4119dfc..5fed8d4e 100644 --- a/commitlint.config.cjs +++ b/commitlint.config.cjs @@ -1,35 +1,36 @@ module.exports = { - extends: ['@commitlint/config-conventional'], + extends: ["@commitlint/config-conventional"], rules: { - 'scope-enum': [ + "scope-enum": [ 2, - 'always', + "always", [ - 'storybook', - 'design', - 'react', - 'deps', - 'deps-dev', + "storybook", + "design", + "react", + "deps", + "deps-dev", // Components as scopes listed below - 'button', - 'icon', - 'input', - 'badge', - 'tab', - 'tooltip', - 'progress-indicator', - 'checkbox-group', - 'checkbox', - 'alert', - 'select', - 'pagination', - 'radio', - 'dialog', - 'drawer', - 'dropdown', - 'switch', - 'textarea', - 'popover', + "button", + "icon", + "input", + "badge", + "tab", + "tooltip", + "progress-indicator", + "checkbox-group", + "checkbox", + "alert", + "select", + "pagination", + "radio", + "dialog", + "drawer", + "dropdown", + "switch", + "textarea", + "popover", + "notification", ], ], }, diff --git a/src/baklava.ts b/src/baklava.ts index f6f7c0a2..43ab0fd7 100644 --- a/src/baklava.ts +++ b/src/baklava.ts @@ -23,4 +23,6 @@ export { default as BlDropdown } from "./components/dropdown/bl-dropdown"; export { default as BlDropdownItem } from "./components/dropdown/item/bl-dropdown-item"; export { default as BlDropdownGroup } from "./components/dropdown/group/bl-dropdown-group"; export { default as BlSwitch } from "./components/switch/bl-switch"; +export { default as BlNotification } from "./components/notification/bl-notification"; +export { default as BlNotificationCard } from "./components/notification/card/bl-notification-card"; export { getIconPath, setIconPath } from "./utilities/asset-paths"; diff --git a/src/components/alert/bl-alert.test.ts b/src/components/alert/bl-alert.test.ts index 064bf2fd..bf7f2299 100644 --- a/src/components/alert/bl-alert.test.ts +++ b/src/components/alert/bl-alert.test.ts @@ -147,12 +147,25 @@ describe("Slot", () => { const el = await fixture( html` Action Slot + Should not render this element Action Slot ` ); - const actionSlot = el.shadowRoot?.querySelector('slot[name="action"]'); - expect(actionSlot).to.exist; + const actionSlot = el.shadowRoot!.querySelector('slot[name="action"]') as HTMLSlotElement; + const [actionElement, actionSpanElement] = actionSlot.assignedElements(); + + expect(actionElement as HTMLElement).to.exist; + expect(actionElement.tagName).to.eq("BL-BUTTON"); + expect(actionSpanElement as HTMLElement).to.not.exist; + + const actionSecondarySlot = el.shadowRoot!.querySelector( + 'slot[name="action-secondary"]' + ) as HTMLSlotElement; + const actionSecondaryElement = actionSecondarySlot?.assignedElements()[0] as HTMLElement; + + expect(actionSecondaryElement).to.exist; + expect(actionSecondaryElement.tagName).to.eq("BL-BUTTON"); }); it("renders `action` slot empty when bl-button is not used", async () => { const el = await fixture( diff --git a/src/components/alert/bl-alert.ts b/src/components/alert/bl-alert.ts index c22b275d..207571e7 100644 --- a/src/components/alert/bl-alert.ts +++ b/src/components/alert/bl-alert.ts @@ -104,7 +104,7 @@ export default class BlAlert extends LitElement { private _initAlertActionSlot(event: Event) { const slotElement = event.target as HTMLSlotElement; - const slotElements = slotElement.assignedElements(); + const slotElements = slotElement.assignedElements({ flatten: true }); slotElements.forEach(element => { if (element.tagName !== "BL-BUTTON") { @@ -112,9 +112,9 @@ export default class BlAlert extends LitElement { return; } - (slotElement.parentElement as HTMLElement).style.display = "flex"; + (this.shadowRoot?.querySelector(".actions") as HTMLElement).style.display = "flex"; - const variant = element.slot === "action-secondary" ? "secondary" : "primary"; + const variant = slotElement.name === "action-secondary" ? "secondary" : "primary"; const buttonTypes: Record = { info: "default", warning: "neutral", diff --git a/src/components/dialog/bl-dialog.mdx b/src/components/dialog/bl-dialog.mdx index 2b25aad8..3709988b 100644 --- a/src/components/dialog/bl-dialog.mdx +++ b/src/components/dialog/bl-dialog.mdx @@ -94,6 +94,14 @@ document.querySelector("bl-dialog").addEventListener("bl-dialog-request-close", }); ``` +## Using HTML Dialog Element + +Starting from version 2.4.0 of Baklava, the `bl-dialog` component uses a polyfill implementation by default due to some quirks in the native HTML Dialog element. +This change was prompted by issues encountered during the development of the `bl-notification` component, where the native dialog element blocked any actions on it, event with Popover attribute. + +If you wish to use the native HTML Dialog element, you can do so by setting the `polyfilled` attribute to `false`. +Please note that this will cause notifications to render under the dialog backdrop. Prior to version 2.4.0, this was the default behavior. + ## Reference diff --git a/src/components/dialog/bl-dialog.test.ts b/src/components/dialog/bl-dialog.test.ts index 7f691084..7a0deaec 100644 --- a/src/components/dialog/bl-dialog.test.ts +++ b/src/components/dialog/bl-dialog.test.ts @@ -90,7 +90,7 @@ describe("bl-dialog", () => { window.HTMLDialogElement = htmlDialogElement; }); it("should render html dialog component with the default values when supports html dialog", async () => { - const el = await fixture(html``); + const el = await fixture(html``); assert.shadowDom.equal( el, @@ -132,7 +132,7 @@ describe("bl-dialog", () => { }); it("should close the dialog when the close btn is clicked", async () => { - const el = await fixture(html` + const el = await fixture(html`
My Content
`); const dialog = el.shadowRoot?.querySelector(".dialog") as HTMLDivElement; @@ -340,7 +340,7 @@ describe("bl-dialog", () => { }); it("should fire bl-dialog-request-close event when dialog closes by clicking backdrop", async () => { - const el = await fixture(html` + const el = await fixture(html` `); const dialog = el?.shadowRoot?.querySelector(".dialog"); diff --git a/src/components/dialog/bl-dialog.ts b/src/components/dialog/bl-dialog.ts index 2c76cc87..a7774259 100644 --- a/src/components/dialog/bl-dialog.ts +++ b/src/components/dialog/bl-dialog.ts @@ -48,9 +48,17 @@ export default class BlDialog extends LitElement { * using polyfill by setting this to true in some cases like to show some content on top of dialog * in case you are not able to use Popover API. Be aware that, polyfilled version can cause some * inconsistencies in terms of accessibility and stacking context. So use it with extra caution. + * + * As of the current implementation, you can render above the dialog HTML element using the Popover API. However, + * it will block any actions on the Popover element. This issue was encountered during the development of the `bl-notification` component. + * As a result, we decided to enable the polyfill for the `bl-dialog` component by default. If you prefer to use the native dialog, you can set + * this property to false. Please note, doing so will cause notifications to render under the dialog backdrop. + * For more information, refer to the comment linked below: + * + * https://github.com/Trendyol/baklava/issues/141#issuecomment-1810301413 */ @property({ type: Boolean, reflect: true }) - polyfilled = !window.HTMLDialogElement; + polyfilled = true; @query(".dialog") private dialog: HTMLDialogElement & DialogElement; @@ -176,7 +184,7 @@ export default class BlDialog extends LitElement { } render(): TemplateResult { - return this.polyfilled + return this.polyfilled || !window.HTMLDialogElement ? html`
${invalidMessage} ${helpMessage}
@@ -440,17 +480,54 @@ export default class BlSelect extends Form } } + private _handleSelectAll(e: CustomEvent) { + const selectAllEl = this.shadowRoot?.querySelector(".select-all") as BlCheckbox; + + const checked = e.detail; + const unselectedOptions = this._connectedOptions.filter(option => !option.selected); + const isAllUnselectedDisabled = unselectedOptions.every(option => option.disabled); + + // If all available options are selected, instead of checking, uncheck all options + if (checked && isAllUnselectedDisabled) { + setTimeout(() => { + const checkbox = selectAllEl?.shadowRoot?.querySelector("input"); + + checkbox?.click(); + }, 0); + return; + } + + this._connectedOptions.forEach(option => { + if (option.disabled) { + return; + } + + option.selected = checked; + }); + + this._handleMultipleSelect(); + + // Make sure the checkbox state is in sync with selected options + setTimeout(() => { + selectAllEl.checked = this.isAllSelected; + selectAllEl.indeterminate = this._selectedOptions.length > 0 && !this.isAllSelected; + }); + } + private _onClickRemove(e: MouseEvent) { e.stopPropagation(); + const selectedDisabledOptions = this._selectedOptions.filter(option => option.disabled); + this._connectedOptions - .filter(option => option.selected) + .filter(option => !option.disabled && option.selected) .forEach(option => { option.selected = false; }); - this.value = null; - this._additionalSelectedOptionCount = 0; + this.value = selectedDisabledOptions.length + ? selectedDisabledOptions.map(option => option.value) + : null; this._handleSelectEvent(); } From ecc8a30c9c3e38194b239aa6f77de331427ba40b Mon Sep 17 00:00:00 2001 From: Levent Anil Ozen Date: Fri, 15 Dec 2023 15:31:19 +0300 Subject: [PATCH 07/18] fix(select): change select all default behaviour to off (#750) Closes #749 --- src/components/select/bl-select.css | 2 +- src/components/select/bl-select.stories.mdx | 10 +++++----- src/components/select/bl-select.test.ts | 10 +++++----- src/components/select/bl-select.ts | 8 ++++---- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/components/select/bl-select.css b/src/components/select/bl-select.css index 4fadb168..6a7621fa 100644 --- a/src/components/select/bl-select.css +++ b/src/components/select/bl-select.css @@ -29,7 +29,7 @@ --popover-position: var(--bl-popover-position, fixed); } -:host([multiple]:not([hide-select-all])) .select-wrapper { +:host([multiple][view-select-all]) .select-wrapper { --menu-height: 290px; } diff --git a/src/components/select/bl-select.stories.mdx b/src/components/select/bl-select.stories.mdx index 1451e886..efc1258b 100644 --- a/src/components/select/bl-select.stories.mdx +++ b/src/components/select/bl-select.stories.mdx @@ -98,7 +98,7 @@ export const SelectTemplate = (args) => html` {SelectTemplate.bind({})} - + {SelectTemplate.bind({})} diff --git a/src/components/select/bl-select.test.ts b/src/components/select/bl-select.test.ts index 5336123d..9d6bd469 100644 --- a/src/components/select/bl-select.test.ts +++ b/src/components/select/bl-select.test.ts @@ -539,7 +539,7 @@ describe("bl-select", () => { describe("select all", () => { it("should select all options", async () => { - const el = await fixture(html` + const el = await fixture(html` Option 1 Option 2 Option 3 @@ -561,7 +561,7 @@ describe("bl-select", () => { }); it("should deselect all options", async () => { - const el = await fixture(html` + const el = await fixture(html` Option 1 Option 2 Option 3 @@ -585,7 +585,7 @@ describe("bl-select", () => { }); it("should not act on disabled options", async () => { - const el = await fixture(html` + const el = await fixture(html` Option 1 Option 2 Option 3 @@ -608,7 +608,7 @@ describe("bl-select", () => { }); it("should display indeterminate state when some options are selected", async () => { - const el = await fixture(html` + const el = await fixture(html` Option 1 Option 2 Option 3 @@ -623,7 +623,7 @@ describe("bl-select", () => { }); it('should uncheck "select all" checkbox when all available options are selected', async () => { - const el = await fixture(html` + const el = await fixture(html` Option 1 Option 2 Option 3 diff --git a/src/components/select/bl-select.ts b/src/components/select/bl-select.ts index 77f82bf7..dbff8254 100644 --- a/src/components/select/bl-select.ts +++ b/src/components/select/bl-select.ts @@ -145,10 +145,10 @@ export default class BlSelect extends Form customInvalidText?: string; /** - * Hides select all option in multiple select + * Views select all option in multiple select */ - @property({ type: Boolean, attribute: "hide-select-all" }) - hideSelectAll = false; + @property({ type: Boolean, attribute: "view-select-all" }) + viewSelectAll = false; /** * Sets select all text in multiple select @@ -353,7 +353,7 @@ export default class BlSelect extends Form } selectAllTemplate() { - if (!this.multiple || this.hideSelectAll) { + if (!this.multiple || !this.viewSelectAll) { return null; } From 1d5f767df275f5d9f9d26b392c4236aeee193958 Mon Sep 17 00:00:00 2001 From: Erbil Date: Thu, 11 Jan 2024 14:42:43 +0300 Subject: [PATCH 08/18] feat(select): add search feature for select (#759) Closes #265 I've pushed the commit unverified as I'm facing operating system-related test errors on my local machine. Despite my efforts, I couldn't resolve the issue. I've opened an issue on [the relevant project](https://github.com/modernweb-dev/web) for further investigation. https://github.com/modernweb-dev/web/issues/2589 --------- Co-authored-by: Erbil Nas Co-authored-by: Ogun Babacan --- src/components/select/bl-select.css | 71 +++++- src/components/select/bl-select.stories.mdx | 33 +++ src/components/select/bl-select.test.ts | 139 +++++++++++- src/components/select/bl-select.ts | 211 +++++++++++++++--- .../select/option/bl-select-option.css | 4 + 5 files changed, 421 insertions(+), 37 deletions(-) diff --git a/src/components/select/bl-select.css b/src/components/select/bl-select.css index 6a7621fa..ad68bf2c 100644 --- a/src/components/select/bl-select.css +++ b/src/components/select/bl-select.css @@ -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; } @@ -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); } @@ -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); @@ -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; +} diff --git a/src/components/select/bl-select.stories.mdx b/src/components/select/bl-select.stories.mdx index efc1258b..bc0fa702 100644 --- a/src/components/select/bl-select.stories.mdx +++ b/src/components/select/bl-select.stories.mdx @@ -100,6 +100,9 @@ export const SelectTemplate = (args) => html` +Select all is designed to operate on filtered results as well, selecting only those options that meet the filter. + + + + {SelectTemplate.bind({})} + + + ## Clear Button The select component includes a clear button. Clear button can be displayed by passing `clearable` attribute to the Select component. @@ -249,6 +260,28 @@ Select component can be disabled by using `disabled` attribute. +## Searchable + +[ADR](https://github.com/Trendyol/baklava/issues/265#issuecomment-1845414216) + +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. + + + + {SelectTemplate.bind({})} + + + + {SelectTemplate.bind({})} + + + + {SelectTemplate.bind({})} + + + ## `bl-select` Event Select component fires `bl-select` event once selection changes. This event has a payload in the type of diff --git a/src/components/select/bl-select.test.ts b/src/components/select/bl-select.test.ts index 9d6bd469..a2304e4c 100644 --- a/src/components/select/bl-select.test.ts +++ b/src/components/select/bl-select.test.ts @@ -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(html` + Turkey + United States of America + `); + + const searchInput = el.shadowRoot?.querySelector("fieldset input"); + + expect(searchInput).to.exist; + }); + + it("should search 'Turkey' when 'turkey' is typed", async () => { + const el = await fixture(html` + Turkey + United States of America + `); + + const searchInput = el.shadowRoot?.querySelector("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(html` + Turkey + United States of America + `); + + const searchInput = el.shadowRoot?.querySelector("fieldset input"); + + searchInput?.focus(); + + const loadingIcon = el.shadowRoot?.querySelector("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(html` + Turkey + United States of America + `); + + const searchInput = el.shadowRoot?.querySelector("fieldset input"); + + searchInput?.focus(); + + await sendKeys({ + type: "netherlands", + }); + + const noResultContainer = el.shadowRoot?.querySelector(".popover .popover-no-result"); + const noResultMessage = el.shadowRoot?.querySelector(".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(html` + Turkey + United States of America + `); + + const searchInput = el.shadowRoot?.querySelector("fieldset input"); + + searchInput?.focus(); + + await sendKeys({ + type: "netherlands", + }); + + const clearSearchButton = el.shadowRoot?.querySelector(".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(html` + Turkey + United States of America + `); + + const dropdownIcon = el.shadowRoot?.querySelector(".dropdown-icon"); + + dropdownIcon?.click(); + + await(()=> expect(document.activeElement).to.equal(el)); + }); + describe("additional selection counter", () => { let el: BlSelect; @@ -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(html` + Turkey + United States of America + `); + + const searchInput = el.shadowRoot?.querySelector("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"); + }); + }); }); diff --git a/src/components/select/bl-select.ts b/src/components/select/bl-select.ts index dbff8254..b8fc4610 100644 --- a/src/components/select/bl-select.ts +++ b/src/components/select/bl-select.ts @@ -156,6 +156,36 @@ export default class BlSelect extends Form @property({ type: String, attribute: "select-all-text" }) selectAllText = "Select All"; + /** + * Enable search functionality for the options within the list + */ + @property({ type: Boolean, attribute: "search-bar", reflect: true }) + searchBar = false; + + /** + * Search for text variations such as "search," "searching," "search by country," and so on + */ + @property({ type: String, attribute: "search-bar-placeholder", reflect: true }) + searchBarPlaceholder?: string; + + /** + * Display a loading icon in place of the search icon. + */ + @property({ type: Boolean, attribute: "search-bar-loading-state", reflect: true }) + searchBarLoadingState = false; + + /** + * Text to display when no search results are found. + */ + @property({ type: String, attribute: "search-not-found-text", reflect: true }) + searchNotFoundText = "No Data Found"; + + /** + * Text to display on the clear search button. + */ + @property({ type: String, attribute: "popover-clear-search-text", reflect: true }) + popoverClearSearchText = "Clear Search"; + /* Declare internal reactive properties */ @state() private _isPopoverOpen = false; @@ -163,6 +193,9 @@ export default class BlSelect extends Form @state() private _additionalSelectedOptionCount = 0; + @state() + private _searchText = ""; + @query(".selected-options") private selectedOptionsContainer!: HTMLElement; @@ -180,6 +213,11 @@ export default class BlSelect extends Form */ @event("bl-select") private _onBlSelect: EventDispatcher[]>; + /** + * Fires when search text changes + */ + @event("bl-search") private _onBlSearch: EventDispatcher; + private _connectedOptions: BlSelectOption[] = []; private _cleanUpPopover: CleanUpFunction | null = null; @@ -203,6 +241,10 @@ export default class BlSelect extends Form return this._isPopoverOpen; } + get noResultFound() { + return this._searchText !== "" && this._connectedOptions.every(option => option.hidden); + } + @state() private _selectedOptions: BlSelectOption[] = []; @@ -217,10 +259,6 @@ export default class BlSelect extends Form return this._additionalSelectedOptionCount; } - get isAllSelected() { - return this._selectedOptions.length === this._connectedOptions.length; - } - validityCallback(): string | void { if (this.customInvalidText) { return this.customInvalidText; @@ -245,6 +283,12 @@ export default class BlSelect extends Form validationTarget: HTMLElement; open() { + if (this.searchBar) { + setTimeout(() => { + document.activeElement?.shadowRoot?.querySelector("input")?.focus(); + }, 100); + } + this._isPopoverOpen = true; this._setupPopover(); document.addEventListener("click", this._interactOutsideHandler, true); @@ -252,6 +296,10 @@ export default class BlSelect extends Form } close() { + this._handleSearchOptions({ target: { value: "" } } as InputEvent & { + target: HTMLInputElement; + }); + this._isPopoverOpen = false; this.focusedOptionIndex = -1; this._cleanUpPopover && this._cleanUpPopover(); @@ -325,46 +373,109 @@ export default class BlSelect extends Form >` : ""; - return html`
0; + + const isDividerShown = isSearchBarVisible || isMultipleWithSelection; + + const searchMagIcon = html``; + + const searchLoadingIcon = html``; + + const actionDivider = isDividerShown ? html`
` : ""; + + const search = html`
0, })} tabindex="${this.disabled ? "-1" : 0}" - ?autofocus=${this.autofocus} - @click=${this.togglePopover} role="button" aria-haspopup="listbox" aria-expanded="${this.opened}" aria-labelledby="label" + @click=${this.open} > ${this.label} - ${this.placeholder} - ${this.label} - ${inputSelectedOptions} - +${this._additionalSelectedOptionCount} -
- ${removeButton} + + ${this._selectedOptions.length > 0 && !this.opened + ? inputSelectedOptions + : html` + + `} + ${!this.opened + ? html`+${this._additionalSelectedOptionCount}` + : ""} + +
+ ${this.opened ? (this.searchBarLoadingState ? searchLoadingIcon : searchMagIcon) : ""} + ${!this.opened ? removeButton : ""} ${actionDivider}
`; + + return this.searchBar + ? search + : html`
0, + })} + tabindex="${this.disabled ? "-1" : 0}" + ?autofocus=${this.autofocus} + @click=${this.togglePopover} + role="button" + aria-haspopup="listbox" + aria-expanded="${this.opened}" + aria-labelledby="label" + > + ${this.label} + ${this.placeholder} + ${this.label} + ${inputSelectedOptions} + +${this._additionalSelectedOptionCount} +
+ ${removeButton} ${actionDivider} + + + +
+
`; } selectAllTemplate() { - if (!this.multiple || !this.viewSelectAll) { + if (!this.multiple || !this.viewSelectAll || this.noResultFound) { return null; } - const isAnySelected = this._selectedOptions.length > 0; + const isAllRenderedOptionsSelected = this._connectedOptions + .filter(option => !option.hidden) + .every(option => option.selected); + const isAnySelected = this._selectedOptions.filter(option => !option.hidden).length > 0; return html` ${this.selectAllText} @@ -403,6 +514,20 @@ export default class BlSelect extends Form > ${this.selectAllTemplate()} + ${this.searchBar && this.noResultFound + ? html`
+ ${this.searchNotFoundText} + { + this._handleSearchOptions({ target: { value: "" } } as InputEvent & { + target: HTMLInputElement; + }); + }} + >${this.popoverClearSearchText} +
` + : ""}
${invalidMessage} ${helpMessage}
`; @@ -453,6 +578,44 @@ export default class BlSelect extends Form ); } + private _handleSearchEvent() { + this._onBlSearch(this._searchText); + } + + private _handleSearchOptions(e: InputEvent): void { + if (!this.searchBar) return; + + this._searchText = (e.target as HTMLInputElement).value; + + this._handleSearchEvent(); + + this._connectedOptions.forEach(option => { + const isVisible = option.textContent?.toLowerCase().includes(this._searchText.toLowerCase()); + + option.hidden = !isVisible; + }); + + this._selectedOptions = this.options.filter(option => option.selected); + + this._handleLastVisibleSearchedOption(); + + this.requestUpdate(); + } + + private _handleLastVisibleSearchedOption() { + const lastVisibleOption = [...this.options].reverse().find(option => !option.hidden); + + if (lastVisibleOption) { + lastVisibleOption?.shadowRoot?.querySelector("div")?.classList.add("no-border-bottom"); + } + + this.options.map(option => { + if (!option.hidden && option !== lastVisibleOption) { + option.shadowRoot?.querySelector("div")?.classList.remove("no-border-bottom"); + } + }); + } + private _handleSingleSelect(optionItem: BlSelectOption) { this.value = optionItem.value; @@ -484,7 +647,9 @@ export default class BlSelect extends Form const selectAllEl = this.shadowRoot?.querySelector(".select-all") as BlCheckbox; const checked = e.detail; - const unselectedOptions = this._connectedOptions.filter(option => !option.selected); + const unselectedOptions = this._connectedOptions.filter( + option => !option.selected && !option.hidden + ); const isAllUnselectedDisabled = unselectedOptions.every(option => option.disabled); // If all available options are selected, instead of checking, uncheck all options @@ -498,7 +663,7 @@ export default class BlSelect extends Form } this._connectedOptions.forEach(option => { - if (option.disabled) { + if (option.disabled || option.hidden) { return; } @@ -506,12 +671,6 @@ export default class BlSelect extends Form }); this._handleMultipleSelect(); - - // Make sure the checkbox state is in sync with selected options - setTimeout(() => { - selectAllEl.checked = this.isAllSelected; - selectAllEl.indeterminate = this._selectedOptions.length > 0 && !this.isAllSelected; - }); } private _onClickRemove(e: MouseEvent) { diff --git a/src/components/select/option/bl-select-option.css b/src/components/select/option/bl-select-option.css index 83d55bf5..8739cdf1 100644 --- a/src/components/select/option/bl-select-option.css +++ b/src/components/select/option/bl-select-option.css @@ -22,6 +22,10 @@ border-bottom: var(--option-separator); } +.no-border-bottom::after { + border-bottom: none; +} + :host(:last-of-type) .option-container::after { border-bottom: none; } From 1b5a10e08a2a9416e2aa9c61cd133e433daa2ce1 Mon Sep 17 00:00:00 2001 From: Fatih Date: Thu, 11 Jan 2024 14:43:11 +0300 Subject: [PATCH 09/18] =?UTF-8?q?fix(select):=20Using=20label=20and=20plac?= =?UTF-8?q?eholder=20on=20non=20label-fixed=20select=20br=E2=80=A6=20(#760?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …eaks input styling --- src/components/select/bl-select.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/select/bl-select.css b/src/components/select/bl-select.css index ad68bf2c..2e77a12d 100644 --- a/src/components/select/bl-select.css +++ b/src/components/select/bl-select.css @@ -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; } From a99ff416883f54d210b5a42e97ce73e159b50c14 Mon Sep 17 00:00:00 2001 From: Ogun Babacan Date: Thu, 11 Jan 2024 14:48:23 +0300 Subject: [PATCH 10/18] feat: add info color and implement it on alert and notification (#761) Implement new color: Info. Uptadate alert and notification components info variant color with the new color and update radius to match design document. Also update tooltip component default background color to info. This change can be overridden by `--bl-popover-background-color` variable. Closes #685 --- docs/design-system/colors.stories.mdx | 5 +++++ src/components/alert/bl-alert.css | 6 +++--- src/components/alert/bl-alert.ts | 2 +- src/components/notification/card/bl-notification-card.css | 2 +- src/components/tooltip/bl-tooltip.css | 2 +- src/themes/default.css | 5 +++++ 6 files changed, 16 insertions(+), 6 deletions(-) diff --git a/docs/design-system/colors.stories.mdx b/docs/design-system/colors.stories.mdx index 00e60daf..0ca26d40 100644 --- a/docs/design-system/colors.stories.mdx +++ b/docs/design-system/colors.stories.mdx @@ -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)' }} /> + = { - info: "default", + info: "neutral", warning: "neutral", success: "success", danger: "danger", diff --git a/src/components/notification/card/bl-notification-card.css b/src/components/notification/card/bl-notification-card.css index 454539c5..1d6b80e2 100644 --- a/src/components/notification/card/bl-notification-card.css +++ b/src/components/notification/card/bl-notification-card.css @@ -53,5 +53,5 @@ } .notification[variant="info"] .duration > .remaining { - background-color: var(--bl-color-primary); + background-color: var(--bl-color-info); } diff --git a/src/components/tooltip/bl-tooltip.css b/src/components/tooltip/bl-tooltip.css index b73f78dc..af4e6f3c 100644 --- a/src/components/tooltip/bl-tooltip.css +++ b/src/components/tooltip/bl-tooltip.css @@ -8,7 +8,7 @@ } bl-popover { - --bl-popover-background-color: var(--bl-color-neutral-darker); + --bl-popover-background-color: var(--bl-color-info); --bl-popover-arrow-display: block; --bl-popover-border-size: 0px; --bl-popover-max-width: 424px; diff --git a/src/themes/default.css b/src/themes/default.css index 4f850579..ba03fad5 100644 --- a/src/themes/default.css +++ b/src/themes/default.css @@ -21,6 +21,11 @@ --bl-color-warning-highlight: #ff9800; --bl-color-warning-contrast: #fff8e6; + /* Info Color */ + --bl-color-info: #5794ff; + --bl-color-info-highlight: #457eff; + --bl-color-info-contrast: #eef4ff; + /* Neutral Color */ --bl-color-neutral-none: #000; --bl-color-neutral-darkest: #0f131a; From 230448534f3973c7c41e4715e81c2dce62c995d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aykut=20Sara=C3=A7?= Date: Thu, 11 Jan 2024 14:58:05 +0300 Subject: [PATCH 11/18] fix(select): return single value for single select (#677) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixes #675 Co-authored-by: Aykut Saraç Co-authored-by: Levent Anil Ozen --- src/components/select/bl-select.test.ts | 4 ++-- src/components/select/bl-select.ts | 23 +++++++++++++---------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/components/select/bl-select.test.ts b/src/components/select/bl-select.test.ts index a2304e4c..10636950 100644 --- a/src/components/select/bl-select.test.ts +++ b/src/components/select/bl-select.test.ts @@ -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; @@ -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 () => { diff --git a/src/components/select/bl-select.ts b/src/components/select/bl-select.ts index b8fc4610..03718514 100644 --- a/src/components/select/bl-select.ts +++ b/src/components/select/bl-select.ts @@ -211,7 +211,9 @@ export default class BlSelect extends Form /** * Fires when selection changes */ - @event("bl-select") private _onBlSelect: EventDispatcher[]>; + @event("bl-select") private _onBlSelect: EventDispatcher< + ISelectOption[] | ISelectOption + >; /** * Fires when search text changes @@ -566,16 +568,17 @@ export default class BlSelect extends Form } private _handleSelectEvent() { - this._onBlSelect( - this._selectedOptions.map( - option => - ({ - value: option.value, - selected: option.selected, - text: option.textContent, - } as ISelectOption) - ) + const options = this._selectedOptions.map( + option => + ({ + value: option.value, + selected: option.selected, + text: option.textContent, + } as ISelectOption) ); + + if (!this.multiple) this._onBlSelect(options[0]); + else this._onBlSelect(options); } private _handleSearchEvent() { From 170b707933cd1f3c40156ad5c70e3ccc5a3f8ed4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mustafa=20Ate=C5=9F=20UZUN?= Date: Thu, 11 Jan 2024 15:15:09 +0300 Subject: [PATCH 12/18] feat(switch): add bl-switch label (#754) https://github.com/Trendyol/baklava/issues/747 --- src/components/switch/bl-switch.css | 27 +++++++++++++++++++++ src/components/switch/bl-switch.stories.mdx | 7 +----- src/components/switch/bl-switch.test.ts | 7 +++++- src/components/switch/bl-switch.ts | 24 +++++++++--------- 4 files changed, 47 insertions(+), 18 deletions(-) diff --git a/src/components/switch/bl-switch.css b/src/components/switch/bl-switch.css index 4f3464cb..8d821082 100644 --- a/src/components/switch/bl-switch.css +++ b/src/components/switch/bl-switch.css @@ -1,6 +1,7 @@ :host { display: inline-block; cursor: pointer; + vertical-align: middle; } span { @@ -40,6 +41,32 @@ span { width: var(--thumb-width); } +label { + display: flex; + gap: var(--bl-size-2xs); + color: var(--bl-color-neutral-darker); + font: var(--bl-font-title-3); + cursor: pointer; + user-select: none; + line-height: normal; + align-items: center; + margin-block: 0; +} + +.label { + overflow-wrap: anywhere; +} + +:host([disabled]) .label { + color: var(--bl-color-neutral-light); + border: 1px solid var(--bl-color-neutral-lighter); +} + +:host([checked]) .label, +:host(:hover) .label { + color: var(--bl-color-primary); +} + :host([checked]) .switch { --switch-color: var(--bl-switch-color-on, var(--bl-switch-color, var(--bl-color-primary))); } diff --git a/src/components/switch/bl-switch.stories.mdx b/src/components/switch/bl-switch.stories.mdx index bc984b17..1cc5bacf 100644 --- a/src/components/switch/bl-switch.stories.mdx +++ b/src/components/switch/bl-switch.stories.mdx @@ -26,14 +26,11 @@ export const SwitchTemplate = (args) => html` `; export const SwitchWithLabel = (args) => html` -
- -
+ >${args.label} `; export const SwitchStyled = args => html` @@ -75,8 +72,6 @@ Switch is _Off_ by default. Switch with label. -Inline styles in this example are only for **demo purposes**. Use regular CSS classes or tag selectors to set styles. - {SwitchWithLabel.bind({})} diff --git a/src/components/switch/bl-switch.test.ts b/src/components/switch/bl-switch.test.ts index 74557798..7c566876 100644 --- a/src/components/switch/bl-switch.test.ts +++ b/src/components/switch/bl-switch.test.ts @@ -15,13 +15,18 @@ describe("bl-switch", () => { assert.shadowDom.equal( el, ` + ` ); }); diff --git a/src/components/switch/bl-switch.ts b/src/components/switch/bl-switch.ts index 8e624f0a..c58705a1 100644 --- a/src/components/switch/bl-switch.ts +++ b/src/components/switch/bl-switch.ts @@ -56,17 +56,19 @@ export default class BlSwitch extends LitElement { this.ariaLabel ?? this.attributes.getNamedItem("aria-label")?.value ?? undefined; return html` - - + `; } } From 63915ca0676929f7748866d06498f5446e2f0b22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Murat=20=C3=87orlu?= <127687+muratcorlu@users.noreply.github.com> Date: Thu, 11 Jan 2024 14:08:38 +0100 Subject: [PATCH 13/18] fix(dropdown): dropdown group borders are not visible (#589) This PR does small refactor on Dropdown component. * Default text for dropdown button is removed. * `aria-label` for `bl-button` inside removed, since it's not needed when we have a text inside the button. --------- Co-authored-by: Levent Anil Ozen --- package-lock.json | 18 +++++----- package.json | 2 +- src/components/dropdown/bl-dropdown.css | 6 ++++ .../dropdown/bl-dropdown.stories.mdx | 12 +++---- src/components/dropdown/bl-dropdown.test.ts | 25 +++++++------ src/components/dropdown/bl-dropdown.ts | 13 ++++--- .../dropdown/group/bl-dropdown-group.css | 10 ++++-- .../group/bl-dropdown-group.stories.mdx | 35 +++++++++++++------ 8 files changed, 72 insertions(+), 49 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8e910f4e..9468c947 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,7 +32,7 @@ "@storybook/addon-mdx-gfm": "^7.4.3", "@storybook/addon-viewport": "^7.4.3", "@storybook/jest": "^0.2.2", - "@storybook/testing-library": "^0.2.0", + "@storybook/testing-library": "^0.2.2", "@storybook/web-components": "7.4.3", "@storybook/web-components-vite": "^7.4.3", "@trivago/prettier-plugin-sort-imports": "^4.1.1", @@ -6654,13 +6654,13 @@ } }, "node_modules/@storybook/testing-library": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@storybook/testing-library/-/testing-library-0.2.1.tgz", - "integrity": "sha512-AdbfLCm1C2nEFrhA3ScdicfW6Fjcorehr6RlGwECMiWwaXisnP971Wd4psqtWxlAqQo4tYBZ0f6rJ3J78JLtsg==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@storybook/testing-library/-/testing-library-0.2.2.tgz", + "integrity": "sha512-L8sXFJUHmrlyU2BsWWZGuAjv39Jl1uAqUHdxmN42JY15M4+XCMjGlArdCCjDe1wpTSW6USYISA9axjZojgtvnw==", "dev": true, "dependencies": { "@testing-library/dom": "^9.0.0", - "@testing-library/user-event": "~14.4.0", + "@testing-library/user-event": "^14.4.0", "ts-dedent": "^2.2.0" } }, @@ -30501,13 +30501,13 @@ } }, "@storybook/testing-library": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@storybook/testing-library/-/testing-library-0.2.1.tgz", - "integrity": "sha512-AdbfLCm1C2nEFrhA3ScdicfW6Fjcorehr6RlGwECMiWwaXisnP971Wd4psqtWxlAqQo4tYBZ0f6rJ3J78JLtsg==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@storybook/testing-library/-/testing-library-0.2.2.tgz", + "integrity": "sha512-L8sXFJUHmrlyU2BsWWZGuAjv39Jl1uAqUHdxmN42JY15M4+XCMjGlArdCCjDe1wpTSW6USYISA9axjZojgtvnw==", "dev": true, "requires": { "@testing-library/dom": "^9.0.0", - "@testing-library/user-event": "~14.4.0", + "@testing-library/user-event": "^14.4.0", "ts-dedent": "^2.2.0" } }, diff --git a/package.json b/package.json index ce549dad..155020c8 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ "@storybook/addon-mdx-gfm": "^7.4.3", "@storybook/addon-viewport": "^7.4.3", "@storybook/jest": "^0.2.2", - "@storybook/testing-library": "^0.2.0", + "@storybook/testing-library": "^0.2.2", "@storybook/web-components": "7.4.3", "@storybook/web-components-vite": "^7.4.3", "@trivago/prettier-plugin-sort-imports": "^4.1.1", diff --git a/src/components/dropdown/bl-dropdown.css b/src/components/dropdown/bl-dropdown.css index 197dc474..e039684e 100644 --- a/src/components/dropdown/bl-dropdown.css +++ b/src/components/dropdown/bl-dropdown.css @@ -14,3 +14,9 @@ :host([kind="danger"]) bl-popover { --bl-popover-border-color: var(--bl-color-danger); } + +.popover-content { + display: flex; + flex-direction: column; + gap: var(--bl-size-xs); +} diff --git a/src/components/dropdown/bl-dropdown.stories.mdx b/src/components/dropdown/bl-dropdown.stories.mdx index bb9a2d4c..8ca805a5 100644 --- a/src/components/dropdown/bl-dropdown.stories.mdx +++ b/src/components/dropdown/bl-dropdown.stories.mdx @@ -92,7 +92,7 @@ Dropdown Button has the same variants ([Primary](/docs/components-button--primar Every variant represents the importance of the actions inside it. - + {Template.bind({})} @@ -103,7 +103,7 @@ Dropdown Button has the same kinds as the button has. Every kind indicates a state of the dropdown buttons. It can has 4 different "kind"s. `default`, `neutral`, `success` and `danger`. - + {ButtonTypes.bind({})} @@ -113,7 +113,7 @@ Every kind indicates a state of the dropdown buttons. It can has 4 different "ki We have 3 sizes of dropdown buttons: **Large**, **Medium**, **Small**. Default size is **Medium**. - + {SizesTemplate.bind({})} @@ -121,7 +121,7 @@ We have 3 sizes of dropdown buttons: **Large**, **Medium**, **Small**. Default s If dropdown button has an action with a long text that can not fit in a single line, popover will be automatically widen to the right side of the dropdown button. - + {SingleDropdownButtonTemplate.bind({})} @@ -131,7 +131,7 @@ If dropdown button has an action with a long text that can not fit in a single l We have 2 types of disabled dropdown buttons: Disable version of Primary and Secondary buttons is the same. - + {SizesTemplate.bind({})} @@ -139,7 +139,7 @@ We have 2 types of disabled dropdown buttons: Disable version of Primary and Sec Whereas Tertiary buttons keep their transparent backgrounds. - + {SizesTemplate.bind({})} diff --git a/src/components/dropdown/bl-dropdown.test.ts b/src/components/dropdown/bl-dropdown.test.ts index b2efc56b..159a02e9 100644 --- a/src/components/dropdown/bl-dropdown.test.ts +++ b/src/components/dropdown/bl-dropdown.test.ts @@ -23,7 +23,7 @@ describe("bl-dropdown", () => { }); it("should render with the default values", async () => { - const el = await fixture(html``); + const el = await fixture(html``); assert.shadowDom.equal( el, @@ -33,17 +33,16 @@ describe("bl-dropdown", () => { kind="default" size="medium" variant="primary" - aria-label="Dropdown Button" > Dropdown Button - +
` ); }); it("should open dropdown", async () => { - const el = await fixture(html``); + const el = await fixture(html``); const buttonHost = el.shadowRoot?.querySelector("bl-button"); const button = buttonHost.shadowRoot?.querySelector(".button") as HTMLElement | null; @@ -56,7 +55,7 @@ describe("bl-dropdown", () => { }); it("should close dropdown", async () => { - const el = await fixture(html``); + const el = await fixture(html``); const buttonHost = el.shadowRoot?.querySelector("bl-button"); const button = buttonHost.shadowRoot?.querySelector(".button") as HTMLElement | null; @@ -73,7 +72,7 @@ describe("bl-dropdown", () => { it("should close dropdown when click outside", async () => { const el = await fixture(html` - + `); const buttonHost = el.shadowRoot?.querySelector("bl-button"); @@ -96,7 +95,7 @@ describe("bl-dropdown", () => { it("should close dropdown when click dropdown item", async () => { const el = await fixture(html` - + dropdown-item `); @@ -122,7 +121,7 @@ describe("bl-dropdown", () => { }); it("should fire event when dropdown opened", async () => { - const el = await fixture(html``); + const el = await fixture(html``); const buttonHost = el.shadowRoot?.querySelector("bl-button"); const button = buttonHost.shadowRoot?.querySelector(".button") as HTMLElement | null; @@ -138,7 +137,7 @@ describe("bl-dropdown", () => { }); it("should fire event when dropdown closed", async () => { - const el = await fixture(html``); + const el = await fixture(html``); const buttonHost = el.shadowRoot?.querySelector("bl-button"); const button = buttonHost.shadowRoot?.querySelector(".button") as HTMLElement | null; @@ -154,7 +153,7 @@ describe("bl-dropdown", () => { }); it("should not change opened property when disabled", async () => { - const el = await fixture(html``); + const el = await fixture(html``); expect(el.opened).to.false; @@ -173,7 +172,7 @@ describe("bl-dropdown", () => { //when const el = await fixture( html`
- + Action 1 Action 2 Action 3 @@ -213,7 +212,7 @@ describe("bl-dropdown", () => { //when const el = await fixture( html`
- + Action 1 Action 2 Action 3 @@ -263,7 +262,7 @@ describe("bl-dropdown", () => { //when const el = await fixture( html`
- + Action 1 Action 2 Action 3 diff --git a/src/components/dropdown/bl-dropdown.ts b/src/components/dropdown/bl-dropdown.ts index 26786faf..46757506 100644 --- a/src/components/dropdown/bl-dropdown.ts +++ b/src/components/dropdown/bl-dropdown.ts @@ -1,6 +1,5 @@ import { LitElement, html, CSSResultGroup, TemplateResult } from "lit"; import { customElement, property, state, query } from "lit/decorators.js"; -import { ifDefined } from "lit/directives/if-defined.js"; import { event, EventDispatcher } from "../../utilities/event"; import "../button/bl-button"; import BlButton, { ButtonSize, ButtonVariant, ButtonKind } from "../button/bl-button"; @@ -32,7 +31,7 @@ export default class BlDropdown extends LitElement { * Sets the dropdown button label */ @property({ type: String, reflect: true }) - label = "Dropdown Button"; + label: string; /** * Sets the dropdown button variant @@ -143,18 +142,18 @@ export default class BlDropdown extends LitElement { return html` ${this.label} - - - `; +
+
`; } } diff --git a/src/components/dropdown/group/bl-dropdown-group.css b/src/components/dropdown/group/bl-dropdown-group.css index d5be0f65..e0a05188 100644 --- a/src/components/dropdown/group/bl-dropdown-group.css +++ b/src/components/dropdown/group/bl-dropdown-group.css @@ -1,4 +1,5 @@ :host { + display: block; position: relative; width: 100%; } @@ -17,14 +18,17 @@ color: var(--bl-color-neutral-dark); } -:host(:not(:first-child)) { +:host(:not(:first-child)) .dropdown-group { border-top: 1px solid var(--bl-color-neutral-lighter); + padding-top: var(--bl-size-xs); } -:host(:not(:last-child)) { +:host(:not(:last-child)) .dropdown-group { border-bottom: 1px solid var(--bl-color-neutral-lighter); + padding-bottom: var(--bl-size-xs); } +/* :host(:not([caption])) ::slotted(:first-child) { padding-block: var(--bl-size-xs) 0; } @@ -35,4 +39,4 @@ :host(:not(:first-child)) .caption { padding-block: var(--bl-size-xs) 0; -} +} */ diff --git a/src/components/dropdown/group/bl-dropdown-group.stories.mdx b/src/components/dropdown/group/bl-dropdown-group.stories.mdx index 4cfc22c5..6815915f 100644 --- a/src/components/dropdown/group/bl-dropdown-group.stories.mdx +++ b/src/components/dropdown/group/bl-dropdown-group.stories.mdx @@ -7,6 +7,8 @@ import { Story, } from '@storybook/addon-docs'; +import { userEvent } from '@storybook/testing-library'; + +export const dropdownOpener = async ({ canvasElement }) => { + const dropdown = canvasElement?.querySelector('bl-dropdown') + if(dropdown.shadowRoot) { + const button = dropdown.shadowRoot.querySelector('bl-button') + await userEvent.click(button); + } +} + # Dropdown Group Dropdown Group component is a component should be used inside a bl-dropdown or bl-dropdown-group component. It is used to display an action in the these components. -export const Template = (args) => html` - - Action outside of Group - Action 1Action 1 - +export const Template = (args) => html` + Action outside of Group + + Action 1 + Action 2 + + + Action 1 + Action 2 + + ` ## Basic Usage + - + {Template.bind({})} ## With Caption + - + {Template.bind({})} - From 9e2d0bad688e7835ad598294dd8a2768ea18400a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mr=C3=BCm=20Baki=20Temiz?= Date: Fri, 12 Jan 2024 14:47:25 +0300 Subject: [PATCH 14/18] fix(select): label property added to bl-select-option to fix #764 (#766) closes #764 --- src/components/select/bl-select.stories.mdx | 26 +++++++++++++++++++ src/components/select/bl-select.test.ts | 22 ++++++++++++++++ src/components/select/bl-select.ts | 4 ++- .../select/option/bl-select-option.ts | 6 +++++ 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/components/select/bl-select.stories.mdx b/src/components/select/bl-select.stories.mdx index bc0fa702..f189be6d 100644 --- a/src/components/select/bl-select.stories.mdx +++ b/src/components/select/bl-select.stories.mdx @@ -89,6 +89,20 @@ export const selectOpener = async ({ canvasElement }) => { } } +export const SpecialUseCaseTemplate = () => html` + Option 1 + +
+ Option 2 + + Recommended + Some tooltip text + +
+
+ Option 3 +
`; + export const SelectTemplate = (args) => html` +## Special Use Cases + +Select component can render a custom option label if `bl-select-option` has a `label` attribute. + +This is useful when you want to show a custom label for an option inside a `bl-select`, but you want to show original content inside the option itself. + + + + {SpecialUseCaseTemplate.bind({})} + + + ## `bl-select` Event Select component fires `bl-select` event once selection changes. This event has a payload in the type of diff --git a/src/components/select/bl-select.test.ts b/src/components/select/bl-select.test.ts index 10636950..01cfa2ff 100644 --- a/src/components/select/bl-select.test.ts +++ b/src/components/select/bl-select.test.ts @@ -93,7 +93,29 @@ describe("bl-select", () => { expect(el.options.length).to.equal(2); expect(el.selectedOptions.length).to.equal(1); }); + it("should render bl-select-option label correctly on bl-select", async () => { + const el = await fixture(html` + Option 1 + Option 2 + `); + const selectedOptions = el.shadowRoot?.querySelector(".selected-options"); + + expect(selectedOptions?.children[0].textContent).to.equal("custom-label-1"); + }); + it("should render bl-select-option label(s) correctly on bl-select when select is multiple", async () => { + const el = await fixture(html` + Option 1 + Option 2 + Option 3 + Option 4 + `); + + const selectedOptions = el.shadowRoot?.querySelector(".selected-options"); + + expect(selectedOptions?.textContent).contains("custom-label-1"); + expect(selectedOptions?.textContent).contains("Option 3"); + }); it("should open select menu", async () => { const el = await fixture(html`button`); diff --git a/src/components/select/bl-select.ts b/src/components/select/bl-select.ts index 03718514..30c4c343 100644 --- a/src/components/select/bl-select.ts +++ b/src/components/select/bl-select.ts @@ -358,7 +358,9 @@ export default class BlSelect extends Form private inputTemplate() { const inputSelectedOptions = html`
    - ${this._selectedOptions.map(item => html`
  • ${item.textContent}
  • `)} + ${this._selectedOptions.map( + item => html`
  • ${item.getAttribute("label") || item.textContent}
  • ` + )}
`; const isAllSelectedDisabled = diff --git a/src/components/select/option/bl-select-option.ts b/src/components/select/option/bl-select-option.ts index 94cf5b53..4107a6a3 100644 --- a/src/components/select/option/bl-select-option.ts +++ b/src/components/select/option/bl-select-option.ts @@ -26,6 +26,12 @@ export default class BlSelectOption extend this._value = val; } + /** + * Sets the label for bl-select, and bl-select renders this value instead of the option's textContent + */ + @property({ type: String, reflect: true, attribute: "label" }) + label = ""; + /** * Sets option as disabled */ From 008dd81c52772a97a248834988897fa1a599c0e0 Mon Sep 17 00:00:00 2001 From: Buse Selvi <106681486+buseselvi@users.noreply.github.com> Date: Mon, 15 Jan 2024 15:38:10 +0200 Subject: [PATCH 15/18] feat(icon): new icons added (#769) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - badge - express - express_delivery - express_furniture - translation icons added—also, the "medal" icon's color issue is fixed. --- src/components/icon/icon-list.ts | 5 +++++ src/components/icon/icons/badge.svg | 5 +++++ src/components/icon/icons/express.svg | 3 +++ src/components/icon/icons/express_delivery.svg | 6 ++++++ src/components/icon/icons/express_furniture.svg | 6 ++++++ src/components/icon/icons/medal.svg | 12 ++---------- src/components/icon/icons/translation.svg | 3 +++ 7 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 src/components/icon/icons/badge.svg create mode 100644 src/components/icon/icons/express.svg create mode 100644 src/components/icon/icons/express_delivery.svg create mode 100644 src/components/icon/icons/express_furniture.svg create mode 100644 src/components/icon/icons/translation.svg diff --git a/src/components/icon/icon-list.ts b/src/components/icon/icon-list.ts index 8ea7f109..df58defc 100644 --- a/src/components/icon/icon-list.ts +++ b/src/components/icon/icon-list.ts @@ -16,6 +16,7 @@ const icons = [ "award", "back", "back_fill", + "badge", "barcode", "bill", "book", @@ -58,6 +59,9 @@ const icons = [ "exit", "expand", "export", + "express", + "express_delivery", + "express_furniture", "external_link", "external_share", "eye_off", @@ -205,6 +209,7 @@ const icons = [ "support", "target", "ticket", + "translation", "truck", "turn_back", "turn_back_fill", diff --git a/src/components/icon/icons/badge.svg b/src/components/icon/icons/badge.svg new file mode 100644 index 00000000..cbba752b --- /dev/null +++ b/src/components/icon/icons/badge.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/components/icon/icons/express.svg b/src/components/icon/icons/express.svg new file mode 100644 index 00000000..af08de49 --- /dev/null +++ b/src/components/icon/icons/express.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/icon/icons/express_delivery.svg b/src/components/icon/icons/express_delivery.svg new file mode 100644 index 00000000..c88562ca --- /dev/null +++ b/src/components/icon/icons/express_delivery.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/components/icon/icons/express_furniture.svg b/src/components/icon/icons/express_furniture.svg new file mode 100644 index 00000000..d2c8828b --- /dev/null +++ b/src/components/icon/icons/express_furniture.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/components/icon/icons/medal.svg b/src/components/icon/icons/medal.svg index 76954f36..4d5d41bd 100644 --- a/src/components/icon/icons/medal.svg +++ b/src/components/icon/icons/medal.svg @@ -1,13 +1,5 @@ - - - - + + - - - - - - diff --git a/src/components/icon/icons/translation.svg b/src/components/icon/icons/translation.svg new file mode 100644 index 00000000..9d0e078e --- /dev/null +++ b/src/components/icon/icons/translation.svg @@ -0,0 +1,3 @@ + + + From e032b7aa25907d269512eb2969fcdb555693ced7 Mon Sep 17 00:00:00 2001 From: Erbil Date: Thu, 18 Jan 2024 17:15:23 +0300 Subject: [PATCH 16/18] fix(select): add string to boolean converter for related prop (#775) No breaking change | Closes #774 Co-authored-by: Erbil Nas --- src/components/select/bl-select.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/select/bl-select.ts b/src/components/select/bl-select.ts index 30c4c343..62102e57 100644 --- a/src/components/select/bl-select.ts +++ b/src/components/select/bl-select.ts @@ -7,6 +7,7 @@ import { FormControlMixin, requiredValidator } from "@open-wc/form-control"; import { FormValue } from "@open-wc/form-helpers"; import "element-internals-polyfill"; import { event, EventDispatcher } from "../../utilities/event"; +import { stringBooleanConverter } from "../../utilities/string-boolean.converter"; import BlCheckbox from "../checkbox-group/checkbox/bl-checkbox"; import "../icon/bl-icon"; import style from "../select/bl-select.css"; @@ -171,7 +172,11 @@ export default class BlSelect extends Form /** * Display a loading icon in place of the search icon. */ - @property({ type: Boolean, attribute: "search-bar-loading-state", reflect: true }) + @property({ + type: Boolean, + attribute: "search-bar-loading-state", + converter: stringBooleanConverter(), + }) searchBarLoadingState = false; /** From 27684267a6b1bbbcdc7579ce0582861208985c07 Mon Sep 17 00:00:00 2001 From: Erbil Nas Date: Tue, 23 Jan 2024 11:52:57 +0300 Subject: [PATCH 17/18] fix(pagination): fix the event of the single select --- src/components/pagination/bl-pagination.test.ts | 2 +- src/components/pagination/bl-pagination.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/pagination/bl-pagination.test.ts b/src/components/pagination/bl-pagination.test.ts index d9f736d8..e886d971 100644 --- a/src/components/pagination/bl-pagination.test.ts +++ b/src/components/pagination/bl-pagination.test.ts @@ -292,7 +292,7 @@ describe("bl-pagination", () => { } const selectOptionEvent = new CustomEvent("bl-select", { - detail: [optionTwo], + detail: optionTwo, }); select?.dispatchEvent(selectOptionEvent); diff --git a/src/components/pagination/bl-pagination.ts b/src/components/pagination/bl-pagination.ts index da2c201e..a5bafaa4 100644 --- a/src/components/pagination/bl-pagination.ts +++ b/src/components/pagination/bl-pagination.ts @@ -181,7 +181,7 @@ export default class BlPagination extends LitElement { } private _selectHandler(event: CustomEvent) { - this.itemsPerPage = +event?.detail[0]?.value || 100; + this.itemsPerPage = +event?.detail?.value || 100; this._changePage(1); } From 793143a0863c2e47928953f50ab9ea0b3c2bb3cd Mon Sep 17 00:00:00 2001 From: Levent Anil Ozen Date: Thu, 25 Jan 2024 15:51:55 +0300 Subject: [PATCH 18/18] feat: major version release (#782) BREAKING CHANGE: bump version