Merge origin/development into studio/batch (upg100's example images)
|
|
@ -105,17 +105,40 @@ const heading = computed(() => config.value.title
|
|||
//
|
||||
// Set on the HOST rather than on .bp-root, deliberately: `dir` takes effect through the inherited
|
||||
// CSS `direction`, and inheritance crosses shadow boundaries — so one attribute covers this
|
||||
// element's own chrome AND both nested elements beneath it. Only ever SET, never cleared: a host
|
||||
// element's own chrome AND both nested elements beneath it. Set and CLEARED, but only ever ours: a host
|
||||
// page that already declares its own dir owns that decision.
|
||||
const textDir = computed(() => {
|
||||
const l = hostLang.value || getRuntimeLocale() || detectLocale()
|
||||
return RTL_LOCALES.has(l) ? 'rtl' : 'ltr'
|
||||
})
|
||||
const _self = getCurrentInstance()
|
||||
// ★ WE CLEAR ONLY THE DIRECTION WE SET. The line below used to be a one-way
|
||||
// `if (rtl) setAttribute('dir','rtl')` with no else, so a reader who switched from an RTL locale to
|
||||
// an LTR one (ar -> zh) kept a right-to-left layout for the rest of the session: Chinese laid out
|
||||
// backwards, which reads as a broken page rather than a stale setting.
|
||||
// The original reason for never clearing is still honoured, and is why this remembers rather than
|
||||
// just removing: a host page that declares its OWN dir owns that decision, so the value found before
|
||||
// we first wrote is restored verbatim, and removed only when there was none.
|
||||
// ★ CAPTURED AT MOUNT, NOT AT FIRST WRITE. The capture used to sit inside the rtl branch, so it
|
||||
// recorded whatever `dir` happened to be on the host the first time WE wrote — and if anything else
|
||||
// had already set rtl by then, that value was recorded as "the page's own" and faithfully restored
|
||||
// forever after. MEASURED on the Big Picture leaf: ar left rtl, and zh put rtl straight back.
|
||||
// Reading it on the FIRST call instead, before any write of ours, is the only moment the attribute
|
||||
// is certainly the page's and not ours.
|
||||
let _hostDir = null
|
||||
let _weSetDir = false
|
||||
function reflectDir() {
|
||||
try {
|
||||
const host = _self?.proxy?.$el?.getRootNode?.()?.host
|
||||
if (host && textDir.value === 'rtl') host.setAttribute('dir', 'rtl')
|
||||
if (!host || !host.setAttribute) return
|
||||
if (_hostDir === null) _hostDir = host.getAttribute('dir') || ''
|
||||
if (textDir.value === 'rtl') {
|
||||
host.setAttribute('dir', 'rtl')
|
||||
_weSetDir = true
|
||||
} else if (_weSetDir) {
|
||||
if (_hostDir) host.setAttribute('dir', _hostDir); else host.removeAttribute('dir')
|
||||
_weSetDir = false
|
||||
}
|
||||
} catch (_) { /* no host (SSR/tests) — nothing to reflect */ }
|
||||
}
|
||||
onMounted(reflectDir)
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ watchEffect(() => { if (hostLang.value) setRuntimeLocale(hostLang.value) })
|
|||
// Set on the custom-element HOST rather than on the layout inside it, deliberately: `dir` takes
|
||||
// effect through the inherited CSS `direction`, and inheritance crosses shadow boundaries — so one
|
||||
// attribute on the host covers this composite's own chrome AND every nested element beneath it,
|
||||
// which is the half the audit found missing. Only ever SET, never cleared: a host page that already
|
||||
// which is the half the audit found missing. Set and CLEARED, but only ever ours: a host page that already
|
||||
// declares its own dir owns that decision.
|
||||
const textDir = computed(() => {
|
||||
const l = hostLang.value || getRuntimeLocale() || detectLocale()
|
||||
|
|
@ -316,10 +316,29 @@ const textDir = computed(() => {
|
|||
// 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()
|
||||
// ★ WE CLEAR ONLY THE DIRECTION WE SET. This was a one-way `if (rtl) setAttribute` with no else,
|
||||
// so ar -> zh kept a right-to-left layout for the rest of the session. The host page's own dir is
|
||||
// still respected: the value found before we first wrote is restored verbatim.
|
||||
// ★ CAPTURED AT MOUNT, NOT AT FIRST WRITE. The capture used to sit inside the rtl branch, so it
|
||||
// recorded whatever `dir` happened to be on the host the first time WE wrote — and if anything else
|
||||
// had already set rtl by then, that value was recorded as "the page's own" and faithfully restored
|
||||
// forever after. MEASURED on the Big Picture leaf: ar left rtl, and zh put rtl straight back.
|
||||
// Reading it on the FIRST call instead, before any write of ours, is the only moment the attribute
|
||||
// is certainly the page's and not ours.
|
||||
let _hostDir = null
|
||||
let _weSetDir = false
|
||||
function reflectDir() {
|
||||
try {
|
||||
const host = _selfInstance?.proxy?.$el?.getRootNode?.()?.host
|
||||
if (host && textDir.value === 'rtl') host.setAttribute('dir', 'rtl')
|
||||
if (!host || !host.setAttribute) return
|
||||
if (_hostDir === null) _hostDir = host.getAttribute('dir') || ''
|
||||
if (textDir.value === 'rtl') {
|
||||
host.setAttribute('dir', 'rtl')
|
||||
_weSetDir = true
|
||||
} else if (_weSetDir) {
|
||||
if (_hostDir) host.setAttribute('dir', _hostDir); else host.removeAttribute('dir')
|
||||
_weSetDir = false
|
||||
}
|
||||
} catch (_) { /* no host (SSR/tests) — nothing to reflect */ }
|
||||
}
|
||||
onMounted(reflectDir)
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 171 KiB |
|
After Width: | Height: | Size: 207 KiB |
|
After Width: | Height: | Size: 167 KiB |
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 166 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 150 KiB |
|
|
@ -278,16 +278,39 @@ const languageCode = computed(() =>
|
|||
// page it owns and useless for an element dropped into someone else's, which is this grid's whole
|
||||
// job. Set on the HOST, like both composites: `dir` takes effect through the inherited CSS
|
||||
// `direction`, and inheritance crosses shadow boundaries, so one attribute turns the element and
|
||||
// everything it renders. Only ever SET, never cleared — a host page that declares its own dir owns
|
||||
// everything it renders. Set and CLEARED, but only ever ours — a host page that declares its own dir owns
|
||||
// that decision.
|
||||
const textDir = computed(() => {
|
||||
const l = languageCode.value || getRuntimeLocale() || detectLocale()
|
||||
return RTL_LOCALES.has(String(l).split('-')[0].toLowerCase()) ? 'rtl' : 'ltr'
|
||||
})
|
||||
// ★ WE CLEAR ONLY THE DIRECTION WE SET. The line below used to be a one-way
|
||||
// `if (rtl) setAttribute('dir','rtl')` with no else, so a reader who switched from an RTL locale to
|
||||
// an LTR one (ar -> zh) kept a right-to-left layout for the rest of the session: Chinese laid out
|
||||
// backwards, which reads as a broken page rather than a stale setting.
|
||||
// The original reason for never clearing is still honoured, and is why this remembers rather than
|
||||
// just removing: a host page that declares its OWN dir owns that decision, so the value found before
|
||||
// we first wrote is restored verbatim, and removed only when there was none.
|
||||
// ★ CAPTURED AT MOUNT, NOT AT FIRST WRITE. The capture used to sit inside the rtl branch, so it
|
||||
// recorded whatever `dir` happened to be on the host the first time WE wrote — and if anything else
|
||||
// had already set rtl by then, that value was recorded as "the page's own" and faithfully restored
|
||||
// forever after. MEASURED on the Big Picture leaf: ar left rtl, and zh put rtl straight back.
|
||||
// Reading it on the FIRST call instead, before any write of ours, is the only moment the attribute
|
||||
// is certainly the page's and not ours.
|
||||
let _hostDir = null
|
||||
let _weSetDir = false
|
||||
function reflectDir() {
|
||||
try {
|
||||
const host = hostEl()
|
||||
if (host && host.setAttribute && textDir.value === 'rtl') host.setAttribute('dir', 'rtl')
|
||||
if (!host || !host.setAttribute) return
|
||||
if (_hostDir === null) _hostDir = host.getAttribute('dir') || ''
|
||||
if (textDir.value === 'rtl') {
|
||||
host.setAttribute('dir', 'rtl')
|
||||
_weSetDir = true
|
||||
} else if (_weSetDir) {
|
||||
if (_hostDir) host.setAttribute('dir', _hostDir); else host.removeAttribute('dir')
|
||||
_weSetDir = false
|
||||
}
|
||||
} catch (_) { /* no host (SSR/tests) — nothing to reflect */ }
|
||||
}
|
||||
watch(textDir, reflectDir)
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ const hostList = computed(() => (typeof hostConfig.value?.list === 'string' ? ho
|
|||
// Set on the custom-element HOST rather than on the layout inside it, deliberately: `dir` takes
|
||||
// effect through the inherited CSS `direction`, and inheritance crosses shadow boundaries — so one
|
||||
// attribute on the host covers this composite's own chrome AND every nested element beneath it,
|
||||
// which is the half the audit found missing. Only ever SET, never cleared: a host page that already
|
||||
// which is the half the audit found missing. Set and CLEARED, but only ever ours: a host page that already
|
||||
// declares its own dir owns that decision.
|
||||
const textDir = computed(() => {
|
||||
const l = hostLang.value || getRuntimeLocale() || detectLocale()
|
||||
|
|
@ -168,10 +168,33 @@ const textDir = computed(() => {
|
|||
// 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()
|
||||
// ★ WE CLEAR ONLY THE DIRECTION WE SET. The line below used to be a one-way
|
||||
// `if (rtl) setAttribute('dir','rtl')` with no else, so a reader who switched from an RTL locale to
|
||||
// an LTR one (ar -> zh) kept a right-to-left layout for the rest of the session: Chinese laid out
|
||||
// backwards, which reads as a broken page rather than a stale setting.
|
||||
// The original reason for never clearing is still honoured, and is why this remembers rather than
|
||||
// just removing: a host page that declares its OWN dir owns that decision, so the value found before
|
||||
// we first wrote is restored verbatim, and removed only when there was none.
|
||||
// ★ CAPTURED AT MOUNT, NOT AT FIRST WRITE. The capture used to sit inside the rtl branch, so it
|
||||
// recorded whatever `dir` happened to be on the host the first time WE wrote — and if anything else
|
||||
// had already set rtl by then, that value was recorded as "the page's own" and faithfully restored
|
||||
// forever after. MEASURED on the Big Picture leaf: ar left rtl, and zh put rtl straight back.
|
||||
// Reading it on the FIRST call instead, before any write of ours, is the only moment the attribute
|
||||
// is certainly the page's and not ours.
|
||||
let _hostDir = null
|
||||
let _weSetDir = false
|
||||
function reflectDir() {
|
||||
try {
|
||||
const host = _selfInstance?.proxy?.$el?.getRootNode?.()?.host
|
||||
if (host && textDir.value === 'rtl') host.setAttribute('dir', 'rtl')
|
||||
if (!host || !host.setAttribute) return
|
||||
if (_hostDir === null) _hostDir = host.getAttribute('dir') || ''
|
||||
if (textDir.value === 'rtl') {
|
||||
host.setAttribute('dir', 'rtl')
|
||||
_weSetDir = true
|
||||
} else if (_weSetDir) {
|
||||
if (_hostDir) host.setAttribute('dir', _hostDir); else host.removeAttribute('dir')
|
||||
_weSetDir = false
|
||||
}
|
||||
} catch (_) { /* no host (SSR/tests) — nothing to reflect */ }
|
||||
}
|
||||
onMounted(reflectDir)
|
||||
|
|
@ -429,7 +452,13 @@ function pushToChildren() {
|
|||
// every push. MEASURED: the map stayed English on a live en->ar switch while the composite
|
||||
// around it changed. The leaf's own chain is fully reactive and was never at fault — it is
|
||||
// reactive to its own prop, and its prop was frozen.
|
||||
if (hostLang.value) cfg.lang = hostLang.value
|
||||
// BOTH KEYS, and `locale` is the one that decides. Every reader takes locale FIRST and falls
|
||||
// back to lang — ProfileLoader.vue:189 and people-groups-grid.vue:273/380 all read
|
||||
// `config.locale || config.lang`. Writing only `lang` is therefore correct exactly while no
|
||||
// child config carries a `locale`, and silently stops working the day one does: a stale locale
|
||||
// from a boot copy or a host-list path would shadow every fresh lang we push, forever. Writing
|
||||
// both keeps the two in step whatever put them there.
|
||||
if (hostLang.value) { cfg.lang = hostLang.value; cfg.locale = hostLang.value }
|
||||
map.setAttribute('profile-config', JSON.stringify(cfg))
|
||||
}
|
||||
const grid = rootEl.querySelector('people-groups-grid')
|
||||
|
|
@ -446,8 +475,9 @@ function pushToChildren() {
|
|||
if (hostLang.value) {
|
||||
let gcfg = {}
|
||||
try { gcfg = JSON.parse(grid.getAttribute('profile-config') || '{}') } catch (_) { gcfg = {} }
|
||||
if (gcfg.lang !== hostLang.value) {
|
||||
if (gcfg.lang !== hostLang.value || gcfg.locale !== hostLang.value) {
|
||||
gcfg.lang = hostLang.value
|
||||
gcfg.locale = hostLang.value
|
||||
grid.setAttribute('profile-config', JSON.stringify(gcfg))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 20 KiB |