diff --git a/changelogs/upcoming/7340.md b/changelogs/upcoming/7340.md new file mode 100644 index 00000000000..bb9c79f0676 --- /dev/null +++ b/changelogs/upcoming/7340.md @@ -0,0 +1,2 @@ +- Updated generic types of `EuiBasicTable`, `EuiInMemoryTable` and `EuiSearchBar.Query.execute` to add `extends object` constraint + - This change should have no impact on your applications since the updated types only affect properties that exclusively accept object values. diff --git a/src-docs/src/views/theme/color/_contrast_js.tsx b/src-docs/src/views/theme/color/_contrast_js.tsx index 2ff52a5a9c0..e2bcb001eb8 100644 --- a/src-docs/src/views/theme/color/_contrast_js.tsx +++ b/src-docs/src/views/theme/color/_contrast_js.tsx @@ -23,7 +23,7 @@ const textVariants = [...brandTextKeys, ...textColors]; type ColorSection = { color: keyof _EuiThemeColorsMode; colorValue?: string; - minimumContrast: string | number; + minimumContrast: number; showTextVariants: boolean; matchPanelColor?: boolean; hookName?: string; @@ -88,7 +88,7 @@ export const ColorSectionJS: FunctionComponent = ({ type ColorsContrastItem = { foreground: string; background: string; - minimumContrast: string | number; + minimumContrast: number; styleString?: string; }; diff --git a/src-docs/src/views/theme/color/_contrast_sass.tsx b/src-docs/src/views/theme/color/_contrast_sass.tsx index eacd2dfd1a7..cb3836195f0 100644 --- a/src-docs/src/views/theme/color/_contrast_sass.tsx +++ b/src-docs/src/views/theme/color/_contrast_sass.tsx @@ -57,7 +57,7 @@ import { getContrastRatings } from './_contrast_utilities'; type ColorSection = { color: string; - minimumContrast: string | number; + minimumContrast: number; showTextVariants: boolean; matchPanelColor?: boolean; }; @@ -114,7 +114,7 @@ export const ColorSectionSass: FunctionComponent = ({ type ColorsContrastItem = { foreground: string; background: string; - minimumContrast: string | number; + minimumContrast: number; }; const ColorsContrastItem: FunctionComponent = ({ diff --git a/src/components/basic_table/action_types.ts b/src/components/basic_table/action_types.ts index 6121c708f5f..cb8d6981cbf 100644 --- a/src/components/basic_table/action_types.ts +++ b/src/components/basic_table/action_types.ts @@ -12,11 +12,11 @@ import { EuiButtonIconProps } from '../button/button_icon/button_icon'; import { EuiButtonEmptyProps } from '../button/button_empty'; import { ExclusiveUnion } from '../common'; -type IconFunction = (item: T) => EuiIconType; +type IconFunction = (item: T) => EuiIconType; type ButtonColor = EuiButtonIconProps['color'] | EuiButtonEmptyProps['color']; type EuiButtonIconColorFunction = (item: T) => ButtonColor; -export interface DefaultItemActionBase { +export interface DefaultItemActionBase { /** * The display name of the action (will render as visible text if rendered within a collapsed menu) */ @@ -43,7 +43,7 @@ export interface DefaultItemActionBase { 'data-test-subj'?: string | ((item: T) => string); } -export interface DefaultItemEmptyButtonAction +export interface DefaultItemEmptyButtonAction extends DefaultItemActionBase { /** * The type of action @@ -52,7 +52,7 @@ export interface DefaultItemEmptyButtonAction color?: EuiButtonEmptyProps['color'] | EuiButtonIconColorFunction; } -export interface DefaultItemIconButtonAction +export interface DefaultItemIconButtonAction extends DefaultItemActionBase { type: 'icon'; /** @@ -65,7 +65,7 @@ export interface DefaultItemIconButtonAction color?: EuiButtonIconProps['color'] | EuiButtonIconColorFunction; } -export type DefaultItemAction = ExclusiveUnion< +export type DefaultItemAction = ExclusiveUnion< DefaultItemEmptyButtonAction, DefaultItemIconButtonAction >; @@ -86,9 +86,11 @@ export interface CustomItemAction { isPrimary?: boolean; } -export type Action = DefaultItemAction | CustomItemAction; +export type Action = + | DefaultItemAction + | CustomItemAction; -export const isCustomItemAction = ( +export const isCustomItemAction = ( action: DefaultItemAction | CustomItemAction ): action is CustomItemAction => { return action.hasOwnProperty('render'); diff --git a/src/components/basic_table/basic_table.tsx b/src/components/basic_table/basic_table.tsx index a423c949159..bb6aa3034fc 100644 --- a/src/components/basic_table/basic_table.tsx +++ b/src/components/basic_table/basic_table.tsx @@ -139,7 +139,7 @@ function getRowProps(item: T, rowProps: RowPropsCallback) { return {}; } -function getCellProps( +function getCellProps( item: T, column: EuiBasicTableColumn, cellProps: CellPropsCallback @@ -154,7 +154,7 @@ function getCellProps( return {}; } -function getColumnFooter( +function getColumnFooter( column: EuiBasicTableColumn, { items, pagination }: EuiTableFooterProps ) { @@ -169,7 +169,7 @@ function getColumnFooter( return undefined; } -export type EuiBasicTableColumn = +export type EuiBasicTableColumn = | EuiTableFieldDataColumnType | EuiTableComputedColumnType | EuiTableActionsColumnType; @@ -201,10 +201,14 @@ export interface CriteriaWithPagination extends Criteria { }; } -type CellPropsCallback = (item: T, column: EuiBasicTableColumn) => object; +type CellPropsCallback = ( + item: T, + column: EuiBasicTableColumn +) => object; type RowPropsCallback = (item: T) => object; -interface BasicTableProps extends Omit { +interface BasicTableProps + extends Omit { /** * Describes how to extract a unique ID from each item, used for selections & expanded rows */ @@ -285,7 +289,7 @@ interface BasicTableProps extends Omit { textOnly?: boolean; } -type BasicTableWithPaginationProps = Omit< +type BasicTableWithPaginationProps = Omit< BasicTableProps, 'pagination' | 'onChange' > & { @@ -293,7 +297,7 @@ type BasicTableWithPaginationProps = Omit< onChange?: (criteria: CriteriaWithPagination) => void; }; -export type EuiBasicTableProps = CommonProps & +export type EuiBasicTableProps = CommonProps & Omit, 'onChange'> & (BasicTableProps | BasicTableWithPaginationProps); @@ -310,13 +314,13 @@ interface SortOptions { readOnly?: boolean; } -function hasPagination( +function hasPagination( x: EuiBasicTableProps ): x is BasicTableWithPaginationProps { return x.hasOwnProperty('pagination') && !!x.pagination; } -export class EuiBasicTable extends Component< +export class EuiBasicTable extends Component< EuiBasicTableProps, State > { @@ -331,7 +335,7 @@ export class EuiBasicTable extends Component< ), }; - static getDerivedStateFromProps( + static getDerivedStateFromProps( nextProps: EuiBasicTableProps, prevState: State ) { @@ -630,9 +634,9 @@ export class EuiBasicTable extends Component< items.push({ name: column.name, - key: `_data_s_${ + key: `_data_s_${String( (column as EuiTableFieldDataColumnType).field - }_${index}`, + )}_${index}`, onSort: this.resolveColumnOnSort(column), isSorted: !!sortDirection, isSortAscending: sortDirection @@ -854,11 +858,11 @@ export class EuiBasicTable extends Component< } headers.push( @@ -897,7 +901,7 @@ export class EuiBasicTable extends Component< if (footer) { footers.push( {footer} @@ -1219,7 +1223,7 @@ export class EuiBasicTable extends Component< ) { const { field, render, dataType } = column; - const key = `_data_column_${field}_${itemId}_${columnIndex}`; + const key = `_data_column_${String(field)}_${itemId}_${columnIndex}`; const contentRenderer = render || this.getRendererForDataType(dataType); const value = get(item, field as string); const content = contentRenderer(value, item); diff --git a/src/components/basic_table/collapsed_item_actions.tsx b/src/components/basic_table/collapsed_item_actions.tsx index 580e21d6a65..69856662ee7 100644 --- a/src/components/basic_table/collapsed_item_actions.tsx +++ b/src/components/basic_table/collapsed_item_actions.tsx @@ -29,7 +29,7 @@ import { } from './action_types'; import { ItemIdResolved } from './table_types'; -export interface CollapsedItemActionsProps { +export interface CollapsedItemActionsProps { actions: Array>; item: T; itemId: ItemIdResolved; diff --git a/src/components/basic_table/default_item_action.tsx b/src/components/basic_table/default_item_action.tsx index 7b71419502a..667da0589d7 100644 --- a/src/components/basic_table/default_item_action.tsx +++ b/src/components/basic_table/default_item_action.tsx @@ -24,14 +24,14 @@ import { callWithItemIfFunction, } from './action_types'; -export interface DefaultItemActionProps { +export interface DefaultItemActionProps { action: Action; enabled: boolean; item: T; className?: string; } -export const DefaultItemAction = ({ +export const DefaultItemAction = ({ action, enabled, item, diff --git a/src/components/basic_table/expanded_item_actions.tsx b/src/components/basic_table/expanded_item_actions.tsx index 677f3db8bac..5ec267ecc83 100644 --- a/src/components/basic_table/expanded_item_actions.tsx +++ b/src/components/basic_table/expanded_item_actions.tsx @@ -18,7 +18,7 @@ import { } from './action_types'; import { ItemIdResolved } from './table_types'; -export interface ExpandedItemActionsProps { +export interface ExpandedItemActionsProps { actions: Array>; itemId: ItemIdResolved; item: T; diff --git a/src/components/basic_table/in_memory_table.tsx b/src/components/basic_table/in_memory_table.tsx index e146bcfe704..833cb8e1de8 100644 --- a/src/components/basic_table/in_memory_table.tsx +++ b/src/components/basic_table/in_memory_table.tsx @@ -47,7 +47,7 @@ interface onChangeArgument { error: Error | null; } -function isEuiSearchBarProps( +function isEuiSearchBarProps( x: EuiInMemoryTableProps['search'] ): x is EuiSearchBarProps { return typeof x !== 'boolean'; @@ -71,7 +71,7 @@ interface SortingOptions { type Sorting = boolean | SortingOptions; -type InMemoryTableProps = Omit< +type InMemoryTableProps = Omit< EuiBasicTableProps, 'pagination' | 'sorting' | 'noItemsMessage' | 'onChange' > & { @@ -130,7 +130,7 @@ type InMemoryTableProps = Omit< childrenBetween?: ReactNode; }; -type InMemoryTablePropsWithPagination = Omit< +type InMemoryTablePropsWithPagination = Omit< InMemoryTableProps, 'pagination' | 'onTableChange' > & { @@ -138,10 +138,10 @@ type InMemoryTablePropsWithPagination = Omit< onTableChange?: (nextValues: CriteriaWithPagination) => void; }; -export type EuiInMemoryTableProps = CommonProps & +export type EuiInMemoryTableProps = CommonProps & (InMemoryTableProps | InMemoryTablePropsWithPagination); -interface State { +interface State { prevProps: { items: T[]; sortName: ReactNode; @@ -230,7 +230,7 @@ const getInitialPagination = ( }; }; -function findColumnByProp( +function findColumnByProp( columns: Array>, prop: 'field' | 'name', value: string | ReactNode @@ -247,7 +247,7 @@ function findColumnByProp( } } -function findColumnByFieldOrName( +function findColumnByFieldOrName( columns: Array>, value: string | ReactNode ) { @@ -260,7 +260,7 @@ function findColumnByFieldOrName( return column; } -function getInitialSorting( +function getInitialSorting( columns: Array>, sorting: Sorting | undefined ) { @@ -292,7 +292,7 @@ function getInitialSorting( }; } -export class EuiInMemoryTable extends Component< +export class EuiInMemoryTable extends Component< EuiInMemoryTableProps, State > { @@ -305,7 +305,7 @@ export class EuiInMemoryTable extends Component< }; tableRef: React.RefObject; - static getDerivedStateFromProps( + static getDerivedStateFromProps( nextProps: EuiInMemoryTableProps, prevState: State ) { diff --git a/src/components/basic_table/table_types.ts b/src/components/basic_table/table_types.ts index 78aa222094f..60856e1e2ee 100644 --- a/src/components/basic_table/table_types.ts +++ b/src/components/basic_table/table_types.ts @@ -132,7 +132,7 @@ export interface EuiTableComputedColumnType readOnly?: boolean; } -export interface EuiTableActionsColumnType { +export interface EuiTableActionsColumnType { /** * An array of one of the objects: #DefaultItemAction or #CustomItemAction */ diff --git a/src/components/common.ts b/src/components/common.ts index 351b03a7979..2f09a052349 100644 --- a/src/components/common.ts +++ b/src/components/common.ts @@ -46,7 +46,7 @@ export type OneOf = Omit & /** * Wraps Object.keys with proper typescript definition of the resulting array */ -export function keysOf(obj: T): K[] { +export function keysOf(obj: T): K[] { return Object.keys(obj) as K[]; } diff --git a/src/components/markdown_editor/markdown_editor.tsx b/src/components/markdown_editor/markdown_editor.tsx index b7298ff9989..65e89b77f51 100644 --- a/src/components/markdown_editor/markdown_editor.tsx +++ b/src/components/markdown_editor/markdown_editor.tsx @@ -377,27 +377,31 @@ export const EuiMarkdownEditor = forwardRef< }, [setEditorToolbarHeight]); useEffect(() => { - if (isPreviewing && autoExpandPreview && height !== 'full') { - if (previewRef.current!.scrollHeight > currentHeight) { - // scrollHeight does not include the border or margin - // so we ask for the computed value for those, - // which is always in pixels because getComputedValue - // returns the resolved values - const elementComputedStyle = window.getComputedStyle( - previewRef.current! - ); - const borderWidth = - parseFloat(elementComputedStyle.borderTopWidth) + - parseFloat(elementComputedStyle.borderBottomWidth); - const marginWidth = - parseFloat(elementComputedStyle.marginTop) + - parseFloat(elementComputedStyle.marginBottom); - - // then add an extra pixel for safety and because the scrollHeight value is rounded - const extraHeight = borderWidth + marginWidth + 1; - - setCurrentHeight(previewRef.current!.scrollHeight + extraHeight); - } + if (height === 'full' || currentHeight === 'full') return; + + if ( + isPreviewing && + autoExpandPreview && + previewRef.current!.scrollHeight > currentHeight + ) { + // scrollHeight does not include the border or margin + // so we ask for the computed value for those, + // which is always in pixels because getComputedValue + // returns the resolved values + const elementComputedStyle = window.getComputedStyle( + previewRef.current! + ); + const borderWidth = + parseFloat(elementComputedStyle.borderTopWidth) + + parseFloat(elementComputedStyle.borderBottomWidth); + const marginWidth = + parseFloat(elementComputedStyle.marginTop) + + parseFloat(elementComputedStyle.marginBottom); + + // then add an extra pixel for safety and because the scrollHeight value is rounded + const extraHeight = borderWidth + marginWidth + 1; + + setCurrentHeight(previewRef.current!.scrollHeight + extraHeight); } }, [currentHeight, isPreviewing, height, autoExpandPreview]); diff --git a/src/components/page_template/bottom_bar/page_bottom_bar.tsx b/src/components/page_template/bottom_bar/page_bottom_bar.tsx index f1db5a9947d..3d2c2e359b2 100644 --- a/src/components/page_template/bottom_bar/page_bottom_bar.tsx +++ b/src/components/page_template/bottom_bar/page_bottom_bar.tsx @@ -58,8 +58,8 @@ export const _EuiPageBottomBar: FunctionComponent<_EuiPageBottomBarProps> = ({ overflow: hidden; flex-shrink: 0; `} - // Using unknown here because of the possible conflict with overriding props and position `sticky` - {...(rest as unknown)} + // Using object here because of the possible conflict with overriding props and position `sticky` + {...(rest as object)} > {/* Wrapping the contents with EuiPageContentBody allows us to match the restrictWidth to keep the contents aligned */} diff --git a/src/components/search_bar/query/date_format.ts b/src/components/search_bar/query/date_format.ts index e65954c163e..add0c6f3b41 100644 --- a/src/components/search_bar/query/date_format.ts +++ b/src/components/search_bar/query/date_format.ts @@ -37,7 +37,7 @@ interface GranularitiesType { YEAR: GranularityType; } -export const Granularity: GranularitiesType = Object.freeze({ +export const Granularity = Object.freeze({ DAY: { es: 'd', js: 'day', diff --git a/src/components/search_bar/query/execute_ast.ts b/src/components/search_bar/query/execute_ast.ts index ea078d2e863..bcd27239a0a 100644 --- a/src/components/search_bar/query/execute_ast.ts +++ b/src/components/search_bar/query/execute_ast.ts @@ -50,7 +50,7 @@ interface Explain { operator?: any; // It's not really worth specifying this at the moment } -const defaultIsClauseMatcher = ( +const defaultIsClauseMatcher = ( item: T, clause: IsClause, explain?: Explain[] @@ -65,7 +65,7 @@ const defaultIsClauseMatcher = ( return hit; }; -const fieldClauseMatcher = ( +const fieldClauseMatcher = ( item: T, field: string, clauses: FieldClause[] = [], @@ -104,7 +104,7 @@ const extractStringFieldsFromItem = (item: any) => { }, [] as string[]); }; -const termClauseMatcher = ( +const termClauseMatcher = ( item: T, fields: string[] | undefined, clauses: TermClause[] = [], @@ -215,7 +215,7 @@ interface Options { explain?: boolean; } -export function executeAst( +export function executeAst( ast: _AST, items: T[], options: Options = {} diff --git a/src/components/search_bar/query/query.ts b/src/components/search_bar/query/query.ts index 3d7c78da94c..e376e8732d8 100644 --- a/src/components/search_bar/query/query.ts +++ b/src/components/search_bar/query/query.ts @@ -171,7 +171,11 @@ export class Query { * information about why the objects matched the query (default to `false`, mainly/only useful for * debugging) */ - static execute(query: string | Query, items: T[], options = {}): T[] { + static execute( + query: string | Query, + items: T[], + options = {} + ): T[] { const q = isString(query) ? Query.parse(query) : query; return executeAst(q.ast, items, options); } diff --git a/src/components/selectable/selectable_list/selectable_list_item.tsx b/src/components/selectable/selectable_list/selectable_list_item.tsx index a603c32bc75..cd41811fee8 100644 --- a/src/components/selectable/selectable_list/selectable_list_item.tsx +++ b/src/components/selectable/selectable_list/selectable_list_item.tsx @@ -300,7 +300,7 @@ export class EuiSelectableListItem extends Component {...defaultOnFocusBadgeProps} /> ); - } else if (!!onFocusBadge && onFocusBadge !== false) { + } else if (typeof onFocusBadge !== 'boolean' && !!onFocusBadge) { const { children, className, ...restBadgeProps } = onFocusBadge; onFocusBadgeNode = ( extends Component> { items={renderedItems} key={id} depth={depth} - renderItem={renderItem} + renderItem={ + renderItem as PropsOf['renderItem'] + } truncate={truncate} childrenOnly={childrenOnly} {...rest} diff --git a/src/components/table/table_row_cell.tsx b/src/components/table/table_row_cell.tsx index 546fbd93d81..3188d217828 100644 --- a/src/components/table/table_row_cell.tsx +++ b/src/components/table/table_row_cell.tsx @@ -183,12 +183,13 @@ export const EuiTableRowCell: FunctionComponent = ({ if (textOnly === true) { modifiedChildren = {children}; } else if (React.isValidElement(children)) { - modifiedChildren = React.Children.map( - children, - (child: ReactElement) => - React.cloneElement(child, { - className: classNames(child.props.className, childClasses), - }) + modifiedChildren = React.Children.map(children, (child: ReactElement) => + React.cloneElement(child, { + className: classNames( + (child.props as CommonProps).className, + childClasses + ), + }) ); } if (isObject(truncateText) && truncateText.lines) { diff --git a/src/components/tree_view/tree_view.tsx b/src/components/tree_view/tree_view.tsx index 35eff6b403d..772e121984d 100644 --- a/src/components/tree_view/tree_view.tsx +++ b/src/components/tree_view/tree_view.tsx @@ -119,24 +119,32 @@ export class EuiTreeView extends Component { static contextType = EuiTreeViewContext; declare context: ContextType; - isNested: boolean = !!this.context; - - state: EuiTreeViewState = { - openItems: this.props.expandByDefault - ? this.props.items - .map(({ id, children }) => - children ? id : (null as unknown as string) - ) - .filter((x) => x != null) - : this.props.items - .map(({ id, children, isExpanded }) => - children && isExpanded ? id : (null as unknown as string) - ) - .filter((x) => x != null), - activeItem: '', - treeID: getTreeId(this.props.id, this.context, this.treeIdGenerator), - expandChildNodes: this.props.expandByDefault || false, - }; + isNested: boolean; + + constructor( + props: EuiTreeViewProps, + context: ContextType + ) { + super(props, context); + + this.isNested = !!this.context; + this.state = { + openItems: this.props.expandByDefault + ? this.props.items + .map(({ id, children }) => + children ? id : (null as unknown as string) + ) + .filter((x) => x != null) + : this.props.items + .map(({ id, children, isExpanded }) => + children && isExpanded ? id : (null as unknown as string) + ) + .filter((x) => x != null), + activeItem: '', + treeID: getTreeId(this.props.id, context, this.treeIdGenerator), + expandChildNodes: this.props.expandByDefault || false, + }; + } componentDidUpdate(prevProps: EuiTreeViewProps) { if (this.props.id !== prevProps.id) { diff --git a/src/services/sort/comparators.ts b/src/services/sort/comparators.ts index 122eee850b3..2ea484ac58f 100644 --- a/src/services/sort/comparators.ts +++ b/src/services/sort/comparators.ts @@ -68,7 +68,10 @@ export const Comparators = Object.freeze({ }; }, - property(prop: string, comparator?: Comparator): Comparator { + property( + prop: string, + comparator?: Comparator + ): Comparator { return this.value((value) => get(value, prop), comparator); }, }); diff --git a/src/utils/prop_types/is.ts b/src/utils/prop_types/is.ts index 520307e436b..f473b2c81e8 100644 --- a/src/utils/prop_types/is.ts +++ b/src/utils/prop_types/is.ts @@ -13,7 +13,7 @@ export const is = (expectedValue: any) => { const compName = componentName || 'ANONYMOUS'; const value = props[propName]; if (value !== expectedValue) { - return new Error(`[${propName}] property in [${compName}] component is expected to equal [${expectedValue}] but + return new Error(`[${propName.toString()}] property in [${compName}] component is expected to equal [${expectedValue}] but [${value}] was provided instead.`); } return null; @@ -28,7 +28,7 @@ export const is = (expectedValue: any) => { const value = props[propName]; if (isNil(value)) { return new Error( - `[${propName}] property in [${compName}] component is required but seems to be missing` + `[${propName.toString()}] property in [${compName}] component is required but seems to be missing` ); } return validator(props, propName, componentName);