Skip to content
4 changes: 2 additions & 2 deletions core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3053,7 +3053,7 @@ export namespace Components {
*/
"cancelButtonIcon"?: string;
/**
* Set the the cancel button text. Only available when the theme is `"ios"`.
* Set the cancel button text. Only available when the theme is `"ios"`.
*/
"cancelButtonText": string;
/**
Expand Down Expand Up @@ -8452,7 +8452,7 @@ declare namespace LocalJSX {
*/
"cancelButtonIcon"?: string;
/**
* Set the the cancel button text. Only available when the theme is `"ios"`.
* Set the cancel button text. Only available when the theme is `"ios"`.
*/
"cancelButtonText"?: string;
/**
Expand Down
52 changes: 39 additions & 13 deletions core/src/components/searchbar/searchbar.ionic.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,18 @@
* @prop --focus-ring-color: The color of the ring around the focused element.
* @prop --focus-ring-width: The width of the ring around the focused element.
*/
--background: #{globals.$ion-primitives-neutral-100};
--background: #{globals.$ion-bg-neutral-subtle-default};
--border-radius: #{globals.$ion-border-radius-400};
--box-shadow: none;
--cancel-button-color: #{globals.$ion-primitives-neutral-800};
--clear-button-color: #{globals.$ion-primitives-neutral-1000};
--color: #{globals.$ion-primitives-neutral-1200};
--icon-color: #{globals.$ion-primitives-neutral-800};
--placeholder-color: #{globals.$ion-primitives-neutral-800};
--icon-color: #{globals.$ion-icon-default};
--placeholder-color: #{globals.$ion-text-subtlest};
--focus-ring-color: #{globals.$ion-border-focus-default};
--focus-ring-width: #{globals.$ion-border-size-050};
--leading-icon-padding: #{calc(globals.$ion-scale-400 + globals.$ion-space-200)};
--clear-button-padding: #{calc(globals.$ion-scale-400 + globals.$ion-space-200)};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why were these new variables added? We need to be careful when adding new ones because it introduces them to the public so we try to make sure that they're necessary.

If they're to make it easier to keep track of then it might be best to make Sass variables.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These variables were created with the purpose of making the searchbar's start and end paddings be dynamic according to whether it is rendering leading and/or trailing icons. That being said, I don't see a reason why they have to be CSS variables instead of SCSS variables so I'll make that change 👍🏼


@include globals.typography(globals.$ion-body-md-regular);
@include globals.padding(0);
Expand All @@ -38,6 +40,8 @@
.searchbar-input {
@include globals.padding(globals.$ion-space-300, null);

text-overflow: ellipsis;

contain: strict;
}

Expand All @@ -55,6 +59,10 @@
contain: strict;
}

:host(:not(.searchbar-should-show-clear)) {
--clear-button-padding: #{globals.$ion-scale-0};
}

// Searchbar Cancel Icon
// -----------------------------------------

Expand All @@ -67,7 +75,7 @@
font-size: globals.$ion-font-size-400;
}

// Searchbar Search & Clear Icon & Cancel Icon
// Searchbar Search Icon & Clear Icon & Cancel Icon
// -----------------------------------------

.searchbar-search-icon,
Expand All @@ -80,7 +88,7 @@
transform: translateY(-50%);
}

// Clear Icon & Cancel Icon
// Searchbar Clear Icon & Cancel Icon
// -----------------------------------------

.searchbar-clear-button:focus-visible,
Expand All @@ -92,6 +100,16 @@
opacity: 1;
}

// Searchbar Search Icon & Cancel Icon
// -----------------------------------------
:host(:not(.searchbar-has-leading-icons)) {
--leading-icon-padding: #{globals.$ion-scale-0};
}

:host(:not(.searchbar-has-value)) {
--icon-color: #{globals.$ion-icon-subtlest};
}

// Searchbar in Toolbar
// -----------------------------------------

Expand All @@ -113,7 +131,7 @@
* the size of the leading icon (search or cancel),
* and the gap between the icon and the input.
*/
padding-inline-start: calc(9px + globals.$ion-scale-400 + globals.$ion-space-200);
padding-inline-start: calc(9px + var(--leading-icon-padding));
}

// Searchbar States
Expand Down Expand Up @@ -143,8 +161,8 @@
/* Disabled */
:host(.searchbar-disabled) {
--color: #{globals.$ion-primitives-neutral-500};
--icon-color: #{globals.$ion-primitives-neutral-500};
--placeholder-color: #{globals.$ion-primitives-neutral-500};
--icon-color: #{globals.$ion-icon-disabled};
--placeholder-color: #{globals.$ion-text-disabled};

cursor: default;
pointer-events: none;
Expand Down Expand Up @@ -181,7 +199,10 @@
* the size of the trailing icon (clear),
* and the gap between the icon and the input.
*/
@include globals.padding-horizontal(calc(globals.$ion-space-300 + globals.$ion-scale-400 + globals.$ion-space-200));
@include globals.padding-horizontal(
calc(globals.$ion-space-300 + var(--leading-icon-padding)),
calc(globals.$ion-space-300 + var(--clear-button-padding))
);

height: globals.$ion-scale-1000;
}
Expand Down Expand Up @@ -210,7 +231,10 @@
* the size of the trailing icon (clear),
* and the gap between the icon and the input.
*/
@include globals.padding-horizontal(calc(globals.$ion-space-400 + globals.$ion-scale-400 + globals.$ion-space-200));
@include globals.padding-horizontal(
calc(globals.$ion-space-400 + var(--leading-icon-padding)),
calc(globals.$ion-space-400 + var(--clear-button-padding))
);

