From 5d7324996aaa7ad16a7f33686d9e8d7a54c33053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isaque=20B=C3=B6ck?= Date: Wed, 22 Jul 2026 13:03:43 -0300 Subject: [PATCH 1/8] fix: [InputText] extend clickable area (ENG-46736) From ff508cedc349c0c8cf8cd6db7e67a99f5ced9c51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isaque=20B=C3=B6ck?= Date: Wed, 22 Jul 2026 13:13:05 -0300 Subject: [PATCH 2/8] fix: extend InputText clickable area to full field (ENG-46736) Add h-full + self-stretch to the inner so it fills the wrapper vertically. Before this fix the input was auto-sized while the wrapper set the row height, leaving a dead band above and below the placeholder line where clicks hit the wrapper without focusing the field. Refs: ENG-46736 --- .../inputs/input-text/input-text.test.ts | 24 +++++++++++++++++++ .../inputs/input-text/input-text.vue | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/packages/webkit/src/components/inputs/input-text/input-text.test.ts b/packages/webkit/src/components/inputs/input-text/input-text.test.ts index 6774f6c10..fff207399 100644 --- a/packages/webkit/src/components/inputs/input-text/input-text.test.ts +++ b/packages/webkit/src/components/inputs/input-text/input-text.test.ts @@ -152,6 +152,30 @@ describe('InputText', () => { }) }) + describe('clickable area (ENG-46736)', () => { + it('input fills the wrapper vertically so padding-area clicks reach it', () => { + const { getByTestId } = render(InputText, { props: { size: 'large' } }) + const input = getByTestId('input-text') as HTMLInputElement + // The spans the full wrapper height via h-full + self-stretch, so + // the wrapper's vertical padding is inside the input's hit area and a + // click anywhere on the field surface focuses the input. + expect(input.className).toMatch(/\bh-full\b/) + expect(input.className).toMatch(/\bself-stretch\b/) + }) + + it('resolves the input at the top edge of the wrapper (previous dead band)', () => { + const { getByTestId } = render(InputText, { props: { size: 'large' } }) + const input = getByTestId('input-text') as HTMLInputElement + const wrapper = input.closest('[data-size]') as HTMLElement + const rect = wrapper.getBoundingClientRect() + // Aim at the vertical edge of the wrapper — the "dead band" before the fix. + const el = document.elementFromPoint(rect.left + rect.width / 2, rect.top + 2) + expect(el).toBe(input) + input.focus() + expect(document.activeElement).toBe(input) + }) + }) + describe('a11y (axe against styled DOM)', () => { it('Default has no violations', async () => { const { container } = render(InputText, { diff --git a/packages/webkit/src/components/inputs/input-text/input-text.vue b/packages/webkit/src/components/inputs/input-text/input-text.vue index 7e62f811c..bb4765a83 100644 --- a/packages/webkit/src/components/inputs/input-text/input-text.vue +++ b/packages/webkit/src/components/inputs/input-text/input-text.vue @@ -114,7 +114,7 @@ :aria-invalid="invalid || undefined" :aria-required="required || undefined" :data-testid="testId" - class="relative z-[1] w-full min-w-0 border-0 bg-transparent p-0 outline-none 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" + class="relative z-[1] h-full w-full min-w-0 self-stretch border-0 bg-transparent p-0 outline-none 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" v-bind="passthroughAttrs" @input="handleInput" /> From 564d42f9ccd94fafbfda9a0cadb638f10109a0a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isaque=20B=C3=B6ck?= Date: Thu, 23 Jul 2026 14:36:46 -0300 Subject: [PATCH 3/8] test: drop ENG-46736 tag and inline comments from clickable area block --- .../src/components/inputs/input-text/input-text.test.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/webkit/src/components/inputs/input-text/input-text.test.ts b/packages/webkit/src/components/inputs/input-text/input-text.test.ts index fff207399..1e25d3939 100644 --- a/packages/webkit/src/components/inputs/input-text/input-text.test.ts +++ b/packages/webkit/src/components/inputs/input-text/input-text.test.ts @@ -152,13 +152,10 @@ describe('InputText', () => { }) }) - describe('clickable area (ENG-46736)', () => { + describe('clickable area', () => { it('input fills the wrapper vertically so padding-area clicks reach it', () => { const { getByTestId } = render(InputText, { props: { size: 'large' } }) const input = getByTestId('input-text') as HTMLInputElement - // The spans the full wrapper height via h-full + self-stretch, so - // the wrapper's vertical padding is inside the input's hit area and a - // click anywhere on the field surface focuses the input. expect(input.className).toMatch(/\bh-full\b/) expect(input.className).toMatch(/\bself-stretch\b/) }) @@ -168,7 +165,6 @@ describe('InputText', () => { const input = getByTestId('input-text') as HTMLInputElement const wrapper = input.closest('[data-size]') as HTMLElement const rect = wrapper.getBoundingClientRect() - // Aim at the vertical edge of the wrapper — the "dead band" before the fix. const el = document.elementFromPoint(rect.left + rect.width / 2, rect.top + 2) expect(el).toBe(input) input.focus() From 2915eb2970c6e62187d9f0ab2fc20f2e9e6beab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isaque=20B=C3=B6ck?= Date: Tue, 28 Jul 2026 14:40:33 -0300 Subject: [PATCH 4/8] fix: [ENG-46736] focus the InputText field from padding and icon areas --- .../inputs/input-text/input-text.test.ts | 40 ++++++++++++++----- .../inputs/input-text/input-text.vue | 19 +++++++-- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/packages/webkit/src/components/inputs/input-text/input-text.test.ts b/packages/webkit/src/components/inputs/input-text/input-text.test.ts index 1e25d3939..8e01e3dff 100644 --- a/packages/webkit/src/components/inputs/input-text/input-text.test.ts +++ b/packages/webkit/src/components/inputs/input-text/input-text.test.ts @@ -153,23 +153,43 @@ describe('InputText', () => { }) describe('clickable area', () => { - it('input fills the wrapper vertically so padding-area clicks reach it', () => { + // The bordered box is the wrapper: its padding, gaps and icon areas are outside the + // input's hit box, so a press there targets the chrome and must be delegated. + const pressOn = (element: Element) => + element.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, cancelable: true })) + + it('focuses the input when the press lands on the wrapper chrome (padding band)', () => { const { getByTestId } = render(InputText, { props: { size: 'large' } }) const input = getByTestId('input-text') as HTMLInputElement - expect(input.className).toMatch(/\bh-full\b/) - expect(input.className).toMatch(/\bself-stretch\b/) + const wrapper = input.closest('[data-size]') as HTMLElement + const notPrevented = pressOn(wrapper) + expect(document.activeElement).toBe(input) + expect(notPrevented).toBe(false) }) - it('resolves the input at the top edge of the wrapper (previous dead band)', () => { - const { getByTestId } = render(InputText, { props: { size: 'large' } }) + it('focuses the input when the press lands on a decorative icon', () => { + const { getByTestId, getByText } = render(InputText, { + props: { size: 'large' }, + slots: { iconLeft: 'L' } + }) const input = getByTestId('input-text') as HTMLInputElement - const wrapper = input.closest('[data-size]') as HTMLElement - const rect = wrapper.getBoundingClientRect() - const el = document.elementFromPoint(rect.left + rect.width / 2, rect.top + 2) - expect(el).toBe(input) - input.focus() + pressOn(getByText('L')) expect(document.activeElement).toBe(input) }) + + it('leaves a press on the input itself untouched so the native caret still lands', () => { + const { getByTestId } = render(InputText, { props: { modelValue: 'azion' } }) + const input = getByTestId('input-text') as HTMLInputElement + expect(pressOn(input)).toBe(true) + }) + + it('does not focus from the wrapper chrome when disabled', () => { + const { getByTestId } = render(InputText, { props: { size: 'large', disabled: true } }) + const input = getByTestId('input-text') as HTMLInputElement + const wrapper = input.closest('[data-size]') as HTMLElement + expect(pressOn(wrapper)).toBe(true) + expect(document.activeElement).not.toBe(input) + }) }) describe('a11y (axe against styled DOM)', () => { diff --git a/packages/webkit/src/components/inputs/input-text/input-text.vue b/packages/webkit/src/components/inputs/input-text/input-text.vue index 9f142fe8e..781bd9451 100644 --- a/packages/webkit/src/components/inputs/input-text/input-text.vue +++ b/packages/webkit/src/components/inputs/input-text/input-text.vue @@ -1,5 +1,5 @@