Merge pull request #8126 from plotly/cam/8047/relayout-update-types · plotly/plotly.js@8dc3846 · GitHub
Skip to content

Commit 8dc3846

Browse files
authored
Merge pull request #8126 from plotly/cam/8047/relayout-update-types
fix(types): Accept attribute paths in plotly_relayout, relayout, restyle, and update
2 parents 641db27 + b0f48b2 commit 8dc3846

10 files changed

Lines changed: 206 additions & 24 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 10 additions & 0 deletions

‎draftlogs/8126_fix.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- Update TypeScript types so that `Plotly.relayout`, `Plotly.restyle`, `Plotly.update`, and the `plotly_relayout` event accept attribute paths such as `'xaxis.autorange'` [[#8126](https://github.com/plotly/plotly.js/pull/8126)]
2+
- Add the `LayoutUpdate` and `DataUpdate` types for these update objects
3+
- Add the `(root, attribute, value)` call form to the types of `Plotly.relayout` and `Plotly.restyle`

‎lib/index.d.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ export type * from '../src/types/generated/schema';
5555

5656
export type {
5757
ButtonClickEvent,
58+
DataUpdate,
5859
Icon,
60+
LayoutUpdate,
5961
ModeBarButton,
6062
ModeBarButtonAny,
6163
ModeBarDefaultButtons,

‎package.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
"test-mock": "node tasks/test_mock.mjs",
6666
"test-image": "node test/image/compare_pixels_test.mjs",
6767
"test-export": "node test/image/export_test.js",
68+
"test-types": "tsc --noEmit -p test/types",
6869
"test-syntax": "tsx tasks/test_syntax.js && npm run find-strings -- --no-output",
6970
"test-bundle": "node tasks/test_bundle.js",
7071
"test-plain-obj": "node tasks/test_plain_obj.mjs",

‎src/types/core/api.d.ts‎

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import type { AnimationOpts, Data, Frame, Layout } from '../generated/schema';
66
import type { Config, DownloadImgopts, ToImgopts } from './config';
77
import type { PlotlyHTMLElement } from './events';
8-
import type { Icon, Template } from './layout';
8+
import type { DataUpdate, Icon, LayoutUpdate, Template } from './layout';
99

1010
// ---------------------------------------------------------------------------
1111
// Roots and request shapes
@@ -208,19 +208,57 @@ export function newPlot(
208208
figure: PlotlyDataLayoutConfig
209209
): Promise<PlotlyHTMLElement>;
210210

211-
/** Update layout properties on an existing plot. */
212-
export function relayout(root: Root, layout: Partial<Layout>): Promise<PlotlyHTMLElement>;
211+
/**
212+
* Update layout properties on an existing plot with an update object.
213+
*
214+
* @param layout - Update object whose keys are layout properties or attribute paths
215+
*/
216+
export function relayout(root: Root, layout: LayoutUpdate): Promise<PlotlyHTMLElement>;
217+
/**
218+
* Update one layout property on an existing plot with an attribute path.
219+
*
220+
* @param astr - Attribute path, for example `'xaxis.autorange'`
221+
* @param val - New value of the attribute
222+
*/
223+
export function relayout(root: Root, astr: string, val: any): Promise<PlotlyHTMLElement>;
224+
/**
225+
* Update layout properties on an existing plot with either call form.
226+
*
227+
* This signature lets a wrapper read the parameter types with `Parameters<typeof relayout>`.
228+
* It does not check that the value matches the form.
229+
*/
230+
export function relayout(root: Root, astr: string | LayoutUpdate, val?: any): Promise<PlotlyHTMLElement>;
213231
/** Re-render the plot at `root` from its current data/layout. */
214232
export function redraw(root: Root): Promise<PlotlyHTMLElement>;
215233
/** Remove a plot and its event listeners from the DOM. */
216234
export function purge(root: Root): void;
217235
/**
218-
* Update trace properties (style) on the existing plot.
236+
* Update trace properties (style) on the existing plot with an update object.
219237
*
220-
* @param aobj - Update object whose keys are attribute paths
238+
* @param aobj - Update object whose keys are trace properties or attribute paths
221239
* @param traces - Trace index/indices to update (defaults to all)
222240
*/
223-
export function restyle(root: Root, aobj: Data, traces?: number[] | number): Promise<PlotlyHTMLElement>;
241+
export function restyle(root: Root, aobj: DataUpdate, traces?: number[] | number): Promise<PlotlyHTMLElement>;
242+
/**
243+
* Update one trace property on the existing plot with an attribute path.
244+
*
245+
* @param astr - Attribute path, for example `'marker.color'`
246+
* @param val - New value of the attribute, or an array with one value for each trace
247+
* @param traces - Trace index/indices to update (defaults to all)
248+
*/
249+
export function restyle(root: Root, astr: string, val: any, traces?: number[] | number): Promise<PlotlyHTMLElement>;
250+
/**
251+
* Update trace properties (style) on the existing plot with either call form.
252+
*
253+
* This signature lets a wrapper read the parameter types with `Parameters<typeof restyle>`.
254+
* It does not check that the arguments match the form.
255+
*/
256+
export function restyle(
257+
root: Root,
258+
astr: string | DataUpdate,
259+
val?: any,
260+
traces?: number[] | number
261+
): Promise<PlotlyHTMLElement>;
224262

225263
/**
226264
* Update both trace and layout properties in a single call.
@@ -231,8 +269,8 @@ export function restyle(root: Root, aobj: Data, traces?: number[] | number): Pro
231269
*/
232270
export function update(
233271
root: Root,
234-
traceUpdate: Data,
235-
layoutUpdate: Partial<Layout>,
272+
traceUpdate: DataUpdate,
273+
layoutUpdate: LayoutUpdate,
236274
traces?: number[] | number
237275
): Promise<PlotlyHTMLElement>;
238276

‎src/types/core/events.d.ts‎

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import type {
1717
} from '../generated/schema';
1818
import type { Datum } from '../lib/common';
1919
import type { Config } from './config';
20+
import type { LayoutUpdate } from './layout';
2021

2122
// ---------------------------------------------------------------------------
2223
// Point / datum types in events
@@ -149,23 +150,12 @@ export interface PlotRestyleEventUpdate {
149150
export type PlotRestyleEvent = [PlotRestyleEventUpdate, number[]];
150151

151152
/**
152-
* Payload for `plotly_relayout`. Carries a `Partial<Layout>` plus a few
153-
* common bracketed axis-range/autorange keys that flatten nested updates.
153+
* Payload for `plotly_relayout`. The keys are layout properties or attribute
154+
* paths of the changed values, for example `'xaxis.range[0]'`. A value behind an
155+
* attribute path has the type `any`, because a range value can be a number or a
156+
* date string.
154157
*/
155-
export interface PlotRelayoutEvent extends Partial<Layout> {
156-
/** New x-axis range minimum, when the user changed the range. */
157-
'xaxis.range[0]'?: number;
158-
/** New x-axis range maximum, when the user changed the range. */
159-
'xaxis.range[1]'?: number;
160-
/** New y-axis range minimum, when the user changed the range. */
161-
'yaxis.range[0]'?: number;
162-
/** New y-axis range maximum, when the user changed the range. */
163-
'yaxis.range[1]'?: number;
164-
/** True when the user toggled x-axis autoranging on. */
165-
'xaxis.autorange'?: boolean;
166-
/** True when the user toggled y-axis autoranging on. */
167-
'yaxis.autorange'?: boolean;
168-
}
158+
export type PlotRelayoutEvent = LayoutUpdate;
169159

170160
// ---------------------------------------------------------------------------
171161
// 3D scene / annotation / animation / legend events

‎src/types/core/layout.d.ts‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,30 @@ export interface Template {
157157
/** Template layout defaults. */
158158
layout?: Partial<Layout> | undefined;
159159
}
160+
161+
// ---------------------------------------------------------------------------
162+
// Update objects (relayout / restyle / update)
163+
// ---------------------------------------------------------------------------
164+
165+
/** Keys that hold an attribute path such as `'xaxis.range[0]'` or `'annotations[0].text'`. */
166+
interface AttributePathKeys {
167+
[key: `${string}.${string}`]: any;
168+
[key: `${string}[${string}`]: any;
169+
}
170+
171+
/**
172+
* Layout update for `Plotly.relayout` and `Plotly.update`.
173+
*
174+
* A key is a layout property or an attribute path, for example `'xaxis.range[0]'` or `'annotations[0].text'`.
175+
* An attribute path changes one property and keeps its siblings. A nested object replaces the whole container.
176+
* A value behind an attribute path has the type `any`.
177+
*/
178+
export type LayoutUpdate = Partial<Layout> & AttributePathKeys;
179+
180+
/**
181+
* Trace update for `Plotly.restyle` and `Plotly.update`.
182+
*
183+
* A key is a trace property or an attribute path, for example `'marker.color'`.
184+
* A value behind an attribute path has the type `any`.
185+
*/
186+
export type DataUpdate = Partial<Data> & AttributePathKeys;

‎test/types/relayout_event.ts‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* Consumer-side checks for the `plotly_relayout` event payload.
3+
*
4+
* Nothing here runs. See `update_api.ts`.
5+
*/
6+
7+
import type { PlotRelayoutEvent } from '../../lib/index';
8+
9+
declare const event: PlotRelayoutEvent;
10+
11+
// A range value can be a number or a date string
12+
const numberRangeStart: number | undefined = event['xaxis.range[0]'];
13+
const dateRangeStart: string | undefined = event['xaxis.range[0]'];
14+
15+
// Any other attribute path is readable
16+
const secondAxisStart = event['xaxis2.range[0]'];
17+
const shapeStart = event['shapes[0].x0'];
18+
19+
// Layout properties are still typed
20+
const autosize: boolean | undefined = event.autosize;
21+
22+
// @ts-expect-error unknown top-level key
23+
const typo = event.titl;

‎test/types/tsconfig.json‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"extends": "../../tsconfig.json",
3+
"include": ["./**/*.ts"],
4+
"exclude": []
5+
}

‎test/types/update_api.ts‎

Lines changed: 83 additions & 0 deletions

0 commit comments

Comments
 (0)