height: globals.$ion-scale-1200;
}
Expand All @@ -229,6 +253,8 @@
/* Large */
:host(.searchbar-size-large) .searchbar-search-icon,
:host(.searchbar-size-large) .searchbar-cancel-button {
--leading-icon-padding: #{calc(globals.$ion-scale-500 + globals.$ion-space-200)};

width: globals.$ion-scale-500;
height: globals.$ion-scale-500;
}
Expand All @@ -244,7 +270,7 @@
* the size of the leading icon (search or cancel),
* and the gap between the icon and the input.
*/
padding-inline-start: calc(9px + globals.$ion-scale-500 + globals.$ion-space-200);
padding-inline-start: calc(9px + var(--leading-icon-padding));
}

:host(.searchbar-size-large) .searchbar-input {
Expand All @@ -262,8 +288,8 @@
* and the gap between the icon and the input.
*/
@include globals.padding-horizontal(
calc(globals.$ion-space-500 + globals.$ion-scale-500 + globals.$ion-space-200),
calc(globals.$ion-space-500 + globals.$ion-scale-400 + globals.$ion-space-200)
calc(globals.$ion-space-500 + var(--leading-icon-padding)),
calc(globals.$ion-space-500 + var(--clear-button-padding))
);

height: globals.$ion-scale-1400;
Expand Down
60 changes: 40 additions & 20 deletions core/src/components/searchbar/searchbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export class Searchbar implements ComponentInterface {
@Prop() cancelButtonIcon?: string;

/**
* Set the the cancel button text. Only available when the theme is `"ios"`.
* Set the cancel button text. Only available when the theme is `"ios"`.
*/
@Prop() cancelButtonText = 'Cancel';

Expand Down Expand Up @@ -626,6 +626,10 @@ export class Searchbar implements ComponentInterface {
return false;
}

if (getIonTheme(this) === 'ionic' && this.disabled) {
return false;
}

return true;
}

Expand Down Expand Up @@ -783,6 +787,8 @@ export class Searchbar implements ComponentInterface {
'searchbar-has-value': this.hasValue(),
'searchbar-left-aligned': this.shouldAlignLeft,
'searchbar-has-focus': this.focused,
'searchbar-has-leading-icons':
theme === 'ionic' && (this.searchIcon !== undefined || this.showCancelButton !== 'never'),
'searchbar-should-show-clear': this.shouldShowClearButton(),
'searchbar-should-show-cancel': this.shouldShowCancelButton(),
[`searchbar-shape-${shape}`]: shape !== undefined,
Expand Down Expand Up @@ -816,25 +822,39 @@ export class Searchbar implements ComponentInterface {

{(theme === 'md' || theme === 'ionic') && cancelButton}

<ion-icon aria-hidden="true" icon={searchbarSearchIcon} lazy={false} class="searchbar-search-icon"></ion-icon>

<button
aria-label="reset"
type="button"
no-blur
class="searchbar-clear-button"
onPointerDown={(ev) => {
/**
* This prevents mobile browsers from
* blurring the input when the clear
* button is activated.
*/
ev.preventDefault();
}}
onClick={() => this.onClearInput(true)}
>
<ion-icon aria-hidden="true" icon={searchbarClearIcon} lazy={false} class="searchbar-clear-icon"></ion-icon>
</button>
{theme !== 'ionic' || this.searchIcon !== undefined ? (
<ion-icon
aria-hidden="true"
icon={searchbarSearchIcon}
lazy={false}
class="searchbar-search-icon"
></ion-icon>
) : null}

{theme !== 'ionic' || this.shouldShowClearButton() !== undefined ? (
<button
aria-label="reset"
type="button"
no-blur
class="searchbar-clear-button"
onPointerDown={(ev) => {
/**
* This prevents mobile browsers from
* blurring the input when the clear
* button is activated.
*/
ev.preventDefault();
}}
onClick={() => this.onClearInput(true)}
>
<ion-icon
aria-hidden="true"
icon={searchbarClearIcon}
lazy={false}
class="searchbar-clear-icon"
></ion-icon>
</button>
) : null}
</div>
{theme === 'ios' && cancelButton}
</Host>
Expand Down
4 changes: 2 additions & 2 deletions core/src/components/searchbar/test/basic/searchbar.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
});
});

configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('searchbar: ios clear button text cut off'), () => {
configs({ modes: ['ios', 'ionic-md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('searchbar: clear button text cut off'), () => {
test('text should not be cut off when clear button is hidden', async ({ page }) => {
await page.setContent(
`
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions core/src/components/searchbar/test/states/searchbar.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,27 @@ configs({ modes: ['md', 'ios', 'ionic-md'], directions: ['ltr'] }).forEach(({ ti
});
});

/**
* This behavior is only applicable to the `ionic-md` mode.
* This behavior does not vary across directions.
*/
configs({ modes: ['ionic-md'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('searchbar: disabled'), () => {
test('should not show clear button', async ({ page }) => {
await page.setContent(
`
<ion-searchbar disabled="true" value="Some text"></ion-searchbar>
`,
config
);

const clearButton = page.locator('.searchbar-clear-button');

await expect(clearButton).toBeHidden();
});
});
});

/**
* This behavior is only applicable to the `ionic-md` mode.
* This behavior does not vary across directions.
Expand Down
Loading