Skip to content

Commit 2d8b5c5

Browse files
authored
fix: guard obsidian inputs from feedback loops (#154)
1 parent 05ff7db commit 2d8b5c5

File tree

2 files changed

+50
-7
lines changed

2 files changed

+50
-7
lines changed

src/ui/obsidian/Slider.svelte

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@
1515
let slider: SliderComponent;
1616
let styles: CSSObject = {};
1717
let changeHandler: ((event: Event) => void) | null = null;
18+
let isProgrammaticUpdate = false;
1819
1920
// This is not a complete implementation. I implemented what I needed.
2021
2122
onMount(() => {
2223
slider = new SliderComponent(sliderRef);
2324
2425
changeHandler = (event: Event) => {
26+
if (isProgrammaticUpdate) return;
27+
2528
const newValue = Number((event.target as HTMLInputElement).value);
2629
dispatch("change", { value: newValue });
2730
};
@@ -45,7 +48,16 @@
4548
currentLimits: [min: number, max: number] | [min: number, max: number, step: number],
4649
currentStyles: CSSObject
4750
) {
48-
if (currentValue !== undefined) sldr.setValue(currentValue);
51+
const sliderValue =
52+
typeof sldr.getValue === "function"
53+
? sldr.getValue()
54+
: Number(sldr.sliderEl?.value);
55+
56+
if (currentValue !== undefined && sliderValue !== currentValue) {
57+
isProgrammaticUpdate = true;
58+
sldr.setValue(currentValue);
59+
isProgrammaticUpdate = false;
60+
}
4961
if (currentLimits) {
5062
if (currentLimits.length === 2) {
5163
sldr.setLimits(currentLimits[0], currentLimits[1], 1);

src/ui/obsidian/Text.svelte

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
let styles: CSSObject = {};
2020
let inputHandler: ((event: Event) => void) | null = null;
2121
let changeHandler: ((value: string) => void) | null = null;
22+
let isProgrammaticUpdate = false;
2223
2324
onMount(() => {
2425
text = new TextComponent(textRef);
@@ -36,6 +37,8 @@
3637
}
3738
3839
function handleInput(event: Event) {
40+
if (isProgrammaticUpdate) return;
41+
3942
const input = event.target as HTMLInputElement | null;
4043
const newValue = input?.value ?? "";
4144
@@ -44,6 +47,8 @@
4447
}
4548
4649
function handleChange(newValue: string) {
50+
if (isProgrammaticUpdate) return;
51+
4752
value = newValue;
4853
dispatch("change", { value: newValue });
4954
}
@@ -66,14 +71,40 @@
6671
currentType: "text" | "password" | "email" | "number" | "tel" | "url",
6772
currentStyles: CSSObject
6873
) {
69-
if (currentValue !== undefined) component.setValue(currentValue);
70-
if (isDisabled) component.setDisabled(isDisabled);
71-
if (currentPlaceholder) component.setPlaceholder(currentPlaceholder);
72-
if (currentType) component.inputEl.type = currentType;
73-
if (currentStyles) {
74-
component.inputEl.setAttr("style", extractStylesFromObj(currentStyles));
74+
const componentValue =
75+
typeof component.getValue === "function"
76+
? component.getValue()
77+
: component.inputEl?.value;
78+
79+
if (currentValue !== undefined && componentValue !== currentValue) {
80+
isProgrammaticUpdate = true;
81+
component.setValue(currentValue);
82+
isProgrammaticUpdate = false;
7583
}
84+
7685
if (component?.inputEl) {
86+
if (component.inputEl.disabled !== isDisabled) {
87+
component.setDisabled(isDisabled);
88+
}
89+
90+
if (
91+
currentPlaceholder &&
92+
component.inputEl.placeholder !== currentPlaceholder
93+
) {
94+
component.setPlaceholder(currentPlaceholder);
95+
}
96+
97+
if (component.inputEl.type !== currentType) {
98+
component.inputEl.type = currentType;
99+
}
100+
101+
if (currentStyles) {
102+
component.inputEl.setAttr(
103+
"style",
104+
extractStylesFromObj(currentStyles),
105+
);
106+
}
107+
77108
el = component.inputEl;
78109
}
79110
}

0 commit comments

Comments
 (0)