Release beta 7 with Drawer component

This commit is contained in:
Ronan Berder
2026-06-25 12:59:15 +08:00
parent b3c5d16e28
commit a0715d17ab
22 changed files with 867 additions and 23 deletions
+1
View File
@@ -12,6 +12,7 @@
@import "./components/command.css";
@import "./components/combobox.css";
@import "./components/dialog.css";
@import "./components/drawer.css";
@import "./components/dropdown-menu.css";
@import "./components/empty.css";
@import "./components/field.css";
+89
View File
@@ -0,0 +1,89 @@
/* Drawer */
@layer components {
.drawer {
@apply fixed inset-0 m-0 size-auto max-h-none max-w-none overflow-visible bg-transparent p-0 text-inherit opacity-0 transition-all transition-discrete duration-500 ease-[cubic-bezier(0.32,0.72,0,1)] backdrop:opacity-0 backdrop:transition-all backdrop:transition-discrete backdrop:duration-500 backdrop:ease-[cubic-bezier(0.32,0.72,0,1)];
> * {
@apply fixed z-50 flex h-auto flex-col transition-transform duration-500 ease-[cubic-bezier(0.32,0.72,0,1)] will-change-transform outline-hidden;
}
&:not([data-side]) > *,
&[data-side='bottom'] > * {
@apply inset-x-0 bottom-0 mt-24 max-h-[80vh] translate-y-full;
}
&[data-side='top'] > * {
@apply inset-x-0 top-0 mb-24 max-h-[80vh] -translate-y-full;
}
&[data-side='left'] > * {
@apply inset-y-0 left-0 w-3/4 max-w-sm -translate-x-full;
}
&[data-side='right'] > * {
@apply inset-y-0 right-0 w-3/4 max-w-sm translate-x-full;
}
&[data-closing] {
@apply opacity-0 backdrop:opacity-0;
}
&[data-closing]:not([data-side]) > *,
&[data-closing][data-side='bottom'] > * {
@apply translate-y-full;
}
&[data-closing][data-side='top'] > * {
@apply -translate-y-full;
}
&[data-closing][data-side='left'] > * {
@apply -translate-x-full;
}
&[data-closing][data-side='right'] > * {
@apply translate-x-full;
}
&:is([open], :popover-open):not([data-closing]) {
@apply opacity-100 backdrop:opacity-100;
> * {
@apply translate-x-0 translate-y-0;
}
@starting-style {
@apply opacity-0 backdrop:opacity-0;
&:not([data-side]) > *,
&[data-side='bottom'] > * {
@apply translate-y-full;
}
&[data-side='top'] > * {
@apply -translate-y-full;
}
&[data-side='left'] > * {
@apply -translate-x-full;
}
&[data-side='right'] > * {
@apply translate-x-full;
}
}
}
> * > header {
@apply flex flex-col;
}
> * > section {
@apply min-h-0 flex-1 overflow-y-auto;
}
> * > footer {
@apply mt-auto flex flex-col;
}
}
}
+33
View File
@@ -589,6 +589,39 @@
@apply text-muted-foreground text-sm text-balance md:text-pretty [&_a]:underline [&_a]:underline-offset-3 [&_a:hover]:text-foreground;
}
/* Drawer */
.drawer::backdrop {
@apply bg-black/30 backdrop-blur-sm;
}
.drawer > * {
@apply before:bg-popover before:border-border relative bg-transparent p-4 text-sm before:absolute before:inset-2 before:-z-10 before:rounded-4xl before:border before:shadow-xl;
}
.drawer > * > header {
@apply gap-0.5 p-4 text-start md:gap-1.5;
}
.drawer:not([data-side]) > * > header,
.drawer[data-side='bottom'] > * > header,
.drawer[data-side='top'] > * > header {
@apply text-center;
}
.drawer > * > footer {
@apply gap-2 p-4;
}
.drawer > * > header > h2,
.drawer > * > [data-title] {
@apply text-lg font-semibold leading-none tracking-tight;
}
.drawer > * > header > p,
.drawer > * > [data-description] {
@apply text-muted-foreground text-sm;
}
/* Dropdown Menu */
.dropdown-menu > [data-popover] {
@apply bg-popover text-popover-foreground ring-foreground/5 dark:ring-foreground/10 min-w-48 gap-0 overflow-x-hidden overflow-y-auto rounded-3xl p-1.5 shadow-lg ring-1 duration-100;
+50
View File
@@ -565,6 +565,56 @@
@apply text-muted-foreground text-xs/relaxed text-balance md:text-pretty [&_a]:underline [&_a]:underline-offset-3 [&_a:hover]:text-foreground;
}
/* Drawer */
.drawer::backdrop {
@apply bg-black/10 backdrop-blur-xs;
}
.drawer > * {
@apply bg-popover text-popover-foreground text-xs/relaxed;
}
.drawer:not([data-side]) > *,
.drawer[data-side='bottom'] > * {
@apply rounded-none border-t;
}
.drawer[data-side='top'] > * {
@apply rounded-none border-b;
}
.drawer[data-side='left'] > * {
@apply rounded-none border-r;
}
.drawer[data-side='right'] > * {
@apply rounded-none border-l;
}
.drawer > * > header {
@apply gap-0.5 p-4 text-start;
}
.drawer:not([data-side]) > * > header,
.drawer[data-side='bottom'] > * > header,
.drawer[data-side='top'] > * > header {
@apply text-center;
}
.drawer > * > footer {
@apply gap-2 p-4;
}
.drawer > * > header > h2,
.drawer > * > [data-title] {
@apply text-sm font-medium;
}
.drawer > * > header > p,
.drawer > * > [data-description] {
@apply text-muted-foreground text-xs/relaxed;
}
/* Dropdown Menu */
.dropdown-menu > [data-popover] {
@apply bg-popover text-popover-foreground ring-foreground/10 gap-0 overflow-x-hidden overflow-y-auto rounded-none p-0 shadow-md ring-1 duration-100;
+33
View File
@@ -577,6 +577,39 @@
@apply text-muted-foreground text-sm text-balance md:text-pretty [&_a]:underline [&_a]:underline-offset-3 [&_a:hover]:text-foreground;
}
/* Drawer */
.drawer::backdrop {
@apply bg-black/80 backdrop-blur-xs;
}
.drawer > * {
@apply before:bg-popover text-popover-foreground before:border-border relative bg-transparent p-4 text-sm before:absolute before:inset-2 before:-z-10 before:rounded-4xl before:border;
}
.drawer > * > header {
@apply gap-0.5 p-4 text-start md:gap-1.5;
}
.drawer:not([data-side]) > * > header,
.drawer[data-side='bottom'] > * > header,
.drawer[data-side='top'] > * > header {
@apply text-center;
}
.drawer > * > footer {
@apply gap-2 p-4;
}
.drawer > * > header > h2,
.drawer > * > [data-title] {
@apply text-lg font-semibold leading-none tracking-tight;
}
.drawer > * > header > p,
.drawer > * > [data-description] {
@apply text-muted-foreground text-sm;
}
/* Dropdown Menu */
.dropdown-menu > [data-popover] {
@apply bg-popover text-popover-foreground ring-foreground/5 dark:ring-foreground/10 min-w-48 gap-0 overflow-x-hidden overflow-y-auto rounded-2xl p-1 shadow-2xl ring-1 duration-100;
+33
View File
@@ -581,6 +581,39 @@
@apply text-muted-foreground text-xs/relaxed text-balance md:text-pretty [&_a]:underline [&_a]:underline-offset-3 [&_a:hover]:text-foreground;
}
/* Drawer */
.drawer::backdrop {
@apply bg-black/80 backdrop-blur-xs;
}
.drawer > * {
@apply before:bg-popover text-popover-foreground before:border-border relative bg-transparent p-2 text-xs/relaxed before:absolute before:inset-2 before:-z-10 before:rounded-xl before:border;
}
.drawer > * > header {
@apply gap-1 p-4 text-start;
}
.drawer:not([data-side]) > * > header,
.drawer[data-side='bottom'] > * > header,
.drawer[data-side='top'] > * > header {
@apply text-center;
}
.drawer > * > footer {
@apply gap-2 p-4;
}
.drawer > * > header > h2,
.drawer > * > [data-title] {
@apply text-sm font-medium;
}
.drawer > * > header > p,
.drawer > * > [data-description] {
@apply text-muted-foreground text-xs/relaxed;
}
/* Dropdown Menu */
.dropdown-menu > [data-popover] {
@apply bg-popover text-popover-foreground ring-foreground/10 gap-0 overflow-x-hidden overflow-y-auto rounded-lg p-1 shadow-md ring-1 duration-100;
+50
View File
@@ -573,6 +573,56 @@
@apply text-muted-foreground text-sm text-balance md:text-pretty [&_a]:underline [&_a]:underline-offset-3 [&_a:hover]:text-foreground;
}
/* Drawer */
.drawer::backdrop {
@apply bg-black/10 backdrop-blur-xs;
}
.drawer > * {
@apply bg-popover text-popover-foreground text-sm;
}
.drawer:not([data-side]) > *,
.drawer[data-side='bottom'] > * {
@apply rounded-t-xl border-t;
}
.drawer[data-side='top'] > * {
@apply rounded-b-xl border-b;
}
.drawer[data-side='left'] > * {
@apply rounded-r-xl border-r;
}
.drawer[data-side='right'] > * {
@apply rounded-l-xl border-l;
}
.drawer > * > header {
@apply gap-0.5 p-4 text-start;
}
.drawer:not([data-side]) > * > header,
.drawer[data-side='bottom'] > * > header,
.drawer[data-side='top'] > * > header {
@apply text-center;
}
.drawer > * > footer {
@apply gap-2 p-4;
}
.drawer > * > header > h2,
.drawer > * > [data-title] {
@apply text-lg font-semibold leading-none tracking-tight;
}
.drawer > * > header > p,
.drawer > * > [data-description] {
@apply text-muted-foreground text-sm;
}
/* Dropdown Menu */
.dropdown-menu > [data-popover] {
@apply bg-popover text-popover-foreground ring-foreground/10 gap-0 overflow-x-hidden overflow-y-auto rounded-lg p-1 shadow-md ring-1 duration-100;
+33
View File
@@ -589,6 +589,39 @@
@apply text-muted-foreground text-sm text-balance md:text-pretty [&_a]:underline [&_a]:underline-offset-3 [&_a:hover]:text-foreground;
}
/* Drawer */
.drawer::backdrop {
@apply bg-black/30 backdrop-blur-sm;
}
.drawer > * {
@apply before:bg-popover before:border-border relative bg-transparent p-4 text-sm before:absolute before:inset-2 before:-z-10 before:rounded-[min(var(--radius-4xl),24px)] before:border before:shadow-xl;
}
.drawer > * > header {
@apply gap-0.5 p-4 text-start md:gap-1.5;
}
.drawer:not([data-side]) > * > header,
.drawer[data-side='bottom'] > * > header,
.drawer[data-side='top'] > * > header {
@apply text-center;
}
.drawer > * > footer {
@apply gap-2 p-4;
}
.drawer > * > header > h2,
.drawer > * > [data-title] {
@apply text-lg font-semibold leading-none tracking-tight;
}
.drawer > * > header > p,
.drawer > * > [data-description] {
@apply text-muted-foreground text-sm;
}
/* Dropdown Menu */
.dropdown-menu > [data-popover] {
@apply bg-popover text-popover-foreground ring-foreground/5 dark:ring-foreground/10 gap-0 overflow-x-hidden overflow-y-auto rounded-2xl p-1 shadow-lg ring-1 duration-100;
+50
View File
@@ -593,6 +593,56 @@
@apply text-muted-foreground mt-0.5 text-sm leading-relaxed text-balance md:text-pretty [&_a]:underline [&_a]:underline-offset-3 [&_a:hover]:text-foreground;
}
/* Drawer */
.drawer::backdrop {
@apply bg-black/20 backdrop-blur-sm;
}
.drawer > * {
@apply bg-popover text-popover-foreground text-sm;
}
.drawer:not([data-side]) > *,
.drawer[data-side='bottom'] > * {
@apply rounded-none border-t;
}
.drawer[data-side='top'] > * {
@apply rounded-none border-b;
}
.drawer[data-side='left'] > * {
@apply rounded-none border-r;
}
.drawer[data-side='right'] > * {
@apply rounded-none border-l;
}
.drawer > * > header {
@apply gap-1 p-4 text-start md:gap-2;
}
.drawer:not([data-side]) > * > header,
.drawer[data-side='bottom'] > * > header,
.drawer[data-side='top'] > * > header {
@apply text-center;
}
.drawer > * > footer {
@apply gap-2 p-4;
}
.drawer > * > header > h2,
.drawer > * > [data-title] {
@apply text-lg font-semibold tracking-wider uppercase;
}
.drawer > * > header > p,
.drawer > * > [data-description] {
@apply text-muted-foreground mt-0.5 text-sm leading-relaxed;
}
/* Dropdown Menu */
.dropdown-menu > [data-popover] {
@apply bg-popover text-popover-foreground ring-foreground/10 min-w-48 gap-0 overflow-x-hidden overflow-y-auto rounded-none p-1.5 shadow-md ring-1 duration-100;
+50
View File
@@ -573,6 +573,56 @@
@apply text-muted-foreground text-sm text-balance md:text-pretty [&_a]:underline [&_a]:underline-offset-3 [&_a:hover]:text-foreground;
}
/* Drawer */
.drawer::backdrop {
@apply bg-black/10 backdrop-blur-xs;
}
.drawer > * {
@apply bg-popover text-popover-foreground text-sm;
}
.drawer:not([data-side]) > *,
.drawer[data-side='bottom'] > * {
@apply rounded-t-xl border-t;
}
.drawer[data-side='top'] > * {
@apply rounded-b-xl border-b;
}
.drawer[data-side='left'] > * {
@apply rounded-r-xl border-r;
}
.drawer[data-side='right'] > * {
@apply rounded-l-xl border-l;
}
.drawer > * > header {
@apply gap-0.5 p-4 text-start md:gap-1.5;
}
.drawer:not([data-side]) > * > header,
.drawer[data-side='bottom'] > * > header,
.drawer[data-side='top'] > * > header {
@apply text-center;
}
.drawer > * > footer {
@apply gap-2 p-4;
}
.drawer > * > header > h2,
.drawer > * > [data-title] {
@apply text-lg font-semibold leading-none tracking-tight;
}
.drawer > * > header > p,
.drawer > * > [data-description] {
@apply text-muted-foreground text-sm;
}
/* Dropdown Menu */
.dropdown-menu > [data-popover] {
@apply bg-popover text-popover-foreground ring-foreground/10 gap-0 overflow-x-hidden overflow-y-auto rounded-md p-1 shadow-md ring-1 duration-100;
+84
View File
@@ -0,0 +1,84 @@
(() => {
const toMs = (value) => {
if (!value) return 0;
const trimmed = value.trim();
if (trimmed.endsWith('ms')) return parseFloat(trimmed) || 0;
if (trimmed.endsWith('s')) return (parseFloat(trimmed) || 0) * 1000;
return parseFloat(trimmed) || 0;
};
const maxTransitionMs = (element) => {
if (!element) return 0;
const styles = getComputedStyle(element);
const durations = styles.transitionDuration.split(',').map(toMs);
const delays = styles.transitionDelay.split(',').map(toMs);
return Math.max(0, ...durations.map((duration, index) => duration + (delays[index] || delays[0] || 0)));
};
const initDrawer = (drawer) => {
if (drawer.dataset.drawerInitialized) return;
const nativeClose = drawer.close.bind(drawer);
let pointerStartedOnBackdrop = false;
let closeTimer = null;
const finishClose = (returnValue) => {
window.clearTimeout(closeTimer);
closeTimer = null;
drawer.removeAttribute('data-closing');
nativeClose(returnValue);
};
drawer.close = (returnValue = '') => {
if (!drawer.open) return;
if (drawer.dataset.closing) return;
const content = drawer.firstElementChild;
const duration = maxTransitionMs(content);
if (duration === 0 || window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
finishClose(returnValue);
return;
}
drawer.dataset.closing = 'true';
closeTimer = window.setTimeout(() => finishClose(returnValue), duration + 50);
};
const handleCancel = (event) => {
event.preventDefault();
drawer.close();
};
const handlePointerDown = (event) => {
pointerStartedOnBackdrop = event.target === drawer;
};
const handlePointerUp = (event) => {
if (pointerStartedOnBackdrop && event.target === drawer) {
drawer.close();
}
pointerStartedOnBackdrop = false;
};
drawer.addEventListener('cancel', handleCancel);
drawer.addEventListener('pointerdown', handlePointerDown);
drawer.addEventListener('pointerup', handlePointerUp);
drawer._destroy = () => {
window.clearTimeout(closeTimer);
drawer.removeEventListener('cancel', handleCancel);
drawer.removeEventListener('pointerdown', handlePointerDown);
drawer.removeEventListener('pointerup', handlePointerUp);
drawer.close = nativeClose;
delete drawer._destroy;
};
drawer.dataset.drawerInitialized = 'true';
drawer.dispatchEvent(new CustomEvent('basecoat:initialized'));
};
if (window.basecoat) {
window.basecoat.register('drawer', '.drawer:not([data-drawer-initialized])', initDrawer);
}
})();