From ac88461fe695d42910c9b20378dd089f42238eb1 Mon Sep 17 00:00:00 2001 From: Kristina Date: Thu, 7 Nov 2024 11:37:49 -0600 Subject: [PATCH] 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 --- .../src/components/Tooltip/Popover.tsx | 4 ++- .../src/components/Tooltip/types.ts | 3 +++ .../dimensions/editors/ResourcePicker.tsx | 26 +++++++++++-------- .../editors/ResourcePickerPopover.tsx | 12 ++++++--- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/packages/grafana-ui/src/components/Tooltip/Popover.tsx b/packages/grafana-ui/src/components/Tooltip/Popover.tsx index 729e4dfce3d..46b8ac849a5 100644 --- a/packages/grafana-ui/src/components/Tooltip/Popover.tsx +++ b/packages/grafana-ui/src/components/Tooltip/Popover.tsx @@ -24,6 +24,7 @@ interface Props extends Omit, 'content'> { referenceElement: HTMLElement; wrapperClassName?: string; renderArrow?: boolean; + hidePopper?: () => void; } export function Popover({ @@ -34,6 +35,7 @@ export function Popover({ wrapperClassName, referenceElement, renderArrow, + hidePopper, ...rest }: Props) { const theme = useTheme2(); @@ -95,7 +97,7 @@ export function Popover({ {renderArrow && } {typeof content === 'string' && content} {React.isValidElement(content) && React.cloneElement(content)} - {typeof content === 'function' && content({})} + {typeof content === 'function' && content({ hidePopper })} diff --git a/packages/grafana-ui/src/components/Tooltip/types.ts b/packages/grafana-ui/src/components/Tooltip/types.ts index bd4d9ba8529..ac01b7f5409 100644 --- a/packages/grafana-ui/src/components/Tooltip/types.ts +++ b/packages/grafana-ui/src/components/Tooltip/types.ts @@ -7,8 +7,11 @@ export interface PopoverContentProps { * It will be removed in a future release. */ 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 TooltipPlacement = Placement | 'auto' | 'auto-start' | 'auto-end'; diff --git a/public/app/features/dimensions/editors/ResourcePicker.tsx b/public/app/features/dimensions/editors/ResourcePicker.tsx index 89375f1439d..ea207674663 100644 --- a/public/app/features/dimensions/editors/ResourcePicker.tsx +++ b/public/app/features/dimensions/editors/ResourcePicker.tsx @@ -1,5 +1,5 @@ import { css } from '@emotion/css'; -import { createRef } from 'react'; +import { useRef } from 'react'; import * as React from 'react'; import { GrafanaTheme2 } from '@grafana/data'; @@ -42,16 +42,19 @@ export const ResourcePicker = (props: Props) => { const styles = useStyles2(getStyles); const theme = useTheme2(); - const pickerTriggerRef = createRef(); - const popoverElement = ( - - ); + const pickerTriggerRef = useRef(null); + const popoverElement = (props: { hidePopper?: () => void }) => { + return ( + + ); + }; let sanitizedSrc = src; if (!sanitizedSrc && value) { @@ -101,6 +104,7 @@ export const ResourcePicker = (props: Props) => { onKeyDown={(event) => { closePopover(event, hidePopper); }} + hidePopper={hidePopper} /> )} diff --git a/public/app/features/dimensions/editors/ResourcePickerPopover.tsx b/public/app/features/dimensions/editors/ResourcePickerPopover.tsx index e62e0c6a202..c56aae069c5 100644 --- a/public/app/features/dimensions/editors/ResourcePickerPopover.tsx +++ b/public/app/features/dimensions/editors/ResourcePickerPopover.tsx @@ -2,7 +2,7 @@ import { css } from '@emotion/css'; import { useDialog } from '@react-aria/dialog'; import { FocusScope } from '@react-aria/focus'; import { useOverlay } from '@react-aria/overlays'; -import { createRef, useState } from 'react'; +import { useRef, useState } from 'react'; import { GrafanaTheme2 } from '@grafana/data'; import { getBackendSrv } from '@grafana/runtime'; @@ -21,20 +21,22 @@ interface Props { mediaType: MediaType; folderName: ResourceFolderName; maxFiles?: number; + hidePopper?: () => void; } interface ErrorResponse { message: string; } 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 onClose = () => { onChange(value); + hidePopper?.(); }; - const ref = createRef(); + const ref = useRef(null); const { dialogProps } = useDialog({}, ref); const { overlayProps } = useOverlay({ onClose, isDismissable: true, isOpen: true }, ref); @@ -124,11 +126,13 @@ export const ResourcePickerPopover = (props: Props) => { getBackendSrv() .get(`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)); } else { onChange(newValue); + hidePopper?.(); } }} >