Mirror of https://github.com/improsocial/impro An extensible Bluesky client for web impro.social
5

Configure Feed

Select the types of activity you want to include in your feed.

Fix android post composer placeholder bug

Grace Kind (Jul 17, 2026, 5:27 PM -0500) 1e89215c 5dc1d74d

+22 -16
+1 -1
package.json
··· 1 1 { 2 2 "name": "impro", 3 - "version": "0.17.195", 3 + "version": "0.17.196", 4 4 "type": "module", 5 5 "scripts": { 6 6 "start": "rm -rf \"${BUILD_DIR:-build}\" && NODE_ENV=development eleventy --serve",
+5 -3
src/js/components/rich-text-input.js
··· 688 688 } 689 689 690 690 handleInput(e) { 691 - if (this.isComposing) return; 692 - 693 691 this.text = getContentEditableText(e.target); 694 692 695 693 this.facets = getUnresolvedFacetsFromText(this.text); 696 694 697 - this.paintFacets(); 695 + // Rewriting the editable's DOM mid-composition cancels the IME, so facet 696 + // painting waits for compositionend 697 + if (!this.isComposing) { 698 + this.paintFacets(); 699 + } 698 700 this.render(); 699 701 700 702 this.updateMentionSuggestions();
+16 -12
tests/unit/specs/components/rich-text-input.test.js
··· 200 200 assert.deepEqual(details[1].inputType, null); 201 201 }); 202 202 203 - it("skips updates while IME composition is in progress", () => { 203 + it("updates text and dispatches input during IME composition without repainting facets", () => { 204 204 const element = document.createElement("rich-text-input"); 205 205 document.body.appendChild(element); 206 - element.setText("hello"); 207 206 208 - let inputEvents = 0; 209 - element.addEventListener("input", () => { 210 - inputEvents++; 207 + const details = []; 208 + element.addEventListener("input", (event) => { 209 + details.push(event.detail); 211 210 }); 212 211 213 212 const input = element.querySelector(".rich-text-input"); 214 213 input.dispatchEvent(new window.CompositionEvent("compositionstart")); 215 - input.textContent = "hello でも"; 214 + input.textContent = "https://example.com"; 216 215 input.dispatchEvent(new Event("input")); 217 216 218 - assert.deepEqual(element.text, "hello"); 219 - assert.deepEqual(inputEvents, 0); 217 + assert.deepEqual(element.text, "https://example.com"); 218 + assert.deepEqual(details.length, 1); 219 + assert.deepEqual(details[0].text, "https://example.com"); 220 + const placeholder = element.querySelector(".rich-text-input-placeholder"); 221 + assert(placeholder.classList.contains("hidden")); 222 + assert.deepEqual(input.querySelectorAll(".facet").length, 0); 220 223 }); 221 224 222 - it("resumes updates after composition ends", () => { 225 + it("paints facets when composition ends", () => { 223 226 const element = document.createElement("rich-text-input"); 224 227 document.body.appendChild(element); 225 - element.setText("hello"); 226 228 227 229 const input = element.querySelector(".rich-text-input"); 228 230 input.dispatchEvent(new window.CompositionEvent("compositionstart")); 229 - input.textContent = "hello でも"; 231 + input.textContent = "https://example.com"; 232 + input.dispatchEvent(new Event("input")); 230 233 input.dispatchEvent(new window.CompositionEvent("compositionend")); 231 234 232 - assert.deepEqual(element.text, "hello でも"); 235 + assert.deepEqual(element.text, "https://example.com"); 236 + assert.deepEqual(input.querySelectorAll(".facet").length, 1); 233 237 }); 234 238 }); 235 239