chore: recovery 2 (#5014) merge to 3.11 (#5175)

Co-authored-by: Alireza <ar.sedghi@gmail.com>
Co-authored-by: Dan Rukas <dan.rukas@gmail.com>
Co-authored-by: Tang Cheng <45505657+tctco@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2025-07-03 14:08:46 -04:00
1 parent 17ed63eb1d
commit 24e0263fb9
44 files changed
+516 -258

No files matched your search

@@ -14,6 +14,8 @@ const serviceImplementation = {
console.warn('isEmpty() NOT IMPLEMENTED');
return true;
},
_updatePosition: (id: string, position: { x: number; y: number }) =>
console.warn('updatePosition() NOT IMPLEMENTED'),
_customComponent: null,
};
@@ -63,6 +65,16 @@ class UIDialogService {
return serviceImplementation._isEmpty();
}
/**
* Update the position of a specific dialog by id
*
* @param {string} id - The dialog id to update
* @param {{ x: number; y: number }} position - The new position
*/
updatePosition(id: string, position: { x: number; y: number }): void {
return serviceImplementation._updatePosition(id, position);
}
/**
* This provides flexibility in customizing the Modal's default component
*
@@ -75,7 +87,14 @@ class UIDialogService {
/**
* Set the service implementation
*/
setServiceImplementation({ show, hide, hideAll, isEmpty, customComponent }: any): void {
setServiceImplementation({
show,
hide,
hideAll,
isEmpty,
updatePosition,
customComponent,
}: any): void {
if (show) {
serviceImplementation._show = show;
}
@@ -88,6 +107,9 @@ class UIDialogService {
if (isEmpty) {
serviceImplementation._isEmpty = isEmpty;
}
if (updatePosition) {
serviceImplementation._updatePosition = updatePosition;
}
if (customComponent) {
serviceImplementation._customComponent = customComponent;
}
+1 -1
View File
@@ -139,4 +139,4 @@ export default function ComponentsList() {
</BrowserOnly>
</Layout>
);
}
}
@@ -6,8 +6,8 @@ export const PowerOff = (props: IconProps) => (
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 28"
aria-labelledby="title"
width="1em"
height="1em"
width="28px"
height="28px"
fill="currentColor"
{...props}
>
@@ -67,9 +67,10 @@ function ViewportPane({
{/* Border overlay */}
<div
className={classNames('pointer-events-none absolute inset-0', {
'border-highlight rounded-md border': isActive,
'group-hover:border-highlight/50 rounded-md border border-transparent': !isActive,
className={classNames('pointer-events-none absolute inset-0 rounded-md border', {
'border-highlight': isActive,
'group-hover/pane:border-highlight/50 border-transparent': !isActive,
'!border-secondary-light border-dashed': isHighlighted,
})}
/>
</div>
@@ -1,11 +1,20 @@
import React, { useState, createContext, useContext, useCallback, useEffect, useMemo } from 'react';
import ManagedDialog, { ManagedDialogProps } from './ManagedDialog';
import React, {
useState,
createContext,
useContext,
useCallback,
useEffect,
useMemo,
useRef,
} from 'react';
import ManagedDialog, { ManagedDialogProps, ManagedDialogRef } from './ManagedDialog';
interface DialogContextType {
show: (options: ManagedDialogProps) => string;
hide: (id: string) => void;
hideAll: () => void;
isEmpty: () => boolean;
updatePosition: (id: string, position: { x: number; y: number }) => void;
}
interface DialogService {
@@ -35,6 +44,7 @@ const DialogProvider: React.FC<DialogProviderProps> = ({
service = null,
}) => {
const [dialogs, setDialogs] = useState<(ManagedDialogProps & { id: string })[]>([]);
const dialogRefs = useRef<Map<string, ManagedDialogRef>>(new Map());
const show = useCallback((options: ManagedDialogProps) => {
const id = options.id;
@@ -44,22 +54,32 @@ const DialogProvider: React.FC<DialogProviderProps> = ({
const hide = useCallback((id: string) => {
setDialogs(prev => prev.filter(dialog => dialog.id !== id));
dialogRefs.current.delete(id);
}, []);
const hideAll = useCallback(() => {
setDialogs([]);
dialogRefs.current.clear();
}, []);
const isEmpty = useCallback(() => dialogs.length === 0, [dialogs]);
const updatePosition = useCallback((id: string, position: { x: number; y: number }) => {
const dialogRef = dialogRefs.current.get(id);
if (dialogRef) {
dialogRef.updatePosition(position);
}
}, []);
const contextValue = useMemo(
() => ({
show,
hide,
hideAll,
isEmpty,
updatePosition,
}),
[show, hide, hideAll, isEmpty]
[show, hide, hideAll, isEmpty, updatePosition]
);
useEffect(() => {
@@ -76,6 +96,11 @@ const DialogProvider: React.FC<DialogProviderProps> = ({
{dialogs.map(dialog => (
<RenderedDialog
key={dialog.id}
ref={(ref: ManagedDialogRef) => {
if (ref) {
dialogRefs.current.set(dialog.id, ref);
}
}}
onClose={hide}
isOpen={true}
{...dialog}
@@ -1,7 +1,12 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import React, { useState, useEffect, useImperativeHandle, forwardRef, useCallback } from 'react';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '../components/Dialog/Dialog';
import { cn } from '../lib/utils';
type Position = {
x: number;
y: number;
};
export interface ManagedDialogProps {
id: string;
isOpen?: boolean;
@@ -19,92 +24,134 @@ export interface ManagedDialogProps {
containerClassName?: string;
}
const ManagedDialog: React.FC<ManagedDialogProps> = ({
id,
isOpen,
title,
content: DialogContentComponent,
contentProps,
isDraggable,
shouldCloseOnEsc = false,
shouldCloseOnOverlayClick = false,
showOverlay = true,
defaultPosition,
onClose,
unstyled,
containerClassName,
}) => {
// When a default position is provided, the assumption is that the position
// is respected unless the position chosen results in the dialog being
// clipped off-screen (i.e. part of the dialog is rendered outside the browser
// window). When the dialog is clipped it will be repositioned about
// the default position such that it is no longer clipped. To avoid a flash
// during the reposition, we initially hide the dialog.
const [contentVisibility, setContentVisibility] = useState(
defaultPosition ? 'invisible' : 'visible'
);
export interface ManagedDialogRef {
updatePosition: (position: Position) => void;
}
// The callback to reposition an explicitly positioned dialog. Note that
// if the dialog is larger than the window (in either dimension), the
// dialog will still be clipped in some manner.
const contentRef = useCallback(
contentNode => {
if (!contentNode) {
return;
}
const _updatePosition = (
contentNode: HTMLElement,
desiredPosition: { x: number; y: number },
setCurrentPosition: (pt: Position) => void
) => {
if (!contentNode) {
return;
}
const boundingClientRect = contentNode.getBoundingClientRect();
if (boundingClientRect.bottom > window.innerHeight) {
defaultPosition.y = defaultPosition.y - boundingClientRect.height;
}
if (boundingClientRect.right > window.innerWidth) {
defaultPosition.x = defaultPosition.x - boundingClientRect.width;
}
setContentVisibility('visible');
},
[defaultPosition]
);
return (
<Dialog
open={isOpen}
modal={false} // keep modal behavior off for independent windows
onOpenChange={open => {
if (!open) {
onClose(id);
}
}}
isDraggable={isDraggable}
shouldCloseOnEsc={shouldCloseOnEsc}
shouldCloseOnOverlayClick={shouldCloseOnOverlayClick}
showOverlay={showOverlay}
>
<DialogContent
ref={contentRef}
className={cn(unstyled ? 'p-0' : '', containerClassName, contentVisibility)}
unstyled={unstyled}
style={{
...(defaultPosition
? {
position: 'fixed',
left: `${defaultPosition.x}px`,
top: `${defaultPosition.y}px`,
transform: 'translate(0, 0)',
margin: 0,
animation: 'none',
transition: 'none',
}
: {}),
}}
>
{!unstyled && <DialogHeader>{title && <DialogTitle>{title}</DialogTitle>}</DialogHeader>}
<DialogContentComponent
{...contentProps}
hide={() => onClose(id)}
/>
</DialogContent>
</Dialog>
);
const boundingClientRect = contentNode.getBoundingClientRect();
if (boundingClientRect.bottom > window.innerHeight) {
desiredPosition.y = desiredPosition.y - boundingClientRect.height;
}
if (boundingClientRect.right > window.innerWidth) {
desiredPosition.x = desiredPosition.x - boundingClientRect.width;
}
setCurrentPosition(desiredPosition);
};
const ManagedDialog = forwardRef<ManagedDialogRef, ManagedDialogProps>(
(
{
id,
isOpen,
title,
content: DialogContentComponent,
contentProps,
isDraggable,
shouldCloseOnEsc = false,
shouldCloseOnOverlayClick = false,
showOverlay = true,
defaultPosition,
onClose,
unstyled,
containerClassName,
},
ref
) => {
const [currentPosition, setCurrentPosition] = useState(defaultPosition);
const [contentNode, setContentNode] = useState<HTMLElement | null>(null);
useImperativeHandle(
ref,
() => ({
updatePosition: (position: Position) => {
_updatePosition(contentNode, position, setCurrentPosition);
},
}),
[]
);
useEffect(() => {
setCurrentPosition(defaultPosition);
}, [defaultPosition]);
// When a default position is provided, the assumption is that the position
// is respected unless the position chosen results in the dialog being
// clipped off-screen (i.e. part of the dialog is rendered outside the browser
// window). When the dialog is clipped it will be repositioned about
// the default position such that it is no longer clipped. To avoid a flash
// during the reposition, we initially hide the dialog.
const [contentVisibility, setContentVisibility] = useState(
defaultPosition ? 'invisible' : 'visible'
);
// The callback to reposition an explicitly positioned dialog. Note that
// if the dialog is larger than the window (in either dimension), the
// dialog will still be clipped in some manner.
const contentRef = useCallback(
contentNode => {
if (!contentNode) {
return;
}
setContentNode(contentNode);
_updatePosition(contentNode, defaultPosition, setCurrentPosition);
setContentVisibility('visible');
},
[defaultPosition]
);
return (
<Dialog
open={isOpen}
modal={false} // keep modal behavior off for independent windows
onOpenChange={open => {
if (!open) {
onClose(id);
}
}}
isDraggable={isDraggable}
shouldCloseOnEsc={shouldCloseOnEsc}
shouldCloseOnOverlayClick={shouldCloseOnOverlayClick}
showOverlay={showOverlay}
>
<DialogContent
ref={contentRef}
className={cn(unstyled ? 'p-0' : '', containerClassName, contentVisibility)}
unstyled={unstyled}
style={{
...(currentPosition
? {
position: 'fixed',
left: `${currentPosition.x}px`,
top: `${currentPosition.y}px`,
transform: 'translate(0, 0)',
margin: 0,
animation: 'none',
transition: 'none',
}
: {}),
}}
>
{!unstyled && <DialogHeader>{title && <DialogTitle>{title}</DialogTitle>}</DialogHeader>}
<DialogContentComponent
{...contentProps}
hide={() => onClose(id)}
/>
</DialogContent>
</Dialog>
);
}
);
ManagedDialog.displayName = 'ManagedDialog';
export default ManagedDialog;