- ${renderAnalyticsDialogHeadline(`${this.eventName} event`, "Close event details", () => this.#close())}
+ ${renderAnalyticsDialogHeadline(html`
+
${this.details ? html`
${this.propertiesEnabled ? activeProperty ? html`
@@ -179,8 +189,8 @@ export class WebAnalyticsEventDetailsDialogElement extends UmbElementMixin(LitEl
`;
}
- static styles = [UmbTextStyles, analyticsDialogStyles, reportTabsStyles, css`
- .dialog-content { --analytics-dialog-body-height: min(28rem, 52dvh); display: flex; flex-direction: column; position: relative; }
+ static styles = [UmbTextStyles, analyticsDialogStyles, analyticsEventDialogStyles, analyticsTableSkeletonStyles, reportTabsStyles, css`
+ .dialog-content { display: flex; flex-direction: column; position: relative; }
.property-controls { border-bottom: 1px solid var(--uui-color-border); display: grid; flex: 0 0 auto; gap: var(--uui-size-space-3); padding: 0 var(--analytics-dialog-inline-padding) var(--uui-size-space-4); }
.property-controls uui-input { box-sizing: border-box; width: 100%; }
.property-controls uui-input [slot="prepend"] { align-items: center; display: flex; margin-inline: var(--uui-size-space-3) var(--uui-size-space-2); }
diff --git a/src/TheBuilder.WebAnalytics/Client/src/analytics/event-dialog.element.test.ts b/src/TheBuilder.WebAnalytics/Client/src/analytics/event-dialog.element.test.ts
new file mode 100644
index 0000000..ce9afcb
--- /dev/null
+++ b/src/TheBuilder.WebAnalytics/Client/src/analytics/event-dialog.element.test.ts
@@ -0,0 +1,26 @@
+// @vitest-environment jsdom
+import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
+
+vi.mock("@umbraco-cms/backoffice/element-api", () => ({
+ UmbElementMixin:
(base: T) => base,
+}));
+vi.mock("@umbraco-cms/backoffice/style", () => ({ UmbTextStyles: [] }));
+
+import type { WebAnalyticsEventDialogElement } from "./event-dialog.element.js";
+import "./event-dialog.element.js";
+
+beforeEach(() => { HTMLDialogElement.prototype.showModal = vi.fn(); });
+afterEach(() => document.body.replaceChildren());
+
+describe("events dialog", () => {
+ it("keeps its accessible name without repeating a visible title", async () => {
+ const dialog = document.createElement("web-analytics-event-dialog") as WebAnalyticsEventDialogElement;
+ document.body.append(dialog);
+ await dialog.updateComplete;
+
+ expect(dialog.shadowRoot?.querySelector("dialog")?.getAttribute("aria-label")).toBe("Events");
+ expect(dialog.shadowRoot?.querySelector(".analytics-dialog-headline h2")).toBeNull();
+ expect(dialog.shadowRoot?.querySelector("uui-input")?.getAttribute("label")).toBe("Search events");
+ expect(dialog.shadowRoot?.querySelector(".analytics-dialog-close")?.getAttribute("aria-label")).toBe("Close events");
+ });
+});
diff --git a/src/TheBuilder.WebAnalytics/Client/src/analytics/event-dialog.element.ts b/src/TheBuilder.WebAnalytics/Client/src/analytics/event-dialog.element.ts
index 624a371..c2a0080 100644
--- a/src/TheBuilder.WebAnalytics/Client/src/analytics/event-dialog.element.ts
+++ b/src/TheBuilder.WebAnalytics/Client/src/analytics/event-dialog.element.ts
@@ -4,7 +4,7 @@ import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
import type { UUIInputElement } from "@umbraco-cms/backoffice/external/uui";
import type { AnalyticsEventRow } from "../api/types.gen.js";
import { renderAnalyticsDialogHeadline } from "./analytics-dialog-headline.js";
-import { analyticsDialogStyles } from "./analytics-dialog.styles.js";
+import { analyticsDialogStyles, analyticsEventDialogStyles } from "./analytics-dialog.styles.js";
import type { AnalyticsFilter } from "./dashboard-url-state.js";
import "./event-table.element.js";
@@ -35,7 +35,7 @@ export class WebAnalyticsEventDialogElement extends UmbElementMixin(LitElement)
- `)}
+ `, false)}
${!this.loading && this.unavailable ? html`
${this.unavailable}
` : ""}
${!this.loading && !this.unavailable && this._search && this.rows.length === 0 ? html`
Try a different search.
` : ""}
@@ -48,8 +48,7 @@ export class WebAnalyticsEventDialogElement extends UmbElementMixin(LitElement)
`;
}
- static styles = [UmbTextStyles, analyticsDialogStyles, css`
- dialog { --analytics-dialog-max-width: 58rem; }
+ static styles = [UmbTextStyles, analyticsDialogStyles, analyticsEventDialogStyles, css`
uui-input { box-sizing: border-box; width: 100%; }
uui-input [slot="prepend"] { align-items: center; display: flex; margin-inline: var(--uui-size-space-3) var(--uui-size-space-2); }
.results { overflow: auto; scrollbar-gutter: stable; }
diff --git a/src/TheBuilder.WebAnalytics/Client/src/analytics/event-table.element.ts b/src/TheBuilder.WebAnalytics/Client/src/analytics/event-table.element.ts
index 3e99df7..5b4ff64 100644
--- a/src/TheBuilder.WebAnalytics/Client/src/analytics/event-table.element.ts
+++ b/src/TheBuilder.WebAnalytics/Client/src/analytics/event-table.element.ts
@@ -3,6 +3,7 @@ import { UmbElementMixin } from "@umbraco-cms/backoffice/element-api";
import type { AnalyticsEventRow } from "../api/types.gen.js";
import type { AnalyticsFilter } from "./dashboard-url-state.js";
import { visibleEventRows } from "./event-rows.js";
+import { analyticsTableSkeletonStyles, renderAnalyticsTableSkeletonRows } from "./analytics-table-skeleton.js";
@customElement("web-analytics-event-table")
export class WebAnalyticsEventTableElement extends UmbElementMixin(LitElement) {
@@ -31,9 +32,7 @@ export class WebAnalyticsEventTableElement extends UmbElementMixin(LitElement) {
Events and goals
| Event | Visitors | Total events |
${this.loading
- ? Array.from({ length: this.skeletonRows }, () => html`
- | | |
- `)
+ ? renderAnalyticsTableSkeletonRows(this.skeletonRows)
: rows.map((row) => {
const activeFilter = this.filters.some((filter) => filter.dimension === "EventName" && filter.value === row.eventName);
const filterLabel = activeFilter ? `Remove ${row.eventName} event filter` : `Filter analytics by ${row.eventName} event`;
@@ -75,7 +74,7 @@ export class WebAnalyticsEventTableElement extends UmbElementMixin(LitElement) {
`;
}
- static styles = css`
+ static styles = [analyticsTableSkeletonStyles, css`
:host { block-size: 100%; display: flex; flex-direction: column; overflow-x: auto; }
table { --bar-inset: var(--uui-size-space-3); border-collapse: collapse; min-inline-size: 30rem; table-layout: fixed; width: 100%; }
caption { clip: rect(0 0 0 0); height: 1px; overflow: hidden; position: absolute; width: 1px; }
@@ -100,17 +99,14 @@ export class WebAnalyticsEventTableElement extends UmbElementMixin(LitElement) {
.filter-action:focus-visible { outline: 2px solid var(--uui-color-selected); outline-offset: 1px; }
.bar { inset-block: var(--uui-size-space-1); inset-inline-start: var(--bar-inset); inline-size: calc(100% + 16rem - 2 * var(--bar-inset)); position: absolute; }
.bar::before { background: color-mix(in srgb, var(--uui-color-interactive) 4%, var(--uui-color-surface)); block-size: 100%; border-radius: var(--uui-border-radius); content: ""; display: block; inline-size: max(var(--bar-minimum), var(--bar-width)); }
- .skeleton-line, .skeleton-number { background: var(--uui-color-surface-alt); block-size: 1lh; border-radius: var(--uui-border-radius); display: block; }
- .skeleton-line { width: 70%; }
- .skeleton-number { margin-inline-start: auto; width: 3.5rem; }
.empty { align-items: center; display: flex; flex: 1; flex-direction: column; gap: var(--uui-size-space-3); justify-content: center; min-block-size: 16rem; padding: var(--uui-size-layout-1); text-align: center; }
- .empty-icon { align-items: center; border: 1px solid var(--uui-color-border); border-radius: 50%; color: var(--uui-color-text-alt); display: inline-flex; font-size: 1.5rem; height: 3rem; justify-content: center; width: 3rem; }
+ .empty-icon { align-items: center; border: 1px solid var(--uui-color-border); border-radius: 50%; color: var(--uui-color-text-alt); display: inline-flex; font-size: var(--uui-type-h4-size); height: 3rem; justify-content: center; width: 3rem; }
.empty p { color: var(--uui-color-text-alt); margin: 0; max-width: 34rem; }
.empty a { align-items: center; color: var(--uui-color-interactive-emphasis); display: inline-flex; gap: var(--uui-size-space-1); }
.empty a:focus-visible { outline: 2px solid var(--uui-color-selected); outline-offset: 2px; }
.visually-hidden { clip: rect(0 0 0 0); clip-path: inset(50%); height: 1px; overflow: hidden; position: absolute; white-space: nowrap; width: 1px; }
@media (hover: none) { .filter-action { opacity: 1; } }
- `;
+ `];
}
declare global {