Skip to content

Commit c53caa4

Browse files
committed
Allow replacing entire components.
1 parent aefb5c2 commit c53caa4

File tree

2 files changed

+62
-36
lines changed

2 files changed

+62
-36
lines changed

chartlets.js/src/lib/actions/helpers/applyStateChangeRequests.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { describe, it, expect } from "vitest";
33
import { type ContribPoint } from "@/lib/types/model/extension";
44
import { type StateChangeRequest } from "@/lib/types/model/callback";
55
import {
6+
type BoxState,
67
type ComponentState,
78
type PlotState,
89
} from "@/lib/types/state/component";
@@ -112,4 +113,24 @@ describe("Test that applyComponentStateChange()", () => {
112113
});
113114
expect(newState).toBe(componentTree);
114115
});
116+
117+
it("replaces state if no property given", () => {
118+
const value: BoxState = {
119+
type: "Box",
120+
id: "b1",
121+
children: ["Hello", "World"],
122+
};
123+
const newState = applyComponentStateChange(componentTree, {
124+
link: "component",
125+
id: "b1",
126+
property: "",
127+
value,
128+
});
129+
expect(newState).toBe(value);
130+
expect(newState).toEqual({
131+
type: "Box",
132+
id: "b1",
133+
children: ["Hello", "World"],
134+
});
135+
});
115136
});

chartlets.js/src/lib/actions/helpers/applyStateChangeRequests.ts

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -30,39 +30,6 @@ export function applyStateChangeRequests(
3030
applyHostStateChanges(stateChangeRequests);
3131
}
3232

33-
function applyHostStateChanges(stateChangeRequests: StateChangeRequest[]) {
34-
const { configuration } = store.getState();
35-
const { hostStore } = configuration;
36-
if (hostStore) {
37-
const hostStateOld = hostStore.getState();
38-
let hostState: object | undefined = hostStateOld;
39-
stateChangeRequests.forEach((stateChangeRequest) => {
40-
hostState = applyStateChanges(
41-
hostState,
42-
stateChangeRequest.stateChanges.filter(
43-
(stateChange) => stateChange.link === "app",
44-
),
45-
);
46-
});
47-
if (hostState !== hostStateOld) {
48-
hostStore.setState(hostState);
49-
}
50-
}
51-
}
52-
53-
function applyComponentStateChanges(
54-
componentOld: ComponentState | undefined,
55-
stateChanges: StateChange[],
56-
) {
57-
let component = componentOld;
58-
if (component) {
59-
stateChanges.forEach((stateChange) => {
60-
component = applyComponentStateChange(component!, stateChange);
61-
});
62-
}
63-
return component;
64-
}
65-
6633
// we export for testing only
6734
export function applyContributionChangeRequests(
6835
contributionsRecord: Record<ContribPoint, ContributionState[]>,
@@ -101,22 +68,40 @@ export function applyContributionChangeRequests(
10168
return contributionsRecord;
10269
}
10370

71+
function applyComponentStateChanges(
72+
componentOld: ComponentState | undefined,
73+
stateChanges: StateChange[],
74+
) {
75+
let component = componentOld;
76+
if (component) {
77+
stateChanges.forEach((stateChange) => {
78+
component = applyComponentStateChange(component!, stateChange);
79+
});
80+
}
81+
return component;
82+
}
83+
10484
// we export for testing only
10585
export function applyComponentStateChange(
10686
component: ComponentState,
10787
stateChange: StateChange,
10888
): ComponentState {
109-
if (component.id === stateChange.id) {
89+
if (isComponentState(component) && component.id === stateChange.id) {
11090
const property = normalizeObjPath(stateChange.property);
111-
const valueOld = getValue(component, property);
11291
const valueNew = stateChange.value;
92+
if (property.length === 0) {
93+
// Special case: If no property given, replace entire component.
94+
// But only if it is one, otherwise don't change state.
95+
return isComponentState(valueNew) ? valueNew : component;
96+
}
97+
const valueOld = getValue(component, property);
11398
if (
11499
property[property.length - 1] === "children" &&
115100
!Array.isArray(valueNew) &&
116101
valueNew !== null &&
117102
valueNew !== undefined
118103
) {
119-
// Special case if the value of "children" is changed:
104+
// Special case: if the value of "children" is changed:
120105
// convert scalar valueNew into one-element array
121106
return setValue(component, property, [valueNew]);
122107
} else if (valueOld !== valueNew) {
@@ -145,6 +130,26 @@ export function applyComponentStateChange(
145130
return component;
146131
}
147132

133+
function applyHostStateChanges(stateChangeRequests: StateChangeRequest[]) {
134+
const { configuration } = store.getState();
135+
const { hostStore } = configuration;
136+
if (hostStore) {
137+
const hostStateOld = hostStore.getState();
138+
let hostState: object | undefined = hostStateOld;
139+
stateChangeRequests.forEach((stateChangeRequest) => {
140+
hostState = applyStateChanges(
141+
hostState,
142+
stateChangeRequest.stateChanges.filter(
143+
(stateChange) => stateChange.link === "app",
144+
),
145+
);
146+
});
147+
if (hostState !== hostStateOld) {
148+
hostStore.setState(hostState);
149+
}
150+
}
151+
}
152+
148153
// we export for testing only
149154
export function applyStateChanges<S extends object | undefined>(
150155
state: S,

0 commit comments

Comments
 (0)