Canvas: Fix references for ResourcePicker (#95580)

* useRef instead of create ref for functional components, pass function to close popper if needed

* Cleanup, hide on save as well

* add comment about when hidePopper is available to content
This commit is contained in:
Kristina 2024-11-07 11:37:49 -06:00 committed by GitHub
parent d5cde0b60a
commit ac88461fe6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 29 additions and 16 deletions

View File

@ -24,6 +24,7 @@ interface Props extends Omit<React.HTMLAttributes<HTMLDivElement>, 'content'> {
referenceElement: HTMLElement; referenceElement: HTMLElement;
wrapperClassName?: string; wrapperClassName?: string;
renderArrow?: boolean; renderArrow?: boolean;
hidePopper?: () => void;
} }
export function Popover({ export function Popover({
@ -34,6 +35,7 @@ export function Popover({
wrapperClassName, wrapperClassName,
referenceElement, referenceElement,
renderArrow, renderArrow,
hidePopper,
...rest ...rest
}: Props) { }: Props) {
const theme = useTheme2(); const theme = useTheme2();
@ -95,7 +97,7 @@ export function Popover({
{renderArrow && <FloatingArrow fill={theme.colors.border.weak} ref={arrowRef} context={context} />} {renderArrow && <FloatingArrow fill={theme.colors.border.weak} ref={arrowRef} context={context} />}
{typeof content === 'string' && content} {typeof content === 'string' && content}
{React.isValidElement(content) && React.cloneElement(content)} {React.isValidElement(content) && React.cloneElement(content)}
{typeof content === 'function' && content({})} {typeof content === 'function' && content({ hidePopper })}
</div> </div>
</div> </div>
</Portal> </Portal>

View File

@ -7,8 +7,11 @@ export interface PopoverContentProps {
* It will be removed in a future release. * It will be removed in a future release.
*/ */
updatePopperPosition?: () => void; updatePopperPosition?: () => void;
hidePopper?: () => void;
} }
// hidePopper is only available to popover content when it is passed as a function
export type PopoverContent = string | React.ReactElement | ((props: PopoverContentProps) => JSX.Element); export type PopoverContent = string | React.ReactElement | ((props: PopoverContentProps) => JSX.Element);
export type TooltipPlacement = Placement | 'auto' | 'auto-start' | 'auto-end'; export type TooltipPlacement = Placement | 'auto' | 'auto-start' | 'auto-end';

View File

@ -1,5 +1,5 @@
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import { createRef } from 'react'; import { useRef } from 'react';
import * as React from 'react'; import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data'; import { GrafanaTheme2 } from '@grafana/data';
@ -42,16 +42,19 @@ export const ResourcePicker = (props: Props) => {
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);
const theme = useTheme2(); const theme = useTheme2();
const pickerTriggerRef = createRef<HTMLDivElement>(); const pickerTriggerRef = useRef<HTMLDivElement>(null);
const popoverElement = ( const popoverElement = (props: { hidePopper?: () => void }) => {
<ResourcePickerPopover return (
onChange={onChange} <ResourcePickerPopover
value={value} onChange={onChange}
mediaType={mediaType} value={value}
folderName={folderName} mediaType={mediaType}
maxFiles={maxFiles} folderName={folderName}
/> maxFiles={maxFiles}
); hidePopper={props.hidePopper}
/>
);
};
let sanitizedSrc = src; let sanitizedSrc = src;
if (!sanitizedSrc && value) { if (!sanitizedSrc && value) {
@ -101,6 +104,7 @@ export const ResourcePicker = (props: Props) => {
onKeyDown={(event) => { onKeyDown={(event) => {
closePopover(event, hidePopper); closePopover(event, hidePopper);
}} }}
hidePopper={hidePopper}
/> />
)} )}

View File

@ -2,7 +2,7 @@ import { css } from '@emotion/css';
import { useDialog } from '@react-aria/dialog'; import { useDialog } from '@react-aria/dialog';
import { FocusScope } from '@react-aria/focus'; import { FocusScope } from '@react-aria/focus';
import { useOverlay } from '@react-aria/overlays'; import { useOverlay } from '@react-aria/overlays';
import { createRef, useState } from 'react'; import { useRef, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data'; import { GrafanaTheme2 } from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime'; import { getBackendSrv } from '@grafana/runtime';
@ -21,20 +21,22 @@ interface Props {
mediaType: MediaType; mediaType: MediaType;
folderName: ResourceFolderName; folderName: ResourceFolderName;
maxFiles?: number; maxFiles?: number;
hidePopper?: () => void;
} }
interface ErrorResponse { interface ErrorResponse {
message: string; message: string;
} }
export const ResourcePickerPopover = (props: Props) => { export const ResourcePickerPopover = (props: Props) => {
const { value, onChange, mediaType, folderName, maxFiles } = props; const { value, onChange, mediaType, folderName, maxFiles, hidePopper } = props;
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);
const onClose = () => { const onClose = () => {
onChange(value); onChange(value);
hidePopper?.();
}; };
const ref = createRef<HTMLElement>(); const ref = useRef<HTMLElement>(null);
const { dialogProps } = useDialog({}, ref); const { dialogProps } = useDialog({}, ref);
const { overlayProps } = useOverlay({ onClose, isDismissable: true, isOpen: true }, ref); const { overlayProps } = useOverlay({ onClose, isDismissable: true, isOpen: true }, ref);
@ -124,11 +126,13 @@ export const ResourcePickerPopover = (props: Props) => {
getBackendSrv() getBackendSrv()
.get(`api/storage/read/${data.path}`) .get(`api/storage/read/${data.path}`)
.then(() => setNewValue(`${config.appUrl}api/storage/read/${data.path}`)) .then(() => setNewValue(`${config.appUrl}api/storage/read/${data.path}`))
.then(() => onChange(`${config.appUrl}api/storage/read/${data.path}`)); .then(() => onChange(`${config.appUrl}api/storage/read/${data.path}`))
.then(() => hidePopper?.());
}) })
.catch((err) => console.error(err)); .catch((err) => console.error(err));
} else { } else {
onChange(newValue); onChange(newValue);
hidePopper?.();
} }
}} }}
> >