Skip to main content

Creating a web component

Basic component structure

Create src/my-widget.ts:

import type {
ImagingProps,
ModalEventDetail,
PluginContext,
PluginSettings,
ScreenContext,
TokenRequestDetail,
TokenRequestResponse,
} from "@acuitas/shared";
import styles from "@acuitas/shared/css/acuitas-design-system.css?inline";
import { LitElement, html, unsafeCSS } from "lit";
import { customElement, property } from "lit/decorators.js";

@customElement("my-acuitas-widget")
export class MyAcuitasWidget extends LitElement {
// Required PluginProps properties
@property() id = "";
@property() name = "";

@property({ type: Object })
context: PluginContext = {
environment: "SANDBOX",
customerId: "",
siteId: "",
staffId: "",
};

@property({ type: Object })
screen: ScreenContext = {
view: "MEDICAL_IMAGES",
maxWidth: 400,
maxHeight: 600,
};

@property({ type: Object })
settings: PluginSettings = {};

@property({ type: Object })
imaging: ImagingProps = {
patientId: '',
images: [],
selectedImage: null,
};

@property({ type: Function })
onOpenModal: ((detail: ModalEventDetail) => void) | undefined;

@property({ type: Function })
onCloseModal: ((detail: ModalEventDetail) => void) | undefined;

@property({ type: Function })
onRequestToken:
| ((detail: TokenRequestDetail) => TokenRequestResponse)
| undefined;

@property({ type: Boolean })
isModalOpen = false;

@property({ type: Object })
additionalProps: Record<string, any> = {};

render() {
const containerStyle = this.isModalOpen
? "max-width: 100%; max-height: 100%;"
: `max-width: ${this.screen.maxWidth}px; ${this.screen.maxHeight ? `max-height: ${this.screen.maxHeight}px;` : ""}`;

return html`
<div class="plugin-container" style="${containerStyle}">
<div class="card">
<div class="card-header">
<h3 class="mb-0">${this.name || "My Acuitas Widget"}</h3>
<div class="d-flex align-center gap-2">
<span class="badge ${this.context.environment === "PRODUCTION" ? "badge-success" : "badge-warning"}">
${this.context.environment}
</span>
</div>
</div>

<div class="card-body">
${this._renderPluginContent()}
${this._renderModalControls()}
</div>
</div>
</div>
`;
}

private _renderPluginContent() {
return html`
<!-- Add your custom widget content here -->
<div class="mb-sm">
<p>Hello from ${this.name}!</p>
<p>Customer: ${this.context.customerId}</p>
<p>Available Images: ${this.imaging.images.length}</p>
</div>
`;
}

private _renderModalControls() {
return html`
<div class="d-flex gap-2">
${
!this.isModalOpen
? html`
<button class="btn btn-primary" @click=${this._openModal}>
🔍 Open Full Screen
</button>
`
: html`
<button class="btn btn-primary" @click=${this._closeModal}>
❌ Close Modal
</button>
`
}
</div>
`;
}

private _openModal() {
if (this.onOpenModal) {
this.onOpenModal(this._createModalEventDetail());
}
}

private _closeModal() {
if (this.onCloseModal) {
this.onCloseModal(this._createModalEventDetail());
}
}

// Apply the Acuitas design system styles
static styles = unsafeCSS(styles);
}

// Register the component globally
declare global {
interface HTMLElementTagNameMap {
"my-acuitas-widget": MyAcuitasWidget;
}
}

Entry point

Create src/index.ts:

// Import and register the web component
import "./my-widget.ts";
import { MyAcuitasWidget } from "./my-widget.ts";

// Export the web component class for module federation
export default MyAcuitasWidget;
export { MyAcuitasWidget };

Type definitions

Create src/vite-env.d.ts:

/// <reference types="vite/client" />

declare module "*?inline" {
const content: string;
export default content;
}