feat(editor): group shortcuts by scope with conflict tiers
Closes #9075
This commit is contained in:
1 parent
b2d56625e0
commit
ea1de14517
17 files changed
+970
-80
No files matched your search
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onBeforeUnmount, ref, watch } from "vue";
|
||||
import { cn } from "@/lib/common/utils";
|
||||
import { floatingArrowOffset, floatingViewportShift } from "@/lib/common/floatingViewportPosition";
|
||||
|
||||
const props = withDefaults(
|
||||
@@ -13,6 +14,7 @@ const props = withDefaults(
|
||||
openOnFocus?: boolean;
|
||||
nowrap?: boolean;
|
||||
surface?: "foreground" | "popover";
|
||||
contentClass?: string;
|
||||
}>(),
|
||||
{
|
||||
disabled: false,
|
||||
@@ -279,7 +281,7 @@ watch(
|
||||
v-if="show"
|
||||
ref="tooltipRef"
|
||||
class="fixed z-50 rounded-md text-xs"
|
||||
:class="[tooltipSurfaceClass, slots.content ? '' : ['inline-flex w-fit max-w-xs items-center gap-1.5 px-3 py-1.5', nowrap ? 'whitespace-nowrap' : ''], tooltipTransformClass]"
|
||||
:class="cn([tooltipSurfaceClass, slots.content ? '' : ['inline-flex w-fit max-w-xs items-center gap-1.5 px-3 py-1.5', nowrap ? 'whitespace-nowrap' : ''], tooltipTransformClass], contentClass)"
|
||||
:style="{ left: `${x}px`, top: `${y}px` }"
|
||||
role="tooltip"
|
||||
@mouseenter="clearCloseTimer"
|
||||
|
||||
@@ -50,3 +50,56 @@ describe("LightTooltip scrolling", () => {
|
||||
app.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
describe("LightTooltip contentClass", () => {
|
||||
async function mountAndHover(props: Record<string, unknown>) {
|
||||
const root = defineComponent({
|
||||
setup() {
|
||||
return () =>
|
||||
h(
|
||||
LightTooltip,
|
||||
{ delay: 0, ...props },
|
||||
{
|
||||
default: () => h("span", { id: "content-class-trigger" }, "pill"),
|
||||
},
|
||||
);
|
||||
},
|
||||
});
|
||||
const container = document.createElement("div");
|
||||
document.body.append(container);
|
||||
const app = createApp(root);
|
||||
app.mount(container);
|
||||
|
||||
const trigger = container.querySelector<HTMLElement>("#content-class-trigger");
|
||||
expect(trigger).toBeTruthy();
|
||||
vi.spyOn(trigger!, "matches").mockImplementation((selector) => selector === ":hover");
|
||||
trigger?.dispatchEvent(new MouseEvent("mouseenter", { bubbles: true }));
|
||||
await vi.runAllTimersAsync();
|
||||
await nextTick();
|
||||
|
||||
return { app, tooltip: document.querySelector<HTMLElement>("[role=tooltip]") };
|
||||
}
|
||||
|
||||
it("merges contentClass into the teleported tooltip and drops the default max-w-xs", async () => {
|
||||
vi.useFakeTimers();
|
||||
const { app, tooltip } = await mountAndHover({ text: "Conflict hint", contentClass: "max-w-[320px]" });
|
||||
|
||||
expect(tooltip).toBeTruthy();
|
||||
expect(tooltip!.classList.contains("max-w-[320px]")).toBe(true);
|
||||
// With both classes present Tailwind v4 emits max-w-[320px] before max-w-xs,
|
||||
// so the default must be removed for the caller width to take effect.
|
||||
expect(tooltip!.classList.contains("max-w-xs")).toBe(false);
|
||||
|
||||
app.unmount();
|
||||
});
|
||||
|
||||
it("keeps the default max-w-xs when no contentClass is passed", async () => {
|
||||
vi.useFakeTimers();
|
||||
const { app, tooltip } = await mountAndHover({ text: "Plain hint" });
|
||||
|
||||
expect(tooltip).toBeTruthy();
|
||||
expect(tooltip!.classList.contains("max-w-xs")).toBe(true);
|
||||
|
||||
app.unmount();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user