| string | null = null;
+ @state() private path: string | null = "";
+
+ declare setHTMLUnsafe: (htmlString: string) => void;
+ protected firstUpdated(): void {
+ if (this.type === "array") {
+ this.content = this.innerHTML;
+
+ this.arrayInstances = Array.from({ length: this.instances }, () => ({
+ id: generateUniqueKey(),
+ content: this.content as string,
+ }));
+ } else {
+ this.content = this.querySelectorAll(":scope > *");
+ }
+
+ this.setHTMLUnsafe("");
+ }
+
+ connectedCallback(): void {
+ super.connectedCallback();
+ if (!this.key) {
+ noKeyWarning("ecc-d-form-group", this.label);
+ this.key = _.camelCase(this.label);
+ }
+
+ this.path = findFieldPath(this.key, this, true);
+ }
+
+ protected updated(): void {
+ setupCustomInputs(
+ this.shadowRoot?.querySelectorAll("[ecc-key]:not([ecc-input-path])")
+ );
+ }
+
+ private fireChangeEvent(
+ key: string,
+ value: string,
+ index?: number,
+ e?: CustomEvent
+ ) {
+ // this event is fired for only users, we want the form to ignore these events instead of handling mulitple input events for one input.
+ this.dispatchEvent(
+ new CustomEvent("ecc-input", {
+ bubbles: true,
+ composed: true,
+ detail: {
+ key,
+ value,
+ index,
+ groupType: this.type,
+ groupKey: this.key,
+ target: this,
+ inputEvent: e,
+ },
+ })
+ );
+ }
+
+ private renderGroupTemplate(): TemplateResult {
+ return this.collapsible
+ ? html`
+
+ {
+ this.fireChangeEvent(e.detail.key, e.detail.value);
+ }}
+ >
+ ${this.content}
+
+
+ `
+ : html`
+ ${this.label} ${this.required ? "*" : ""}
+ {
+ this.fireChangeEvent(e.detail.key, e.detail.value);
+ }}
+ >
+ ${this.content}
+
+ `;
+ }
+
+ private renderArrayItem(
+ instance: { content: string },
+ index: number
+ ): TemplateResult {
+ const resolveDeleteButtonIsActive = () => {
+ if (!this.minInstances) return true;
+ if (Number(this.minInstances) >= this.arrayInstances.length || 0)
+ return false;
+ return true;
+ };
+
+ const deleteItem = (itemIndex: number) => {
+ if (resolveDeleteButtonIsActive()) {
+ const newItems = [...this.arrayInstances];
+ newItems.splice(itemIndex, 1);
+
+ this.arrayInstances = newItems;
+
+ this.dispatchEvent(
+ new CustomEvent("ecc-array-delete", {
+ detail: {
+ key: this.key,
+ instances: this.arrayInstances.length,
+ },
+ bubbles: true,
+ composed: true,
+ })
+ );
+ }
+ };
+
+ return html`
+ {
+ e.stopPropagation();
+ this.fireChangeEvent(e.detail.key, e.detail.value, index, e);
+ }}
+ >
+
{
+ deleteItem(index);
+ }}
+ >
+
+
+
+
+
${unsafeHTML(instance.content)}
+
+ `;
+ }
+
+ private renderArrayTemplate(): TemplateResult {
+ const resolveAddButtonIsActive = () => {
+ if (!this.maxInstances) return true;
+ if (Number(this.maxInstances) > this.arrayInstances.length || 0)
+ return true;
+ return false;
+ };
+
+ const addItem = () => {
+ if (resolveAddButtonIsActive()) {
+ const newInstance = {
+ id: generateUniqueKey(),
+ content: this.content as string,
+ };
+
+ this.arrayInstances = [...this.arrayInstances, newInstance];
+
+ this.dispatchEvent(
+ new CustomEvent("ecc-array-add", {
+ detail: {
+ key: this.key,
+ instances: this.arrayInstances.length,
+ },
+ bubbles: true,
+ composed: true,
+ })
+ );
+ }
+ };
+
+ return html`
+
+
+ ${repeat(
+ this.arrayInstances,
+ (instance) => instance.id,
+ this.renderArrayItem.bind(this)
+ )}
+
+ `;
+ }
+
+ render() {
+ if (this.type === "array") {
+ return this.renderArrayTemplate();
+ }
+
+ return this.renderGroupTemplate();
+ }
+}
+
+window.customElements.define("ecc-d-form-group", EccUtilsDesignFormGroup);
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ecc-d-form-group": EccUtilsDesignFormGroup;
+ }
+}
diff --git a/packages/ecc-utils-design/src/components/form/formInput.ts b/packages/ecc-utils-design/src/components/form/formInput.ts
new file mode 100644
index 00000000..f092386d
--- /dev/null
+++ b/packages/ecc-utils-design/src/components/form/formInput.ts
@@ -0,0 +1,431 @@
+import * as _ from "lodash-es";
+import { html, LitElement, TemplateResult } from "lit";
+import { property, state, query } from "lit/decorators.js";
+import { repeat } from "lit/directives/repeat.js";
+import {
+ renderInTooltip,
+ noKeyWarning,
+ removeDuplicates,
+ findFieldPath,
+} from "./utils.js";
+import "@shoelace-style/shoelace/dist/components/alert/alert.js";
+import "@shoelace-style/shoelace/dist/components/icon/icon.js";
+import "@shoelace-style/shoelace/dist/components/input/input.js";
+import "@shoelace-style/shoelace/dist/components/switch/switch.js";
+import "@shoelace-style/shoelace/dist/components/details/details.js";
+import "@shoelace-style/shoelace/dist/components/tooltip/tooltip.js";
+import "@shoelace-style/shoelace/dist/components/select/select.js";
+import "@shoelace-style/shoelace/dist/components/option/option.js";
+
+export type FormItemType =
+ | "text"
+ | "date"
+ | "number"
+ | "email"
+ | "password"
+ | "tel"
+ | "url"
+ | "search"
+ | "datetime-local"
+ | "time"
+ | "array"
+ | "switch"
+ | "file"
+ | "group"
+ | "select";
+
+type AlertType = "info" | "success" | "warning" | "error";
+
+/**
+ * @element ecc-d-form-group
+ * @summary A versatile form group component that can render as either a standard group or an array of form elements.
+ * @description
+ * The `ecc-d-form-group` component provides two main functionalities:
+ * 1. Group mode: Organizes form elements into logical groups, with optional collapsible sections
+ * 2. Array mode: Creates repeatable sets of form elements with add/remove capabilities
+ *
+ * @property {String} label - The display label for the form group
+ * @property {String} key - Unique identifier for the form group, used in form data structure
+ * @property {"array"|"group"} type - The type of form group, defaults to "group"
+ * @property {Boolean} required - Whether the form group is required
+ * @property {String} tooltip - Tooltip text to display additional information about the form group
+ * @property {Number} instances - Initial number of instances for array type
+ * @property {Number} maxInstances - Maximum number of instances allowed for array type
+ * @property {Number} minInstances - Minimum number of instances required for array type
+ * @property {Boolean} collapsible - Whether the group is collapsible (only applies to group type)
+ *
+ * @state {Array<{id: string, content: string}>} arrayInstances - Internal state for array instances
+ * @state {String} content - Internal state for content
+ * @state {String|null} path - Internal state for path
+ *
+ * @method connectedCallback - Public lifecycle method called when element is connected to DOM
+ * @method firstUpdated - Protected lifecycle method called after first update
+ *
+ * @private {method} fireChangeEvent - Fires a change event when input values change
+ * @private {method} renderGroupTemplate - Renders the group template
+ * @private {method} renderArrayItem - Renders an individual array item
+ * @private {method} renderArrayTemplate - Renders the array template
+ *
+ * @event ecc-input - Fired when any child input element changes value. Detail contains: {key, value, index, groupType, groupKey}
+ * @event ecc-array-add - Fired when a new array item is added. Detail contains: {key, instances}
+ * @event ecc-array-delete - Fired when an array item is deleted. Detail contains: {key, instances}
+ *
+ * @slot - Default slot for child form elements
+ *
+ * @dependency @shoelace-style/shoelace - Uses Shoelace components for UI elements
+ */
+export default class EccUtilsDesignFormInput extends LitElement {
+ @property({ type: String }) label = "";
+ @property({ type: String }) key = "";
+ @property({ type: String, reflect: true }) type: FormItemType = "text";
+ @property({ type: Boolean, reflect: true }) disabled = false;
+ @property({ type: String, reflect: true }) tooltip = "";
+ @property({ type: Boolean, reflect: true }) required = false;
+ @property({ type: String, reflect: true }) placeholder = "";
+ @property({ type: String, reflect: true }) default = "";
+ @property({ type: Boolean, reflect: true }) checked = false;
+ @property({ type: Boolean, reflect: true }) multiple = false;
+ @property({ type: String, reflect: true }) value: any;
+ @property({ type: String, reflect: true }) accept = "*";
+ @property({ type: String, attribute: "endpoint" }) tusEndpoint = "";
+ @property({ type: Array, reflect: true }) options = [];
+ @property({ type: String, reflect: true }) protocol: "native" | "tus" =
+ "native";
+
+ @state() private alertText = "Something went wrong";
+ @state() private alertType: AlertType = "info";
+ @state() private showAlert = false;
+ @state() path: string | null = "";
+
+ @query("sl-input") input!: HTMLInputElement;
+
+ connectedCallback(): void {
+ super.connectedCallback();
+ if (!this.key) {
+ noKeyWarning("ecc-d-form-group", this.label);
+ this.key = _.camelCase(this.label);
+ }
+
+ this.path = findFieldPath(this.key, this);
+
+ if (this.type === "switch") {
+ this.value = !!this.value;
+ this.dispatchEvent(new CustomEvent("ecc-input", this.eventData()));
+ }
+
+ if (this.value || this.type === "switch") {
+ if (this.type === "switch") {
+ this.value = !!this.value;
+ }
+
+ this.dispatchEvent(new CustomEvent("ecc-input", this.eventData()));
+ }
+ }
+
+ private eventData() {
+ return {
+ detail: {
+ key: this.key,
+ value: this.value,
+ path: this.path,
+ target: this,
+ },
+ bubbles: true,
+ composed: true,
+ };
+ }
+
+ private handleDismissAlert() {
+ this.alertText = "";
+ this.showAlert = false;
+ this.requestUpdate();
+ }
+
+ private handleShowAlert(alertType: AlertType, alertText: string) {
+ this.alertText = alertText;
+ this.alertType = alertType;
+ this.showAlert = true;
+ this.requestUpdate();
+ }
+
+ validity() {
+ return this.input.validity;
+ }
+
+ checkValidity() {
+ return this.input.checkValidity();
+ }
+
+ reportValidity() {
+ return this.input.reportValidity();
+ }
+
+ private handleClear() {
+ this.dispatchEvent(new CustomEvent("ecc-input", this.eventData()));
+ this.dispatchEvent(new CustomEvent("ecc-clear", this.eventData()));
+ this.dispatchEvent(new CustomEvent("ecc-change", this.eventData()));
+ }
+
+ private handleValueUpdate(e: Event) {
+ const target = e.target as HTMLInputElement;
+ this.value = this.type === "switch" ? target.checked : target.value;
+
+ this.dispatchEvent(new CustomEvent("ecc-input", this.eventData()));
+ this.requestUpdate();
+ }
+
+ private handleFileUpload(e: Event) {
+ const { files } = e.target as HTMLInputElement;
+
+ if (!files?.length) {
+ this.handleShowAlert("error", "No file selected for upload.");
+ return;
+ }
+
+ this.dispatchEvent(new CustomEvent("ecc-input", this.eventData()));
+
+ if (this.protocol === "native") {
+ this.value = files;
+ this.requestUpdate();
+ return;
+ }
+
+ if (!this.tusEndpoint) {
+ this.handleShowAlert("error", "No tus endpoint provided for tus uploads");
+ return;
+ }
+
+ Array.from(files).forEach((file) => {
+ import("@anurag_gupta/tus-js-client")
+ .then(({ Upload }) => {
+ this.handleDismissAlert();
+ this.handleShowAlert("info", `Uploading ${file.name}: 0%`);
+ const upload = new Upload(file, {
+ endpoint: this.tusEndpoint,
+ retryDelays: [0, 3000, 5000, 10000, 20000],
+ metadata: {
+ filename: file.name,
+ filetype: file.type,
+ },
+ onError: (error) => {
+ this.handleShowAlert("error", `Upload failed: ${error.message}`);
+ },
+ onProgress: (bytesUploaded, bytesTotal) => {
+ const percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(
+ 2
+ );
+
+ this.handleShowAlert(
+ "info",
+ `Uploading ${file.name}: ${percentage}%`
+ );
+ this.requestUpdate();
+ },
+ onSuccess: () => {
+ this.handleShowAlert("success", `File(s) Uploaded Successfully`);
+ },
+ });
+
+ upload.findPreviousUploads().then((uploads) => {
+ if (uploads.length > 0) {
+ upload.resumeFromPreviousUpload(uploads[0]);
+ }
+ });
+
+ upload.start();
+ })
+ .catch((error) => {
+ // TO-DO: better error message display
+ this.handleShowAlert(
+ "error",
+ `An error occurred while initializing the upload: ${error.message}`
+ );
+ });
+ });
+ }
+
+ private renderSwitchTemplate(): TemplateResult {
+ const content = html`
+
+ this.dispatchEvent(new CustomEvent("ecc-change", this.eventData()))}
+ @sl-invalid=${() =>
+ this.dispatchEvent(new CustomEvent("ecc-invalid", this.eventData()))}
+ >
+ ${this.label}
+
+ `;
+
+ return html`
+
+ ${renderInTooltip(content, this.tooltip)}
+
+ `;
+ }
+
+ private renderInputTemplate(): TemplateResult {
+ const label = html` ${this.label} `;
+
+ return html`
+
+ this.dispatchEvent(new CustomEvent("ecc-change", this.eventData()))}
+ @sl-invalid=${() =>
+ this.dispatchEvent(new CustomEvent("ecc-invalid", this.eventData()))}
+ >
+ ${renderInTooltip(label, this.tooltip)}
+
+ `;
+ }
+
+ private renderFileTemplate(): TemplateResult {
+ const label = html`
+
+
+ ${this.label} ${this.required ? "*" : ""}
+
+
+ `;
+
+ return html`
+
+ ${renderInTooltip(label, this.tooltip)}
+
+
+ `;
+ }
+
+ private renderSelectTemplate(): TemplateResult {
+ const label = html`
+
+ ${this.label} ${this.required ? "*" : ""}
+
+ `;
+
+ const getSelectValue = () =>
+ this.multiple && this.value && Array.isArray(this.value)
+ ? this.value.join(" ")
+ : this.value;
+
+ const getOptionLabelAndValue = (str: string, labelAttr = true) => {
+ const values = str.split(/(? 1) {
+ return labelAttr ? values[0] : _.kebabCase(values[1]);
+ }
+
+ return labelAttr ? values[0] : _.kebabCase(values[0]);
+ };
+
+ return html`
+
+ ${renderInTooltip(label, this.tooltip)}
+
+ this.dispatchEvent(new CustomEvent("ecc-change", this.eventData()))}
+ @sl-invalid=${() =>
+ this.dispatchEvent(
+ new CustomEvent("ecc-invalid", this.eventData())
+ )}
+ @sl-show=${() =>
+ this.dispatchEvent(new CustomEvent("ecc-show", this.eventData()))}
+ @sl-after-show=${() =>
+ this.dispatchEvent(
+ new CustomEvent("ecc-after-show", this.eventData())
+ )}
+ @sl-hide=${() =>
+ this.dispatchEvent(
+ new CustomEvent("ecc-after-show", this.eventData())
+ )}
+ @sl-after-hide=${() =>
+ this.dispatchEvent(
+ new CustomEvent("ecc-after-show", this.eventData())
+ )}
+ >
+ ${repeat(
+ removeDuplicates(this.options),
+ (opt) => html`
+
+ ${getOptionLabelAndValue(opt)}
+
+ `
+ )}
+
+
+ `;
+ }
+
+ private renderTemplate(): TemplateResult {
+ const { type } = this;
+ if (type === "switch") return this.renderSwitchTemplate();
+ if (type === "file") return this.renderFileTemplate();
+ if (type === "select") return this.renderSelectTemplate();
+
+ return this.renderInputTemplate();
+ }
+
+ render() {
+ return html`
+
+ ${this.alertType === "error"
+ ? html` `
+ : html` `}
+ ${this.alertText}
+
+
+ ${this.renderTemplate()}
+ `;
+ }
+}
+
+window.customElements.define("ecc-d-form-input", EccUtilsDesignFormInput);
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ecc-d-form-input": EccUtilsDesignFormInput;
+ }
+}
diff --git a/packages/ecc-utils-design/src/components/form/index.ts b/packages/ecc-utils-design/src/components/form/index.ts
index 8cfa1aa8..794965c6 100644
--- a/packages/ecc-utils-design/src/components/form/index.ts
+++ b/packages/ecc-utils-design/src/components/form/index.ts
@@ -1,12 +1,9 @@
import EccUtilsDesignForm from "./form.js";
+import EccUtilsDesignFormInput from "./formInput.js";
+import EccUtilsDesignFormGroup from "./formGroup.js";
export * from "./form.js";
-export default EccUtilsDesignForm;
+export * from "./formInput.js";
+export * from "./formGroup.js";
-window.customElements.define("ecc-utils-design-form", EccUtilsDesignForm);
-
-declare global {
- interface HTMLElementTagNameMap {
- "ecc-utils-design-form": EccUtilsDesignForm;
- }
-}
+export { EccUtilsDesignFormInput, EccUtilsDesignFormGroup, EccUtilsDesignForm };
diff --git a/packages/ecc-utils-design/src/components/form/utils.ts b/packages/ecc-utils-design/src/components/form/utils.ts
new file mode 100644
index 00000000..c124b7f3
--- /dev/null
+++ b/packages/ecc-utils-design/src/components/form/utils.ts
@@ -0,0 +1,119 @@
+import { html, TemplateResult } from "lit";
+
+export function renderInTooltip(
+ content: TemplateResult,
+ tooltipText: string
+): TemplateResult {
+ return tooltipText.trim()
+ ? html`
+
+ ${content}
+
+ `
+ : content;
+}
+
+export function devWarn(message: string): void {
+ // eslint-disable-next-line turbo/no-undeclared-env-vars
+ if (process.env.NODE_ENV === "development") {
+ console.warn(message);
+ }
+}
+
+export function noKeyWarning(Element: string, label: string): void {
+ console.warn(
+ `${Element}: Key attribute is required. We will auto generate a key from label but cannot guarantee uniqness. To ensure optimal functionality Please add a key for this field: ${label}`
+ );
+}
+
+export function generateUniqueKey() {
+ return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
+}
+
+export const findFieldPath = (
+ key: string,
+ element: HTMLElement | null,
+ isGroup = false
+): string | null => {
+ const gropEl = findNearestFormGroup(element, isGroup);
+
+ if (!gropEl) return null;
+
+ const parentPath = gropEl?.getAttribute("path");
+ return parentPath ? `${parentPath}.${key}` : key;
+};
+
+export const findNearestFormGroup = (
+ element: HTMLElement | null,
+ isGroup = false
+): Element | null => {
+ if (!element) return null;
+
+ const topLevelElement = element.closest("ecc-d-form, ecc-d-form-group");
+ if (
+ topLevelElement &&
+ element.shadowRoot &&
+ (topLevelElement.matches("ecc-d-form") ||
+ (!isGroup && topLevelElement.matches("ecc-d-form-group")))
+ ) {
+ return null;
+ }
+
+ const specialElement = element.closest(
+ "[ecc-array], [ecc-group], [ecc-form]"
+ );
+
+ if (specialElement) {
+ return specialElement;
+ }
+
+ return element.parentElement
+ ? findNearestFormGroup(element.parentElement, isGroup)
+ : null;
+};
+
+export const removeDuplicates = (arr: string[]) => {
+ const lowercaseMap = new Map();
+ arr.forEach((item) => {
+ if (!item) return;
+ lowercaseMap.set(item.toLowerCase(), item);
+ });
+
+ return Array.from(lowercaseMap.values());
+};
+
+export const setupCustomInputs = (
+ inputs: NodeListOf | undefined
+) => {
+ inputs?.forEach((input) => {
+ // if the path has already been set don't set it again
+ if (input.getAttribute("ecc-input-path")) return;
+ // if it has children then it's not an input but one or more of its children may be
+ if (input.hasChildNodes()) {
+ setupCustomInputs(input.childNodes as NodeListOf);
+ }
+ // if it is not an input return
+ if (typeof input.value === "undefined") return;
+
+ const key = input.getAttribute("ecc-key");
+ if (!key) return;
+
+ const path = findFieldPath(key, input as HTMLElement);
+ input.setAttribute("ecc-d-input-path", path || "");
+
+ input.addEventListener("input", () => {
+ input.dispatchEvent(
+ new CustomEvent("ecc-input", {
+ detail: {
+ key,
+ path,
+ target: input,
+ value: input.value,
+ },
+ bubbles: true,
+ composed: true,
+ })
+ );
+ });
+ });
+};
diff --git a/packages/ecc-utils-design/src/components/index.ts b/packages/ecc-utils-design/src/components/index.ts
index d4a4d22c..91639cd5 100644
--- a/packages/ecc-utils-design/src/components/index.ts
+++ b/packages/ecc-utils-design/src/components/index.ts
@@ -1,4 +1,4 @@
-export { default as EccUtilsDesignForm } from "./form/index.js";
-export { default as EccUtilsDesignCollection } from "./collection/index.js";
-export { default as EccUtilsDesignDetails } from "./details/index.js";
-export { default as EccUtilsDesignCode } from "./code/index.js";
+export * from "./form/index.js";
+export * from "./code/index.js";
+export * from "./collection/index.js";
+export * from "./details/index.js";
diff --git a/packages/ecc-utils-design/src/events/ecc-after-show.ts b/packages/ecc-utils-design/src/events/ecc-after-show.ts
new file mode 100644
index 00000000..c24bd9fc
--- /dev/null
+++ b/packages/ecc-utils-design/src/events/ecc-after-show.ts
@@ -0,0 +1,7 @@
+export type EccAfterShowEvent = CustomEvent>;
+
+declare global {
+ interface GlobalEventHandlersEventMap {
+ "ecc-after-show": EccAfterShowEvent;
+ }
+}
diff --git a/packages/ecc-utils-design/src/events/ecc-array-add.ts b/packages/ecc-utils-design/src/events/ecc-array-add.ts
new file mode 100644
index 00000000..8c76331a
--- /dev/null
+++ b/packages/ecc-utils-design/src/events/ecc-array-add.ts
@@ -0,0 +1,7 @@
+export type EccArrayAddEvent = CustomEvent>;
+
+declare global {
+ interface GlobalEventHandlersEventMap {
+ "ecc-array-add": EccArrayAddEvent;
+ }
+}
diff --git a/packages/ecc-utils-design/src/events/ecc-array-delete.ts b/packages/ecc-utils-design/src/events/ecc-array-delete.ts
new file mode 100644
index 00000000..dca02184
--- /dev/null
+++ b/packages/ecc-utils-design/src/events/ecc-array-delete.ts
@@ -0,0 +1,7 @@
+export type EccArrayDeleteEvent = CustomEvent>;
+
+declare global {
+ interface GlobalEventHandlersEventMap {
+ "ecc-array-delete": EccArrayDeleteEvent;
+ }
+}
diff --git a/packages/ecc-utils-design/src/events/ecc-button-click.ts b/packages/ecc-utils-design/src/events/ecc-button-click.ts
new file mode 100644
index 00000000..db3f538a
--- /dev/null
+++ b/packages/ecc-utils-design/src/events/ecc-button-click.ts
@@ -0,0 +1,7 @@
+export type EccButtonClickEvent = CustomEvent>;
+
+declare global {
+ interface GlobalEventHandlersEventMap {
+ "ecc-button-click": EccButtonClickEvent;
+ }
+}
diff --git a/packages/ecc-utils-design/src/events/ecc-change.ts b/packages/ecc-utils-design/src/events/ecc-change.ts
new file mode 100644
index 00000000..a7346634
--- /dev/null
+++ b/packages/ecc-utils-design/src/events/ecc-change.ts
@@ -0,0 +1,7 @@
+export type EccChangeEvent = CustomEvent>;
+
+declare global {
+ interface GlobalEventHandlersEventMap {
+ "ecc-change": EccChangeEvent;
+ }
+}
diff --git a/packages/ecc-utils-design/src/events/ecc-clear.ts b/packages/ecc-utils-design/src/events/ecc-clear.ts
new file mode 100644
index 00000000..838f3b09
--- /dev/null
+++ b/packages/ecc-utils-design/src/events/ecc-clear.ts
@@ -0,0 +1,7 @@
+export type EccClearEvent = CustomEvent>;
+
+declare global {
+ interface GlobalEventHandlersEventMap {
+ "ecc-clear": EccClearEvent;
+ }
+}
diff --git a/packages/ecc-utils-design/src/events/ecc-expand.ts b/packages/ecc-utils-design/src/events/ecc-expand.ts
new file mode 100644
index 00000000..8c482a72
--- /dev/null
+++ b/packages/ecc-utils-design/src/events/ecc-expand.ts
@@ -0,0 +1,7 @@
+export type EccExpandEvent = CustomEvent<{ key?: number }>;
+
+declare global {
+ interface GlobalEventHandlersEventMap {
+ "ecc-expand": EccExpandEvent;
+ }
+}
diff --git a/packages/ecc-utils-design/src/events/ecc-filter.ts b/packages/ecc-utils-design/src/events/ecc-filter.ts
new file mode 100644
index 00000000..6d8b3572
--- /dev/null
+++ b/packages/ecc-utils-design/src/events/ecc-filter.ts
@@ -0,0 +1,7 @@
+export type EccFilterEvent = CustomEvent<{ key: string; value: string }>;
+
+declare global {
+ interface GlobalEventHandlersEventMap {
+ "ecc-filter": EccFilterEvent;
+ }
+}
diff --git a/packages/ecc-utils-design/src/events/ecc-input.ts b/packages/ecc-utils-design/src/events/ecc-input.ts
new file mode 100644
index 00000000..49612b59
--- /dev/null
+++ b/packages/ecc-utils-design/src/events/ecc-input.ts
@@ -0,0 +1,7 @@
+export type EccInputEvent = CustomEvent>;
+
+declare global {
+ interface GlobalEventHandlersEventMap {
+ "ecc-input": EccInputEvent;
+ }
+}
diff --git a/packages/ecc-utils-design/src/events/ecc-invalid.ts b/packages/ecc-utils-design/src/events/ecc-invalid.ts
new file mode 100644
index 00000000..24086cac
--- /dev/null
+++ b/packages/ecc-utils-design/src/events/ecc-invalid.ts
@@ -0,0 +1,7 @@
+export type EccInvalidEvent = CustomEvent>;
+
+declare global {
+ interface GlobalEventHandlersEventMap {
+ "ecc-invalid": EccInvalidEvent;
+ }
+}
diff --git a/packages/ecc-utils-design/src/events/ecc-page-change.ts b/packages/ecc-utils-design/src/events/ecc-page-change.ts
new file mode 100644
index 00000000..6e403b7d
--- /dev/null
+++ b/packages/ecc-utils-design/src/events/ecc-page-change.ts
@@ -0,0 +1,7 @@
+export type EccPageChangeEvent = CustomEvent<{ page: number }>;
+
+declare global {
+ interface GlobalEventHandlersEventMap {
+ "ecc-page-change": EccPageChangeEvent;
+ }
+}
diff --git a/packages/ecc-utils-design/src/events/ecc-show.ts b/packages/ecc-utils-design/src/events/ecc-show.ts
new file mode 100644
index 00000000..3f184c33
--- /dev/null
+++ b/packages/ecc-utils-design/src/events/ecc-show.ts
@@ -0,0 +1,7 @@
+export type EccShowEvent = CustomEvent>;
+
+declare global {
+ interface GlobalEventHandlersEventMap {
+ "ecc-show": EccShowEvent;
+ }
+}
diff --git a/packages/ecc-utils-design/src/events/ecc-submit.ts b/packages/ecc-utils-design/src/events/ecc-submit.ts
new file mode 100644
index 00000000..e3add214
--- /dev/null
+++ b/packages/ecc-utils-design/src/events/ecc-submit.ts
@@ -0,0 +1,7 @@
+export type EccSubmitEvent = CustomEvent<{ form: object }>;
+
+declare global {
+ interface GlobalEventHandlersEventMap {
+ "ecc-submit": EccSubmitEvent;
+ }
+}
diff --git a/packages/ecc-utils-design/src/events/ecc-utils-button-click.ts b/packages/ecc-utils-design/src/events/ecc-utils-button-click.ts
deleted file mode 100644
index e018bcf2..00000000
--- a/packages/ecc-utils-design/src/events/ecc-utils-button-click.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export type EccUtilsButtonClickEvent = CustomEvent>;
-
-declare global {
- interface GlobalEventHandlersEventMap {
- "ecc-utils-button-click": EccUtilsButtonClickEvent;
- }
-}
diff --git a/packages/ecc-utils-design/src/events/ecc-utils-change.ts b/packages/ecc-utils-design/src/events/ecc-utils-change.ts
deleted file mode 100644
index 5b0f615f..00000000
--- a/packages/ecc-utils-design/src/events/ecc-utils-change.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export type EccUtilsChangeEvent = CustomEvent>;
-
-declare global {
- interface GlobalEventHandlersEventMap {
- "ecc-utils-change": EccUtilsChangeEvent;
- }
-}
diff --git a/packages/ecc-utils-design/src/events/ecc-utils-expand.ts b/packages/ecc-utils-design/src/events/ecc-utils-expand.ts
deleted file mode 100644
index 7f1d57c1..00000000
--- a/packages/ecc-utils-design/src/events/ecc-utils-expand.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export type EccUtilsExpandEvent = CustomEvent<{ key?: number }>;
-
-declare global {
- interface GlobalEventHandlersEventMap {
- "ecc-utils-expand": EccUtilsExpandEvent;
- }
-}
diff --git a/packages/ecc-utils-design/src/events/ecc-utils-filter.ts b/packages/ecc-utils-design/src/events/ecc-utils-filter.ts
deleted file mode 100644
index d109c78f..00000000
--- a/packages/ecc-utils-design/src/events/ecc-utils-filter.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export type EccUtilsFilterEvent = CustomEvent<{ key: string; value: string }>;
-
-declare global {
- interface GlobalEventHandlersEventMap {
- "ecc-utils-filter": EccUtilsFilterEvent;
- }
-}
diff --git a/packages/ecc-utils-design/src/events/ecc-utils-page-change.ts b/packages/ecc-utils-design/src/events/ecc-utils-page-change.ts
deleted file mode 100644
index ba7426e3..00000000
--- a/packages/ecc-utils-design/src/events/ecc-utils-page-change.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export type EccUtilsPageChangeEvent = CustomEvent<{ page: number }>;
-
-declare global {
- interface GlobalEventHandlersEventMap {
- "ecc-utils-page-change": EccUtilsPageChangeEvent;
- }
-}
diff --git a/packages/ecc-utils-design/src/events/ecc-utils-submit.ts b/packages/ecc-utils-design/src/events/ecc-utils-submit.ts
deleted file mode 100644
index b7b8cf03..00000000
--- a/packages/ecc-utils-design/src/events/ecc-utils-submit.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export type EccUtilsSubmitEvent = CustomEvent<{ form: object }>;
-
-declare global {
- interface GlobalEventHandlersEventMap {
- "ecc-utils-submit": EccUtilsSubmitEvent;
- }
-}
diff --git a/packages/ecc-utils-design/src/events/index.ts b/packages/ecc-utils-design/src/events/index.ts
index 0dbf6d83..d6706992 100644
--- a/packages/ecc-utils-design/src/events/index.ts
+++ b/packages/ecc-utils-design/src/events/index.ts
@@ -1,6 +1,13 @@
-export type { EccUtilsSubmitEvent } from "./ecc-utils-submit.js";
-export type { EccUtilsExpandEvent } from "./ecc-utils-expand.js";
-export type { EccUtilsFilterEvent } from "./ecc-utils-filter.js";
-export type { EccUtilsPageChangeEvent } from "./ecc-utils-page-change.js";
-export type { EccUtilsButtonClickEvent } from "./ecc-utils-button-click.js";
-export type { EccUtilsChangeEvent } from "./ecc-utils-change.js";
+export type { EccSubmitEvent } from "./ecc-submit.js";
+export type { EccExpandEvent } from "./ecc-expand.js";
+export type { EccFilterEvent } from "./ecc-filter.js";
+export type { EccPageChangeEvent } from "./ecc-page-change.js";
+export type { EccButtonClickEvent } from "./ecc-button-click.js";
+export type { EccChangeEvent } from "./ecc-change.js";
+export type { EccArrayAddEvent } from "./ecc-array-add.js";
+export type { EccArrayDeleteEvent } from "./ecc-array-delete.js";
+export type { EccInputEvent } from "./ecc-input.js";
+export type { EccAfterShowEvent } from "./ecc-after-show.js";
+export type { EccClearEvent } from "./ecc-clear.js";
+export type { EccInvalidEvent } from "./ecc-invalid.js";
+export type { EccShowEvent } from "./ecc-show.js";
diff --git a/scripts/templates/custom-elements-manifest.config.js b/scripts/templates/custom-elements-manifest.config.js
index 81fe8669..ceb08cda 100644
--- a/scripts/templates/custom-elements-manifest.config.js
+++ b/scripts/templates/custom-elements-manifest.config.js
@@ -4,7 +4,6 @@ import fs from "fs";
import { program } from "commander";
import { customElementVsCodePlugin } from "custom-element-vs-code-integration";
import { customElementJetBrainsPlugin } from "custom-element-jet-brains-integration";
-import packageJson from "./package.json" assert { type: "json" };
const options = program
.option("-o, --outdir ")
@@ -13,9 +12,16 @@ const options = program
.parse()
.opts();
-const componentsPrefix = packageJson.componentsPrefix;
const packageData = JSON.parse(fs.readFileSync("package.json", "utf8"));
-const { name, description, version, author, homepage, license } = packageData;
+const {
+ name,
+ description,
+ version,
+ author,
+ homepage,
+ license,
+ componentsPrefix,
+} = packageData;
const getComponentDocumentation = (tag) =>
`https://elixir-cloud-components.vercel.app/design/components/${tag.replace(
@@ -63,6 +69,8 @@ export default {
?.map((jsDoc) => jsDoc.getFullText())
.join("\n");
+ console.log("class docs", classDoc.events);
+
if (classDoc?.events) {
classDoc.events.forEach((event) => {
// eslint-disable-next-line no-undef
diff --git a/turbo.json b/turbo.json
index f1f6e2f2..54a4015d 100644
--- a/turbo.json
+++ b/turbo.json
@@ -1,7 +1,7 @@
{
"$schema": "https://turbo.build/schema.json",
- "globalDependencies": ["**/.env.*local"],
- "pipeline": {
+ "globalDependencies": ["**/.env.*local", "NODE_ENV"],
+ "tasks": {
"topo": {
"dependsOn": ["^topo"]
},