Repair stale native composer layout

After removing the former collapse feature, force a one-time reflow of DSH input mirrors and textareas and refresh the conversation composer-height variable. Restore every temporary inline style immediately and mark each mounted input so normal prompt behavior remains entirely native afterward.
This commit is contained in:
Шурупов Илья Викторович 2026-09-14 13:54:52 +03:00
parent 9ca766a809
commit 35f26fa32b
3 changed files with 56 additions and 1 deletions

View file

@ -252,6 +252,32 @@ window.__ModuleLoader__.load({
document.querySelectorAll("[data-composer-seat]").forEach((seat) => seat.removeAttribute("data-dsh-composer-collapsed"));
}
function repairNativeComposerLayouts() {
document.querySelectorAll("[data-input-scroll]").forEach((scrollport) => {
if (scrollport.getAttribute("data-dsh-composer-repaired") === "1") return;
scrollport.setAttribute("data-dsh-composer-repaired", "1");
requestAnimationFrame(() => requestAnimationFrame(() => {
if (!scrollport.isConnected) return;
const mirror = scrollport.querySelector("[data-input-mirror]");
const input = scrollport.querySelector("textarea");
if (!mirror || !input) return;
const mirrorPosition = mirror.style.position;
mirror.style.position = "absolute";
mirror.offsetHeight;
scrollport.offsetHeight;
mirror.style.position = mirrorPosition;
mirror.offsetHeight;
const inputHeight = input.style.height;
input.style.height = `${String(input.clientHeight + 1)}px`;
input.offsetHeight;
input.style.height = inputHeight;
input.offsetHeight;
const seat = scrollport.closest("[data-composer-seat]");
seat?.parentElement?.style.setProperty("--dsh-composer-height", `${String(seat.offsetHeight)}px`);
}));
});
}
function updateChatControls() {
document.querySelectorAll(".dsh-chat-controls").forEach((controls) => {
const zen = controls.querySelector(".dsh-zen-toggle");
@ -342,6 +368,7 @@ window.__ModuleLoader__.load({
function removeChatControls() {
setZenActive(false);
document.querySelectorAll(".dsh-chat-controls").forEach((controls) => controls.remove());
document.querySelectorAll('[data-dsh-composer-repaired="1"]').forEach((scrollport) => scrollport.removeAttribute("data-dsh-composer-repaired"));
restoreNativeComposer();
}
@ -382,6 +409,7 @@ window.__ModuleLoader__.load({
/** Enhance every header-utilities region currently in the DOM (idempotent). */
function enhance() {
repairNativeComposerLayouts();
enhanceChatControls();
if (!COLLAPSE_HEADER) return;
const panels = document.querySelectorAll('[class*="_headerUtilities"]');

View file

@ -1,7 +1,7 @@
{
"name": "dsh-ui-tweaks",
"description": "dsh web plugin: cohesive sidebar, header, and Zen-mode controls for the DSH Web chat interface. Client-only.",
"version": "0.3.0",
"version": "0.3.1",
"private": true,
"type": "module",
"engines": {

View file

@ -14,6 +14,16 @@ class Element {
this.textContent = ''
this.title = ''
this.type = ''
this.clientHeight = 32
this.offsetHeight = 32
this.isConnected = true
const properties = new Map()
this.style = {
position: '',
height: '',
setProperty: (name, value) => properties.set(name, String(value)),
getPropertyValue: (name) => properties.get(name) ?? '',
}
}
append(...children) {
@ -58,6 +68,8 @@ class Element {
querySelector(selector) {
if (selector === ':scope > .dsh-chat-controls') return this.children.find((child) => child.hasClass('dsh-chat-controls')) ?? null
if (selector === 'header [class*="_headerUtilities"]') return this.descendants().find((child) => child.tagName === 'div' && child.className.includes('_headerUtilities')) ?? null
if (selector === '[data-input-mirror]') return this.descendants().find((child) => child.attributes.has('data-input-mirror')) ?? null
if (selector === 'textarea') return this.descendants().find((child) => child.tagName === 'textarea') ?? null
if (selector.startsWith('.')) return this.descendants().find((child) => child.hasClass(selector.slice(1))) ?? null
return null
}
@ -71,6 +83,7 @@ class Element {
let current = this
while (current) {
if (selector === '[data-phase]' && current.attributes.has('data-phase')) return current
if (selector === '[data-composer-seat]' && current.attributes.has('data-composer-seat')) return current
current = current.parentElement
}
return null
@ -109,6 +122,13 @@ header.appendChild(titleRow)
const seat = new Element('div')
seat.setAttribute('data-composer-seat', '')
seat.setAttribute('data-dsh-composer-collapsed', '1')
const inputScroll = new Element('div')
inputScroll.setAttribute('data-input-scroll', '')
const input = new Element('textarea')
const mirror = new Element('div')
mirror.setAttribute('data-input-mirror', '')
inputScroll.append(input, mirror)
seat.appendChild(inputScroll)
const nestedPhase = new Element('div')
nestedPhase.setAttribute('data-phase', 'streaming')
const strayControls = new Element('div')
@ -128,6 +148,8 @@ const document = {
querySelectorAll(selector) {
if (selector === '[data-phase]') return allElements().filter((element) => element.attributes.has('data-phase'))
if (selector === '[data-composer-seat]') return allElements().filter((element) => element.attributes.has('data-composer-seat'))
if (selector === '[data-input-scroll]') return allElements().filter((element) => element.attributes.has('data-input-scroll'))
if (selector === '[data-dsh-composer-repaired="1"]') return allElements().filter((element) => element.getAttribute('data-dsh-composer-repaired') === '1')
if (selector === '.dsh-chat-controls') return allElements().filter((element) => element.hasClass('dsh-chat-controls'))
if (selector === '.dsh-hdr-menu-trigger' || selector === '[data-dsh-hdr-menu]' || selector === '[class*="_headerUtilities"]') return []
return []
@ -178,6 +200,10 @@ assert.equal(controls.querySelector('.dsh-composer-collapse-toggle'), null)
assert.equal(zen.textContent, 'Zen')
assert.equal(seat.getAttribute('data-dsh-composer-collapsed'), null)
assert.equal(storage.has('dsh-ui-tweaks:composer-collapsed'), false)
assert.equal(inputScroll.getAttribute('data-dsh-composer-repaired'), '1')
assert.equal(mirror.style.position, '')
assert.equal(input.style.height, '')
assert.equal(conversation.style.getPropertyValue('--dsh-composer-height'), '32px')
zen.click()
assert.equal(documentElement.getAttribute('data-dsh-zen'), '1')
@ -196,6 +222,7 @@ assert.equal(controls.getAttribute('data-floating'), null)
cleanup()
assert.equal(conversation.querySelector('.dsh-chat-controls'), null)
assert.equal(seat.getAttribute('data-dsh-composer-collapsed'), null)
assert.equal(inputScroll.getAttribute('data-dsh-composer-repaired'), null)
assert.equal(documentElement.getAttribute('data-dsh-zen'), null)
assert(source.includes('[data-sidebar-collapsed] [class*="_sidebarCol"] [class*="_regionArea"]'))
assert(source.includes('[class*="_detailsCol"]{visibility:hidden !important;pointer-events:none !important;border:0 !important}'))