From 437e591da8c33184ad76d671c0cbf1793172f2d3 Mon Sep 17 00:00:00 2001 From: Doxa Maps Date: Sun, 27 Sep 2026 04:29:05 +0000 Subject: [PATCH] Arabic set after mount never turned the composites RTL, because the instance was read too late MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit goal (d). Both composites reflect the reader's direction onto their custom-element host with reflectDir(), and reflectDir read `getCurrentInstance()` at the moment it ran. That call answers only while setup or a lifecycle hook is on the stack. reflectDir is called from BOTH: onMounted(reflectDir) -> Vue has set the current instance; this worked watch(textDir, reflectDir) -> nothing has; the read returned null and nothing was reflected So a host that declared lang=ar BEFORE mount got dir=rtl correctly, and a host that SWITCHED to ar afterwards got nothing at all. Arabic then rendered in a left-to-right layout — readable glyphs in the wrong places, which the comment above this code already names as reading like "a styling quirk rather than the bug it is". THAT SPLIT IS WHY IT SURVIVED REVIEW, and it is the part worth remembering: the function is not wrong and neither caller is wrong; the pairing is. Either line read alone is correct code, and first paint — the thing anyone actually checks — was right. Only the later switch was broken. The instance is now captured in setup as _selfInstance, which is the fix research-map.vue already carries for the same failure in emitFilterState (measured there under Vue 3.5.42). TWO THINGS DELIBERATELY NOT CHANGED, so nobody has to wonder: - reflectDir still only ever SETS dir and never clears it. That is documented directly above it — a host page that declares its own dir owns that decision — so switching ar -> en leaving the attribute is intended, not a second bug. - research-map-plus-grid.vue's onMounted(() => { getCurrentInstance()... }) at :422 is CORRECT and is left alone. Vue sets the current instance for the duration of a lifecycle hook, so that read resolves. Changing it would be churn, and flagging it would be a gate crying wolf on working code. --- .../dashboard-plus-grid/dashboard-plus-grid.vue | 12 +++++++++++- .../research-map-plus-grid.vue | 12 +++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/plugin-designs/dashboard-plus-grid/dashboard-plus-grid.vue b/plugin-designs/dashboard-plus-grid/dashboard-plus-grid.vue index 7a410d29d..978813493 100644 --- a/plugin-designs/dashboard-plus-grid/dashboard-plus-grid.vue +++ b/plugin-designs/dashboard-plus-grid/dashboard-plus-grid.vue @@ -298,9 +298,19 @@ const textDir = computed(() => { const l = hostLang.value || getRuntimeLocale() || detectLocale() return RTL_LOCALES.has(l) ? 'rtl' : 'ltr' }) +// ★ THE INSTANCE IS CAPTURED IN SETUP, NOT READ WHEN THIS RUNS, and that is the whole bug. +// getCurrentInstance() answers only while setup or a lifecycle hook is on the stack. reflectDir is +// called from BOTH — onMounted (where it works) and watch(textDir) (where there is no current +// instance, so the read returned null and nothing was reflected). So a host that set lang=ar before +// mount got dir=rtl correctly, and a host that SWITCHED to ar afterwards silently got nothing: +// first paint was right, which is exactly why this read as correct. Arabic then rendered in a +// left-to-right layout — the failure the comment above calls "a styling quirk rather than the bug +// it is". Measured in this tree before, under Vue 3.5.42, when research-map.vue's emitFilterState +// died the same way; the fix is its _selfInstance, and this is the same fix. +const _selfInstance = getCurrentInstance() function reflectDir() { try { - const host = getCurrentInstance()?.proxy?.$el?.getRootNode?.()?.host + const host = _selfInstance?.proxy?.$el?.getRootNode?.()?.host if (host && textDir.value === 'rtl') host.setAttribute('dir', 'rtl') } catch (_) { /* no host (SSR/tests) — nothing to reflect */ } } diff --git a/plugin-designs/research-map-plus-grid/research-map-plus-grid.vue b/plugin-designs/research-map-plus-grid/research-map-plus-grid.vue index 305eebad5..6a466d869 100644 --- a/plugin-designs/research-map-plus-grid/research-map-plus-grid.vue +++ b/plugin-designs/research-map-plus-grid/research-map-plus-grid.vue @@ -147,9 +147,19 @@ const textDir = computed(() => { const l = hostLang.value || getRuntimeLocale() || detectLocale() return RTL_LOCALES.has(l) ? 'rtl' : 'ltr' }) +// ★ THE INSTANCE IS CAPTURED IN SETUP, NOT READ WHEN THIS RUNS, and that is the whole bug. +// getCurrentInstance() answers only while setup or a lifecycle hook is on the stack. reflectDir is +// called from BOTH — onMounted (where it works) and watch(textDir) (where there is no current +// instance, so the read returned null and nothing was reflected). So a host that set lang=ar before +// mount got dir=rtl correctly, and a host that SWITCHED to ar afterwards silently got nothing: +// first paint was right, which is exactly why this read as correct. Arabic then rendered in a +// left-to-right layout — the failure the comment above calls "a styling quirk rather than the bug +// it is". Measured in this tree before, under Vue 3.5.42, when research-map.vue's emitFilterState +// died the same way; the fix is its _selfInstance, and this is the same fix. +const _selfInstance = getCurrentInstance() function reflectDir() { try { - const host = getCurrentInstance()?.proxy?.$el?.getRootNode?.()?.host + const host = _selfInstance?.proxy?.$el?.getRootNode?.()?.host if (host && textDir.value === 'rtl') host.setAttribute('dir', 'rtl') } catch (_) { /* no host (SSR/tests) — nothing to reflect */ } }