feat(TypographyMenu): add bindable "open" prop to close popover from outside

This commit is contained in:
Ilia Mashkov
2026-04-17 16:30:41 +03:00
parent bb5c3667b4
commit 5eb9584797
2 changed files with 13 additions and 7 deletions

View File

@@ -1,7 +1,6 @@
<!-- <!--
Component: TypographyMenu Component: TypographyMenu
Floating controls bar for typography settings. Floating controls bar for typography settings.
Warm surface, sharp corners, Settings icon header, dividers between units.
Mobile: popover with slider controls anchored to settings button. Mobile: popover with slider controls anchored to settings button.
Desktop: inline bar with combo controls. Desktop: inline bar with combo controls.
--> -->
@@ -37,14 +36,17 @@ interface Props {
* @default false * @default false
*/ */
hidden?: boolean; hidden?: boolean;
/**
* Bindable popover open state
* @default false
*/
open?: boolean;
} }
const { class: className, hidden = false }: Props = $props(); let { class: className, hidden = false, open = $bindable(false) }: Props = $props();
const responsive = getContext<ResponsiveManager>('responsive'); const responsive = getContext<ResponsiveManager>('responsive');
let isOpen = $state(false);
/** /**
* Sets the common font size multiplier based on the current responsive state. * Sets the common font size multiplier based on the current responsive state.
*/ */
@@ -70,7 +72,7 @@ $effect(() => {
{#if !hidden} {#if !hidden}
{#if responsive.isMobileOrTablet} {#if responsive.isMobileOrTablet}
<Popover.Root bind:open={isOpen}> <Popover.Root bind:open>
<Popover.Trigger> <Popover.Trigger>
{#snippet child({ props })} {#snippet child({ props })}
<Button class={className} variant="primary" {...props}> <Button class={className} variant="primary" {...props}>
@@ -84,7 +86,7 @@ $effect(() => {
<Popover.Portal> <Popover.Portal>
<Popover.Content <Popover.Content
side="top" side="top"
align="start" align="end"
sideOffset={8} sideOffset={8}
class={clsx( class={clsx(
'z-50 w-72', 'z-50 w-72',

View File

@@ -52,6 +52,7 @@ const responsive = getContext<ResponsiveManager>('responsive');
const isMobile = $derived(responsive?.isMobile ?? false); const isMobile = $derived(responsive?.isMobile ?? false);
let isDragging = $state(false); let isDragging = $state(false);
let isTypographyMenuOpen = $state(false);
// New high-performance layout engine // New high-performance layout engine
const comparisonEngine = new CharacterComparisonEngine(); const comparisonEngine = new CharacterComparisonEngine();
@@ -76,6 +77,8 @@ function handleMove(e: PointerEvent) {
function startDragging(e: PointerEvent) { function startDragging(e: PointerEvent) {
e.preventDefault(); e.preventDefault();
// Close typography menu popover
isTypographyMenuOpen = false;
isDragging = true; isDragging = true;
handleMove(e); handleMove(e);
} }
@@ -222,7 +225,7 @@ const scaleClass = $derived(
class=" class="
relative w-full max-w-6xl h-full relative w-full max-w-6xl h-full
flex flex-col justify-center flex flex-col justify-center
select-none touch-none cursor-ew-resize select-none touch-none outline-none cursor-ew-resize
py-8 px-4 sm:py-12 sm:px-8 md:py-16 md:px-12 lg:py-20 lg:px-24 py-8 px-4 sm:py-12 sm:px-8 md:py-16 md:px-12 lg:py-20 lg:px-24
" "
in:fade={{ duration: 300, delay: 300 }} in:fade={{ duration: 300, delay: 300 }}
@@ -253,6 +256,7 @@ const scaleClass = $derived(
</div> </div>
<TypographyMenu <TypographyMenu
bind:open={isTypographyMenuOpen}
class={clsx( class={clsx(
'absolute z-50', 'absolute z-50',
responsive.isMobileOrTablet responsive.isMobileOrTablet