Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1915,6 +1915,8 @@ ion-searchbar,css-prop,--clear-button-color,md
ion-searchbar,css-prop,--color,ionic
ion-searchbar,css-prop,--color,ios
ion-searchbar,css-prop,--color,md
ion-searchbar,css-prop,--focus-ring-color,ionic
ion-searchbar,css-prop,--focus-ring-width,ionic
ion-searchbar,css-prop,--icon-color,ionic
ion-searchbar,css-prop,--icon-color,ios
ion-searchbar,css-prop,--icon-color,md
Expand Down
138 changes: 112 additions & 26 deletions core/src/components/searchbar/searchbar.ionic.scss
Original file line number Diff line number Diff line change
@@ -1,46 +1,63 @@
@use "searchbar.common";
@use "../../themes/ionic/ionic.globals.scss" as globals;
@use "searchbar.common";

// Ionic Searchbar
// --------------------------------------------------

:host {
/**
* @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.$ionic-color-neutral-100};
--border-radius: #{globals.$ionic-border-radius-800};
--border-radius: #{globals.$ionic-border-radius-400};
--box-shadow: none;
--cancel-button-color: #{globals.$ionic-color-neutral-800};
--clear-button-color: #{globals.$ionic-color-neutral-800};
--color: #{globals.$ionic-color-neutral-800};
--clear-button-color: #{globals.$ionic-color-neutral-1000};
--color: #{globals.$ionic-color-neutral-1200};
--icon-color: #{globals.$ionic-color-neutral-800};
--placeholder-color: #{globals.$ionic-color-neutral-800};
--focus-ring-color: #{globals.$ionic-state-focus-1};
--focus-ring-width: #{globals.$ionic-border-size-050};

@include globals.typography(globals.$ionic-body-md-regular);
@include globals.padding(0);

min-height: globals.$ionic-scale-1000;

contain: content;
}

.searchbar-input-container {
min-height: globals.$ionic-scale-1000;
}

// Searchbar Search Icon
// -----------------------------------------

.searchbar-search-icon {
display: none;
// Position is based on the size of the search icon.
@include globals.position(globals.$ionic-scale-400, null, null, globals.$ionic-scale-400);

width: globals.$ionic-scale-400;
height: globals.$ionic-scale-400;
}

// Searchbar Input Field
// -----------------------------------------

.searchbar-input {
@include globals.padding(globals.$ionic-space-300);

height: 100%;

font-size: globals.$ionic-font-size-350;
font-weight: globals.$ionic-font-weight-regular;
/**
* Padding start is based on
* desired padding from design,
* the size of the search icon,
* and the gap between the icon and the input.
*
* Padding end is based on
* desired padding from design,
* the size of the clear icon,
* and the gap between the icon and the input.
*/
@include globals.padding(
globals.$ionic-space-300,
calc(globals.$ionic-space-400 + globals.$ionic-scale-400 + globals.$ionic-space-200),
globals.$ionic-space-300,
calc(globals.$ionic-space-400 + globals.$ionic-scale-400 + globals.$ionic-space-200)
);

min-height: globals.$ionic-scale-1200;

contain: strict;
}
Expand All @@ -49,25 +66,94 @@
// -----------------------------------------

.searchbar-clear-button {
@include globals.position(50%, globals.$ionic-space-200, null, null);
// Position is based on the size of the clear icon.
@include globals.position(globals.$ionic-scale-400, globals.$ionic-scale-400, null, null);

position: absolute;
width: globals.$ionic-scale-400;
height: globals.$ionic-scale-400;

width: globals.$ionic-scale-600;
height: globals.$ionic-scale-600;
background-color: transparent;

font-size: globals.$ionic-scale-400;

contain: strict;
}

transform: translateY(-50%);
// Searchbar Cancel Icon
// -----------------------------------------

.searchbar-cancel-button {
/**
* The left edge of the cancel button
* should align with the left edge
* of the back button if the searchbar
* is used in a toolbar.
*/
@include globals.position(0, null, null, 9px);

background-color: transparent;

font-size: globals.$ionic-font-size-400;
}

contain: strict;
// Searchbar Search & Clear Icon & Cancel Icon
// -----------------------------------------

.searchbar-search-icon,
.searchbar-clear-button,
.searchbar-cancel-button {
position: absolute;
}

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

.searchbar-clear-button:focus-visible,
.searchbar-cancel-button:focus-visible ion-icon {
@include globals.border-radius(globals.$ionic-border-radius-100);

outline: globals.$ionic-border-size-050 globals.$ionic-border-style-solid globals.$ionic-state-focus-1;

opacity: 1;
}

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

:host-context(ion-toolbar) {
min-height: globals.$ionic-scale-1000;
min-height: globals.$ionic-scale-1200;
}

// Searchbar States
// --------------------------------------------------

/* Hover */
:host(:hover) {
--background: #{globals.$ionic-color-neutral-200};
}

