Skip to content

Commit

Permalink
feat: notification component (#741)
Browse files Browse the repository at this point in the history
Closes #141

---------

Signed-off-by: Ogun Babacan <babacanogun@gmail.com>
Co-authored-by: Aykut Saraç <aykutsarac0@gmail.com>
  • Loading branch information
ogunb and AykutSarac authored Nov 30, 2023
1 parent 43d6b0d commit cb12aa6
Show file tree
Hide file tree
Showing 17 changed files with 2,104 additions and 48 deletions.
55 changes: 28 additions & 27 deletions commitlint.config.cjs
Original file line number Diff line number Diff line change
@@ -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",
],
],
},
Expand Down
2 changes: 2 additions & 0 deletions src/baklava.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
17 changes: 15 additions & 2 deletions src/components/alert/bl-alert.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,25 @@ describe("Slot", () => {
const el = await fixture<typeofBlAlert>(
html`<bl-alert>
<bl-button slot="action"> Action Slot </bl-button>
<span slot="action">Should not render this element</span>
<bl-button slot="action-secondary"> Action Slot </bl-button>
</bl-alert>`
);
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<typeofBlAlert>(
Expand Down
6 changes: 3 additions & 3 deletions src/components/alert/bl-alert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,17 +104,17 @@ 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") {
element.parentNode?.removeChild(element);
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<AlertVariant, string> = {
info: "default",
warning: "neutral",
Expand Down
8 changes: 8 additions & 0 deletions src/components/dialog/bl-dialog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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

<ArgsTable of="bl-dialog" />
Expand Down
6 changes: 3 additions & 3 deletions src/components/dialog/bl-dialog.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeOfBlDialog>(html`<bl-dialog></bl-dialog>`);
const el = await fixture<typeOfBlDialog>(html`<bl-dialog .polyfilled=${false}></bl-dialog>`);

assert.shadowDom.equal(
el,
Expand Down Expand Up @@ -132,7 +132,7 @@ describe("bl-dialog", () => {
});

it("should close the dialog when the close btn is clicked", async () => {
const el = await fixture<typeOfBlDialog>(html` <bl-dialog open caption="My title">
const el = await fixture<typeOfBlDialog>(html` <bl-dialog .polyfilled=${false} open caption="My title">
<div>My Content</div>
</bl-dialog>`);
const dialog = el.shadowRoot?.querySelector(".dialog") as HTMLDivElement;
Expand Down Expand Up @@ -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<typeOfBlDialog>(html`<bl-dialog open caption="My title">
const el = await fixture<typeOfBlDialog>(html`<bl-dialog .polyfilled=${false} open caption="My title">
</bl-dialog>`);

const dialog = el?.shadowRoot?.querySelector<HTMLDialogElement>(".dialog");
Expand Down
12 changes: 10 additions & 2 deletions src/components/dialog/bl-dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -176,7 +184,7 @@ export default class BlDialog extends LitElement {
}

render(): TemplateResult {
return this.polyfilled
return this.polyfilled || !window.HTMLDialogElement
? html`<div
class="dialog-polyfill"
role="dialog"
Expand Down
106 changes: 106 additions & 0 deletions src/components/notification/bl-notification.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
:host {
--bl-notification-width: 396px;
--bl-notification-gap: var(--bl-size-2xs);
--bl-notification-animation-duration: 0.3s;
}

.wrapper {
--margin: var(--bl-size-xl);

display: flex;
flex-direction: column-reverse;
position: fixed;
top: 0;
right: 0;
max-width: var(--bl-notification-width);
margin: var(--margin);
width: calc(100% - var(--margin) * 2);
z-index: var(--bl-index-notification);
}

@media screen and (max-width: 480px) {
.wrapper {
flex-direction: column;
max-width: 100%;
}
}

.notification {
will-change: transform height margin;
animation: slide-in-right var(--bl-notification-animation-duration) ease;
margin-bottom: var(--bl-notification-gap);
touch-action: none;
}

.notification[data-slide="top"] {
animation: slide-in-top var(--bl-notification-animation-duration) ease;
}

:host([no-animation]) .notification {
animation: none;
}

.notification.removing {
animation: slide-out-right var(--bl-notification-animation-duration) ease forwards,
size-to-zero var(--bl-notification-animation-duration) ease
var(--bl-notification-animation-duration) forwards;
}

.notification[data-slide="top"].removing {
animation: slide-out-top var(--bl-notification-animation-duration) ease forwards,
size-to-zero var(--bl-notification-animation-duration) ease
var(--bl-notification-animation-duration) forwards;
}

:host([no-animation]) .notification.removing {
animation: size-to-zero 0;
}

@media (prefers-reduced-motion) {
.notification.removing {
animation: size-to-zero 0;
}

.notification {
animation: none;
}
}

@keyframes slide-in-right {
from {
transform: translateX(var(--travel-distance, 10px));
height: 0;
opacity: 0;
margin: 0;
}
}

@keyframes slide-out-right {
to {
transform: translateX(var(--travel-distance, 10px));
opacity: 0;
}
}

@keyframes slide-in-top {
from {
transform: translateY(var(--travel-distance, -10px));
height: 0;
opacity: 0;
margin: 0;
}
}

@keyframes slide-out-top {
to {
transform: translateY(var(--travel-distance, -10px));
opacity: 0;
}
}

@keyframes size-to-zero {
to {
height: 0;
margin: 0;
}
}
Loading

0 comments on commit cb12aa6

Please sign in to comment.