fix(ui): keep floating menus inside viewport and clipping containers
This commit is contained in:
1 parent
9520651330
commit
7c1fcd19d4
16 files changed
+138
-33
No files matched your search
@@ -376,7 +376,7 @@
|
|||||||
},
|
},
|
||||||
"packages/csr": {
|
"packages/csr": {
|
||||||
"name": "@wrnexus/csr",
|
"name": "@wrnexus/csr",
|
||||||
"version": "0.8.74",
|
"version": "0.8.75",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/core": "^0.8.12",
|
"@wrnexus/core": "^0.8.12",
|
||||||
},
|
},
|
||||||
@@ -391,7 +391,7 @@
|
|||||||
},
|
},
|
||||||
"packages/design-studio": {
|
"packages/design-studio": {
|
||||||
"name": "@wrnexus/design-studio",
|
"name": "@wrnexus/design-studio",
|
||||||
"version": "0.1.4",
|
"version": "0.1.5",
|
||||||
"bin": {
|
"bin": {
|
||||||
"wrnexus-design-studio": "src/cli.ts",
|
"wrnexus-design-studio": "src/cli.ts",
|
||||||
},
|
},
|
||||||
@@ -413,7 +413,7 @@
|
|||||||
},
|
},
|
||||||
"packages/dev-server": {
|
"packages/dev-server": {
|
||||||
"name": "@wrnexus/dev-server",
|
"name": "@wrnexus/dev-server",
|
||||||
"version": "0.8.83",
|
"version": "0.8.84",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/authz": "workspace:*",
|
"@wrnexus/authz": "workspace:*",
|
||||||
"@wrnexus/cache": "workspace:*",
|
"@wrnexus/cache": "workspace:*",
|
||||||
@@ -782,7 +782,7 @@
|
|||||||
},
|
},
|
||||||
"packages/ui": {
|
"packages/ui": {
|
||||||
"name": "@wrnexus/ui",
|
"name": "@wrnexus/ui",
|
||||||
"version": "0.8.120",
|
"version": "0.8.121",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/core": "workspace:*",
|
"@wrnexus/core": "workspace:*",
|
||||||
"@wrnexus/design-system": "workspace:*",
|
"@wrnexus/design-system": "workspace:*",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"releaseLine": "0.8",
|
"releaseLine": "0.8",
|
||||||
"artifacts": {
|
"artifacts": {
|
||||||
"packages/ui/components/Accordion.wrn": "51714cc2103e4727fc64a5e6cb37f060d5b495c72e1660c1a04948982b7f4c53",
|
"packages/ui/components/Accordion.wrn": "51714cc2103e4727fc64a5e6cb37f060d5b495c72e1660c1a04948982b7f4c53",
|
||||||
"packages/ui/components/AdvancedSelect.wrn": "b812acc74cd717af6f102d29fd07b47de2b2ad6e3879706730e0a32eada6f3ee",
|
"packages/ui/components/AdvancedSelect.wrn": "4b867a384feb3c089804d7c7f20bb7b152ffc650ece503480d109a532e7ef3a7",
|
||||||
"packages/ui/components/AnnouncementBar.wrn": "b2b833350eb9a37627e4047f371c12ff7a8c25385a70294c0fc25ddfd4bb74c8",
|
"packages/ui/components/AnnouncementBar.wrn": "b2b833350eb9a37627e4047f371c12ff7a8c25385a70294c0fc25ddfd4bb74c8",
|
||||||
"packages/ui/components/AuthForm.wrn": "8a7bf17ee92d98caae1e987eeade29d0effc89b0eca4b8787dc10b2abad25de8",
|
"packages/ui/components/AuthForm.wrn": "8a7bf17ee92d98caae1e987eeade29d0effc89b0eca4b8787dc10b2abad25de8",
|
||||||
"packages/ui/components/AuthSplitLayout.wrn": "e5ca3b96f68fbc666d47ad2efac9f6c37fe321fcf222109aec5f05f4433b99d6",
|
"packages/ui/components/AuthSplitLayout.wrn": "e5ca3b96f68fbc666d47ad2efac9f6c37fe321fcf222109aec5f05f4433b99d6",
|
||||||
@@ -21,14 +21,14 @@
|
|||||||
"packages/ui/components/Collapse.wrn": "c5ecae44b455498e5eae527100abdc27bf9e18f7a361ce563d45087c0cc4a3d3",
|
"packages/ui/components/Collapse.wrn": "c5ecae44b455498e5eae527100abdc27bf9e18f7a361ce563d45087c0cc4a3d3",
|
||||||
"packages/ui/components/ColorPicker.wrn": "561b1cef73ff86f50072fefabade212b0cf10a48e6dd6c6aa93fd6e900fe3f50",
|
"packages/ui/components/ColorPicker.wrn": "561b1cef73ff86f50072fefabade212b0cf10a48e6dd6c6aa93fd6e900fe3f50",
|
||||||
"packages/ui/components/Columns.wrn": "c892798d910745453b617a7f0dcf20ab1fd6506095c150de0f36e9fcf7661783",
|
"packages/ui/components/Columns.wrn": "c892798d910745453b617a7f0dcf20ab1fd6506095c150de0f36e9fcf7661783",
|
||||||
"packages/ui/components/Combobox.wrn": "1268286b6dcb00f187d985d5e7fedf0371c8febf04c16907beb10cf36ced2d25",
|
"packages/ui/components/Combobox.wrn": "2096855460f58c250a056037ae3355496b0cdbf179f33baa8c2a55d7532ca60b",
|
||||||
"packages/ui/components/Confetti.wrn": "91f72aa66babd721d5b8406992b13df442cd3d2a093540b0e504380242479ca6",
|
"packages/ui/components/Confetti.wrn": "91f72aa66babd721d5b8406992b13df442cd3d2a093540b0e504380242479ca6",
|
||||||
"packages/ui/components/Container.wrn": "eefa6f3dfaecb1e86172f6f2b886adfad7dcacf07f75098f7d07948bff5d0a50",
|
"packages/ui/components/Container.wrn": "eefa6f3dfaecb1e86172f6f2b886adfad7dcacf07f75098f7d07948bff5d0a50",
|
||||||
"packages/ui/components/ContextMenu.wrn": "5dcf067343e35307c1e0de1c319112e6741bcc9b1c827cef5d09721383f4d066",
|
"packages/ui/components/ContextMenu.wrn": "5dcf067343e35307c1e0de1c319112e6741bcc9b1c827cef5d09721383f4d066",
|
||||||
"packages/ui/components/CustomScrollbar.wrn": "5325c9429b432b113e232a19786bb3f873454f8f4c7c0d6a3ecf81897fa35f09",
|
"packages/ui/components/CustomScrollbar.wrn": "5325c9429b432b113e232a19786bb3f873454f8f4c7c0d6a3ecf81897fa35f09",
|
||||||
"packages/ui/components/DataMap.wrn": "66752f98718c748f25e0eed76d39f504fc20b26d3b3ae841db85f5d5f02df6cb",
|
"packages/ui/components/DataMap.wrn": "66752f98718c748f25e0eed76d39f504fc20b26d3b3ae841db85f5d5f02df6cb",
|
||||||
"packages/ui/components/DataTable.wrn": "c25aa8849d140562970cd2ffaa33b720cc903e809ef7fb20a564425e8295d5b9",
|
"packages/ui/components/DataTable.wrn": "eb2e2cfe1eb5306b85261199a833605213e0d2094f3823a5acfedd30147144a1",
|
||||||
"packages/ui/components/DatePicker.wrn": "107be1aa2ae2b329b50c9063f2f25bf4ac7dccebe6a2b6ca412cc12afac8f3af",
|
"packages/ui/components/DatePicker.wrn": "7ab1567a878bb78bb7c3eac637236c7ca157e942a79ac9262b1a78f3190d6c98",
|
||||||
"packages/ui/components/DeviceFrame.wrn": "ae6a19ee27ba24d5673e3b4fa951bfcf8f12f6ef40bad0e61f349666e13afa64",
|
"packages/ui/components/DeviceFrame.wrn": "ae6a19ee27ba24d5673e3b4fa951bfcf8f12f6ef40bad0e61f349666e13afa64",
|
||||||
"packages/ui/components/Divider.wrn": "3d1065aa2dccb11f31eff35105ce7a3a0321317850e4df02b6c298e4a492cadc",
|
"packages/ui/components/Divider.wrn": "3d1065aa2dccb11f31eff35105ce7a3a0321317850e4df02b6c298e4a492cadc",
|
||||||
"packages/ui/components/DragAndDrop.wrn": "5af6c01a9b58eca44868205708f47738c1c2b25589b94035cb2f4f31eec06ba6",
|
"packages/ui/components/DragAndDrop.wrn": "5af6c01a9b58eca44868205708f47738c1c2b25589b94035cb2f4f31eec06ba6",
|
||||||
@@ -62,13 +62,13 @@
|
|||||||
"packages/ui/components/MetricGrid.wrn": "c9f228b4b6bd371ad94c1e534501b9708ea555bef1e64c8bdf95fa5e07576d1d",
|
"packages/ui/components/MetricGrid.wrn": "c9f228b4b6bd371ad94c1e534501b9708ea555bef1e64c8bdf95fa5e07576d1d",
|
||||||
"packages/ui/components/Modal.wrn": "7ad50502de6f6ff20ec2dc62fdc923f78afc222509771c5f26e5a56810ead374",
|
"packages/ui/components/Modal.wrn": "7ad50502de6f6ff20ec2dc62fdc923f78afc222509771c5f26e5a56810ead374",
|
||||||
"packages/ui/components/Nav.wrn": "dd7d67b15ffe88fb991321a3707c82770bc0c14ced5cc6f2710adf7ef2045c6c",
|
"packages/ui/components/Nav.wrn": "dd7d67b15ffe88fb991321a3707c82770bc0c14ced5cc6f2710adf7ef2045c6c",
|
||||||
"packages/ui/components/Navbar.wrn": "02081bcbbf88f9fbbaff7348ad7183d914a424c8fe22ed3c870b61620c2920fa",
|
"packages/ui/components/Navbar.wrn": "22b2b22befd57605d3fa8aa0714d46230790720ea12425dbe642feaef6a47675",
|
||||||
"packages/ui/components/PageHeader.wrn": "7586f4579031e9391d673eb413dfe2ca65f9e3da2a0257c6f987bfc3b3482927",
|
"packages/ui/components/PageHeader.wrn": "7586f4579031e9391d673eb413dfe2ca65f9e3da2a0257c6f987bfc3b3482927",
|
||||||
"packages/ui/components/Pagination.wrn": "df6faf0dbafd1249092b45e586159b575c3d37c73d81847376a28c3ea8fdb5cd",
|
"packages/ui/components/Pagination.wrn": "df6faf0dbafd1249092b45e586159b575c3d37c73d81847376a28c3ea8fdb5cd",
|
||||||
"packages/ui/components/PinInput.wrn": "c17b2a1bb38ba0420de7c9179e64fd104cbd8d3b84127a308a4333d46232b3fb",
|
"packages/ui/components/PinInput.wrn": "c17b2a1bb38ba0420de7c9179e64fd104cbd8d3b84127a308a4333d46232b3fb",
|
||||||
"packages/ui/components/Popover.wrn": "aa73c63bde88d6f52061a98fdc8c84f1147e784abfeb802f094a89c061b9a893",
|
"packages/ui/components/Popover.wrn": "aa73c63bde88d6f52061a98fdc8c84f1147e784abfeb802f094a89c061b9a893",
|
||||||
"packages/ui/components/PortalDashboard.wrn": "ef67fdf9faac850ef34b1d2564386d41a0cfa4c754ed0988e85f2e7ea2f50cdb",
|
"packages/ui/components/PortalDashboard.wrn": "ef67fdf9faac850ef34b1d2564386d41a0cfa4c754ed0988e85f2e7ea2f50cdb",
|
||||||
"packages/ui/components/PreferenceSwitcher.wrn": "b1a5a72997dec35a1294f8a7724abc52ba9e50a108e175da9442816ca9adf0ec",
|
"packages/ui/components/PreferenceSwitcher.wrn": "33637d758e63a4a6ce5ca51362f34387aacc1f64134434912c7ecd119b7cb5a8",
|
||||||
"packages/ui/components/PublicPageShell.wrn": "1e28f4f387f235198a723ed13b0128fe484894e4962b73a482a5a28c8acf003f",
|
"packages/ui/components/PublicPageShell.wrn": "1e28f4f387f235198a723ed13b0128fe484894e4962b73a482a5a28c8acf003f",
|
||||||
"packages/ui/components/RangeSlider.wrn": "a4005dcca80e3e23b6488e865b92486b368f46e00d3f05e7b0663d421652be06",
|
"packages/ui/components/RangeSlider.wrn": "a4005dcca80e3e23b6488e865b92486b368f46e00d3f05e7b0663d421652be06",
|
||||||
"packages/ui/components/Rating.wrn": "8456d577da017eac6e54db78b4beced73930da6fe8ef7a5b74c65c2902571ea9",
|
"packages/ui/components/Rating.wrn": "8456d577da017eac6e54db78b4beced73930da6fe8ef7a5b74c65c2902571ea9",
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
"packages/ui/components/StyledIcon.wrn": "64ac0aeaa9f0b833f68943dc0116acc1d0a9c8816d3b4bb2c91d00cf7ec3dc0a",
|
"packages/ui/components/StyledIcon.wrn": "64ac0aeaa9f0b833f68943dc0116acc1d0a9c8816d3b4bb2c91d00cf7ec3dc0a",
|
||||||
"packages/ui/components/Tabs.wrn": "462b8d821dd4390213fc6e75263d30d2b0f9a3d19f7b83053ae41f780c2c2671",
|
"packages/ui/components/Tabs.wrn": "462b8d821dd4390213fc6e75263d30d2b0f9a3d19f7b83053ae41f780c2c2671",
|
||||||
"packages/ui/components/TextLink.wrn": "3d8ec57f065fbb12a2ba42e85f1d66ff24adf041e8a1ec4b59cc3f1a17004f4e",
|
"packages/ui/components/TextLink.wrn": "3d8ec57f065fbb12a2ba42e85f1d66ff24adf041e8a1ec4b59cc3f1a17004f4e",
|
||||||
"packages/ui/components/TimePicker.wrn": "1695e1cc66f1c41f61bd194db0ba8abfba45a528ca414bb700272a1884f908de",
|
"packages/ui/components/TimePicker.wrn": "385a90f2f6db134ab86450bc2a3e60f2237b511989ce3c8b1bdc2bfe1f0a8276",
|
||||||
"packages/ui/components/Timeline.wrn": "1f46194e222b7eb04750785542a8933028fb4d23a94f199874ffe27d9dc74e79",
|
"packages/ui/components/Timeline.wrn": "1f46194e222b7eb04750785542a8933028fb4d23a94f199874ffe27d9dc74e79",
|
||||||
"packages/ui/components/Toaster.wrn": "e46b15818d8f50467521e58c5dae605871c107c09e80e8dade60da675b40b8e6",
|
"packages/ui/components/Toaster.wrn": "e46b15818d8f50467521e58c5dae605871c107c09e80e8dade60da675b40b8e6",
|
||||||
"packages/ui/components/ToggleCount.wrn": "b95bc9967d40d954427caea544c1b465f30dede623ed8d25b0aefee5b2453910",
|
"packages/ui/components/ToggleCount.wrn": "b95bc9967d40d954427caea544c1b465f30dede623ed8d25b0aefee5b2453910",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/csr",
|
"name": "@wrnexus/csr",
|
||||||
"version": "0.8.74",
|
"version": "0.8.75",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -3244,6 +3244,16 @@ export const REACTIVE_RUNTIME = String.raw`
|
|||||||
function clampAnchored(element) {
|
function clampAnchored(element) {
|
||||||
// Measure the untouched position; the offset is recomputed from scratch.
|
// Measure the untouched position; the offset is recomputed from scratch.
|
||||||
element.style.translate = "";
|
element.style.translate = "";
|
||||||
|
// Restore authored limits before measuring, including after a resize.
|
||||||
|
if (element.__wrnAnchorLimits) {
|
||||||
|
var saved = element.__wrnAnchorLimits;
|
||||||
|
element.style.maxWidth = saved[0];
|
||||||
|
element.style.maxHeight = saved[1];
|
||||||
|
element.style.minWidth = saved[2];
|
||||||
|
element.style.minHeight = saved[3];
|
||||||
|
element.style.overflow = saved[4];
|
||||||
|
element.style.boxSizing = saved[5];
|
||||||
|
}
|
||||||
var arrow = element.querySelector("[data-wrn-anchor-arrow]");
|
var arrow = element.querySelector("[data-wrn-anchor-arrow]");
|
||||||
if (arrow) arrow.style.translate = "";
|
if (arrow) arrow.style.translate = "";
|
||||||
if (!isRenderedElement(element)) return;
|
if (!isRenderedElement(element)) return;
|
||||||
@@ -3251,6 +3261,38 @@ export const REACTIVE_RUNTIME = String.raw`
|
|||||||
var rect = element.getBoundingClientRect();
|
var rect = element.getBoundingClientRect();
|
||||||
var viewportWidth = window.innerWidth || document.documentElement.clientWidth;
|
var viewportWidth = window.innerWidth || document.documentElement.clientWidth;
|
||||||
var viewportHeight = window.innerHeight || document.documentElement.clientHeight;
|
var viewportHeight = window.innerHeight || document.documentElement.clientHeight;
|
||||||
|
var visual = window.visualViewport;
|
||||||
|
var left = (visual ? visual.offsetLeft : 0) + ANCHOR_MARGIN;
|
||||||
|
var top = (visual ? visual.offsetTop : 0) + ANCHOR_MARGIN;
|
||||||
|
var right = left + (visual ? visual.width : viewportWidth) - ANCHOR_MARGIN * 2;
|
||||||
|
var bottom = top + (visual ? visual.height : viewportHeight) - ANCHOR_MARGIN * 2;
|
||||||
|
// A preview, sidebar or scroll container may clip well before the screen edge.
|
||||||
|
for (var parent = element.parentElement; parent && parent !== document.documentElement; parent = parent.parentElement) {
|
||||||
|
var css = window.getComputedStyle(parent);
|
||||||
|
var clipX = /auto|scroll|hidden|clip/.test(css.overflowX || css.overflow);
|
||||||
|
var clipY = /auto|scroll|hidden|clip/.test(css.overflowY || css.overflow);
|
||||||
|
if (!clipX && !clipY) continue;
|
||||||
|
var bounds = parent.getBoundingClientRect();
|
||||||
|
if (clipX) {
|
||||||
|
left = Math.max(left, bounds.left + parent.clientLeft + ANCHOR_MARGIN);
|
||||||
|
right = Math.min(right, bounds.left + parent.clientLeft + parent.clientWidth - ANCHOR_MARGIN);
|
||||||
|
}
|
||||||
|
if (clipY) {
|
||||||
|
top = Math.max(top, bounds.top + parent.clientTop + ANCHOR_MARGIN);
|
||||||
|
bottom = Math.min(bottom, bounds.top + parent.clientTop + parent.clientHeight - ANCHOR_MARGIN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (right <= left || bottom <= top) return;
|
||||||
|
if (!element.__wrnAnchorLimits) element.__wrnAnchorLimits = [element.style.maxWidth, element.style.maxHeight, element.style.minWidth, element.style.minHeight, element.style.overflow, element.style.boxSizing];
|
||||||
|
if (rect.width > right - left || rect.height > bottom - top) {
|
||||||
|
element.style.boxSizing = "border-box";
|
||||||
|
element.style.minWidth = "0px";
|
||||||
|
element.style.minHeight = "0px";
|
||||||
|
element.style.maxWidth = Math.min(rect.width, right - left) + "px";
|
||||||
|
element.style.maxHeight = Math.min(rect.height, bottom - top) + "px";
|
||||||
|
element.style.overflow = "auto";
|
||||||
|
rect = element.getBoundingClientRect();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clamp only while the overlay's own trigger is on screen.
|
* Clamp only while the overlay's own trigger is on screen.
|
||||||
@@ -3263,7 +3305,7 @@ export const REACTIVE_RUNTIME = String.raw`
|
|||||||
* one very much does need moving; skipping it left the menu invisible
|
* one very much does need moving; skipping it left the menu invisible
|
||||||
* with no way to reach it. The trigger tells the two apart.
|
* with no way to reach it. The trigger tells the two apart.
|
||||||
*/
|
*/
|
||||||
var host = element.closest("[data-ui-component]") || element.parentElement;
|
var host = element.parentElement && element.parentElement.closest("[data-wrn-menu]") || element.closest("[data-ui-component]") || element.parentElement;
|
||||||
var anchor = host ? host.getBoundingClientRect() : rect;
|
var anchor = host ? host.getBoundingClientRect() : rect;
|
||||||
var anchorVisible =
|
var anchorVisible =
|
||||||
anchor.bottom > 0 &&
|
anchor.bottom > 0 &&
|
||||||
@@ -3278,17 +3320,20 @@ export const REACTIVE_RUNTIME = String.raw`
|
|||||||
var shiftX = 0;
|
var shiftX = 0;
|
||||||
var shiftY = 0;
|
var shiftY = 0;
|
||||||
|
|
||||||
if (rect.width < viewportWidth - ANCHOR_MARGIN * 2) {
|
if (rect.width <= right - left) {
|
||||||
if (rect.left < ANCHOR_MARGIN) shiftX = ANCHOR_MARGIN - rect.left;
|
if (rect.left < left) shiftX = left - rect.left;
|
||||||
else if (rect.right > viewportWidth - ANCHOR_MARGIN) {
|
else if (rect.right > right) {
|
||||||
shiftX = viewportWidth - ANCHOR_MARGIN - rect.right;
|
shiftX = right - rect.right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rect.height < viewportHeight - ANCHOR_MARGIN * 2) {
|
if (rect.height <= bottom - top) {
|
||||||
if (rect.top < ANCHOR_MARGIN) shiftY = ANCHOR_MARGIN - rect.top;
|
if (rect.top < top) shiftY = top - rect.top;
|
||||||
else if (rect.bottom > viewportHeight - ANCHOR_MARGIN) {
|
else if (rect.bottom > bottom) {
|
||||||
shiftY = viewportHeight - ANCHOR_MARGIN - rect.bottom;
|
// Prefer opening above the trigger when there is enough room.
|
||||||
|
shiftY = anchor.top - rect.height - ANCHOR_MARGIN >= top && rect.top >= anchor.bottom
|
||||||
|
? anchor.top - rect.height - ANCHOR_MARGIN - rect.top
|
||||||
|
: bottom - rect.bottom;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3392,6 +3437,10 @@ export const REACTIVE_RUNTIME = String.raw`
|
|||||||
|
|
||||||
window.addEventListener("resize", scheduleAnchoredReposition);
|
window.addEventListener("resize", scheduleAnchoredReposition);
|
||||||
window.addEventListener("scroll", scheduleAnchoredReposition, true);
|
window.addEventListener("scroll", scheduleAnchoredReposition, true);
|
||||||
|
if (window.visualViewport) {
|
||||||
|
window.visualViewport.addEventListener("resize", scheduleAnchoredReposition);
|
||||||
|
window.visualViewport.addEventListener("scroll", scheduleAnchoredReposition);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { test, expect } from "bun:test";
|
||||||
|
import { Window } from "happy-dom";
|
||||||
|
import { REACTIVE_RUNTIME } from "../src/reactive-runtime.ts";
|
||||||
|
|
||||||
|
function fixture(panel: Record<string, number>, clipped = false) {
|
||||||
|
const win = new Window();
|
||||||
|
win.document.body.innerHTML = '<div id="clip"><div data-ui-component="ComboBox"><div data-wrn-anchored></div></div></div>';
|
||||||
|
const element = win.document.querySelector('[data-wrn-anchored]')! as any;
|
||||||
|
const host = element.parentElement;
|
||||||
|
const rect = (left: number, top: number, width: number, height: number) => ({left, top, width, height, right:left+width, bottom:top+height});
|
||||||
|
host.getBoundingClientRect = () => rect(270, 170, 40, 30);
|
||||||
|
element.getBoundingClientRect = () => rect(panel.left, panel.top,
|
||||||
|
Math.min(panel.width, parseFloat(element.style.maxWidth) || Infinity),
|
||||||
|
Math.min(panel.height, parseFloat(element.style.maxHeight) || Infinity));
|
||||||
|
if (clipped) {
|
||||||
|
const clip = win.document.querySelector('#clip')! as any;
|
||||||
|
clip.style.overflow = 'hidden';
|
||||||
|
clip.getBoundingClientRect = () => rect(100, 50, 220, 220);
|
||||||
|
Object.defineProperty(clip, 'clientWidth', {value:220});
|
||||||
|
Object.defineProperty(clip, 'clientHeight', {value:220});
|
||||||
|
}
|
||||||
|
const start = REACTIVE_RUNTIME.indexOf(' function isRenderedElement(');
|
||||||
|
const end = REACTIVE_RUNTIME.indexOf(' function repositionAnchored(', start);
|
||||||
|
const clamp = new Function('window', 'document', 'ANCHOR_MARGIN', REACTIVE_RUNTIME.slice(start,end) + '; return clampAnchored;')(win, win.document, 8);
|
||||||
|
return {win, element, clamp};
|
||||||
|
}
|
||||||
|
|
||||||
|
test('anchored panels fit clipping containers and positioning does not drift', async () => {
|
||||||
|
const {win, element, clamp} = fixture({left:40,top:208,width:180,height:100}, true);
|
||||||
|
clamp(element);
|
||||||
|
expect(element.style.translate).toBe('68px -146px');
|
||||||
|
clamp(element);
|
||||||
|
expect(element.style.translate).toBe('68px -146px');
|
||||||
|
await win.happyDOM.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('oversized panels become scrollable and recover authored sizing when space returns', async () => {
|
||||||
|
const {win, element, clamp} = fixture({left:40,top:60,width:500,height:400}, true);
|
||||||
|
element.style.minWidth = '300px';
|
||||||
|
clamp(element);
|
||||||
|
expect(element.style.maxWidth).toBe('204px');
|
||||||
|
expect(element.style.maxHeight).toBe('204px');
|
||||||
|
expect(element.style.overflow).toBe('auto');
|
||||||
|
element.parentElement.parentElement.style.overflow = 'visible';
|
||||||
|
clamp(element);
|
||||||
|
expect(element.style.minWidth).toBe('300px');
|
||||||
|
expect(element.style.maxWidth).toBe('');
|
||||||
|
await win.happyDOM.close();
|
||||||
|
});
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/design-studio",
|
"name": "@wrnexus/design-studio",
|
||||||
"version": "0.1.4",
|
"version": "0.1.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/dev-server",
|
"name": "@wrnexus/dev-server",
|
||||||
"version": "0.8.83",
|
"version": "0.8.84",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -338,7 +338,7 @@ component AdvancedSelect {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="wrn-next__select-dropdown {fixed ? 'wrn-next__select-dropdown--fixed' : ''}"
|
data-wrn-anchored="true" class="wrn-next__select-dropdown {fixed ? 'wrn-next__select-dropdown--fixed' : ''}"
|
||||||
data-show="open"
|
data-show="open"
|
||||||
style="{open ? '' : 'display: none'}"
|
style="{open ? '' : 'display: none'}"
|
||||||
data-wrn-owner="AdvancedSelect" data-wrn-part="selectDropdown" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}">
|
data-wrn-owner="AdvancedSelect" data-wrn-part="selectDropdown" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}">
|
||||||
|
|||||||
@@ -293,7 +293,7 @@ component ComboBox {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="wrn-next__select-dropdown {fixed ? 'wrn-next__select-dropdown--fixed' : ''}"
|
data-wrn-anchored="true" class="wrn-next__select-dropdown {fixed ? 'wrn-next__select-dropdown--fixed' : ''}"
|
||||||
data-show="shouldShowDropdown()"
|
data-show="shouldShowDropdown()"
|
||||||
style="{shouldShowDropdown() ? '' : 'display: none'}"
|
style="{shouldShowDropdown() ? '' : 'display: none'}"
|
||||||
data-wrn-owner="ComboBox" data-wrn-part="selectDropdown" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}">
|
data-wrn-owner="ComboBox" data-wrn-part="selectDropdown" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}">
|
||||||
|
|||||||
@@ -959,7 +959,7 @@ component DataTable {
|
|||||||
slot so it stays reactive -- a prop would be fixed at the
|
slot so it stays reactive -- a prop would be fixed at the
|
||||||
value the dropdown was first rendered with. -->
|
value the dropdown was first rendered with. -->
|
||||||
<Dropdown
|
<Dropdown
|
||||||
class="wrn-table__page-dropdown"
|
data-wrn-anchored="true" class="wrn-table__page-dropdown"
|
||||||
width="sm"
|
width="sm"
|
||||||
size="sm"
|
size="sm"
|
||||||
placement="top-end"
|
placement="top-end"
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ size: string = "default"
|
|||||||
<div {...attrs} class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--field wrn-next--date-picker {class}" data-variant="{variant}" data-inline="{inline}" data-invalid="{error ? 'true' : 'false'}" data-expanded="{expanded}" @keydown="calendarKeydown(event)" data-wrn-owner="DatePicker" data-wrn-part="root" data-wrn-component="DatePicker" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">
|
<div {...attrs} class="wrn-component wrn-component--color-{color} wrn-component--size-{size} wrn-next--field wrn-next--date-picker {class}" data-variant="{variant}" data-inline="{inline}" data-invalid="{error ? 'true' : 'false'}" data-expanded="{expanded}" @keydown="calendarKeydown(event)" data-wrn-owner="DatePicker" data-wrn-part="root" data-wrn-component="DatePicker" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">
|
||||||
<div class="wrn-next__field-heading" data-wrn-owner="DatePicker" data-wrn-part="heading" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"><label for="{id || name}" data-wrn-owner="DatePicker" data-wrn-part="label" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{label}</label>{#if cornerHint}<span class="wrn-next__field-hint" data-wrn-owner="DatePicker" data-wrn-part="hint" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{cornerHint}</span>{/if}</div>
|
<div class="wrn-next__field-heading" data-wrn-owner="DatePicker" data-wrn-part="heading" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"><label for="{id || name}" data-wrn-owner="DatePicker" data-wrn-part="label" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{label}</label>{#if cornerHint}<span class="wrn-next__field-hint" data-wrn-owner="DatePicker" data-wrn-part="hint" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{cornerHint}</span>{/if}</div>
|
||||||
<div class="wrn-next__picker-control" data-wrn-owner="DatePicker" data-wrn-part="pickerControl" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"><input id="{id || name}" class="wrn-next__sr-only wrn-next__picker-value" type="text" name="{name}" value="{currentValue}" required="{required}" readonly aria-hidden="true" tabindex="-1" @invalid="handleInvalid(event)" data-wrn-owner="DatePicker" data-wrn-part="srOnly" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"/><button type="button" class="wrn-next__date-trigger" aria-label="{label}" disabled="{disabled || readonly}" aria-haspopup="dialog" aria-expanded="{expanded}" @click="openCalendar(event)" @focus="handleFocus(event)" @blur="handleBlur(event)" data-wrn-owner="DatePicker" data-wrn-part="dateTrigger" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"><span>{displayValue()}</span><i class="icon-[lucide--calendar-days]" aria-hidden="true"></i></button>{#if currentValue && !readonly && !disabled}<button type="button" class="wrn-next__picker-clear" aria-label="Clear date" @click="clearDate(event)" data-wrn-owner="DatePicker" data-wrn-part="pickerClear" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">×</button>{/if}</div>
|
<div class="wrn-next__picker-control" data-wrn-owner="DatePicker" data-wrn-part="pickerControl" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"><input id="{id || name}" class="wrn-next__sr-only wrn-next__picker-value" type="text" name="{name}" value="{currentValue}" required="{required}" readonly aria-hidden="true" tabindex="-1" @invalid="handleInvalid(event)" data-wrn-owner="DatePicker" data-wrn-part="srOnly" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"/><button type="button" class="wrn-next__date-trigger" aria-label="{label}" disabled="{disabled || readonly}" aria-haspopup="dialog" aria-expanded="{expanded}" @click="openCalendar(event)" @focus="handleFocus(event)" @blur="handleBlur(event)" data-wrn-owner="DatePicker" data-wrn-part="dateTrigger" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"><span>{displayValue()}</span><i class="icon-[lucide--calendar-days]" aria-hidden="true"></i></button>{#if currentValue && !readonly && !disabled}<button type="button" class="wrn-next__picker-clear" aria-label="Clear date" @click="clearDate(event)" data-wrn-owner="DatePicker" data-wrn-part="pickerClear" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">×</button>{/if}</div>
|
||||||
<button type="button" class="wrn-picker-dismiss" aria-label="Close calendar" data-show="expanded" @click="finishDate(event)" data-wrn-owner="DatePicker" data-wrn-part="button" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"></button><div data-show="expanded" class="wrn-next__calendar" role="dialog" aria-label="{label}" data-wrn-owner="DatePicker" data-wrn-part="calendar" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"><div class="wrn-next__date-selectors" data-wrn-owner="DatePicker" data-wrn-part="dateSelectors" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"><label data-wrn-owner="DatePicker" data-wrn-part="label" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">Month<select value="{selectedMonth}" @change="updateDate('month', event.currentTarget.value, event)" data-wrn-owner="DatePicker" data-wrn-part="control" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{#each months as month}<option value="{month.value}" selected="{month.value === selectedMonth}">{month.label}</option>{/each}</select></label><label data-wrn-owner="DatePicker" data-wrn-part="label" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">Year<select value="{selectedYear}" @change="updateDate('year', event.currentTarget.value, event)" data-wrn-owner="DatePicker" data-wrn-part="control" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{#each calendarYears() as calendarYear}<option value="{calendarYear}" selected="{String(calendarYear) === selectedYear}" data-text="calendarYear"></option>{/each}</select></label></div><div class="wrn-next__calendar-weekdays" aria-hidden="true" data-wrn-owner="DatePicker" data-wrn-part="calendarWeekdays" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{#each weekdays() as weekday}<span>{weekday}</span>{/each}</div><div class="wrn-next__calendar-grid" data-wrn-owner="DatePicker" data-wrn-part="calendarGrid" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{#each calendarDays() as day}<button type="button" data-value="{day.value}" data-today="{day.today}" style="grid-column: {day.column}" disabled="{day.disabled}" aria-label="{day.label}" aria-pressed="{day.value === currentValue.slice(0, 10)}" @click="selectDay(event)" data-wrn-owner="DatePicker" data-wrn-part="button" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{day.day}</button>{/each}</div>{#if type === "datetime-local"}<TimePicker label="Time" value="{selectedTime}" @change="selectedTime = payload.value; currentValue = (currentValue ? currentValue.slice(0, 10) : selectedYear + '-' + selectedMonth + '-01') + 'T' + selectedTime; output.change({ value: currentValue, name: name })" />{/if}<button type="button" class="wrn-next__date-done" disabled="{!currentValue}" @click="finishDate(event)" data-wrn-owner="DatePicker" data-wrn-part="dateDone" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">Done</button></div>
|
<button type="button" class="wrn-picker-dismiss" aria-label="Close calendar" data-show="expanded" @click="finishDate(event)" data-wrn-owner="DatePicker" data-wrn-part="button" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"></button><div data-show="expanded" data-wrn-anchored="true" class="wrn-next__calendar" role="dialog" aria-label="{label}" data-wrn-owner="DatePicker" data-wrn-part="calendar" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"><div class="wrn-next__date-selectors" data-wrn-owner="DatePicker" data-wrn-part="dateSelectors" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"><label data-wrn-owner="DatePicker" data-wrn-part="label" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">Month<select value="{selectedMonth}" @change="updateDate('month', event.currentTarget.value, event)" data-wrn-owner="DatePicker" data-wrn-part="control" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{#each months as month}<option value="{month.value}" selected="{month.value === selectedMonth}">{month.label}</option>{/each}</select></label><label data-wrn-owner="DatePicker" data-wrn-part="label" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">Year<select value="{selectedYear}" @change="updateDate('year', event.currentTarget.value, event)" data-wrn-owner="DatePicker" data-wrn-part="control" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{#each calendarYears() as calendarYear}<option value="{calendarYear}" selected="{String(calendarYear) === selectedYear}" data-text="calendarYear"></option>{/each}</select></label></div><div class="wrn-next__calendar-weekdays" aria-hidden="true" data-wrn-owner="DatePicker" data-wrn-part="calendarWeekdays" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{#each weekdays() as weekday}<span>{weekday}</span>{/each}</div><div class="wrn-next__calendar-grid" data-wrn-owner="DatePicker" data-wrn-part="calendarGrid" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{#each calendarDays() as day}<button type="button" data-value="{day.value}" data-today="{day.today}" style="grid-column: {day.column}" disabled="{day.disabled}" aria-label="{day.label}" aria-pressed="{day.value === currentValue.slice(0, 10)}" @click="selectDay(event)" data-wrn-owner="DatePicker" data-wrn-part="button" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{day.day}</button>{/each}</div>{#if type === "datetime-local"}<TimePicker label="Time" value="{selectedTime}" @change="selectedTime = payload.value; currentValue = (currentValue ? currentValue.slice(0, 10) : selectedYear + '-' + selectedMonth + '-01') + 'T' + selectedTime; output.change({ value: currentValue, name: name })" />{/if}<button type="button" class="wrn-next__date-done" disabled="{!currentValue}" @click="finishDate(event)" data-wrn-owner="DatePicker" data-wrn-part="dateDone" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">Done</button></div>
|
||||||
{#if helperText}<small class="wrn-next__field-help" data-wrn-owner="DatePicker" data-wrn-part="help" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{helperText}</small>{/if}<small class="wrn-next__field-error" data-error="{name}" data-wrn-owner="DatePicker" data-wrn-part="error" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{error}</small>
|
{#if helperText}<small class="wrn-next__field-help" data-wrn-owner="DatePicker" data-wrn-part="help" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{helperText}</small>{/if}<small class="wrn-next__field-error" data-error="{name}" data-wrn-owner="DatePicker" data-wrn-part="error" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{error}</small>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ size: string = "default"
|
|||||||
<span data-t="{translationKey(item, 'label')}">{item.label}</span>
|
<span data-t="{translationKey(item, 'label')}">{item.label}</span>
|
||||||
<span class="wrn-navbar__chevron" aria-hidden="true" data-wrn-owner="Navbar" data-wrn-part="chevron" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}"></span>
|
<span class="wrn-navbar__chevron" aria-hidden="true" data-wrn-owner="Navbar" data-wrn-part="chevron" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}"></span>
|
||||||
</button>
|
</button>
|
||||||
<div class="wrn-navbar__panel wrn-navbar__panel--columns-{item.columns || 1}" data-wrn-owner="Navbar" data-wrn-part="panel" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}">
|
<div data-wrn-anchored="true" class="wrn-navbar__panel wrn-navbar__panel--columns-{item.columns || 1}" data-wrn-owner="Navbar" data-wrn-part="panel" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}">
|
||||||
{#if item.description}<p class="wrn-navbar__panel-intro" data-t="{translationKey(item, 'description')}" data-wrn-owner="Navbar" data-wrn-part="panelIntro" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}">{item.description}</p>{/if}
|
{#if item.description}<p class="wrn-navbar__panel-intro" data-t="{translationKey(item, 'description')}" data-wrn-owner="Navbar" data-wrn-part="panelIntro" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}">{item.description}</p>{/if}
|
||||||
{#each dropdownItems(item) as child}
|
{#each dropdownItems(item) as child}
|
||||||
<div class="wrn-navbar__group" data-wrn-owner="Navbar" data-wrn-part="group" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}">
|
<div class="wrn-navbar__group" data-wrn-owner="Navbar" data-wrn-part="group" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}">
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ size: string = "default"
|
|||||||
<span class="{themeIcon}" aria-hidden="true"></span>
|
<span class="{themeIcon}" aria-hidden="true"></span>
|
||||||
{#if !iconOnly && !compact}<span>{themeLabel}</span>{/if}
|
{#if !iconOnly && !compact}<span>{themeLabel}</span>{/if}
|
||||||
</button>
|
</button>
|
||||||
<div class="wrn-preferences__panel" data-wrn-owner="PreferenceSwitcher" data-wrn-part="panel" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-compact="{compact}">
|
<div data-wrn-anchored="true" class="wrn-preferences__panel" data-wrn-owner="PreferenceSwitcher" data-wrn-part="panel" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-compact="{compact}">
|
||||||
<strong>{themeLabel}</strong>
|
<strong>{themeLabel}</strong>
|
||||||
<div class="wrn-preferences__options" data-wrn-owner="PreferenceSwitcher" data-wrn-part="options" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-compact="{compact}">
|
<div class="wrn-preferences__options" data-wrn-owner="PreferenceSwitcher" data-wrn-part="options" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-compact="{compact}">
|
||||||
<button type="button" data-wrn-theme-set="light" @click="choose('theme', 'light')" data-wrn-owner="PreferenceSwitcher" data-wrn-part="button" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-compact="{compact}"><span class="icon-[lucide--sun]" aria-hidden="true"></span>Light</button>
|
<button type="button" data-wrn-theme-set="light" @click="choose('theme', 'light')" data-wrn-owner="PreferenceSwitcher" data-wrn-part="button" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-compact="{compact}"><span class="icon-[lucide--sun]" aria-hidden="true"></span>Light</button>
|
||||||
@@ -64,7 +64,7 @@ size: string = "default"
|
|||||||
<span class="{colorIcon}" aria-hidden="true"></span>
|
<span class="{colorIcon}" aria-hidden="true"></span>
|
||||||
{#if !iconOnly && !compact}<span>{colorLabel}</span>{/if}
|
{#if !iconOnly && !compact}<span>{colorLabel}</span>{/if}
|
||||||
</button>
|
</button>
|
||||||
<div class="wrn-preferences__panel wrn-preferences__panel--colors" data-wrn-owner="PreferenceSwitcher" data-wrn-part="panel" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-compact="{compact}">
|
<div data-wrn-anchored="true" class="wrn-preferences__panel wrn-preferences__panel--colors" data-wrn-owner="PreferenceSwitcher" data-wrn-part="panel" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-compact="{compact}">
|
||||||
<strong>{colorLabel}</strong>
|
<strong>{colorLabel}</strong>
|
||||||
<div class="wrn-preferences__swatches" data-wrn-owner="PreferenceSwitcher" data-wrn-part="swatches" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-compact="{compact}">
|
<div class="wrn-preferences__swatches" data-wrn-owner="PreferenceSwitcher" data-wrn-part="swatches" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-compact="{compact}">
|
||||||
{#each colors as item}
|
{#each colors as item}
|
||||||
@@ -80,7 +80,7 @@ size: string = "default"
|
|||||||
{#if showCurrentLanguage}<span class="wrn-preferences__current-language" aria-hidden="true" data-wrn-owner="PreferenceSwitcher" data-wrn-part="currentLanguage" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-compact="{compact}">EN</span>{/if}
|
{#if showCurrentLanguage}<span class="wrn-preferences__current-language" aria-hidden="true" data-wrn-owner="PreferenceSwitcher" data-wrn-part="currentLanguage" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-compact="{compact}">EN</span>{/if}
|
||||||
{#if !iconOnly && !compact}<span>{languageLabel}</span>{/if}
|
{#if !iconOnly && !compact}<span>{languageLabel}</span>{/if}
|
||||||
</button>
|
</button>
|
||||||
<div class="wrn-preferences__panel wrn-preferences__panel--language" data-wrn-owner="PreferenceSwitcher" data-wrn-part="panel" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-compact="{compact}">
|
<div data-wrn-anchored="true" class="wrn-preferences__panel wrn-preferences__panel--language" data-wrn-owner="PreferenceSwitcher" data-wrn-part="panel" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-compact="{compact}">
|
||||||
<strong>{languageLabel}</strong>
|
<strong>{languageLabel}</strong>
|
||||||
{#each languages as item}
|
{#each languages as item}
|
||||||
<button type="button" data-wrn-lang-set="{item.value}" lang="{item.value}" @click="choose('language', item.value)" data-wrn-owner="PreferenceSwitcher" data-wrn-part="button" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-compact="{compact}">
|
<button type="button" data-wrn-lang-set="{item.value}" lang="{item.value}" @click="choose('language', item.value)" data-wrn-owner="PreferenceSwitcher" data-wrn-part="button" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-compact="{compact}">
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ size: string = "default"
|
|||||||
<input id="{id || name}" class="wrn-next__sr-only wrn-next__time-value" type="text" name="{name}" value="{currentValue}" required="{required}" readonly aria-hidden="true" tabindex="-1" @invalid="handleInvalid(event)" data-wrn-owner="TimePicker" data-wrn-part="srOnly" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"/>
|
<input id="{id || name}" class="wrn-next__sr-only wrn-next__time-value" type="text" name="{name}" value="{currentValue}" required="{required}" readonly aria-hidden="true" tabindex="-1" @invalid="handleInvalid(event)" data-wrn-owner="TimePicker" data-wrn-part="srOnly" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"/>
|
||||||
<button type="button" class="wrn-next__time-trigger" disabled="{disabled || readonly}" aria-haspopup="dialog" aria-expanded="{expanded}" @click="openPicker(event)" @focus="handleFocus(event)" @blur="handleBlur(event)" data-wrn-owner="TimePicker" data-wrn-part="timeTrigger" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"><span>{currentValue || placeholder || "Select time"}</span><i class="{icon}" aria-hidden="true"></i></button>
|
<button type="button" class="wrn-next__time-trigger" disabled="{disabled || readonly}" aria-haspopup="dialog" aria-expanded="{expanded}" @click="openPicker(event)" @focus="handleFocus(event)" @blur="handleBlur(event)" data-wrn-owner="TimePicker" data-wrn-part="timeTrigger" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"><span>{currentValue || placeholder || "Select time"}</span><i class="{icon}" aria-hidden="true"></i></button>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="wrn-time-dismiss" aria-label="Close time picker" data-show="expanded" @click="closePicker(event)" data-wrn-owner="TimePicker" data-wrn-part="button" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"></button><div data-show="expanded" class="wrn-next__time-panel" role="dialog" aria-label="{label}" data-wrn-owner="TimePicker" data-wrn-part="timePanel" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"><div><strong>Hour</strong><div class="wrn-next__time-options" data-wrn-owner="TimePicker" data-wrn-part="timeOptions" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{#each hours as hour}<button type="button" data-part="hour" data-value="{hour}" aria-pressed="{!!currentValue && String(hour) === selectedHour}" @click="selectTimePart(event)" data-wrn-owner="TimePicker" data-wrn-part="button" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{hour}</button>{/each}</div></div><div><strong>Minute</strong><div class="wrn-next__time-options" data-wrn-owner="TimePicker" data-wrn-part="timeOptions" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{#each minutes as minute}<button type="button" data-part="minute" data-value="{minute}" aria-pressed="{!!currentValue && String(minute) === selectedMinute}" @click="selectTimePart(event)" data-wrn-owner="TimePicker" data-wrn-part="button" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{minute}</button>{/each}</div></div><button type="button" class="wrn-next__time-done" @click="closePicker(event)" data-wrn-owner="TimePicker" data-wrn-part="timeDone" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">Done</button></div>
|
<button type="button" class="wrn-time-dismiss" aria-label="Close time picker" data-show="expanded" @click="closePicker(event)" data-wrn-owner="TimePicker" data-wrn-part="button" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"></button><div data-show="expanded" data-wrn-anchored="true" class="wrn-next__time-panel" role="dialog" aria-label="{label}" data-wrn-owner="TimePicker" data-wrn-part="timePanel" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}"><div><strong>Hour</strong><div class="wrn-next__time-options" data-wrn-owner="TimePicker" data-wrn-part="timeOptions" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{#each hours as hour}<button type="button" data-part="hour" data-value="{hour}" aria-pressed="{!!currentValue && String(hour) === selectedHour}" @click="selectTimePart(event)" data-wrn-owner="TimePicker" data-wrn-part="button" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{hour}</button>{/each}</div></div><div><strong>Minute</strong><div class="wrn-next__time-options" data-wrn-owner="TimePicker" data-wrn-part="timeOptions" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{#each minutes as minute}<button type="button" data-part="minute" data-value="{minute}" aria-pressed="{!!currentValue && String(minute) === selectedMinute}" @click="selectTimePart(event)" data-wrn-owner="TimePicker" data-wrn-part="button" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{minute}</button>{/each}</div></div><button type="button" class="wrn-next__time-done" @click="closePicker(event)" data-wrn-owner="TimePicker" data-wrn-part="timeDone" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">Done</button></div>
|
||||||
{#if helperText}<small class="wrn-next__field-help" data-wrn-owner="TimePicker" data-wrn-part="help" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{helperText}</small>{/if}
|
{#if helperText}<small class="wrn-next__field-help" data-wrn-owner="TimePicker" data-wrn-part="help" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{helperText}</small>{/if}
|
||||||
<small class="wrn-next__field-error" data-error="{name}" data-wrn-owner="TimePicker" data-wrn-part="error" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{error}</small>
|
<small class="wrn-next__field-error" data-error="{name}" data-wrn-owner="TimePicker" data-wrn-part="error" data-wrn-axis-size="{size}" data-wrn-axis-color="{color}" data-wrn-axis-variant="{variant}">{error}</small>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/ui",
|
"name": "@wrnexus/ui",
|
||||||
"version": "0.8.120",
|
"version": "0.8.121",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
|
|||||||
@@ -246,3 +246,9 @@ describe("account shell UI regressions", () => {
|
|||||||
expect(source("Footer")).toMatch(/\.wrn-footer__copyright-right\s*\{\s*grid-column: 3;/);
|
expect(source("Footer")).toMatch(/\.wrn-footer__copyright-right\s*\{\s*grid-column: 3;/);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('floating selection and preference panels opt into shared boundary handling', async () => {
|
||||||
|
for (const name of ['PreferenceSwitcher', 'ComboBox', 'AdvancedSelect', 'TimePicker', 'DataTable', 'Navbar']) {
|
||||||
|
expect(readFileSync(uiComponentPath(name), 'utf8')).toContain('data-wrn-anchored="true"');
|
||||||
|
}
|
||||||
|
});
|
||||||
Reference in new issue
Block a user