mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-21 05:20:02 +00:00
fix(schema-diff): keep maximized dialog fullscreen on legacy webviews
This commit is contained in:
@@ -1283,7 +1283,7 @@ const targetConnectionInfo = computed(() => {
|
||||
|
||||
<template>
|
||||
<Dialog v-model:open="open">
|
||||
<DialogContent :class="['flex flex-col overflow-hidden', isMaximized ? 'min-w-0' : 'min-w-[800px] resize']" :portal-class="isMaximized ? 'p-0' : undefined" :style="dialogStyle" @interact-outside.prevent @escape-key-down="handleDialogEscape">
|
||||
<DialogContent :class="['flex flex-col overflow-hidden dbx-schema-diff-dialog', isMaximized ? 'dbx-dialog-maximized min-w-0' : 'min-w-[800px] resize']" :portal-class="isMaximized ? 'p-0' : undefined" :style="dialogStyle" @interact-outside.prevent @escape-key-down="handleDialogEscape">
|
||||
<Button variant="ghost" size="icon-sm" class="absolute top-2 right-10 z-10" @click="toggleMaximize">
|
||||
<Maximize2 v-if="!isMaximized" class="w-4 h-4" />
|
||||
<Minimize2 v-else class="w-4 h-4" />
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
// Source-contract guard for shared button press feedback.
|
||||
|
||||
// Overview: desktop click responsiveness depends on buttons giving immediate
|
||||
// visual feedback while pressed. DOM `click` only fires on pointer-up, so a
|
||||
// press with zero visual delta reads as "the click did nothing" and users
|
||||
// retry or hold the button (~1s holds measured in click-probe sessions).
|
||||
//
|
||||
// Two guarantees keep that regression from re-appearing:
|
||||
// 1. Every button variant styles an `active:` pressed state, so pressing
|
||||
// always changes something on screen before pointer-up.
|
||||
// 2. The pressed state must not move or scale the button (`scale-*` /
|
||||
// `translate-*`). A moving hit target can land pointer-up outside the
|
||||
// element it was pressed on, which genuinely drops the click.
|
||||
// Keep these assertions updated alongside the variant class strings.
|
||||
|
||||
import { readFileSync } from "node:fs";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const buttonVariantsSource = readFileSync(new URL("../index.ts", import.meta.url), "utf8");
|
||||
|
||||
const VARIANTS = ["default", "outline", "secondary", "ghost", "destructive", "link"] as const;
|
||||
|
||||
function variantClasses(variant: string): string {
|
||||
const match = buttonVariantsSource.match(new RegExp(`${variant}:\\s*"([^"]+)"`));
|
||||
expect(match, `variant "${variant}" exists in buttonVariants`).toBeTruthy();
|
||||
return match![1];
|
||||
}
|
||||
|
||||
describe("button press feedback guard", () => {
|
||||
it.each(VARIANTS)("styles an active pressed state for the %s variant", (variant) => {
|
||||
expect(variantClasses(variant)).toMatch(/(^|\s)active:/);
|
||||
});
|
||||
|
||||
it.each(VARIANTS)("does not move the hit target while %s is pressed", (variant) => {
|
||||
expect(variantClasses(variant)).not.toMatch(/active:(scale|translate|-translate)-/);
|
||||
});
|
||||
|
||||
it("does not move the hit target from the shared base classes", () => {
|
||||
const base = buttonVariantsSource.match(/cva\(\s*"([^"]+)"/);
|
||||
expect(base).toBeTruthy();
|
||||
expect(base![1]).not.toMatch(/active:(scale|translate|-translate)-/);
|
||||
});
|
||||
});
|
||||
@@ -34,6 +34,7 @@ const mainSource = readFileSync(new URL("../../main.ts", import.meta.url), "utf8
|
||||
const tabPresentationSource = readFileSync(new URL("../../lib/tabs/tabPresentation.ts", import.meta.url), "utf8");
|
||||
const editorGroupTabBarSource = readFileSync(new URL("../../components/layout/EditorGroupTabBar.vue", import.meta.url), "utf8");
|
||||
const appTabBarCssSource = readFileSync(new URL("../../components/layout/appTabBar.css", import.meta.url), "utf8");
|
||||
const schemaDiffDialogSource = readFileSync(new URL("../../components/diff/SchemaDiffDialog.vue", import.meta.url), "utf8");
|
||||
|
||||
describe("legacy WebView CSS fallbacks", () => {
|
||||
it("keeps globals.css balanced and free of min-width media wrappers", () => {
|
||||
@@ -547,6 +548,34 @@ describe("legacy WebView CSS fallbacks", () => {
|
||||
expect(globalsCss).toContain('html.dbx-legacy-webview input[type="number"]:not([class*="appearance-none"]):disabled::-webkit-inner-spin-button');
|
||||
});
|
||||
|
||||
it("keeps the schema diff dialog inline sizing working in legacy WebViews", () => {
|
||||
// The shared DialogContent base carries max-w-sm, whose legacy !important cap
|
||||
// outranks the dialog's inline width/max-width styles: the normal state then
|
||||
// renders at its min-w floor and the maximize toggle collapses to 24rem wide.
|
||||
// The rescue rules must sit after the max-w-* caps to win by source order.
|
||||
const fallbackStart = globalsCss.indexOf("html.dbx-legacy-webview .sm\\:block");
|
||||
const splitpanesStart = globalsCss.indexOf("/* Splitpanes */");
|
||||
const fallback = globalsCss.slice(fallbackStart, splitpanesStart);
|
||||
const maxWsmCap = fallback.indexOf('html.dbx-legacy-webview [data-slot="dialog-content"][class~="max-w-sm"]');
|
||||
const normalRule = fallback.indexOf('html.dbx-legacy-webview [data-slot="dialog-content"].dbx-schema-diff-dialog {');
|
||||
const maximizedRule = fallback.indexOf('html.dbx-legacy-webview [data-slot="dialog-content"].dbx-schema-diff-dialog.dbx-dialog-maximized {');
|
||||
|
||||
expect(fallbackStart).toBeGreaterThan(-1);
|
||||
expect(splitpanesStart).toBeGreaterThan(fallbackStart);
|
||||
expect(maxWsmCap).toBeGreaterThan(-1);
|
||||
expect(normalRule).toBeGreaterThan(maxWsmCap);
|
||||
expect(maximizedRule).toBeGreaterThan(normalRule);
|
||||
expect(fallback.slice(normalRule, maximizedRule)).toContain("max-width: calc(100vw - 2rem) !important;");
|
||||
expect(fallback.slice(normalRule, maximizedRule)).toContain("max-height: calc(var(--dbx-viewport-height) - 2rem) !important;");
|
||||
expect(fallback.slice(maximizedRule)).toContain("width: calc(100vw - 2rem) !important;");
|
||||
expect(fallback.slice(maximizedRule)).toContain("height: calc(var(--dbx-viewport-height) - 2rem) !important;");
|
||||
expect(fallback.slice(maximizedRule)).toContain("max-width: none !important;");
|
||||
expect(fallback.slice(maximizedRule)).toContain("max-height: none !important;");
|
||||
expect(fallback.slice(maximizedRule)).toContain("border-radius: 0 !important;");
|
||||
expect(schemaDiffDialogSource).toContain("'flex flex-col overflow-hidden dbx-schema-diff-dialog'");
|
||||
expect(schemaDiffDialogSource).toContain("isMaximized ? 'dbx-dialog-maximized min-w-0' : 'min-w-[800px] resize'");
|
||||
});
|
||||
|
||||
it("keeps settings field stacks spaced in legacy WebViews", () => {
|
||||
const fallbackStart = editorSettingsDialogSource.indexOf("html.dbx-legacy-webview .settings-layout");
|
||||
const fallbackEnd = editorSettingsDialogSource.indexOf("@media (max-width: 760px)", fallbackStart);
|
||||
|
||||
@@ -1914,6 +1914,25 @@ html.dbx-legacy-webview [data-slot="dialog-content"][class*="max-w-[min(1080px"]
|
||||
html.dbx-legacy-webview [data-slot="dialog-content"][class*="max-w-[1800px]"] {
|
||||
max-width: 1800px !important;
|
||||
}
|
||||
|
||||
/* The schema diff dialog sizes itself through inline width/height styles, which
|
||||
* the max-w-sm !important cap above outranks in legacy WebViews — the dialog then
|
||||
* renders at its min-w floor and the maximize toggle collapses to 24rem wide.
|
||||
* Pin both states explicitly; these rules must stay after the max-w-* caps
|
||||
* because they share specificity and win by source order. */
|
||||
html.dbx-legacy-webview [data-slot="dialog-content"].dbx-schema-diff-dialog {
|
||||
max-width: calc(100vw - 2rem) !important;
|
||||
max-height: calc(var(--dbx-viewport-height) - 2rem) !important;
|
||||
}
|
||||
|
||||
html.dbx-legacy-webview [data-slot="dialog-content"].dbx-schema-diff-dialog.dbx-dialog-maximized {
|
||||
width: calc(100vw - 2rem) !important;
|
||||
height: calc(var(--dbx-viewport-height) - 2rem) !important;
|
||||
max-width: none !important;
|
||||
max-height: none !important;
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
html.dbx-legacy-webview [data-slot="dialog-content"].dbx-form-dialog {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
|
||||
Reference in New Issue
Block a user