@schukai/monster 4.148.8 → 4.149.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/source/components/accessibility/stylesheet/locale-picker.mjs +61 -1
- package/source/components/content/image-editor.mjs +79 -11
- package/source/components/content/style/copy.pcss +1 -1
- package/source/components/content/stylesheet/camera-capture.mjs +1 -1
- package/source/components/content/stylesheet/copy.mjs +1 -1
- package/source/components/content/stylesheet/fetch-box.mjs +1 -1
- package/source/components/content/stylesheet/viewer.mjs +61 -1
- package/source/components/data/kpi-tile.mjs +5 -3
- package/source/components/data/metric-graph.mjs +22 -20
- package/source/components/data/metric.mjs +20 -18
- package/source/components/data/style/kpi-tile.pcss +65 -43
- package/source/components/data/style/metric-graph.pcss +35 -18
- package/source/components/data/style/metric.pcss +35 -28
- package/source/components/data/stylesheet/kpi-tile.mjs +61 -1
- package/source/components/data/stylesheet/metric-graph.mjs +61 -1
- package/source/components/data/stylesheet/metric.mjs +61 -1
- package/source/components/datatable/columnbar.mjs +4 -2
- package/source/components/datatable/datatable.mjs +73 -15
- package/source/components/datatable/filter/date-range.mjs +61 -61
- package/source/components/datatable/filter/date-time.mjs +5 -1
- package/source/components/datatable/filter/range.mjs +3 -3
- package/source/components/datatable/filter/select-operator.mjs +7 -1
- package/source/components/datatable/filter/text-operator.mjs +11 -3
- package/source/components/datatable/filter.mjs +16 -0
- package/source/components/datatable/pagination.mjs +2 -2
- package/source/components/datatable/style/column-bar.pcss +115 -23
- package/source/components/datatable/style/datatable.pcss +257 -29
- package/source/components/datatable/style/embedded-pagination.pcss +63 -34
- package/source/components/datatable/style/filter-button.pcss +1 -1
- package/source/components/datatable/style/filter-controls-defaults.pcss +49 -3
- package/source/components/datatable/style/filter-select.pcss +4 -1
- package/source/components/datatable/style/filter.pcss +18 -1
- package/source/components/datatable/stylesheet/change-button.mjs +61 -1
- package/source/components/datatable/stylesheet/column-bar.mjs +69 -1
- package/source/components/datatable/stylesheet/dataset.mjs +61 -1
- package/source/components/datatable/stylesheet/datatable.mjs +71 -1
- package/source/components/datatable/stylesheet/embedded-pagination.mjs +1 -1
- package/source/components/datatable/stylesheet/filter-button.mjs +1 -1
- package/source/components/datatable/stylesheet/filter-controls-defaults.mjs +1 -1
- package/source/components/datatable/stylesheet/filter-select.mjs +61 -1
- package/source/components/datatable/stylesheet/filter.mjs +61 -1
- package/source/components/datatable/stylesheet/pagination.mjs +67 -1
- package/source/components/datatable/stylesheet/save-button.mjs +61 -1
- package/source/components/datatable/stylesheet/status.mjs +61 -1
- package/source/components/form/action-button.mjs +2 -1
- package/source/components/form/button-bar.mjs +7 -2
- package/source/components/form/context-error.mjs +4 -3
- package/source/components/form/context-help.mjs +10 -4
- package/source/components/form/context-hint.mjs +1 -1
- package/source/components/form/context-info.mjs +1 -1
- package/source/components/form/context-note.mjs +1 -1
- package/source/components/form/context-success.mjs +1 -1
- package/source/components/form/context-warning.mjs +1 -1
- package/source/components/form/control-bar.mjs +300 -14
- package/source/components/form/credential-button.mjs +4 -2
- package/source/components/form/digits.mjs +28 -1
- package/source/components/form/field-set.mjs +30 -0
- package/source/components/form/login.mjs +13 -10
- package/source/components/form/password.mjs +6 -0
- package/source/components/form/popper-button.mjs +1 -1
- package/source/components/form/quantity.mjs +14 -6
- package/source/components/form/register-wizard.mjs +46 -26
- package/source/components/form/select.mjs +17 -10
- package/source/components/form/sheet.mjs +13 -2
- package/source/components/form/style/action-button.pcss +131 -5
- package/source/components/form/style/button-bar.pcss +204 -3
- package/source/components/form/style/control-bar.pcss +254 -26
- package/source/components/form/style/digits.pcss +7 -6
- package/source/components/form/style/input-group.pcss +65 -1
- package/source/components/form/style/login.pcss +1 -1
- package/source/components/form/style/mixin/field-set-layout.pcss +8 -0
- package/source/components/form/style/password.pcss +25 -1
- package/source/components/form/style/popper-button.pcss +1 -0
- package/source/components/form/style/quantity.pcss +11 -20
- package/source/components/form/style/select.pcss +52 -7
- package/source/components/form/style/sheet.pcss +70 -1
- package/source/components/form/style/state-button.pcss +5 -2
- package/source/components/form/style/toggle-switch.pcss +7 -4
- package/source/components/form/stylesheet/action-button.mjs +63 -1
- package/source/components/form/stylesheet/button-bar.mjs +153 -1
- package/source/components/form/stylesheet/button.mjs +61 -1
- package/source/components/form/stylesheet/control-bar.mjs +163 -1
- package/source/components/form/stylesheet/digits.mjs +1 -1
- package/source/components/form/stylesheet/field-layout.mjs +1 -1
- package/source/components/form/stylesheet/field-set.mjs +1 -1
- package/source/components/form/stylesheet/form.mjs +1 -1
- package/source/components/form/stylesheet/input-group.mjs +15 -1
- package/source/components/form/stylesheet/login.mjs +1 -1
- package/source/components/form/stylesheet/password.mjs +7 -1
- package/source/components/form/stylesheet/popper-button.mjs +61 -1
- package/source/components/form/stylesheet/quantity.mjs +1 -1
- package/source/components/form/stylesheet/register-wizard.mjs +1 -1
- package/source/components/form/stylesheet/select.mjs +3 -1
- package/source/components/form/stylesheet/sheet.mjs +1 -1
- package/source/components/form/stylesheet/state-button.mjs +3 -1
- package/source/components/form/stylesheet/toggle-switch.mjs +1 -1
- package/source/components/form/stylesheet/wizard.mjs +1 -1
- package/source/components/form/util/floating-ui.mjs +35 -7
- package/source/components/host/call-button.mjs +3 -1
- package/source/components/host/stylesheet/call-button.mjs +61 -1
- package/source/components/host/stylesheet/host.mjs +1 -1
- package/source/components/host/stylesheet/toggle-button.mjs +61 -1
- package/source/components/layout/full-screen.mjs +31 -23
- package/source/components/layout/iframe.mjs +5 -1
- package/source/components/layout/popper.mjs +34 -4
- package/source/components/layout/style/full-screen.pcss +94 -23
- package/source/components/layout/style/split-panel.pcss +57 -5
- package/source/components/layout/style/tabs.pcss +277 -47
- package/source/components/layout/style/vertical-tabs.pcss +147 -0
- package/source/components/layout/stylesheet/collapse.mjs +61 -1
- package/source/components/layout/stylesheet/details.mjs +61 -1
- package/source/components/layout/stylesheet/full-screen.mjs +23 -1
- package/source/components/layout/stylesheet/overlay.mjs +1 -1
- package/source/components/layout/stylesheet/panel.mjs +1 -1
- package/source/components/layout/stylesheet/slider.mjs +1 -1
- package/source/components/layout/stylesheet/split-panel.mjs +17 -1
- package/source/components/layout/stylesheet/tabs.mjs +97 -1
- package/source/components/layout/stylesheet/vertical-tabs.mjs +33 -95
- package/source/components/layout/tabs.mjs +63 -0
- package/source/components/layout/vertical-tabs.mjs +63 -0
- package/source/components/navigation/stylesheet/site-navigation.mjs +1 -1
- package/source/components/navigation/stylesheet/table-of-content.mjs +1 -1
- package/source/components/navigation/stylesheet/wizard-navigation.mjs +1 -1
- package/source/components/navigation/table-of-content.mjs +13 -0
- package/source/components/notify/style/notify.pcss +1 -2
- package/source/components/notify/stylesheet/message.mjs +1 -1
- package/source/components/notify/stylesheet/notify.mjs +1 -1
- package/source/components/state/style/log.pcss +1 -0
- package/source/components/state/style/state.pcss +5 -1
- package/source/components/state/stylesheet/log.mjs +1 -1
- package/source/components/state/stylesheet/state.mjs +7 -1
- package/source/components/style/button.css +61 -205
- package/source/components/style/button.pcss +78 -34
- package/source/components/style/common.css +1 -170
- package/source/components/style/common.pcss +5 -9
- package/source/components/style/form.css +1 -49
- package/source/components/style/form.pcss +24 -6
- package/source/components/style/link.css +1 -39
- package/source/components/style/link.pcss +8 -16
- package/source/components/style/mixin/button.pcss +19 -10
- package/source/components/style/mixin/property.pcss +8 -0
- package/source/components/style/mixin/skeleton.pcss +11 -5
- package/source/components/style/normalize.css +1 -144
- package/source/components/style/normalize.pcss +5 -5
- package/source/components/style/property.css +1 -387
- package/source/components/style/skeleton.css +1 -198
- package/source/components/style/skeleton.pcss +8 -2
- package/source/components/style/theme-modern.css +74 -0
- package/source/components/style/theme-modern.pcss +498 -0
- package/source/components/stylesheet/button.mjs +61 -1
- package/source/components/stylesheet/common.mjs +1 -1
- package/source/components/stylesheet/form.mjs +1 -1
- package/source/components/stylesheet/link.mjs +1 -1
- package/source/components/stylesheet/normalize.mjs +1 -1
- package/source/components/stylesheet/property.mjs +1 -1
- package/source/components/stylesheet/skeleton.mjs +1 -1
- package/source/components/stylesheet/theme-modern.mjs +110 -0
- package/source/components/time/stylesheet/day.mjs +61 -1
- package/source/components/time/stylesheet/month-calendar.mjs +61 -1
- package/source/components/time/timeline/stylesheet/appointment.mjs +61 -1
- package/source/components/time/timeline/stylesheet/segment.mjs +61 -1
- package/source/components/tree-menu/style/tree-menu.pcss +26 -37
- package/source/components/tree-menu/stylesheet/tree-menu.mjs +1 -1
- package/source/dom/customelement.mjs +105 -40
- package/source/dom/updater.mjs +381 -119
- package/test/cases/components/content/image-editor.mjs +19 -0
- package/test/cases/components/datatable/accessibility-defaults.mjs +112 -0
- package/test/cases/components/datatable/filter-availability.mjs +37 -0
- package/test/cases/components/datatable/filter-date-range-layout.mjs +40 -0
- package/test/cases/components/datatable/filter-select-operator.mjs +118 -0
- package/test/cases/components/datatable/mobile-layout.mjs +203 -0
- package/test/cases/components/datatable/responsive-breakpoint.mjs +41 -0
- package/test/cases/components/datatable/selection.mjs +149 -0
- package/test/cases/components/form/action-button-style.mjs +85 -0
- package/test/cases/components/form/button-bar.mjs +222 -3
- package/test/cases/components/form/context-theme-colors.mjs +59 -0
- package/test/cases/components/form/control-bar.mjs +228 -3
- package/test/cases/components/form/control-heights.mjs +103 -0
- package/test/cases/components/form/digits-accessibility.mjs +65 -0
- package/test/cases/components/form/field-set.mjs +54 -0
- package/test/cases/components/form/floating-ui.mjs +74 -0
- package/test/cases/components/form/input-group.mjs +61 -28
- package/test/cases/components/form/login.mjs +47 -0
- package/test/cases/components/form/password.mjs +63 -0
- package/test/cases/components/form/popper-button.mjs +30 -15
- package/test/cases/components/form/quantity-accessibility.mjs +46 -0
- package/test/cases/components/form/register-wizard.mjs +79 -0
- package/test/cases/components/form/select.mjs +94 -2
- package/test/cases/components/form/sheet.mjs +56 -2
- package/test/cases/components/host/toggle-button.mjs +50 -0
- package/test/cases/components/layout/full-screen.mjs +60 -0
- package/test/cases/components/layout/iframe-accessibility.mjs +44 -0
- package/test/cases/components/layout/popper.mjs +128 -0
- package/test/cases/components/layout/slit-panel.mjs +30 -1
- package/test/cases/components/layout/tabs.mjs +93 -0
- package/test/cases/components/navigation/table-of-content.mjs +18 -0
- package/test/cases/components/state/state-style.mjs +31 -0
- package/test/cases/components/style/action-menu.mjs +74 -0
- package/test/cases/components/style/form-controls.mjs +37 -0
- package/test/cases/components/style/kpi-tile.mjs +60 -0
- package/test/cases/components/style/legacy-theme-compatibility.mjs +137 -0
- package/test/cases/components/style/metric-layout.mjs +94 -0
- package/test/cases/components/style/skeleton.mjs +69 -0
- package/test/cases/components/style/theme-component-catalog.mjs +853 -0
- package/test/cases/components/style/theme-modern.mjs +439 -0
- package/test/cases/components/style/theme-review-regressions.mjs +41 -0
- package/test/cases/dom/customelement.mjs +136 -1
- package/test/cases/dom/updater.mjs +174 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as chai from "chai";
|
|
2
|
+
import { initJSDOM } from "../../../util/jsdom.mjs";
|
|
3
|
+
|
|
4
|
+
const expect = chai.expect;
|
|
5
|
+
|
|
6
|
+
describe("ToggleButton", function () {
|
|
7
|
+
before(async function () {
|
|
8
|
+
await initJSDOM({});
|
|
9
|
+
await import("../../../../source/components/host/toggle-button.mjs");
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
document.getElementById("mocks").innerHTML = "";
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("should expose a native button trigger and toggle the referenced target", async function () {
|
|
17
|
+
const mocks = document.getElementById("mocks");
|
|
18
|
+
const target = document.createElement("div");
|
|
19
|
+
const toggleButton = document.createElement("monster-toggle-button");
|
|
20
|
+
let toggleCount = 0;
|
|
21
|
+
|
|
22
|
+
target.className = "toggle-target";
|
|
23
|
+
target.toggle = () => {
|
|
24
|
+
toggleCount++;
|
|
25
|
+
};
|
|
26
|
+
toggleButton.setOptions({
|
|
27
|
+
references: {
|
|
28
|
+
callableSelector: [".toggle-target"],
|
|
29
|
+
},
|
|
30
|
+
labels: {
|
|
31
|
+
button: "Toggle details",
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
mocks.append(target, toggleButton);
|
|
35
|
+
|
|
36
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
37
|
+
|
|
38
|
+
const trigger = toggleButton.shadowRoot.querySelector(
|
|
39
|
+
'[data-monster-role="call-button"]',
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
expect(trigger).to.be.instanceof(HTMLButtonElement);
|
|
43
|
+
expect(trigger.type).to.equal("button");
|
|
44
|
+
expect(trigger.hasAttribute("href")).to.equal(false);
|
|
45
|
+
|
|
46
|
+
trigger.click();
|
|
47
|
+
|
|
48
|
+
expect(toggleCount).to.equal(1);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { expect } from "chai";
|
|
3
|
+
|
|
4
|
+
const componentSource = readFileSync(
|
|
5
|
+
new URL(
|
|
6
|
+
"../../../../source/components/layout/full-screen.mjs",
|
|
7
|
+
import.meta.url,
|
|
8
|
+
),
|
|
9
|
+
"utf8",
|
|
10
|
+
);
|
|
11
|
+
const styleSource = readFileSync(
|
|
12
|
+
new URL(
|
|
13
|
+
"../../../../source/components/layout/style/full-screen.pcss",
|
|
14
|
+
import.meta.url,
|
|
15
|
+
),
|
|
16
|
+
"utf8",
|
|
17
|
+
);
|
|
18
|
+
const generatedStyleSheet = readFileSync(
|
|
19
|
+
new URL(
|
|
20
|
+
"../../../../source/components/layout/stylesheet/full-screen.mjs",
|
|
21
|
+
import.meta.url,
|
|
22
|
+
),
|
|
23
|
+
"utf8",
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
describe("FullScreen", () => {
|
|
27
|
+
it("exposes the fullscreen control as a named toggle button", () => {
|
|
28
|
+
expect(componentSource).to.include(
|
|
29
|
+
'<button type="button" data-monster-role="control" part="control"',
|
|
30
|
+
);
|
|
31
|
+
expect(componentSource).to.include('aria-label="Enter full screen"');
|
|
32
|
+
expect(componentSource).to.include('aria-pressed="false"');
|
|
33
|
+
expect(componentSource).to.include(
|
|
34
|
+
'isFullScreen ? "Exit full screen" : "Enter full screen"',
|
|
35
|
+
);
|
|
36
|
+
expect(componentSource).to.include(
|
|
37
|
+
'element.setAttribute("aria-pressed", isFullScreen ? "true" : "false")',
|
|
38
|
+
);
|
|
39
|
+
expect(componentSource).to.include(
|
|
40
|
+
"rootNode?.fullscreenElement || document.fullscreenElement",
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("uses theme-aware control states and a visible keyboard focus ring", () => {
|
|
45
|
+
for (const token of [
|
|
46
|
+
"--monster-full-screen-control-size",
|
|
47
|
+
"--monster-full-screen-control-background-color",
|
|
48
|
+
"--monster-full-screen-control-hover-background-color",
|
|
49
|
+
"--monster-full-screen-control-active-background-color",
|
|
50
|
+
"--monster-full-screen-control-border-radius",
|
|
51
|
+
"--monster-focus-ring-color",
|
|
52
|
+
]) {
|
|
53
|
+
expect(styleSource, token).to.include(token);
|
|
54
|
+
expect(generatedStyleSheet, token).to.include(token);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
expect(styleSource).to.include(":focus-visible");
|
|
58
|
+
expect(styleSource).to.include("prefers-reduced-motion: reduce");
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as chai from "chai";
|
|
2
|
+
import { initJSDOM } from "../../../util/jsdom.mjs";
|
|
3
|
+
import { ResizeObserverMock } from "../../../util/resize-observer.mjs";
|
|
4
|
+
|
|
5
|
+
const { expect } = chai;
|
|
6
|
+
const nextTask = () => new Promise((resolve) => setTimeout(resolve, 0));
|
|
7
|
+
|
|
8
|
+
describe("Iframe accessibility", function () {
|
|
9
|
+
before(async () => {
|
|
10
|
+
await initJSDOM();
|
|
11
|
+
globalThis.ResizeObserver ??= ResizeObserverMock;
|
|
12
|
+
await import("../../../../source/components/layout/iframe.mjs");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
document.getElementById("mocks").replaceChildren();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should provide and update a configurable native iframe title", async function () {
|
|
20
|
+
const component = document.createElement("monster-iframe");
|
|
21
|
+
document.getElementById("mocks").append(component);
|
|
22
|
+
await nextTask();
|
|
23
|
+
const iframe = component.shadowRoot.querySelector("iframe");
|
|
24
|
+
|
|
25
|
+
expect(iframe.getAttribute("title")).to.equal("Embedded content");
|
|
26
|
+
component.setOption("labels.title", "Account preview");
|
|
27
|
+
await nextTask();
|
|
28
|
+
expect(iframe.getAttribute("title")).to.equal("Account preview");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("should accept its title through the public option attribute", async function () {
|
|
32
|
+
const component = document.createElement("monster-iframe");
|
|
33
|
+
component.setAttribute(
|
|
34
|
+
"data-monster-option-labels-title",
|
|
35
|
+
"Theme Lab fixture",
|
|
36
|
+
);
|
|
37
|
+
document.getElementById("mocks").append(component);
|
|
38
|
+
await nextTask();
|
|
39
|
+
|
|
40
|
+
expect(
|
|
41
|
+
component.shadowRoot.querySelector("iframe").getAttribute("title"),
|
|
42
|
+
).to.equal("Theme Lab fixture");
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import * as chai from "chai";
|
|
2
|
+
import { initJSDOM } from "../../../util/jsdom.mjs";
|
|
3
|
+
|
|
4
|
+
const expect = chai.expect;
|
|
5
|
+
|
|
6
|
+
describe("Popper", function () {
|
|
7
|
+
this.timeout(10000);
|
|
8
|
+
|
|
9
|
+
before(async function () {
|
|
10
|
+
await initJSDOM({});
|
|
11
|
+
await import("../../../../source/components/layout/popper.mjs");
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
document.getElementById("mocks").innerHTML = "";
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("should position against the assigned button instead of the full-width control", async function () {
|
|
19
|
+
const mocks = document.getElementById("mocks");
|
|
20
|
+
const host = document.createElement("monster-popper");
|
|
21
|
+
const button = document.createElement("button");
|
|
22
|
+
|
|
23
|
+
button.slot = "button";
|
|
24
|
+
button.textContent = "Open";
|
|
25
|
+
host.setOptions({
|
|
26
|
+
mode: "manual",
|
|
27
|
+
content: "<p>Actions</p>",
|
|
28
|
+
popper: {
|
|
29
|
+
placement: "bottom",
|
|
30
|
+
middleware: [],
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
host.appendChild(button);
|
|
34
|
+
mocks.appendChild(host);
|
|
35
|
+
|
|
36
|
+
await waitForTimeout();
|
|
37
|
+
|
|
38
|
+
const control = host.shadowRoot.querySelector(
|
|
39
|
+
'[data-monster-role="control"]',
|
|
40
|
+
);
|
|
41
|
+
const popper = host.shadowRoot.querySelector(
|
|
42
|
+
'[data-monster-role="popper"]',
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
setElementRect(control, {
|
|
46
|
+
x: 100,
|
|
47
|
+
y: 100,
|
|
48
|
+
width: 500,
|
|
49
|
+
height: 40,
|
|
50
|
+
});
|
|
51
|
+
setElementRect(button, {
|
|
52
|
+
x: 100,
|
|
53
|
+
y: 100,
|
|
54
|
+
width: 120,
|
|
55
|
+
height: 40,
|
|
56
|
+
});
|
|
57
|
+
setElementRect(popper, {
|
|
58
|
+
x: 0,
|
|
59
|
+
y: 0,
|
|
60
|
+
width: 200,
|
|
61
|
+
height: 80,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
host.showDialog();
|
|
65
|
+
|
|
66
|
+
await waitForCondition(() => popper.style.transform !== "");
|
|
67
|
+
|
|
68
|
+
expect(popper.style.transform).to.contain("translate(60px,140px)");
|
|
69
|
+
host.hideDialog();
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
function setElementRect(element, { x, y, width, height }) {
|
|
74
|
+
const rect = {
|
|
75
|
+
x,
|
|
76
|
+
y,
|
|
77
|
+
width,
|
|
78
|
+
height,
|
|
79
|
+
top: y,
|
|
80
|
+
left: x,
|
|
81
|
+
right: x + width,
|
|
82
|
+
bottom: y + height,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
element.getBoundingClientRect = () => rect;
|
|
86
|
+
for (const [property, value] of Object.entries({
|
|
87
|
+
offsetWidth: width,
|
|
88
|
+
offsetHeight: height,
|
|
89
|
+
clientWidth: width,
|
|
90
|
+
clientHeight: height,
|
|
91
|
+
})) {
|
|
92
|
+
Object.defineProperty(element, property, {
|
|
93
|
+
configurable: true,
|
|
94
|
+
value,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function waitForTimeout(timeout = 0) {
|
|
100
|
+
return new Promise((resolve) => setTimeout(resolve, timeout));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function waitForCondition(check, { timeout = 1000, interval = 10 } = {}) {
|
|
104
|
+
const deadline = Date.now() + timeout;
|
|
105
|
+
|
|
106
|
+
return new Promise((resolve, reject) => {
|
|
107
|
+
const tick = () => {
|
|
108
|
+
try {
|
|
109
|
+
if (check()) {
|
|
110
|
+
resolve();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
} catch (error) {
|
|
114
|
+
reject(error);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (Date.now() >= deadline) {
|
|
119
|
+
reject(new Error("Timed out waiting for condition."));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
setTimeout(tick, interval);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
tick();
|
|
127
|
+
});
|
|
128
|
+
}
|
|
@@ -7,6 +7,7 @@ const expect = chai.expect;
|
|
|
7
7
|
chai.use(chaiDom);
|
|
8
8
|
|
|
9
9
|
const global = getGlobal();
|
|
10
|
+
let SplitPanel;
|
|
10
11
|
|
|
11
12
|
// language=html
|
|
12
13
|
const html1 = `
|
|
@@ -32,7 +33,11 @@ describe("SplitScreen", () => {
|
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
promises.push(
|
|
35
|
-
import("../../../../source/components/layout/split-panel.mjs")
|
|
36
|
+
import("../../../../source/components/layout/split-panel.mjs").then(
|
|
37
|
+
(module) => {
|
|
38
|
+
SplitPanel = module.SplitPanel;
|
|
39
|
+
},
|
|
40
|
+
),
|
|
36
41
|
);
|
|
37
42
|
|
|
38
43
|
Promise.all(promises)
|
|
@@ -69,6 +74,30 @@ describe("SplitScreen", () => {
|
|
|
69
74
|
}, 0);
|
|
70
75
|
});
|
|
71
76
|
|
|
77
|
+
it("should expose a visible theme-aware drag handle", () => {
|
|
78
|
+
const cssText = SplitPanel.getCSSStyleSheet()
|
|
79
|
+
.flatMap((styleSheet) => Array.from(styleSheet.cssRules))
|
|
80
|
+
.map((rule) => rule.cssText)
|
|
81
|
+
.join("\n");
|
|
82
|
+
|
|
83
|
+
expect(cssText).to.contain(
|
|
84
|
+
"--monster-split-panel-dragger-background-color",
|
|
85
|
+
);
|
|
86
|
+
expect(cssText).to.contain(
|
|
87
|
+
"--monster-split-panel-dragger-hover-background-color",
|
|
88
|
+
);
|
|
89
|
+
expect(cssText).to.contain(
|
|
90
|
+
"--monster-split-panel-handle-background-color",
|
|
91
|
+
);
|
|
92
|
+
expect(cssText).to.contain(
|
|
93
|
+
"--monster-split-panel-handle-hover-background-color",
|
|
94
|
+
);
|
|
95
|
+
expect(cssText).to.contain("--monster-split-panel-transition-duration");
|
|
96
|
+
expect(cssText).to.contain("--monster-split-panel-handle-active-scale");
|
|
97
|
+
expect(cssText).to.contain("cursor: inherit");
|
|
98
|
+
expect(cssText).to.contain("prefers-reduced-motion");
|
|
99
|
+
});
|
|
100
|
+
|
|
72
101
|
it("should use the configured dragger width for vertical panel dimensions", (done) => {
|
|
73
102
|
const mocks = document.getElementById("mocks");
|
|
74
103
|
mocks.innerHTML = html1;
|
|
@@ -342,6 +342,46 @@ describe("Tabs", function () {
|
|
|
342
342
|
mocks.innerHTML = "";
|
|
343
343
|
});
|
|
344
344
|
|
|
345
|
+
it("should expose an accessible theme-aware appearance", function () {
|
|
346
|
+
const cssText = Tabs.getCSSStyleSheet()
|
|
347
|
+
.flatMap((styleSheet) => Array.from(styleSheet.cssRules))
|
|
348
|
+
.map((rule) => rule.cssText)
|
|
349
|
+
.join("\n");
|
|
350
|
+
|
|
351
|
+
expect(cssText).to.contain("--monster-tabs-nav-background-color");
|
|
352
|
+
expect(cssText).to.contain("--monster-tabs-nav-align-items");
|
|
353
|
+
expect(cssText).to.contain("--monster-tabs-button-color");
|
|
354
|
+
expect(cssText).to.contain(
|
|
355
|
+
"--monster-tabs-button-active-background-color",
|
|
356
|
+
);
|
|
357
|
+
expect(cssText).to.contain("--monster-tabs-indicator-inline-size");
|
|
358
|
+
expect(cssText).to.contain("--monster-tabs-indicator-active-opacity");
|
|
359
|
+
expect(cssText).to.contain("button:before");
|
|
360
|
+
expect(cssText).to.contain("prefers-reduced-motion");
|
|
361
|
+
expect(cssText).to.contain(":focus-visible");
|
|
362
|
+
expect(cssText).to.contain(
|
|
363
|
+
"min-height: var(--monster-tabs-button-min-block-size",
|
|
364
|
+
);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it("should expose a readable theme-aware vertical layout", function () {
|
|
368
|
+
const cssText = VerticalTabs.getCSSStyleSheet()
|
|
369
|
+
.flatMap((styleSheet) => Array.from(styleSheet.cssRules))
|
|
370
|
+
.map((rule) => rule.cssText)
|
|
371
|
+
.join("\n");
|
|
372
|
+
|
|
373
|
+
expect(cssText).to.contain("--monster-vertical-tabs-control-gap");
|
|
374
|
+
expect(cssText).to.contain(
|
|
375
|
+
"--monster-vertical-tabs-control-min-block-size",
|
|
376
|
+
);
|
|
377
|
+
expect(cssText).to.contain("--monster-vertical-tabs-nav-block-size");
|
|
378
|
+
expect(cssText).to.contain("--monster-vertical-tabs-nav-min-block-size");
|
|
379
|
+
expect(cssText).to.contain("--monster-vertical-tabs-nav-min-inline-size");
|
|
380
|
+
expect(cssText).to.contain("--monster-vertical-tabs-nav-max-block-size");
|
|
381
|
+
expect(cssText).to.contain("--monster-vertical-tabs-label-writing-mode");
|
|
382
|
+
expect(cssText).to.contain("horizontal-tb");
|
|
383
|
+
});
|
|
384
|
+
|
|
345
385
|
it("should have buttons and tabs", function (done) {
|
|
346
386
|
let mocks = document.getElementById("mocks");
|
|
347
387
|
mocks.innerHTML = html1;
|
|
@@ -475,6 +515,59 @@ describe("Tabs", function () {
|
|
|
475
515
|
}, 0);
|
|
476
516
|
});
|
|
477
517
|
|
|
518
|
+
it("should name overflow switches and expose their expanded state", async function () {
|
|
519
|
+
const mocks = document.getElementById("mocks");
|
|
520
|
+
mocks.innerHTML = `${html1}${htmlVerticalIconModes}`;
|
|
521
|
+
|
|
522
|
+
const tabs = document.getElementById("mytabs");
|
|
523
|
+
const verticalTabs = document.getElementById("vertical-icon-mode-tabs");
|
|
524
|
+
await waitForCondition(() => {
|
|
525
|
+
return Boolean(
|
|
526
|
+
tabs.shadowRoot?.querySelector('[data-monster-role="switch"]') &&
|
|
527
|
+
verticalTabs.shadowRoot?.querySelector(
|
|
528
|
+
'[data-monster-role="switch"]',
|
|
529
|
+
),
|
|
530
|
+
);
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
for (const element of [tabs, verticalTabs]) {
|
|
534
|
+
const switchButton = element.shadowRoot.querySelector(
|
|
535
|
+
'[data-monster-role="switch"]',
|
|
536
|
+
);
|
|
537
|
+
const popper = element.shadowRoot.querySelector(
|
|
538
|
+
'[data-monster-role="popper"]',
|
|
539
|
+
);
|
|
540
|
+
expect(switchButton.type).to.equal("button");
|
|
541
|
+
expect(switchButton.getAttribute("aria-label")).to.equal("More tabs");
|
|
542
|
+
expect(switchButton.getAttribute("aria-controls")).to.equal(popper.id);
|
|
543
|
+
expect(switchButton.getAttribute("aria-expanded")).to.equal("false");
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
tabs.setOption("labels.moreActions", "Additional sections");
|
|
547
|
+
await waitForCondition(() => {
|
|
548
|
+
return (
|
|
549
|
+
tabs.shadowRoot
|
|
550
|
+
.querySelector('[data-monster-role="switch"]')
|
|
551
|
+
.getAttribute("aria-label") === "Additional sections"
|
|
552
|
+
);
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
const switchButton = tabs.shadowRoot.querySelector(
|
|
556
|
+
'[data-monster-role="switch"]',
|
|
557
|
+
);
|
|
558
|
+
switchButton.click();
|
|
559
|
+
expect(switchButton.getAttribute("aria-expanded")).to.equal("true");
|
|
560
|
+
switchButton.dispatchEvent(
|
|
561
|
+
new KeyboardEvent("keydown", {
|
|
562
|
+
key: "Escape",
|
|
563
|
+
bubbles: true,
|
|
564
|
+
composed: true,
|
|
565
|
+
}),
|
|
566
|
+
);
|
|
567
|
+
expect(switchButton.getAttribute("aria-expanded")).to.equal("false");
|
|
568
|
+
expect(tabs.shadowRoot.activeElement).to.equal(switchButton);
|
|
569
|
+
});
|
|
570
|
+
|
|
478
571
|
it("should move overflowing tabs into the popper without losing them", function (done) {
|
|
479
572
|
this.timeout(15000);
|
|
480
573
|
|
|
@@ -159,6 +159,24 @@ describe('TableOfContent', function () {
|
|
|
159
159
|
expect(navigation.style.top).to.equal('');
|
|
160
160
|
});
|
|
161
161
|
|
|
162
|
+
it('should position the navigation popper against the fixed trigger without an ancestor clipping boundary', async function () {
|
|
163
|
+
const target = document.getElementById('target');
|
|
164
|
+
const tableOfContent = document.createElement('monster-table-of-content');
|
|
165
|
+
const heading = document.createElement('h2');
|
|
166
|
+
|
|
167
|
+
heading.textContent = 'Introduction';
|
|
168
|
+
tableOfContent.appendChild(heading);
|
|
169
|
+
target.appendChild(tableOfContent);
|
|
170
|
+
|
|
171
|
+
const popper = tableOfContent.shadowRoot.querySelector('monster-popper');
|
|
172
|
+
|
|
173
|
+
await waitForCondition(() => {
|
|
174
|
+
return popper.getOption('popper.boundaryElement') === null;
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
expect(popper.getOption('popper.boundaryElement')).to.equal(null);
|
|
178
|
+
});
|
|
179
|
+
|
|
162
180
|
it('should enable scroll following at runtime', async function () {
|
|
163
181
|
const target = document.getElementById('target');
|
|
164
182
|
const outerScroller = document.createElement('div');
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { expect } from "chai";
|
|
3
|
+
|
|
4
|
+
const stateStyleSource = readFileSync(
|
|
5
|
+
new URL(
|
|
6
|
+
"../../../../source/components/state/style/state.pcss",
|
|
7
|
+
import.meta.url,
|
|
8
|
+
),
|
|
9
|
+
"utf8",
|
|
10
|
+
);
|
|
11
|
+
const generatedStateStyle = readFileSync(
|
|
12
|
+
new URL(
|
|
13
|
+
"../../../../source/components/state/stylesheet/state.mjs",
|
|
14
|
+
import.meta.url,
|
|
15
|
+
),
|
|
16
|
+
"utf8",
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
describe("State visual styles", () => {
|
|
20
|
+
it("inherits the current text color for slotted SVG fills", () => {
|
|
21
|
+
expect(stateStyleSource).to.include("::slotted([slot=visual])");
|
|
22
|
+
expect(stateStyleSource).to.include("::slotted([part=visual])");
|
|
23
|
+
expect(stateStyleSource).to.include("fill: currentColor");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("keeps the generated state stylesheet in sync", () => {
|
|
27
|
+
expect(generatedStateStyle).to.include(
|
|
28
|
+
"::slotted([part=visual]),::slotted([slot=visual]){fill:currentColor}",
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { expect } from "chai";
|
|
3
|
+
|
|
4
|
+
const sources = new Map(
|
|
5
|
+
[
|
|
6
|
+
["button bar", "form/style/button-bar.pcss"],
|
|
7
|
+
["action button", "form/style/action-button.pcss"],
|
|
8
|
+
["sheet context menu", "form/style/sheet.pcss"],
|
|
9
|
+
["tab overflow", "layout/style/tabs.pcss"],
|
|
10
|
+
].map(([name, path]) => [
|
|
11
|
+
name,
|
|
12
|
+
readFileSync(
|
|
13
|
+
new URL(`../../../../source/components/${path}`, import.meta.url),
|
|
14
|
+
"utf8",
|
|
15
|
+
),
|
|
16
|
+
]),
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
const generatedSources = new Map(
|
|
20
|
+
[
|
|
21
|
+
["button bar", "form/stylesheet/button-bar.mjs"],
|
|
22
|
+
["action button", "form/stylesheet/action-button.mjs"],
|
|
23
|
+
["sheet context menu", "form/stylesheet/sheet.mjs"],
|
|
24
|
+
["tab overflow", "layout/stylesheet/tabs.mjs"],
|
|
25
|
+
].map(([name, path]) => [
|
|
26
|
+
name,
|
|
27
|
+
readFileSync(
|
|
28
|
+
new URL(`../../../../source/components/${path}`, import.meta.url),
|
|
29
|
+
"utf8",
|
|
30
|
+
),
|
|
31
|
+
]),
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
describe("Shared action menu styles", () => {
|
|
35
|
+
it("uses the same popper frame tokens in every action menu", () => {
|
|
36
|
+
for (const [name, source] of sources) {
|
|
37
|
+
for (const token of [
|
|
38
|
+
"--monster-action-menu-padding",
|
|
39
|
+
"--monster-action-menu-border-width",
|
|
40
|
+
"--monster-action-menu-border-style",
|
|
41
|
+
"--monster-action-menu-border-color",
|
|
42
|
+
"--monster-action-menu-border-radius",
|
|
43
|
+
"--monster-action-menu-box-shadow",
|
|
44
|
+
]) {
|
|
45
|
+
expect(source, `${name}: ${token}`).to.include(token);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("uses the same padding and border contract for every menu item", () => {
|
|
51
|
+
for (const [name, source] of sources) {
|
|
52
|
+
for (const token of [
|
|
53
|
+
"--monster-action-menu-item-min-block-size",
|
|
54
|
+
"--monster-action-menu-item-padding",
|
|
55
|
+
"--monster-action-menu-item-border-width",
|
|
56
|
+
"--monster-action-menu-item-border-radius",
|
|
57
|
+
"--monster-action-menu-item-hover-background-color",
|
|
58
|
+
]) {
|
|
59
|
+
expect(source, `${name}: ${token}`).to.include(token);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("keeps generated component styles in sync", () => {
|
|
65
|
+
for (const [name, source] of generatedSources) {
|
|
66
|
+
expect(source, `${name}: frame`).to.include(
|
|
67
|
+
"--monster-action-menu-padding",
|
|
68
|
+
);
|
|
69
|
+
expect(source, `${name}: item`).to.include(
|
|
70
|
+
"--monster-action-menu-item-padding",
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { expect } from "chai";
|
|
3
|
+
|
|
4
|
+
const formSource = readFileSync(
|
|
5
|
+
new URL("../../../../source/components/style/form.pcss", import.meta.url),
|
|
6
|
+
"utf8",
|
|
7
|
+
);
|
|
8
|
+
const generatedStyleSheet = readFileSync(
|
|
9
|
+
new URL("../../../../source/components/stylesheet/form.mjs", import.meta.url),
|
|
10
|
+
"utf8",
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
describe("Global form controls", () => {
|
|
14
|
+
it("keeps native choice controls separate from text-control sizing", () => {
|
|
15
|
+
expect(formSource).to.include(
|
|
16
|
+
'input:not([type="checkbox"]):not([type="radio"]),',
|
|
17
|
+
);
|
|
18
|
+
expect(formSource).to.include(
|
|
19
|
+
'input:is([type="checkbox"], [type="radio"])',
|
|
20
|
+
);
|
|
21
|
+
expect(formSource).to.match(
|
|
22
|
+
/input:is\(\[type="checkbox"\], \[type="radio"\]\) \{[^}]*block-size: 1rem;[^}]*inline-size: 1rem;[^}]*min-height: 0;[^}]*padding: 0;[^}]*vertical-align: middle;/s,
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("keeps the generated stylesheet synchronized", () => {
|
|
27
|
+
expect(generatedStyleSheet).to.include(
|
|
28
|
+
'input:not([type=checkbox]):not([type=radio])',
|
|
29
|
+
);
|
|
30
|
+
expect(generatedStyleSheet).to.include(
|
|
31
|
+
'input:is([type=checkbox],[type=radio])',
|
|
32
|
+
);
|
|
33
|
+
expect(generatedStyleSheet).to.include(
|
|
34
|
+
"block-size:1rem;inline-size:1rem;min-height:0;padding:0;vertical-align:middle",
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { expect } from "chai";
|
|
3
|
+
|
|
4
|
+
const kpiTileSource = readFileSync(
|
|
5
|
+
new URL(
|
|
6
|
+
"../../../../source/components/data/style/kpi-tile.pcss",
|
|
7
|
+
import.meta.url,
|
|
8
|
+
),
|
|
9
|
+
"utf8",
|
|
10
|
+
);
|
|
11
|
+
const kpiTileStyleSheet = readFileSync(
|
|
12
|
+
new URL(
|
|
13
|
+
"../../../../source/components/data/stylesheet/kpi-tile.mjs",
|
|
14
|
+
import.meta.url,
|
|
15
|
+
),
|
|
16
|
+
"utf8",
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
describe("KpiTile styles", () => {
|
|
20
|
+
it("keeps long headings intact and uses normal title casing", () => {
|
|
21
|
+
for (const declaration of [
|
|
22
|
+
"hyphens: none",
|
|
23
|
+
"overflow-wrap: normal",
|
|
24
|
+
"text-transform: none",
|
|
25
|
+
"word-break: normal",
|
|
26
|
+
]) {
|
|
27
|
+
expect(kpiTileSource).to.include(declaration);
|
|
28
|
+
expect(kpiTileStyleSheet).to.include(declaration.replace(": ", ":"));
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("aligns the default tile with the metric card hierarchy", () => {
|
|
33
|
+
for (const token of [
|
|
34
|
+
"--monster-theme-surface",
|
|
35
|
+
"--monster-theme-text",
|
|
36
|
+
"--monster-theme-border",
|
|
37
|
+
"--monster-theme-accent",
|
|
38
|
+
]) {
|
|
39
|
+
expect(kpiTileSource).to.include(token);
|
|
40
|
+
expect(kpiTileStyleSheet).to.include(token);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
expect(kpiTileSource).to.include("width: 15rem");
|
|
44
|
+
expect(kpiTileSource).to.include("height: 12rem");
|
|
45
|
+
expect(kpiTileSource).to.include(
|
|
46
|
+
"grid-template-rows: 2.75rem 2.5rem minmax(0, 1fr)",
|
|
47
|
+
);
|
|
48
|
+
expect(kpiTileSource).to.include("align-items: flex-start");
|
|
49
|
+
expect(kpiTileSource).to.include("text-align: left");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("preserves the unboxed compact variant", () => {
|
|
53
|
+
expect(kpiTileSource).to.match(
|
|
54
|
+
/:host\(\.small\) \[data-monster-role="control"\]\s*\{[\s\S]*?background:\s*transparent;[\s\S]*?border:\s*0;[\s\S]*?box-shadow:\s*none;[\s\S]*?height:\s*auto;[\s\S]*?width:\s*fit-content;/u,
|
|
55
|
+
);
|
|
56
|
+
expect(kpiTileStyleSheet).to.include(
|
|
57
|
+
":host(.small) [data-monster-role=control]{background:transparent;border:0;border-radius:0;box-shadow:none",
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
});
|