import { html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import {
ancestorAttribute,
onAssign,
autoSubscribe,
awaitConnectedAncestors,
dispatchConnectedEvent,
} from "@supersoniks/concorde/decorators";
import {
PublisherManager,
PublisherProxy,
} from "@supersoniks/concorde/core/utils/PublisherProxy";
import { Objects } from "@supersoniks/concorde/utils";
import { tailwind } from "../tailwind";
import "./decorators-demo-bind-demos";
import "./decorators-demo-subscribe-publish-get-demos";
@customElement("demo-ancestor-attribute")
export class DemoAncestorAttribute extends LitElement {
@ancestorAttribute("dataProvider")
dataProvider: string | null = null;
@ancestorAttribute("testAttribute")
testAttribute: string | null = null;
render() {
return html`
DataProvider property initialized from ancestor:
${this.dataProvider || "null"}
TestAttribute property initialized from ancestor:
${this.testAttribute || "null"}
`;
}
}
@customElement("demo-on-assign")
export class DemoOnAssign extends LitElement {
static styles = [tailwind];
@state() userWithSettings: any = null;
@state() isReady: boolean = false;
@state() lastUpdate: string = "";
@onAssign("demoUser", "demoUserSettings")
handleDataReady(user: any, settings: any) {
this.isReady =
Object.keys(user).length > 0 && Object.keys(settings).length > 0;
this.userWithSettings = { ...user, ...settings };
this.lastUpdate = new Date().toLocaleTimeString();
this.requestUpdate();
}
render() {
const { name, email, theme, language } = this.userWithSettings;
return html`
Update Data
${this.isReady === false
? html`
No settings yet...
`
: html`
${name || "N/A"}
${email || "N/A"}
${theme || "N/A"}
${language || "N/A"}
Last updated: ${this.lastUpdate}
`}
`;
}
updateData() {
const user = PublisherManager.get("demoUser");
const userSettings = PublisherManager.get("demoUserSettings");
const userNumber = Math.floor(Math.random() * 100);
user.set({
name: `User n°${userNumber}`,
email: `user-${userNumber}@example.com`,
});
userSettings.set({
theme: ["light", "dark", "auto"][Math.floor(Math.random() * 3)],
language: ["en", "fr", "es"][Math.floor(Math.random() * 3)],
});
}
}
@customElement("demo-on-assign-dynamic")
export class DemoOnAssignDynamic extends LitElement {
static styles = [tailwind];
@property({ type: String })
dataProvider: "demoUsers" | "demoUsersAlt" = "demoUsers";
@property({ type: Number })
userIndex: number = 0;
@state() user: any = null;
@state() userSettings: any = null;
@onAssign(
"${dataProvider}.${userIndex}",
"${dataProvider}Settings.${userIndex}",
)
handleUserDataReady(user: any, settings: any) {
this.user = user;
this.userSettings = settings;
}
updateUserIndex(e: Event) {
this.userIndex = parseInt((e.target as HTMLInputElement).value);
}
updateDataProvider(e: Event) {
this.dataProvider = (e.target as HTMLSelectElement).value as
| "demoUsers"
| "demoUsersAlt";
}
updateCurrentUserData() {
const usersPublisher = PublisherManager.get(this.dataProvider);
const settingsPublisher = PublisherManager.get(
`${this.dataProvider}Settings`,
);
const userPublisher = Objects.traverse(usersPublisher, [
String(this.userIndex),
]) as PublisherProxy;
const settingPublisher = Objects.traverse(settingsPublisher, [
String(this.userIndex),
]) as PublisherProxy;
if (userPublisher && settingPublisher) {
const randomNames = [
{ firstName: "Alice", lastName: "Wonder" },
{ firstName: "Bob", lastName: "Builder" },
{ firstName: "Charlie", lastName: "Chaplin" },
{ firstName: "Diana", lastName: "Prince" },
{ firstName: "Eve", lastName: "Adams" },
];
const randomThemes = ["light", "dark", "auto"];
const randomLanguages = ["en", "fr", "es", "de", "it"];
const randomName =
randomNames[Math.floor(Math.random() * randomNames.length)];
const randomEmail = `${randomName.firstName.toLowerCase()}.${randomName.lastName.toLowerCase()}@example.com`;
const randomTheme =
randomThemes[Math.floor(Math.random() * randomThemes.length)];
const randomLanguage =
randomLanguages[Math.floor(Math.random() * randomLanguages.length)];
const currentUser = userPublisher.get() || {};
userPublisher.set({
...currentUser,
firstName: randomName.firstName,
lastName: randomName.lastName,
email: randomEmail,
});
settingPublisher.set({
theme: randomTheme,
language: randomLanguage,
});
}
}
render() {
return html`
Update current user data
${this.user?.firstName} ${this.user?.lastName}
${this.user?.email}
Theme: ${this.userSettings?.theme} | Language:
${this.userSettings?.language}
`;
}
}
@customElement("demo-auto-subscribe")
export class DemoAutoSubscribe extends LitElement {
static styles = [tailwind];
@state() displayText: string = "";
@state() computedValue: number = 0;
@autoSubscribe()
updateDisplay() {
const value1 = PublisherManager.get("autoValue1").get() || 0;
const value2 = PublisherManager.get("autoValue2").get() || 0;
this.computedValue = value1 + value2;
this.displayText = `${value1} + ${value2} = ${this.computedValue}`;
}
render() {
return html`
${this.displayText}
this.randomizeValue("autoValue1")}>
Randomize Value 1
this.randomizeValue("autoValue2")}>
Randomize Value 2
`;
}
randomizeValue(publisherId: string) {
const value = PublisherManager.get(publisherId);
value.set(Math.floor(Math.random() * 100));
}
}
@dispatchConnectedEvent()
export class DemoWaitAncestorContainer extends LitElement {
render() {
return html``;
}
}
@customElement("demo-wait-ancestor-value")
@awaitConnectedAncestors("demo-wait-ancestor-container[dataProvider]")
export class DemoWaitAncestorValue extends LitElement {
@ancestorAttribute("dataProvider")
dataProvider: string | null = null;
@state() initializedAt = "";
connectedCallback() {
super.connectedCallback();
this.initializedAt = new Date().toISOString();
}
render() {
return html`
DataProvider from ancestor:
${this.dataProvider || "—"}
Initialized at: ${this.initializedAt || "(waiting for parent…)"}
`;
}
}
@customElement("demo-wait-ancestors-section")
export class DemoWaitAncestorsSection extends LitElement {
static styles = [tailwind];
@state() parentRegistered = false;
registerParent() {
if (customElements.get("demo-wait-ancestor-container")) {
this.parentRegistered = true;
return;
}
customElements.define(
"demo-wait-ancestor-container",
DemoWaitAncestorContainer,
);
this.parentRegistered = true;
}
render() {
return html`
${this.parentRegistered
? "Parent already registered"
: "Register parent component"}
`;
}
}
@dispatchConnectedEvent()
export class DemoWaitAncestorOuter extends LitElement {
render() {
return html``;
}
}
@dispatchConnectedEvent()
export class DemoWaitAncestorInner extends LitElement {
render() {
return html``;
}
}
@customElement("demo-wait-ancestor-value-multi")
@awaitConnectedAncestors("demo-wait-ancestor-outer", "demo-wait-ancestor-inner")
export class DemoWaitAncestorValueMulti extends LitElement {
@ancestorAttribute("dataProvider")
dataProvider: string | null = null;
@state() initializedAt = "";
connectedCallback() {
super.connectedCallback();
this.initializedAt = new Date().toISOString();
}
render() {
return html`
DataProvider from ancestor:
${this.dataProvider || "—"}
Initialized at: ${this.initializedAt || "(waiting for both ancestors…)"}
`;
}
}
@customElement("demo-wait-ancestors-multi-section")
export class DemoWaitAncestorsMultiSection extends LitElement {
static styles = [tailwind];
@state() outerRegistered = false;
@state() innerRegistered = false;
registerOuter() {
if (!customElements.get("demo-wait-ancestor-outer")) {
customElements.define("demo-wait-ancestor-outer", DemoWaitAncestorOuter);
}
this.outerRegistered = true;
}
registerInner() {
if (!customElements.get("demo-wait-ancestor-inner")) {
customElements.define("demo-wait-ancestor-inner", DemoWaitAncestorInner);
}
this.innerRegistered = true;
}
render() {
return html`
${this.outerRegistered ? "Outer registered" : "Register outer"}
${this.innerRegistered ? "Inner registered" : "Register inner"}
`;
}
}
@customElement("demo-wait-ancestor-ready")
@dispatchConnectedEvent()
export class DemoWaitAncestorReady extends LitElement {
render() {
return html``;
}
}
@customElement("demo-wait-ancestor-value-ready")
@awaitConnectedAncestors("demo-wait-ancestor-ready")
export class DemoWaitAncestorValueReady extends LitElement {
@ancestorAttribute("dataProvider")
dataProvider: string | null = null;
@state() initializedAt = "";
connectedCallback() {
super.connectedCallback();
this.initializedAt = new Date().toISOString();
}
render() {
return html`
DataProvider: ${this.dataProvider || "—"}
Initialized at: ${this.initializedAt}
`;
}
}
@customElement("demo-wait-ancestors-ready-section")
export class DemoWaitAncestorsReadySection extends LitElement {
static styles = [tailwind];
@state() childInDom = false;
addChild() {
this.childInDom = true;
}
render() {
return html`
Parent défini au chargement. Ajout dynamique de l’enfant — initialisation
immédiate si l’ancêtre est prêt.
${this.childInDom ? "Child added" : "Add child dynamically"}
${this.childInDom
? html``
: html``}
`;
}
}
@customElement("demo-wait-ancestors-static-section")
export class DemoWaitAncestorsStaticSection extends LitElement {
static styles = [tailwind];
render() {
return html`
Parent et enfant présents dès le chargement — pas de délai.
`;
}
}