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>
| 
		 Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 3.9 KiB  | 
| 
		 Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.4 KiB  | 
| 
		 Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.3 KiB  | 
| 
		 Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB  | 
| 
		 Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 6.1 KiB  | 
| 
		 Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 5.3 KiB  | 
@ -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`));
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 3.9 KiB  | 
| 
		 Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB  | 
| 
		 Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB  | 
| 
		 After Width: | Height: | Size: 3.4 KiB  | 
| 
		 After Width: | Height: | Size: 5.6 KiB  | 
| 
		 After Width: | Height: | Size: 4.5 KiB  | 
@ -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};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										62
									
								
								core/src/components/textarea/textarea.ionic.solid.scss
									
									
									
									
									
										Normal 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};
 | 
			
		||||
}
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||