Skip to content

Commit

Permalink
update structure
Browse files Browse the repository at this point in the history
  • Loading branch information
mimshins committed Nov 19, 2024
1 parent 1af484d commit 5764a1a
Show file tree
Hide file tree
Showing 13 changed files with 426 additions and 196 deletions.

This file was deleted.

This file was deleted.

32 changes: 0 additions & 32 deletions packages/web-components/src/bottom-navigation-item/index.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,41 +1,29 @@
import { css } from "lit";

export default css`
:host {
*,
*::before,
*::after {
box-sizing: border-box;
}
:host *,
:host *::before,
:host *::after {
box-sizing: inherit;
:host {
display: block;
}
[hidden] {
display: none !important;
.root ::slotted(tap-bottom-navigation-item) {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0;
}
.bottom-navigation {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 72px;
background: var(
--tap-bottom-navigation-background,
var(--tap-sys-color-surface-secondary)
);
border-top-width: var(
--tap-bottom-navigation-border-top-width,
var(--tap-sys-stroke-1)
);
border-top-style: solid;
border-top-color: var(
--tap-bottom-navigation-border-top-color,
var(--tap-sys-color-border-primary)
);
.root {
height: 4rem;
background-color: var(--tap-sys-color-surface-secondary);
box-shadow: 0 calc(-1 * var(--tap-sys-stroke-1)) 0 0
var(--tap-sys-color-border-primary);
display: flex;
align-items: center;
justify-content: space-evenly;
}
`;
144 changes: 118 additions & 26 deletions packages/web-components/src/bottom-navigation/bottom-navigation.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1,147 @@
import { LitElement, html } from "lit";
import { queryAssignedElements } from "lit/decorators.js";
import { type BottomNavigationItem } from "../bottom-navigation-item/bottom-navigation-item";
import { LitElement, html, isServer } from "lit";
import { property } from "lit/decorators.js";
import { getRenderRootSlot } from "../utils";
import { Slots } from "./constants";
import { ActivateEvent, BottomNavigationItem, DeactivateEvent } from "./item";

export class BottomNavigation extends LitElement {
@queryAssignedElements()
private _items!: BottomNavigationItem[];
private _activeItem = "";

private get _items() {
const itemsSlot = getRenderRootSlot(this.renderRoot, Slots.DEFAULT);

if (!itemsSlot) return [];

const items = itemsSlot
.assignedNodes()
.filter(node => node instanceof BottomNavigationItem);

return items;
}

private get _queryActiveItem() {
return this._items.find(item => item.active) ?? null;
}

/**
* The value of the currently activated item.
*/
@property({ type: String, attribute: false })
public get activeItem() {
return this._activeItem;
}

public set activeItem(value: string) {
if (isServer) return;

this._activate(value);
}

/**
* The label used for screen readers.
*/
@property({ type: String, attribute: "screen-reader-label" })
public screenReaderLabel = "Bottombar navigation";

constructor() {
super();

if (!isServer) {
this._handleItemActivation = this._handleItemActivation.bind(this);
this._handleItemDeactivation = this._handleItemDeactivation.bind(this);
}
}

public override connectedCallback() {
super.connectedCallback();

this.addEventListener(
"bottom-navigation-item-click",
this._handleBottomNavigationItemClick,
ActivateEvent.type,
this._handleItemActivation as EventListener,
);
}

private get _firstItem() {
return this._items[0];
this.addEventListener(
DeactivateEvent.type,
this._handleItemDeactivation as EventListener,
);
}

private _handleBottomNavigationItemClick(e: Event) {
const clicked = this._items.find(item => item === e.target);
public override disconnectedCallback(): void {
super.disconnectedCallback();

this.removeEventListener(
ActivateEvent.type,
this._handleItemActivation as EventListener,
);

this.removeEventListener(
DeactivateEvent.type,
this._handleItemDeactivation as EventListener,
);
}

if (!clicked || clicked.active) return;
private _activate(itemValue: string) {
const targetItem = this._items.find(item => {
return item.value === itemValue;
});

clicked.active = true;
if (!targetItem || targetItem.active) return;

this._items.forEach(item => {
if (item !== clicked) {
item.active = false;
}
if (item !== targetItem) item.active = false;
});

this._activeItem = itemValue;
targetItem.active = true;
}

private _handleSlotChange() {
const active = this._items.find(item => item.active);
private _deactivate(itemValue: string) {
const targetItem = this._items.find(item => item.value === itemValue);

if (!active && this._firstItem) {
this._firstItem.active = true;
}
if (!targetItem || !targetItem.active) return;

targetItem.active = false;
this._activeItem = "";

const hasActiveItem = !!this._queryActiveItem;
const firstItem = this._items[0];

if (hasActiveItem || !firstItem) return;

firstItem.active = true;
this._activeItem = firstItem.value;
}

private _handleItemDeactivation(event: DeactivateEvent) {
const { itemValue } = event.details;

this._deactivate(itemValue);
}

private _handleItemActivation(event: ActivateEvent) {
const { itemValue } = event.details;

this._activate(itemValue);
}

private _handleItemsSlotChange() {
const hasActiveItem = !!this._queryActiveItem;
const firstItem = this._items[0];

if (hasActiveItem || !firstItem) return;

firstItem.active = true;
}

protected override render() {
return html`
<nav
role="navigation"
class="bottom-navigation"
part="bottom-navigation"
aria-label="bottom-navigation"
class="root"
part="root"
aria-label=${this.screenReaderLabel}
>
<slot @slotchange=${this._handleSlotChange}></slot>
<slot @slotchange=${this._handleItemsSlotChange}></slot>
</nav>
`;
}
Expand Down
3 changes: 3 additions & 0 deletions packages/web-components/src/bottom-navigation/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const Slots = {
DEFAULT: "",
} as const;
Loading

0 comments on commit 5764a1a

Please sign in to comment.