@ribajs/bs5
Version:
Bootstrap 5 module for Riba.js
182 lines (159 loc) • 4.74 kB
text/typescript
/**
* This components is used to trigger a toggle event used in other components or parts of your project. This site itself uses the bs5-toggle-button to open or close the sidebar.
* @attribute "target-id" (Required) The id with which the toggle event is triggered
* @method toggle Triggeres the toggle event
* @property state Can be 'hidden' or something else
* @property isClosed Is true if the state is 'hidden'
* @property targetId Passed attribute value, see `target-id` attribute
*/
import { Component, TemplateFunction, ScopeBase } from "@ribajs/core";
import { EventDispatcher } from "@ribajs/events";
import { hasChildNodesTrim } from "@ribajs/utils/src/dom.js";
import { JsxBs5ToggleButtonProps } from "../../types/index.js";
import { TOGGLE_BUTTON } from "../../constants/index.js";
type State =
| "undefined"
| "overlay-left"
| "overlay-right"
| "side-left"
| "side-right"
| "hidden"
| "added"
| "removed";
interface Scope extends ScopeBase {
targetId?: string;
toggle: Bs5ToggleButtonComponent["toggle"];
state: State;
isActive: boolean;
/** @deprecated use !isActive instead */
isClosed: boolean;
}
// TODO extend from Bs5ButtonComponent
export class Bs5ToggleButtonComponent extends Component {
static get observedAttributes(): (keyof JsxBs5ToggleButtonProps)[] {
return ["target-id"];
}
protected requiredAttributes(): (keyof JsxBs5ToggleButtonProps)[] {
return ["target-id"];
}
public static tagName = "bs5-toggle-button";
protected autobind = true;
public _debug = false;
protected eventDispatcher?: EventDispatcher;
protected lifecycleEvents = EventDispatcher.getInstance("lifecycle");
public scope: Scope = {
targetId: undefined,
toggle: this.toggle,
state: "undefined",
isActive: true,
isClosed: false,
};
constructor() {
super();
this.lifecycleEvents.once(
"ComponentLifecycle:allBound",
this.onAllComponentsReady,
this,
);
}
public toggle() {
this.debug("toggle", this.eventDispatcher);
if (this.eventDispatcher) {
this.eventDispatcher.trigger(
TOGGLE_BUTTON.eventNames.toggle,
this.scope.targetId,
);
}
}
protected onAllComponentsReady() {
this.debug("onAllComponentsReady");
// Trigger init to trigger there current state of all the components that are connected to this component
this.eventDispatcher?.trigger(
TOGGLE_BUTTON.eventNames.init,
this.scope.targetId,
);
}
protected async afterBind() {
await super.afterBind();
}
protected connectedCallback() {
super.connectedCallback();
this.init(Bs5ToggleButtonComponent.observedAttributes);
}
protected onToggledEvent(state: State) {
this.scope.state = state;
this.scope.isActive = state !== "hidden" && state !== "removed";
this.scope.isClosed = !this.scope.isActive;
}
protected initEventDispatcher(id: string) {
if (this.eventDispatcher) {
this.eventDispatcher.off(
TOGGLE_BUTTON.eventNames.toggled,
this.onToggledEvent,
this,
);
}
const namespace = TOGGLE_BUTTON.nsPrefix + id;
this.debug(`Init event dispatcher for namespace ${namespace}`);
this.eventDispatcher = new EventDispatcher(namespace);
this.eventDispatcher.on(
TOGGLE_BUTTON.eventNames.toggled,
this.onToggledEvent,
this,
);
// Triggered state triggered by `..trigger('init', ...`
this.eventDispatcher.on(
TOGGLE_BUTTON.eventNames.state,
this.onToggledEvent,
this,
);
}
protected async attributeChangedCallback(
attributeName: string,
oldValue: any,
newValue: any,
namespace: string | null,
) {
super.attributeChangedCallback(
attributeName,
oldValue,
newValue,
namespace,
);
}
protected parsedAttributeChangedCallback(
attributeName: string,
oldValue: any,
newValue: any,
namespace: string | null,
) {
super.parsedAttributeChangedCallback(
attributeName,
oldValue,
newValue,
namespace,
);
if (attributeName === "targetId" && newValue) {
this.initEventDispatcher(newValue);
}
}
// deconstruction
protected disconnectedCallback() {
super.disconnectedCallback();
if (this.eventDispatcher) {
this.eventDispatcher.off(
TOGGLE_BUTTON.eventNames.toggled,
this.onToggledEvent,
this,
);
}
}
protected template(): ReturnType<TemplateFunction> {
if (!hasChildNodesTrim(this)) {
console.warn(
"No child elements found, this component as no template so you need to define your own as child of this component.",
);
}
return null;
}
}