From 273a0cd4897a9edfddf6a20c6c1ff294127178ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isaque=20B=C3=B6ck?= Date: Wed, 22 Jul 2026 13:03:34 -0300 Subject: [PATCH 1/3] fix: [Inputs] normalize z-index to semantic tokens (ENG-46735) From 6b2026d62bf7d0b700060fdfd806e7d071a3e251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isaque=20B=C3=B6ck?= Date: Wed, 22 Jul 2026 13:16:35 -0300 Subject: [PATCH 2/3] fix: normalize input z-index to semantic tokens (ENG-46735) Audit every explicit z-index across the inputs family and replace magic numbers with three semantic tokens declared in @aziontech/theme: --z-input-field (1) field/interactive foreground above the input's own icons, adornments and background surface --z-input-popup (10) inline (non-teleported) input-anchored overlay --z-input-overlay (1100) teleported overlay that must clear application chrome (dialog=1000, dialog-content/drawer=1001) Fixes the transversal stacking bug where the teleported `select` and `multi-select` listboxes (`z-50`) rendered behind an open Dialog or Drawer overlay (`z-[1001]`). All input-family components now share one stack ordering: field < inline popup < teleported overlay > modal chrome. Components touched: - input-text, input-password, input-number, chip, theme-switcher (field foreground: z-[1] -> z-[var(--z-input-field)]) - select-content, multi-select-content (teleported panel: z-50 -> z-[var(--z-input-overlay)]) Tokens are declared in packages/theme/src/tokens/semantic/z-indices.data.js and emitted as CSS custom properties by build-tokens.mjs alongside the existing spacing/container/text semantic tokens. Refs: ENG-46735 --- packages/theme/dist/v4/globals.css | 3 ++ packages/theme/dist/v4/globals.scss | 3 ++ packages/theme/src/scripts/build-tokens.mjs | 4 +++ .../src/tokens/semantic/z-indices.data.js | 30 +++++++++++++++++++ .../src/components/inputs/chip/chip.vue | 4 ++- .../inputs/input-number/input-number.vue | 10 +++---- .../inputs/input-password/input-password.vue | 2 +- .../inputs/input-text/input-text.vue | 2 +- .../multi-select-content.vue | 2 +- .../select/select-content/select-content.vue | 2 +- .../inputs/theme-switcher/theme-switcher.vue | 2 +- 11 files changed, 53 insertions(+), 11 deletions(-) create mode 100644 packages/theme/src/tokens/semantic/z-indices.data.js diff --git a/packages/theme/dist/v4/globals.css b/packages/theme/dist/v4/globals.css index 336c3951b..ebfe1dec5 100644 --- a/packages/theme/dist/v4/globals.css +++ b/packages/theme/dist/v4/globals.css @@ -661,6 +661,9 @@ --spacing-sm: 0.75rem; --spacing-xs: 0.5rem; --spacing-xxs: 0.25rem; + --z-input-field: 1; + --z-input-popup: 10; + --z-input-overlay: 1100; --text-big-number-md-font-size: 1.25rem; --text-big-number-md-line-height: 1.25; --text-big-number-md-font-weight: 400; diff --git a/packages/theme/dist/v4/globals.scss b/packages/theme/dist/v4/globals.scss index 336c3951b..ebfe1dec5 100644 --- a/packages/theme/dist/v4/globals.scss +++ b/packages/theme/dist/v4/globals.scss @@ -661,6 +661,9 @@ --spacing-sm: 0.75rem; --spacing-xs: 0.5rem; --spacing-xxs: 0.25rem; + --z-input-field: 1; + --z-input-popup: 10; + --z-input-overlay: 1100; --text-big-number-md-font-size: 1.25rem; --text-big-number-md-line-height: 1.25; --text-big-number-md-font-weight: 400; diff --git a/packages/theme/src/scripts/build-tokens.mjs b/packages/theme/src/scripts/build-tokens.mjs index 70004177d..187111bc6 100644 --- a/packages/theme/src/scripts/build-tokens.mjs +++ b/packages/theme/src/scripts/build-tokens.mjs @@ -34,6 +34,7 @@ import { compileThemeCss, compileThemeVars } from './compile-theme.js'; import { containersData } from '../tokens/semantic/containers.data.js'; import { spacingsData } from '../tokens/semantic/spacings.data.js'; import { textsData } from '../tokens/semantic/texts.data.js'; +import { zIndicesData } from '../tokens/semantic/z-indices.data.js'; const BREAKPOINT_ORDER = ['sm', 'md', 'lg', 'xl', '2xl']; @@ -91,6 +92,7 @@ const buildFlatModel = () => ({ primitives: flattenPrimitives(), containers: flattenSingleValue(containersData, (k) => `--container-${k}`), spacings: flattenSingleValue(spacingsData, (k) => `--${k}`), + zIndices: flattenSingleValue(zIndicesData, (k) => `--${k}`), texts: flattenBundle(textsData), }); @@ -295,6 +297,7 @@ const emitCssV4 = () => { ...rootPrimitiveVars, ...(m.containers._ || {}), ...(m.spacings._ || {}), + ...(m.zIndices._ || {}), ...(m.texts._ || {}), }; @@ -303,6 +306,7 @@ const emitCssV4 = () => { const merged = { ...(m.containers[bp] || {}), ...(m.spacings[bp] || {}), + ...(m.zIndices[bp] || {}), ...(m.texts[bp] || {}), }; if (Object.keys(merged).length === 0) continue; diff --git a/packages/theme/src/tokens/semantic/z-indices.data.js b/packages/theme/src/tokens/semantic/z-indices.data.js new file mode 100644 index 000000000..ee31fb136 --- /dev/null +++ b/packages/theme/src/tokens/semantic/z-indices.data.js @@ -0,0 +1,30 @@ +/** + * Declarative z-index tokens. + * + * Intra-input stacking: + * + * - `z-input-field` → native field / interactive foreground (e.g. an + * `` or trigger button) sitting above the + * input's own background surface, icons, and + * adornments so keyboard/mouse focus is never + * hijacked by a decorative sibling. + * - `z-input-popup` → inline (non-teleported) overlays anchored to the + * input — dropdown menus, option lists, popovers — + * that must sit above surrounding form content but + * within the current stacking context. + * - `z-input-overlay` → teleported overlays (rendered under `` via + * ``) that must clear application chrome + * such as drawers, modals, and fixed headers. + * + * Values are intentionally small and well-spaced to make future additions + * obvious. Consume as `z-[var(--z-input-*)]` in components — do not + * introduce ad-hoc numeric z-index in input `.vue` files. + */ + +export const zIndicesData = { + 'z-input-field': { _: '1' }, + 'z-input-popup': { _: '10' }, + 'z-input-overlay': { _: '1100' }, +}; + +export default { zIndicesData }; diff --git a/packages/webkit/src/components/inputs/chip/chip.vue b/packages/webkit/src/components/inputs/chip/chip.vue index ce2bf8ca7..dfaef57b8 100644 --- a/packages/webkit/src/components/inputs/chip/chip.vue +++ b/packages/webkit/src/components/inputs/chip/chip.vue @@ -109,7 +109,9 @@ @click="onClick" @keydown="onKeydown" > - + @@ -145,21 +145,21 @@ :aria-required="required || undefined" :data-testid="testId" v-bind="passthroughAttrs" - class="relative z-[1] w-full min-w-0 border-0 bg-transparent outline-none px-[var(--spacing-md)] text-label-sm text-[var(--text-default)] placeholder:text-[var(--text-muted)] disabled:cursor-not-allowed disabled:text-[var(--text-disabled)] read-only:cursor-default [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none" + class="relative z-[var(--z-input-field)] w-full min-w-0 border-0 bg-transparent outline-none px-[var(--spacing-md)] text-label-sm text-[var(--text-default)] placeholder:text-[var(--text-muted)] disabled:cursor-not-allowed disabled:text-[var(--text-disabled)] read-only:cursor-default [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none" @input="handleInput" @change="handleChange" />