Compare commits

..
Author SHA1 Message Date
grugbraindev 605d332d1a Keep parent popovers open when a nested one opens
Opening a popover, dropdown menu, select or combobox closed every
other open one, including the popover it sits in. Only close the
ones that don't contain the source, like native popover=auto.
2026-10-23 09:53:43 +08:00
17 changed files with 15 additions and 49 deletions
+1 -7
View File
@@ -1,12 +1,6 @@
# Changelog
## [Unreleased]
### Fixed
- Prevented Escape from dismissing an enclosing dialog while closing an open Combobox popup.
- Fixed long Tooltip text clipping instead of showing an ellipsis across all style packs.
- Locked page scroll while a modal Dialog, Alert Dialog, Command Dialog or Drawer is open.
## Unreleased
## [1.0.2] - 2026-07-06
-2
View File
@@ -85,8 +85,6 @@ Combobox is input-first. The visible input filters the list; the hidden input st
</Step>
</Steps>
Pressing Escape in the input closes an open suggestions popup without dismissing an enclosing dialog. Once the popup is closed, press Escape again to dismiss the dialog.
### HTML structure
<dl>
-8
View File
@@ -53,14 +53,6 @@ Basecoat tooltips are CSS-only and text-only. This intentionally differs from sh
<button class="btn" data-variant="outline" data-tooltip="Default tooltip">Default</button>
</Preview>
### Long text
Tooltips stay on one line and truncate with an ellipsis when the text exceeds the maximum width. This intentionally differs from shadcn/ui's multiline tooltip content.
<Preview>
<button class="btn" data-variant="outline" data-tooltip="A tooltip with enough text to exceed the default maximum width and demonstrate truncation">Hover</button>
</Preview>
### Sides
<Preview>
-14
View File
@@ -1,19 +1,5 @@
/* Dialog */
@keyframes dialog-scroll-lock {
from, to {
scrollbar-gutter: stable;
}
}
@layer components {
/* Lock page scroll while a modal dialog is open. The scroll timeline only
reserves the scrollbar gutter if the page can scroll, so nothing shifts. */
html:has(:is(.dialog, .alert-dialog, .command-dialog, .drawer):modal) {
overflow: hidden;
animation: dialog-scroll-lock linear both;
animation-timeline: scroll(self);
}
.dialog,
.alert-dialog {
@apply bg-transparent p-0 text-inherit opacity-0 transition-all transition-discrete backdrop:opacity-0 backdrop:transition-all backdrop:transition-discrete;
+1 -1
View File
@@ -4,7 +4,7 @@
@apply relative;
&:before {
@apply absolute block z-[60] w-fit max-w-xs origin-(--transform-origin) scale-95 truncate invisible opacity-0 transition-all pointer-events-none content-[attr(data-tooltip)];
@apply absolute z-[60] w-fit max-w-xs origin-(--transform-origin) scale-95 truncate invisible opacity-0 transition-all pointer-events-none content-[attr(data-tooltip)];
}
&:hover:before {
+1 -1
View File
@@ -1324,7 +1324,7 @@
/* Tooltip */
[data-tooltip]::before {
@apply bg-foreground text-background rounded-xl px-3 py-1.5 text-xs;
@apply bg-foreground text-background inline-flex items-center gap-1.5 rounded-xl px-3 py-1.5 text-xs has-[.kbd]:pe-1.5 [&_.kbd]:relative [&_.kbd]:isolate [&_.kbd]:z-50 [&_.kbd]:rounded-lg;
}
[data-tooltip][data-arrow]::after {
+1 -1
View File
@@ -1327,7 +1327,7 @@
/* Tooltip */
[data-tooltip]::before {
@apply bg-foreground text-background rounded-none px-3 py-1.5 text-xs;
@apply bg-foreground text-background inline-flex items-center gap-1.5 rounded-none px-3 py-1.5 text-xs has-[.kbd]:pe-1.5 [&_.kbd]:relative [&_.kbd]:isolate [&_.kbd]:z-50 [&_.kbd]:rounded-none;
}
[data-tooltip][data-arrow]::after {
+1 -1
View File
@@ -1312,7 +1312,7 @@
/* Tooltip */
[data-tooltip]::before {
@apply bg-foreground text-background rounded-2xl px-3 py-1.5 text-xs;
@apply bg-foreground text-background inline-flex items-center gap-1.5 rounded-2xl px-3 py-1.5 text-xs has-[.kbd]:pe-1.5 [&_.kbd]:relative [&_.kbd]:isolate [&_.kbd]:z-50 [&_.kbd]:rounded-4xl;
}
[data-tooltip][data-arrow]::after {
+1 -1
View File
@@ -1321,7 +1321,7 @@
/* Tooltip */
[data-tooltip]::before {
@apply bg-foreground text-background rounded-md px-3 py-1.5 text-xs;
@apply bg-foreground text-background inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs has-[.kbd]:pe-1.5 [&_.kbd]:relative [&_.kbd]:isolate [&_.kbd]:z-50 [&_.kbd]:rounded-sm;
}
[data-tooltip][data-arrow]::after {
+1 -1
View File
@@ -1335,7 +1335,7 @@
/* Tooltip */
[data-tooltip]::before {
@apply bg-foreground text-background rounded-md px-3 py-1.5 text-xs;
@apply bg-foreground text-background inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs has-[.kbd]:pe-1.5 [&_.kbd]:relative [&_.kbd]:isolate [&_.kbd]:z-50 [&_.kbd]:rounded-sm;
}
[data-tooltip][data-arrow]::after {
+1 -1
View File
@@ -1329,7 +1329,7 @@
/* Tooltip */
[data-tooltip]::before {
@apply bg-foreground text-background rounded-xl px-3 py-1.5 text-xs;
@apply bg-foreground text-background inline-flex items-center gap-1.5 rounded-xl px-3 py-1.5 text-xs has-[.kbd]:pe-1.5 [&_.kbd]:relative [&_.kbd]:isolate [&_.kbd]:z-50 [&_.kbd]:rounded-lg;
}
[data-tooltip][data-arrow]::after {
+1 -1
View File
@@ -1345,7 +1345,7 @@
/* Tooltip */
[data-tooltip]::before {
@apply bg-foreground text-background rounded-none px-3 py-1.5 text-xs;
@apply bg-foreground text-background inline-flex items-center gap-1.5 rounded-none px-3 py-1.5 text-xs has-[.kbd]:pe-1.5 [&_.kbd]:relative [&_.kbd]:isolate [&_.kbd]:z-50 [&_.kbd]:rounded-none;
}
[data-tooltip][data-arrow]::after {
+1 -1
View File
@@ -1334,7 +1334,7 @@
/* Tooltip */
[data-tooltip]::before {
@apply bg-foreground text-background rounded-md px-3 py-1.5 text-xs;
@apply bg-foreground text-background inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs has-[.kbd]:pe-1.5 [&_.kbd]:relative [&_.kbd]:isolate [&_.kbd]:z-50 [&_.kbd]:rounded-sm;
}
[data-tooltip][data-arrow]::after {
+2 -6
View File
@@ -390,11 +390,7 @@
}
if (event.key === 'Escape') {
if (isOpen) {
event.preventDefault();
event.stopPropagation();
root.close(true);
}
root.close(true);
return;
}
@@ -507,7 +503,7 @@
if (!root.contains(event.target)) root.close(false);
};
const handleDocumentPopover = (event) => {
if (event.detail.source !== root) root.close(false);
if (!root.contains(event.detail.source)) root.close(false);
};
state.input.addEventListener('focus', handleInputFocus);
+1 -1
View File
@@ -165,7 +165,7 @@
};
const handleDocumentPopover = (event) => {
if (event.detail.source !== root) root.close(false);
if (!root.contains(event.detail.source)) root.close(false);
};
state.trigger.addEventListener('click', handleTriggerClick);
+1 -1
View File
@@ -60,7 +60,7 @@
};
const handleDocumentPopover = (event) => {
if (event.detail.source !== popoverComponent) {
if (!popoverComponent.contains(event.detail.source)) {
closePopover(false);
}
};
+1 -1
View File
@@ -373,7 +373,7 @@
if (!root.contains(event.target)) root.close(false);
};
const handleDocumentPopover = (event) => {
if (event.detail.source !== root) root.close(false);
if (!root.contains(event.detail.source)) root.close(false);
};
state.trigger.addEventListener('keydown', handleTriggerKeydown);