feat(packages/excalidraw): support ViewportStatusFrame label onClick (#11838)

This commit is contained in:
David Luzar
2026-08-05 18:28:52 +02:00
committed by GitHub
parent e33a1c0e85
commit 74789584be
5 changed files with 74 additions and 15 deletions
+2
View File
@@ -2355,6 +2355,8 @@ class App extends React.Component<AppProps, AppState> {
"excalidraw--allow-browser-zoom":
!this.isInteractionEnabled() && this.isBrowserZoomEnabled(),
"excalidraw--ui-hidden": !this.isDefaultUIEnabled(),
"excalidraw--viewport-status-label":
!!this.props.viewportStatusFrame?.label,
})}
style={{
["--ui-pointerEvents" as any]: shouldBlockPointerEvents
@@ -4,7 +4,7 @@
inset: 0;
box-sizing: border-box;
pointer-events: none;
border: 2px solid;
border: 4px solid;
z-index: 9999;
}
@@ -18,20 +18,46 @@
background-color: var(--color-primary-hover);
color: var(--color-primary-light);
padding: 0.25rem 0.5rem;
border-radius: 0.5rem;
font-size: 0.75rem;
display: flex;
gap: 0.5rem;
align-items: center;
overflow: hidden;
}
.viewport-status-frame__badge--clickable {
cursor: pointer;
&:active {
transform: translateX(-50%) scale(0.96);
}
}
.viewport-status-frame__badge-action {
position: absolute;
inset: 0;
margin: 0;
border: 0;
padding: 0;
background: transparent;
cursor: inherit;
&:focus-visible {
outline: 2px solid currentColor;
outline-offset: -2px;
border-radius: 0.5rem;
}
}
.viewport-status-frame__badge-label {
position: relative;
display: flex;
align-items: center;
gap: 0.25rem;
padding: 0.25rem 0.5rem;
white-space: pre-wrap;
line-height: 1;
pointer-events: none;
}
.viewport-status-frame__badge-icon {
@@ -48,6 +74,8 @@
all: unset;
cursor: pointer;
border-radius: 0.25rem;
margin-right: 0.5rem;
position: relative;
&:hover {
background-color: var(--color-primary-darker);
@@ -1,3 +1,7 @@
import { useId } from "react";
import clsx from "clsx";
import { t } from "../../i18n";
import { CloseIcon } from "../icons";
@@ -11,6 +15,15 @@ interface ViewportStatusFrameProps {
const ViewportStatusFrame = ({ status }: ViewportStatusFrameProps) => {
const { border, label } = status;
const labelId = useId();
const labelContent = label && (
<>
{label.icon && (
<span className="viewport-status-frame__badge-icon">{label.icon}</span>
)}
{label.label}
</>
);
return (
<>
@@ -22,20 +35,28 @@ const ViewportStatusFrame = ({ status }: ViewportStatusFrameProps) => {
)}
{label && (
<div
className="viewport-status-frame__badge"
className={clsx("viewport-status-frame__badge", {
"viewport-status-frame__badge--clickable": label.onClick,
})}
role="status"
style={{
backgroundColor: label.background || border || undefined,
color: label.color,
}}
>
<div className="viewport-status-frame__badge-label">
{label.icon && (
<span className="viewport-status-frame__badge-icon">
{label.icon}
</span>
)}
{label.label}
{label.onClick && (
<button
type="button"
className="viewport-status-frame__badge-action"
aria-labelledby={labelId}
onClick={label.onClick}
/>
)}
<div
className="viewport-status-frame__badge-label"
id={label.onClick ? labelId : undefined}
>
{labelContent}
</div>
{label.onClose && (
<button
+10 -4
View File
@@ -39,6 +39,12 @@ body.excalidraw-cursor-resize * {
.excalidraw {
--ui-font: Assistant, system-ui, BlinkMacSystemFont, -apple-system, Segoe UI,
Roboto, Helvetica, Arial, sans-serif;
--viewport-status-label-offset: 0px;
&.excalidraw--viewport-status-label {
--viewport-status-label-offset: 0.75rem;
}
font-family: var(--ui-font);
position: relative;
@@ -510,7 +516,7 @@ body.excalidraw-cursor-resize * {
padding: 10px 20px;
position: absolute;
left: 50%;
bottom: 30px;
bottom: calc(30px + var(--viewport-status-label-offset));
transform: translateX(-50%);
pointer-events: var(--ui-pointerEvents);
font-family: inherit;
@@ -527,7 +533,7 @@ body.excalidraw-cursor-resize * {
.floating-status-stack {
position: absolute;
left: 50%;
bottom: 30px;
bottom: calc(30px + var(--viewport-status-label-offset));
transform: translateX(-50%);
display: flex;
flex-direction: column;
@@ -585,12 +591,12 @@ body.excalidraw-cursor-resize * {
}
.floating-status-stack {
bottom: calc(30px + var(--sab, 0));
bottom: calc(30px + var(--viewport-status-label-offset) + var(--sab, 0));
z-index: var(--zIndex-ui-bottom);
}
.scroll-back-to-content {
bottom: calc(100px + var(--sab, 0));
bottom: calc(100px + var(--viewport-status-label-offset) + var(--sab, 0));
z-index: -1;
}
+2
View File
@@ -645,6 +645,8 @@ export type ViewportStatusFrame = {
background?: string;
/** badge text color; defaults to var(--color-primary-light) */
color?: string;
/** makes the badge label interactive */
onClick?: () => void;
/** renders a close button when set */
onClose?: () => void;
};