diff --git a/packages/charts/src/chart_types/xy_chart/specs/axis.tsx b/packages/charts/src/chart_types/xy_chart/specs/axis.tsx index d80e8c469d0..b95e4467b9e 100644 --- a/packages/charts/src/chart_types/xy_chart/specs/axis.tsx +++ b/packages/charts/src/chart_types/xy_chart/specs/axis.tsx @@ -10,11 +10,11 @@ import React from 'react'; import { ChartType } from '../..'; import { SpecType } from '../../../specs/constants'; -import { specComponentFactory, getConnect } from '../../../state/spec_factory'; +import { specComponentFactory, getConnect, DefaultFactorProps } from '../../../state/spec_factory'; import { Position } from '../../../utils/common'; import { AxisSpec, DEFAULT_GLOBAL_ID } from '../utils/specs'; -const defaultProps = { +const defaultProps: DefaultProps = { chartType: ChartType.XYAxis, specType: SpecType.Axis, groupId: DEFAULT_GLOBAL_ID, @@ -22,14 +22,18 @@ const defaultProps = { showOverlappingTicks: false, showOverlappingLabels: false, position: Position.Left, + domain: { + min: NaN, + max: NaN, + }, }; type SpecRequired = Pick; type SpecOptionals = Partial>; +type DefaultKeys = 'groupId' | 'hide' | 'showOverlappingTicks' | 'showOverlappingLabels' | 'position' | 'domain'; +type DefaultProps = DefaultFactorProps; /** @public */ export const Axis: React.FunctionComponent = getConnect()( - specComponentFactory( - defaultProps, - ), + specComponentFactory(defaultProps, ['domain']), ); diff --git a/packages/charts/src/state/spec_factory.ts b/packages/charts/src/state/spec_factory.ts index b65f89e2417..d70d1ad8c36 100644 --- a/packages/charts/src/state/spec_factory.ts +++ b/packages/charts/src/state/spec_factory.ts @@ -11,23 +11,46 @@ import { connect } from 'react-redux'; import { Dispatch, bindActionCreators } from 'redux'; import { Spec } from '../specs'; -import { upsertSpec, removeSpec } from './actions/specs'; +import { isObject } from '../utils/common'; +import { upsertSpec as upsertSpecAction, removeSpec as removeSpecAction } from './actions/specs'; /** @internal */ export interface DispatchProps { - upsertSpec: (spec: Spec) => void; - removeSpec: (id: string) => void; + upsertSpec: typeof upsertSpecAction; + removeSpec: typeof removeSpecAction; } -/** @internal */ -export function specComponentFactory( - defaultProps: Pick, +/** + * Get default factory props type + * @internal */ +export type DefaultFactorProps = Pick; + +/** + * Spec instance factory + * @param defaultProps + * @param deepDefaults objects to do a shallow spread + * @returns spec instance Component + * @internal + */ +export function specComponentFactory( + defaultProps: DefaultFactorProps, + deepDefaults: (keyof DefaultFactorProps)[] = [], ) { /* eslint-disable no-shadow, react-hooks/exhaustive-deps, unicorn/consistent-function-scoping */ - const SpecInstance = (props: U & DispatchProps) => { + const SpecInstance = (props: S & DispatchProps) => { const { removeSpec, upsertSpec, ...SpecInstance } = props; + useEffect(() => { - upsertSpec(SpecInstance); + upsertSpec({ + ...SpecInstance, + ...deepDefaults.reduce((acc, k) => { + const key = k as keyof typeof SpecInstance; + if (SpecInstance && isObject(SpecInstance[key])) { + acc[key] = { ...defaultProps, ...props[key] } as any; + } + return acc; + }, {} as any), + }); }); useEffect( () => () => { @@ -45,8 +68,8 @@ export function specComponentFactory( const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => bindActionCreators( { - upsertSpec, - removeSpec, + upsertSpec: upsertSpecAction, + removeSpec: removeSpecAction, }, dispatch, ); diff --git a/packages/charts/src/utils/common.tsx b/packages/charts/src/utils/common.tsx index 4557decfca6..53e361ad45a 100644 --- a/packages/charts/src/utils/common.tsx +++ b/packages/charts/src/utils/common.tsx @@ -623,3 +623,8 @@ export function range(start: number, stop: number, step: number): Array } return output; } + +/** @internal */ +export function isObject(o: unknown): o is Record { + return Boolean(o) && typeof o === 'object' && !Array.isArray(o); +} diff --git a/storybook/stories/bar/32_scale_to_extent.story.tsx b/storybook/stories/bar/32_scale_to_extent.story.tsx index 243966fad84..e1ee327450d 100644 --- a/storybook/stories/bar/32_scale_to_extent.story.tsx +++ b/storybook/stories/bar/32_scale_to_extent.story.tsx @@ -9,7 +9,7 @@ import { boolean, number, select } from '@storybook/addon-knobs'; import React from 'react'; -import { Axis, Chart, DomainPaddingUnit, Position, ScaleType, Settings } from '@elastic/charts'; +import { Axis, Chart, DomainPaddingUnit, Position, ScaleType, Settings, YDomainRange } from '@elastic/charts'; import { computeContinuousDataDomain } from '@elastic/charts/src/utils/domain'; import { useBaseTheme } from '../../use_base_theme'; @@ -67,10 +67,9 @@ export const Example = () => { default: data = mixed; } - const customDomain = { fit, padding, paddingUnit, constrainPadding, nice, min: NaN, max: NaN }; if (shouldLogDomains) { - logDomains(data, customDomain); + logDomains(data, { fit, padding, paddingUnit, constrainPadding }); } return ( @@ -79,7 +78,7 @@ export const Example = () => { Number(d).toFixed(2)}