feat(textarea): add styles for textarea solid fill (#30685)

Issue number: internal

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- highlight should only appear on md;
- fix some textarea ionic css vars usage;
- create sheet for ionic.solid;

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

<!--
  If this introduces a breaking change:
1. Describe the impact and migration path for existing applications
below.
  2. Update the BREAKING.md file with the breaking change.
3. Add "BREAKING CHANGE: [...]" to the commit description when merging.
See
https://github.com/ionic-team/ionic-framework/blob/main/docs/CONTRIBUTING.md#footer
for more information.
-->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

[fill](https://ionic-framework-git-rou-12225-ionic1.vercel.app/src/components/textarea/test/fill?ionic:theme=ionic)

[color](https://ionic-framework-git-rou-12225-ionic1.vercel.app/src/components/textarea/test/color?ionic:theme=ionic)

[states](https://ionic-framework-git-rou-12225-ionic1.vercel.app/src/components/textarea/test/states?ionic:theme=ionic)

---------

Co-authored-by: ionitron <hi@ionicframework.com>
Co-authored-by: Brandy Smith <brandyscarney@users.noreply.github.com>
This commit is contained in:
João Ferreira
2025-09-25 18:43:53 +01:00
committed by GitHub
parent 4faa1a0f39
commit 42f3447075
17 changed files with 109 additions and 11 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -151,6 +151,31 @@ configs({ modes: ['ionic-md'], directions: ['ltr'] }).forEach(({ title, screensh
await expect(container).toHaveScreenshot(screenshot(`textarea-readonly-no-fill`));
});
});
test.describe(title('solid'), () => {
test('should render readonly invalid textarea correctly', async ({ page }) => {
await page.setContent(
`
<div class="container">
<ion-textarea
label="Email"
label-placement="stacked"
value="hi@ionic.io"
helper-text="Enter an email"
counter="true"
maxlength="20"
class="ion-touched ion-invalid"
readonly="true"
></ion-textarea>
</div>
`,
config
);
const container = page.locator('.container');
await expect(container).toHaveScreenshot(screenshot(`textarea-readonly-solid-invalid`));
});
});
});
});
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@ -60,9 +60,18 @@
margin-top: globals.$ion-space-100;
}
// Input Focus
// Focus
// ----------------------------------------------------------------
:host(.textarea-fill-outline.has-focus) {
--border-width: #{globals.$ion-border-size-050};
:host(.textarea-fill-outline.has-focus.ion-valid),
:host(.textarea-fill-outline.ion-touched.ion-invalid) {
--border-color: var(--highlight-color);
}
// Ionic Textarea - Readonly
// ----------------------------------------------------------------
:host(.textarea-fill-outline.textarea-readonly) {
--border-color: #{globals.$ion-border-input-default};
--border-width: #{globals.$ion-border-size-025};
}

View File

@ -1,6 +1,7 @@
@use "../../themes/ionic/ionic.globals.scss" as globals;
@use "./textarea.common";
@use "./textarea.ionic.outline.scss" as outline;
@use "./textarea.ionic.solid.scss" as solid;
// Ionic Textarea
// --------------------------------------------------
@ -122,7 +123,7 @@
// ----------------------------------------------------------------
ion-icon {
color: globals.$ion-primitives-neutral-800;
--color: globals.$ion-icon-subtlest;
font-size: globals.$ion-scale-400;
}
@ -177,6 +178,7 @@ ion-icon {
:host(.has-focus) {
--border-color: #{globals.$ion-border-focus-default};
--border-width: #{globals.$ion-border-size-050};
}
:host(.has-focus) .textarea-highlight {
@ -188,7 +190,7 @@ ion-icon {
@media (any-hover: hover) {
:host(:hover) {
--border-color: #{globals.$ion-primitives-neutral-600};
--border-color: #{globals.$ion-border-focus-default};
}
}
@ -196,10 +198,10 @@ ion-icon {
// ----------------------------------------------------------------
:host(.textarea-disabled) {
--color: #{globals.$ion-primitives-neutral-500};
--background: #{globals.$ion-primitives-neutral-100};
--border-color: #{globals.$ion-primitives-neutral-300};
--placeholder-color: #{globals.$ion-primitives-neutral-500};
--color: #{globals.$ion-text-disabled};
--background: #{globals.$ion-bg-input-disabled};
--border-color: #{globals.$ion-border-disabled};
--placeholder-color: #{globals.$ion-text-disabled};
}
:host(.textarea-disabled:not(.ion-valid)) .textarea-bottom .helper-text,
@ -229,7 +231,7 @@ ion-icon {
// ----------------------------------------------------------------
:host(.textarea-readonly) {
--background: #{globals.$ion-primitives-neutral-100};
--background: #{globals.$ion-bg-input-read-only};
}
/**

View File

@ -0,0 +1,62 @@
@use "../../themes/ionic/ionic.globals.scss" as globals;
// Ionic Textarea Fill: Solid
// ----------------------------------------------------------------
:host(.textarea-fill-solid) {
--border-color: #{globals.$ion-bg-input-bold-default};
--border-width: #{globals.$ion-border-size-050};
--background: #{globals.$ion-bg-input-bold-default};
}
:host(.textarea-fill-solid) .textarea-wrapper {
border-bottom: none;
background: none;
}
:host(.textarea-fill-solid) .textarea-wrapper-inner {
@include globals.border-radius(var(--border-radius));
position: relative;
border: var(--border-width) var(--border-style) var(--border-color);
background: var(--background);
}
:host(.textarea-fill-solid) .textarea-bottom {
--border-width: #{globals.$ion-scale-0};
}
// Focus
// ----------------------------------------------------------------
:host(.textarea-fill-solid.has-focus) {
--border-color: #{globals.$ion-border-focus-default};
}
:host(.textarea-fill-solid.has-focus.ion-valid),
:host(.textarea-fill-solid.ion-touched.ion-invalid) {
--border-width: #{globals.$ion-border-size-050};
--border-color: var(--highlight-color);
}
// Ionic Textarea - Readonly
// ----------------------------------------------------------------
:host(.textarea-fill-solid.textarea-readonly) {
--background: #{globals.$ion-bg-input-bold-read-only};
--border-color: #{globals.$ion-bg-input-bold-read-only};
}
:host(.textarea-fill-solid.textarea-readonly.ion-invalid) {
--border-color: rgba(#{globals.$ion-semantics-danger-base-rgb}, 0.6);
}
// Textarea - Disabled
// ----------------------------------------------------------------
:host(.textarea-fill-solid.textarea-disabled) {
--background: #{globals.$ion-bg-input-bold-disabled};
--border-color: #{globals.$ion-bg-input-bold-disabled};
}

View File

@ -776,7 +776,7 @@ export class Textarea implements ComponentInterface {
const shape = this.getShape();
const value = this.getValue();
const inItem = hostContext('ion-item', this.el);
const shouldRenderHighlight = (theme === 'md' || theme === 'ionic') && fill !== 'outline' && !inItem;
const shouldRenderHighlight = theme === 'md' && fill !== 'outline' && !inItem;
const hasValue = this.hasValue();
const hasStartEndSlots = el.querySelector('[slot="start"], [slot="end"]') !== null;