/* Focus */
:host(.searchbar-has-focus) .searchbar-input {
outline: var(--focus-ring-width) globals.$ionic-border-style-solid var(--focus-ring-color);
}

:host(.searchbar-has-focus) .searchbar-search-icon,
:host(.searchbar-has-focus) .searchbar-cancel-button,
:host(.searchbar-should-show-cancel) .searchbar-cancel-button {
display: block;
}

:host(.searchbar-has-focus) .searchbar-cancel-button + .searchbar-search-icon,
:host(.searchbar-should-show-cancel) .searchbar-cancel-button + .searchbar-search-icon {
display: none;
}

/* Disabled */
:host(.searchbar-disabled) {
--color: #{globals.$ionic-color-neutral-500};
--icon-color: #{globals.$ionic-color-neutral-500};
--placeholder-color: #{globals.$ionic-color-neutral-500};

cursor: default;
pointer-events: none;
}
14 changes: 8 additions & 6 deletions core/src/components/searchbar/test/basic/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,18 @@
<script src="../../../../../scripts/testing/scripts.js"></script>
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>

<style>
/* TODO(ROU-11256): Remove the border that is added through the testing styling */
ion-searchbar button {
border: none;
padding: initial;
}
</style>
</head>

<body>
<ion-app>
<ion-header>
<ion-toolbar>
<ion-title>Searchbar - Basic</ion-title>
</ion-toolbar>
</ion-header>

<ion-content id="content">
<h5 class="ion-padding-start ion-padding-top">Search - Default</h5>
<ion-searchbar id="basic" value="test" type="tel" show-cancel-button="focus" debounce="500"> </ion-searchbar>
Expand Down
17 changes: 2 additions & 15 deletions core/src/components/searchbar/test/basic/searchbar.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
});
});

configs().forEach(({ title, screenshot, config }) => {
configs({ modes: ['md', 'ios', 'ionic-md'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('searchbar: rendering'), () => {
test('should render searchbar', async ({ page }) => {
await page.setContent(
Expand Down Expand Up @@ -143,19 +143,6 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
await expect(searchbar).toHaveScreenshot(screenshot(`searchbar-color`));
});

test('should render disabled searchbar', async ({ page }) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved this to the states test folder.

await page.setContent(
`
<ion-searchbar disabled="true"></ion-searchbar>
`,
config
);

const searchbar = page.locator('ion-searchbar');

await expect(searchbar).toHaveScreenshot(screenshot(`searchbar-disabled`));
});

test('should render custom search icon', async ({ page }) => {
await page.setContent(
`
Expand Down Expand Up @@ -199,7 +186,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, screenshot, c
});
});

configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
configs({ modes: ['md', 'ionic-md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('searchbar: cancel button alignment'), () => {
test('should align with the back button when used in a toolbar', async ({ page }, testInfo) => {
testInfo.annotations.push({
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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.
86 changes: 86 additions & 0 deletions core/src/components/searchbar/test/states/searchbar.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';

/**
* This behavior does not vary across directions.
*/
configs({ modes: ['md', 'ios', 'ionic-md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('searchbar: disabled'), () => {
test('should render disabled searchbar', async ({ page }) => {
await page.setContent(
`
<ion-searchbar disabled="true"></ion-searchbar>
`,
config
);

const searchbar = page.locator('ion-searchbar');

await expect(searchbar).toHaveScreenshot(screenshot(`searchbar-state-disabled`));
});
});
});

/**
* 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, screenshot, config }) => {
test.describe(title('searchbar: focused'), () => {
test('should render focus ring on the component', async ({ page, pageUtils }) => {
await page.setContent(
`
<style>
/* Add padding to the container to prevent the focus ring from being clipped */
#container {
padding: 5px;
}
</style>

<div id="container">
<ion-searchbar></ion-searchbar>
</div>
`,
config
);

await pageUtils.pressKeys('Tab'); // Focused on the input

const container = page.locator('#container');

await expect(container).toHaveScreenshot(screenshot(`searchbar-state-focused`));
});

test('should render focus ring on the cancel button', async ({ page, pageUtils }) => {
await page.setContent(
`
<ion-searchbar show-cancel-button="always"></ion-searchbar>
`,
config
);

await pageUtils.pressKeys('Tab'); // Focused on the input
await pageUtils.pressKeys('Tab'); // Focused on the cancel button

const searchbar = page.locator('ion-searchbar');

await expect(searchbar).toHaveScreenshot(screenshot(`searchbar-state-focused-cancel-button`));
});

test('should render focus ring on the clear button', async ({ page, pageUtils }) => {
await page.setContent(
`
<ion-searchbar show-clear-button="always" value="Filled text"></ion-searchbar>
`,
config
);

await pageUtils.pressKeys('Tab'); // Focused on the input
await pageUtils.pressKeys('Tab'); // Focused on the clear button

const searchbar = page.locator('ion-searchbar');

await expect(searchbar).toHaveScreenshot(screenshot(`searchbar-state-focused-clear-button`));
});
});
});
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