diff --git a/packages/grafana-ui/src/components/Forms/Field.tsx b/packages/grafana-ui/src/components/Forms/Field.tsx index 2f1d1230ede..8b6a40c2e8a 100644 --- a/packages/grafana-ui/src/components/Forms/Field.tsx +++ b/packages/grafana-ui/src/components/Forms/Field.tsx @@ -4,7 +4,7 @@ import { stylesFactory, useTheme2 } from '../../themes'; import { css, cx } from '@emotion/css'; import { GrafanaTheme2 } from '@grafana/data'; import { FieldValidationMessage } from './FieldValidationMessage'; -import { getChildId } from '../../utils/children'; +import { getChildId } from '../../utils/reactUtils'; export interface FieldProps extends HTMLAttributes { /** Form input element, i.e Input or Switch */ diff --git a/packages/grafana-ui/src/components/Forms/InlineField.tsx b/packages/grafana-ui/src/components/Forms/InlineField.tsx index 583af8b9b80..1f3291f658c 100644 --- a/packages/grafana-ui/src/components/Forms/InlineField.tsx +++ b/packages/grafana-ui/src/components/Forms/InlineField.tsx @@ -5,7 +5,7 @@ import { useTheme } from '../../themes'; import { InlineLabel } from './InlineLabel'; import { PopoverContent } from '../Tooltip/Tooltip'; import { FieldProps } from './Field'; -import { getChildId } from '../../utils/children'; +import { getChildId } from '../../utils/reactUtils'; export interface Props extends Omit { /** Content for the label's tooltip */ diff --git a/packages/grafana-ui/src/components/Select/Select.tsx b/packages/grafana-ui/src/components/Select/Select.tsx index 81104c38bcb..b6219969017 100644 --- a/packages/grafana-ui/src/components/Select/Select.tsx +++ b/packages/grafana-ui/src/components/Select/Select.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { SelectableValue } from '@grafana/data'; import { SelectCommonProps, MultiSelectCommonProps, SelectAsyncProps } from './types'; import { SelectBase } from './SelectBase'; +import { SelectContainer, SelectContainerProps } from './SelectContainer'; export function Select(props: SelectCommonProps) { return ; @@ -31,3 +32,5 @@ export function AsyncMultiSelect(props: AsyncMultiSelectProps) { // @ts-ignore return ; } + +export { SelectContainer, SelectContainerProps }; diff --git a/packages/grafana-ui/src/components/Select/SelectContainer.tsx b/packages/grafana-ui/src/components/Select/SelectContainer.tsx index f322e6e34f2..e0792b21038 100644 --- a/packages/grafana-ui/src/components/Select/SelectContainer.tsx +++ b/packages/grafana-ui/src/components/Select/SelectContainer.tsx @@ -9,13 +9,13 @@ import { focusCss } from '../../themes/mixins'; import { components, ContainerProps as BaseContainerProps, GroupTypeBase } from 'react-select'; // isFocus prop is actually available, but its not in the types for the version we have. -export interface ContainerProps> +export interface SelectContainerProps> extends BaseContainerProps { isFocused: boolean; } export const SelectContainer = >( - props: ContainerProps + props: SelectContainerProps ) => { const { isDisabled, diff --git a/packages/grafana-ui/src/components/index.ts b/packages/grafana-ui/src/components/index.ts index c761d43f2b9..2d8ae40140f 100644 --- a/packages/grafana-ui/src/components/index.ts +++ b/packages/grafana-ui/src/components/index.ts @@ -201,6 +201,7 @@ export { selectOptionInTest } from './Select/test-utils'; export * from './Select/Select'; export { DropdownIndicator } from './Select/DropdownIndicator'; export { getSelectStyles } from './Select/getSelectStyles'; +export * from './Select/types'; export { HorizontalGroup, VerticalGroup, Container } from './Layout/Layout'; export { Badge, BadgeColor, BadgeProps } from './Badge/Badge'; diff --git a/packages/grafana-ui/src/utils/index.ts b/packages/grafana-ui/src/utils/index.ts index 52cbd388c46..cecdb086f2b 100644 --- a/packages/grafana-ui/src/utils/index.ts +++ b/packages/grafana-ui/src/utils/index.ts @@ -12,8 +12,12 @@ export { ansicolor } from 'ansicolor'; import * as DOMUtil from './dom'; // includes Element.closest polyfill export { DOMUtil }; -export { renderOrCallToRender } from './renderOrCallToRender'; + export { createLogger } from './logger'; export { attachDebugger } from './debug'; export * from './nodeGraph'; export { fuzzyMatch } from './fuzzy'; + +// React utils +import * as ReactUtils from './reactUtils'; +export { ReactUtils }; diff --git a/packages/grafana-ui/src/utils/children.ts b/packages/grafana-ui/src/utils/reactUtils.ts similarity index 50% rename from packages/grafana-ui/src/utils/children.ts rename to packages/grafana-ui/src/utils/reactUtils.ts index d2556ea23e1..33d9c8ed5a1 100644 --- a/packages/grafana-ui/src/utils/children.ts +++ b/packages/grafana-ui/src/utils/reactUtils.ts @@ -17,3 +17,24 @@ export function getChildId(children: ReactElement): string | undefined { return typeof inputId === 'string' ? inputId : undefined; } + +/** + * Given react node or function returns element accordingly + * + * @param itemToRender + * @param props props to be passed to the function if item provided as such + */ +export function renderOrCallToRender( + itemToRender: ((props?: TProps) => React.ReactNode) | React.ReactNode, + props?: TProps +): React.ReactNode { + if (React.isValidElement(itemToRender) || typeof itemToRender === 'string' || typeof itemToRender === 'number') { + return itemToRender; + } + + if (typeof itemToRender === 'function') { + return itemToRender(props); + } + + throw new Error(`${itemToRender} is not a React element nor a function that returns React element`); +} diff --git a/packages/grafana-ui/src/utils/renderOrCallToRender.ts b/packages/grafana-ui/src/utils/renderOrCallToRender.ts deleted file mode 100644 index b99d97dfda6..00000000000 --- a/packages/grafana-ui/src/utils/renderOrCallToRender.ts +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; - -/** - * Given react node or function returns element accordingly - * - * @param itemToRender - * @param props props to be passed to the function if item provided as such - */ -export function renderOrCallToRender( - itemToRender: ((props?: TProps) => React.ReactNode) | React.ReactNode, - props?: TProps -): React.ReactNode { - if (React.isValidElement(itemToRender) || typeof itemToRender === 'string' || typeof itemToRender === 'number') { - return itemToRender; - } - - if (typeof itemToRender === 'function') { - return itemToRender(props); - } - - throw new Error(`${itemToRender} is not a React element nor a function that returns React element`); -} diff --git a/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx b/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx index 84f6fcd322f..146b21f9e68 100644 --- a/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx +++ b/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx @@ -1,5 +1,5 @@ import React, { useCallback, useState } from 'react'; -import { Icon, renderOrCallToRender, stylesFactory, useTheme } from '@grafana/ui'; +import { Icon, ReactUtils, stylesFactory, useTheme } from '@grafana/ui'; import { GrafanaTheme } from '@grafana/data'; import { css, cx } from '@emotion/css'; import { useUpdateEffect } from 'react-use'; @@ -69,9 +69,9 @@ export const QueryOperationRow: React.FC = ({ }, }; - const titleElement = title && renderOrCallToRender(title, renderPropArgs); - const actionsElement = actions && renderOrCallToRender(actions, renderPropArgs); - const headerElementRendered = headerElement && renderOrCallToRender(headerElement, renderPropArgs); + const titleElement = title && ReactUtils.renderOrCallToRender(title, renderPropArgs); + const actionsElement = actions && ReactUtils.renderOrCallToRender(actions, renderPropArgs); + const headerElementRendered = headerElement && ReactUtils.renderOrCallToRender(headerElement, renderPropArgs); const rowHeader = (
diff --git a/public/app/plugins/datasource/cloudwatch/components/ui/EditorField.tsx b/public/app/plugins/datasource/cloudwatch/components/ui/EditorField.tsx index 98e1b8ccfb8..510e6095de8 100644 --- a/public/app/plugins/datasource/cloudwatch/components/ui/EditorField.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/ui/EditorField.tsx @@ -1,7 +1,6 @@ import { css } from '@emotion/css'; import { GrafanaTheme2 } from '@grafana/data'; -import { Field, Icon, PopoverContent, stylesFactory, Tooltip, useTheme2 } from '@grafana/ui'; -import { getChildId } from '@grafana/ui/src/utils/children'; +import { Field, Icon, PopoverContent, stylesFactory, Tooltip, useTheme2, ReactUtils } from '@grafana/ui'; import { Space } from 'app/plugins/datasource/grafana-azure-monitor-datasource/components/Space'; import React from 'react'; @@ -18,7 +17,7 @@ const EditorField: React.FC = (props) => { const theme = useTheme2(); const styles = getStyles(theme, props); - const childInputId = getChildId(children); + const childInputId = ReactUtils.getChildId(children); const labelEl = ( <> diff --git a/public/app/plugins/datasource/cloudwatch/components/ui/InlineSelect.tsx b/public/app/plugins/datasource/cloudwatch/components/ui/InlineSelect.tsx index efa201cbd02..91f66d10eed 100644 --- a/public/app/plugins/datasource/cloudwatch/components/ui/InlineSelect.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/ui/InlineSelect.tsx @@ -2,7 +2,7 @@ import { css, cx } from '@emotion/css'; import { GrafanaTheme2 } from '@grafana/data'; import { Select, stylesFactory, useTheme2 } from '@grafana/ui'; import { - ContainerProps, + SelectContainerProps, SelectContainer as BaseSelectContainer, } from '@grafana/ui/src/components/Select/SelectContainer'; import { SelectCommonProps } from '@grafana/ui/src/components/Select/types'; @@ -39,7 +39,7 @@ function InlineSelect({ label: labelProp, ...props }: InlineSelectProps) { export default InlineSelect; const SelectContainer = >( - props: ContainerProps + props: SelectContainerProps ) => { const { children } = props; @@ -54,7 +54,7 @@ const SelectContainer = >( - props: ContainerProps + props: SelectContainerProps ) => { const { className, children } = props; const theme = useTheme2();