@jskit-ai/shell-web 0.1.179 → 0.1.180
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/shell-web",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.180",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "node --test"
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@mdi/js": "^7.4.47"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
|
-
"@jskit-ai/kernel": "0.1.
|
|
34
|
+
"@jskit-ai/kernel": "0.1.176",
|
|
35
35
|
"pinia": "^3.0.4",
|
|
36
36
|
"vue": "^3.5.13",
|
|
37
37
|
"vue-router": "^5.0.4",
|
|
@@ -17,6 +17,7 @@ const theme = useTheme();
|
|
|
17
17
|
:theme="theme.name.value"
|
|
18
18
|
location="end"
|
|
19
19
|
content-class="shell-navigation-tooltip"
|
|
20
|
+
:open-delay="400"
|
|
20
21
|
:open-on-focus="true"
|
|
21
22
|
:open-on-hover="true"
|
|
22
23
|
>
|
|
@@ -32,6 +33,5 @@ const theme = useTheme();
|
|
|
32
33
|
rgb(var(--v-theme-inverse-surface, var(--v-theme-on-surface))) !important;
|
|
33
34
|
color:
|
|
34
35
|
rgb(var(--v-theme-inverse-on-surface, var(--v-theme-surface))) !important;
|
|
35
|
-
opacity: 1 !important;
|
|
36
36
|
}
|
|
37
37
|
</style>
|
|
@@ -57,6 +57,7 @@ async function assertTooltipContrast(page, linkName, interaction) {
|
|
|
57
57
|
}
|
|
58
58
|
const tooltip = page.locator(".shell-navigation-tooltip").filter({ hasText: linkName }).last();
|
|
59
59
|
await expect(tooltip).toBeVisible();
|
|
60
|
+
await expect(tooltip).toHaveCSS("opacity", "1");
|
|
60
61
|
const colors = await tooltip.evaluate((element) => {
|
|
61
62
|
const style = window.getComputedStyle(element);
|
|
62
63
|
return {
|
|
@@ -76,6 +77,49 @@ async function assertTooltipContrast(page, linkName, interaction) {
|
|
|
76
77
|
await page.keyboard.press("Escape");
|
|
77
78
|
}
|
|
78
79
|
|
|
80
|
+
async function assertRapidTooltipTraversal(page) {
|
|
81
|
+
const result = await page.locator(".shell-menu-link-item").evaluateAll(async (links) => {
|
|
82
|
+
const pause = (duration) => new Promise((resolve) => window.setTimeout(resolve, duration));
|
|
83
|
+
const countVisibleTooltips = () => Array.from(
|
|
84
|
+
document.querySelectorAll(".shell-navigation-tooltip")
|
|
85
|
+
).filter((element) => {
|
|
86
|
+
const style = window.getComputedStyle(element);
|
|
87
|
+
const rect = element.getBoundingClientRect();
|
|
88
|
+
return (
|
|
89
|
+
style.display !== "none" &&
|
|
90
|
+
style.visibility !== "hidden" &&
|
|
91
|
+
Number(style.opacity) > 0 &&
|
|
92
|
+
rect.width > 0 &&
|
|
93
|
+
rect.height > 0
|
|
94
|
+
);
|
|
95
|
+
}).length;
|
|
96
|
+
|
|
97
|
+
const samples = [];
|
|
98
|
+
let activeLink = null;
|
|
99
|
+
for (const link of links) {
|
|
100
|
+
activeLink?.dispatchEvent(new MouseEvent("mouseleave"));
|
|
101
|
+
link.dispatchEvent(new MouseEvent("mouseenter"));
|
|
102
|
+
activeLink = link;
|
|
103
|
+
await pause(24);
|
|
104
|
+
samples.push(countVisibleTooltips());
|
|
105
|
+
}
|
|
106
|
+
activeLink?.dispatchEvent(new MouseEvent("mouseleave"));
|
|
107
|
+
await pause(100);
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
afterLeaving: countVisibleTooltips(),
|
|
111
|
+
maximumVisible: Math.max(0, ...samples)
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
assert.equal(
|
|
116
|
+
result.maximumVisible,
|
|
117
|
+
0,
|
|
118
|
+
"Briefly crossing navigation links must not leave tooltip overlays on screen."
|
|
119
|
+
);
|
|
120
|
+
assert.equal(result.afterLeaving, 0, "Navigation tooltips must remain hidden after traversal.");
|
|
121
|
+
}
|
|
122
|
+
|
|
79
123
|
async function assertDrawerFit(page) {
|
|
80
124
|
const drawer = page.getByTestId("jskit-shell-drawer");
|
|
81
125
|
await expect(drawer).toHaveAttribute("data-presentation", "drawer");
|
|
@@ -203,11 +247,22 @@ test("shell-web adaptive navigation passes package-owned browser contracts", {
|
|
|
203
247
|
await page.goto(pathAndTheme);
|
|
204
248
|
await expect(page.getByTestId("jskit-shell-drawer")).toBeVisible();
|
|
205
249
|
await assertDrawerFit(page);
|
|
250
|
+
await assertRapidTooltipTraversal(page);
|
|
206
251
|
await assertTooltipContrast(page, "Bookings", "focus");
|
|
207
252
|
await assertTooltipContrast(page, "Help and support", "hover");
|
|
208
253
|
await page.close();
|
|
209
254
|
}
|
|
210
255
|
|
|
256
|
+
const mediumTooltipPage = await context.newPage();
|
|
257
|
+
await mediumTooltipPage.setViewportSize({ width: 1024, height: 1024 });
|
|
258
|
+
await mediumTooltipPage.goto("/w/acme/admin/bookings?theme=light");
|
|
259
|
+
await expect(mediumTooltipPage.getByTestId("jskit-shell-drawer")).toHaveAttribute(
|
|
260
|
+
"data-layout",
|
|
261
|
+
"medium"
|
|
262
|
+
);
|
|
263
|
+
await assertRapidTooltipTraversal(mediumTooltipPage);
|
|
264
|
+
await mediumTooltipPage.close();
|
|
265
|
+
|
|
211
266
|
const railPage = await context.newPage();
|
|
212
267
|
await railPage.setViewportSize({ width: 1280, height: 900 });
|
|
213
268
|
await railPage.goto("/w/acme/admin/bookings?theme=light");
|
|
@@ -126,6 +126,16 @@ test("shell-web shell layout registers navigation at the app layout level", asyn
|
|
|
126
126
|
assert.doesNotMatch(template, /ShellOutlet|ShellRouteTransition|useShellLayoutState|pointerdown|v-navigation-drawer|v-bottom-navigation/);
|
|
127
127
|
});
|
|
128
128
|
|
|
129
|
+
test("shell navigation tooltips ignore incidental pointer traversal", async () => {
|
|
130
|
+
const source = await readFile(
|
|
131
|
+
path.join(PACKAGE_DIR, "src", "client", "components", "ShellNavigationTooltip.vue"),
|
|
132
|
+
"utf8"
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
assert.match(source, /:open-delay="400"/u);
|
|
136
|
+
assert.doesNotMatch(source, /opacity:\s*1\s*!important/u);
|
|
137
|
+
});
|
|
138
|
+
|
|
129
139
|
test("shell-web error host uses one explicit close affordance for banner errors", async () => {
|
|
130
140
|
const source = await readFile(path.join(PACKAGE_DIR, "src", "client", "components", "ShellErrorHost.vue"), "utf8");
|
|
131
141
|
|