fix(lit-components): fix rendering and interaction issues in force-graph, html-table, and draggable-dom
Build and Deploy / build-and-deploy (push) Has been cancelled
Build and Deploy / build-and-deploy (push) Has been cancelled
- lit-force-graph: Refactored for instance reuse, better lifecycle management, and added dynamic imports for AR/VR modes. - lit-html-table: Improved visual design, readability of headers, and fixed reactivity in editable mode. - lit-draggable-dom: Fixed clipping issues by switching to relative/absolute positioning and resolved a panning speed bug caused by CSS variable inheritance.
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
import { html, TemplateResult } from "lit";
|
||||
|
||||
import "@material/mwc-top-app-bar-fixed";
|
||||
import "@material/mwc-icon-button";
|
||||
import { iconButton } from "./app-button";
|
||||
|
||||
const TITLE = "TODOS";
|
||||
|
||||
export const appBar = (props: {
|
||||
navigation?: TemplateResult;
|
||||
title?: string;
|
||||
content?: TemplateResult;
|
||||
actions?: TemplateResult[];
|
||||
}) => {
|
||||
return html` <mwc-top-app-bar-fixed>
|
||||
${props?.navigation ?? ""}
|
||||
<div slot="title">${props?.title ?? TITLE}</div>
|
||||
${props?.actions ?? ""}
|
||||
<div>${props?.content ?? ""}</div>
|
||||
</mwc-top-app-bar-fixed>`;
|
||||
};
|
||||
|
||||
export const navigationIcon = (callback: () => void, icon: string = "menu") => {
|
||||
return iconButton({
|
||||
icon: icon,
|
||||
slot: "navigationIcon",
|
||||
callback: () => callback(),
|
||||
});
|
||||
};
|
||||
|
||||
export const actionButton = (icon: string, callback: () => void) => {
|
||||
return iconButton({
|
||||
icon: icon,
|
||||
slot: "actionItems",
|
||||
callback: () => callback(),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
import { html } from "lit";
|
||||
|
||||
import "@material/mwc-button";
|
||||
import "@material/mwc-icon-button";
|
||||
|
||||
interface ButtonOptions {
|
||||
icon?: string;
|
||||
label?: string;
|
||||
action?: string;
|
||||
slot?: string;
|
||||
type?: string;
|
||||
form?: string;
|
||||
callback: () => void;
|
||||
}
|
||||
export const button = (options: ButtonOptions) => {
|
||||
return html` <mwc-button
|
||||
@click=${() => options.callback()}
|
||||
slot=${options?.slot ?? ""}
|
||||
label=${options?.label ?? ""}
|
||||
action=${options?.action ?? ""}
|
||||
type=${options?.type ?? ""}
|
||||
form=${options?.form ?? ""}
|
||||
icon=${options?.icon ?? ""}
|
||||
>
|
||||
</mwc-button>`;
|
||||
};
|
||||
|
||||
export const iconButton = (options: ButtonOptions) => {
|
||||
return html` <mwc-icon-button
|
||||
@click=${() => options.callback()}
|
||||
slot=${options?.slot ?? ""}
|
||||
action=${options?.action ?? ""}
|
||||
type=${options?.type ?? ""}
|
||||
form=${options?.form ?? ""}
|
||||
icon=${options.icon ?? ""}
|
||||
>
|
||||
</mwc-icon-button>`;
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
import "@material/mwc-dialog";
|
||||
import "@material/mwc-button/mwc-button";
|
||||
|
||||
import { html, TemplateResult } from "lit";
|
||||
|
||||
interface DialogOptions {
|
||||
open: boolean;
|
||||
title: string;
|
||||
content: () => TemplateResult;
|
||||
dismiss: (target: HTMLElement) => void;
|
||||
}
|
||||
|
||||
export const appDialog = (options: DialogOptions) => {
|
||||
return html`<mwc-dialog
|
||||
?open=${options?.open ?? false}
|
||||
heading="${options.title}"
|
||||
@closed=${(e: any) => options.dismiss(e.target)}
|
||||
>
|
||||
<div>${options.content()}</div>
|
||||
</mwc-dialog>`;
|
||||
};
|
||||
|
||||
interface DialogActionOptions {
|
||||
label: string;
|
||||
action?: string;
|
||||
callback: () => void;
|
||||
}
|
||||
export const dialogAction = (options: DialogActionOptions) => {
|
||||
return html` <mwc-button
|
||||
slot="primaryAction"
|
||||
dialogAction="${options?.action ?? "close"}"
|
||||
@click=${() => options.callback()}
|
||||
>
|
||||
${options.label}
|
||||
</mwc-button>`;
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
import { html, TemplateResult } from "lit";
|
||||
|
||||
import "@material/mwc-drawer";
|
||||
import { Drawer } from "@material/mwc-drawer";
|
||||
|
||||
export const appDrawer = (props: {
|
||||
title?: string;
|
||||
subtitle?: string;
|
||||
drawerContent?: TemplateResult;
|
||||
appContent?: TemplateResult;
|
||||
open?: boolean;
|
||||
}) => {
|
||||
return html`
|
||||
<mwc-drawer hasHeader type="modal" ?open=${props?.open ?? false}>
|
||||
${props?.title ? html` <span slot="title">${props.title}e</span>` : ""}
|
||||
${props?.subtitle
|
||||
? html` <span slot="subtitle">${props.subtitle}e</span>`
|
||||
: ""}
|
||||
<div>${props?.drawerContent ?? ""}</div>
|
||||
<div slot="appContent">${props?.appContent ?? ""}</div>
|
||||
</mwc-drawer>
|
||||
`;
|
||||
};
|
||||
|
||||
export const toggleDrawer = (root: HTMLElement | ShadowRoot) => {
|
||||
const drawer = root.querySelector("mwc-drawer")! as Drawer;
|
||||
drawer.open = !drawer.open;
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
import { TemplateResult } from "lit";
|
||||
import { appBar, navigationIcon } from "./app-bar";
|
||||
import { appDrawer, toggleDrawer } from "./app-drawer";
|
||||
|
||||
export interface ScaffoldOptions {
|
||||
root: HTMLElement | ShadowRoot;
|
||||
body: () => TemplateResult;
|
||||
actions?: TemplateResult[];
|
||||
title?: string;
|
||||
}
|
||||
export const appScaffold = (options: ScaffoldOptions) => {
|
||||
return appDrawer({
|
||||
appContent: appBar({
|
||||
title: options.title,
|
||||
navigation: navigationIcon(() => toggleDrawer(options.root)),
|
||||
content: options.body(),
|
||||
actions: options.actions ? options.actions : DEFAULT_ACTIONS,
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
const DEFAULT_ACTIONS: TemplateResult[] = [];
|
||||
@@ -0,0 +1,45 @@
|
||||
import { html, TemplateResult } from "lit";
|
||||
|
||||
export const formBuilder = (
|
||||
content: TemplateResult,
|
||||
onSubmit: (form: HTMLFormElement) => void
|
||||
) => {
|
||||
return html`<form
|
||||
@submit=${(e: any) => {
|
||||
e.preventDefault();
|
||||
const form = e.currentTarget as HTMLFormElement;
|
||||
onSubmit(form);
|
||||
}}
|
||||
>
|
||||
${content} <br />
|
||||
<input type="submit" value="Submit" />
|
||||
</form>`;
|
||||
};
|
||||
|
||||
export const input = (
|
||||
id: string,
|
||||
label: string,
|
||||
options?: { type?: "text" | "number"; required?: boolean }
|
||||
) => {
|
||||
return html`
|
||||
<div>
|
||||
<label for="${id}">${label}</label><br />
|
||||
<input
|
||||
id="${id}"
|
||||
type="${options?.type ?? "text"}"
|
||||
?required=${options?.required ?? false}
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
|
||||
export const inputValue = (
|
||||
form: HTMLFormElement,
|
||||
id: string,
|
||||
fallback: string = ""
|
||||
) => {
|
||||
const input = form.querySelector(`#${id}`) as HTMLInputElement;
|
||||
const value = input.value;
|
||||
if (value.length > 0) return value;
|
||||
return fallback;
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
import { TemplateResult, html } from "lit";
|
||||
import { until } from "lit/directives/until.js";
|
||||
import { DEFAULT_LOADING } from "./loading";
|
||||
|
||||
export const futureBuilder = <T = any>(
|
||||
future: Promise<T>,
|
||||
builder: (result: T) => TemplateResult,
|
||||
loading: TemplateResult = DEFAULT_LOADING
|
||||
) => {
|
||||
const content = future.then((result) => builder(result));
|
||||
return html`${until(content, loading)}`;
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
import { html, TemplateResult } from "lit";
|
||||
|
||||
export const listViewBuilder = <T = any>(
|
||||
items: T[],
|
||||
builder: (item: T, index: number) => TemplateResult
|
||||
) => {
|
||||
return html` <ul>
|
||||
${items?.map((n: any, i) => {
|
||||
return html`<li>${builder(n, i)}</li>`;
|
||||
})}
|
||||
</ul>`;
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
import { html } from "lit";
|
||||
|
||||
export const DEFAULT_LOADING = html`<span>Loading...</span>`;
|
||||
Reference in New Issue
Block a user