Skip to content

Commit fc552ad

Browse files
authored
feat(searchbar): add shapes for ionic theme (#30210)
1 parent a314950 commit fc552ad

17 files changed

+119
-2
lines changed

core/api.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1886,6 +1886,7 @@ ion-searchbar,prop,mode,"ios" | "md",undefined,false,false
18861886
ion-searchbar,prop,name,string,this.inputId,false,false
18871887
ion-searchbar,prop,placeholder,string,'Search',false,false
18881888
ion-searchbar,prop,searchIcon,string | undefined,undefined,false,false
1889+
ion-searchbar,prop,shape,"rectangular" | "round" | "soft" | undefined,undefined,false,false
18891890
ion-searchbar,prop,showCancelButton,"always" | "focus" | "never",'never',false,false
18901891
ion-searchbar,prop,showClearButton,"always" | "focus" | "never",'always',false,false
18911892
ion-searchbar,prop,spellcheck,boolean,false,false,false

core/src/components.d.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3107,6 +3107,10 @@ export namespace Components {
31073107
* Sets focus on the native `input` in `ion-searchbar`. Use this method instead of the global `input.focus()`. Developers who wish to focus an input when a page enters should call `setFocus()` in the `ionViewDidEnter()` lifecycle method. Developers who wish to focus an input when an overlay is presented should call `setFocus` after `didPresent` has resolved. See [managing focus](/docs/developing/managing-focus) for more information.
31083108
*/
31093109
"setFocus": () => Promise<void>;
3110+
/**
3111+
* Set to `"soft"` for a searchbar with slightly rounded corners, `"round"` for a searchbar with fully rounded corners, or `"rectangular"` for a searchbar without rounded corners. Defaults to `"round"` for the ionic theme, and `undefined` for all other themes.
3112+
*/
3113+
"shape"?: 'soft' | 'round' | 'rectangular';
31103114
/**
31113115
* Sets the behavior for the cancel button. Defaults to `"never"`. Setting to `"focus"` shows the cancel button on focus. Setting to `"never"` hides the cancel button. Setting to `"always"` shows the cancel button regardless of focus state.
31123116
*/
@@ -8514,6 +8518,10 @@ declare namespace LocalJSX {
85148518
* The icon to use as the search icon. Defaults to `"search-outline"` in the `"ios"` theme and `"search-sharp"` in the `"md"` and `"ionic"` themes.
85158519
*/
85168520
"searchIcon"?: string;
8521+
/**
8522+
* Set to `"soft"` for a searchbar with slightly rounded corners, `"round"` for a searchbar with fully rounded corners, or `"rectangular"` for a searchbar without rounded corners. Defaults to `"round"` for the ionic theme, and `undefined` for all other themes.
8523+
*/
8524+
"shape"?: 'soft' | 'round' | 'rectangular';
85178525
/**
85188526
* Sets the behavior for the cancel button. Defaults to `"never"`. Setting to `"focus"` shows the cancel button on focus. Setting to `"never"` hides the cancel button. Setting to `"always"` shows the cancel button regardless of focus state.
85198527
*/

core/src/components/searchbar/searchbar.ionic.scss

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,18 @@
157157
cursor: default;
158158
pointer-events: none;
159159
}
160+
161+
// Searchbar Shapes
162+
// --------------------------------------------------
163+
164+
:host(.searchbar-shape-soft) {
165+
--border-radius: #{globals.$ion-border-radius-200};
166+
}
167+
168+
:host(.searchbar-shape-round) {
169+
--border-radius: #{globals.$ion-border-radius-400};
170+
}
171+
172+
:host(.searchbar-shape-rectangular) {
173+
--border-radius: #{globals.$ion-border-radius-0};
174+
}

core/src/components/searchbar/searchbar.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,14 @@ export class Searchbar implements ComponentInterface {
216216
*/
217217
@Prop({ mutable: true }) value?: string | null = '';
218218

219+
/**
220+
* Set to `"soft"` for a searchbar with slightly rounded corners,
221+
* `"round"` for a searchbar with fully rounded corners,
222+
* or `"rectangular"` for a searchbar without rounded corners.
223+
* Defaults to `"round"` for the ionic theme, and `undefined` for all other themes.
224+
*/
225+
@Prop() shape?: 'soft' | 'round' | 'rectangular';
226+
219227
/**
220228
* Emitted when the `value` of the `ion-searchbar` element has changed.
221229
*/
@@ -612,6 +620,22 @@ export class Searchbar implements ComponentInterface {
612620
return true;
613621
}
614622

623+
private getShape() {
624+
const theme = getIonTheme(this);
625+
const { shape } = this;
626+
627+
// TODO(ROU-11677): Remove theme check when shapes are defined for all themes.
628+
if (theme !== 'ionic') {
629+
return undefined;
630+
}
631+
632+
if (shape === undefined) {
633+
return 'round';
634+
}
635+
636+
return shape;
637+
}
638+
615639
/**
616640
* Get the icon to use for the clear icon.
617641
* If an icon is set on the component, use that.
@@ -698,6 +722,7 @@ export class Searchbar implements ComponentInterface {
698722
const animated = this.animated && config.getBoolean('animated', true);
699723
const theme = getIonTheme(this);
700724
const shouldShowCancelButton = this.shouldShowCancelButton();
725+
const shape = this.getShape();
701726

702727
const cancelButton = this.showCancelButton !== 'never' && (
703728
<button
@@ -734,6 +759,7 @@ export class Searchbar implements ComponentInterface {
734759
'searchbar-has-focus': this.focused,
735760
'searchbar-should-show-clear': this.shouldShowClearButton(),
736761
'searchbar-should-show-cancel': this.shouldShowCancelButton(),
762+
[`searchbar-shape-${shape}`]: shape !== undefined,
737763
})}
738764
>
739765
<div class="searchbar-input-container">
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<!DOCTYPE html>
2+
<html lang="en" dir="ltr">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<title>Searchbar - Shape</title>
6+
<meta
7+
name="viewport"
8+
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
9+
/>
10+
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
11+
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
12+
<script src="../../../../../scripts/testing/scripts.js"></script>
13+
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
14+
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
15+
</head>
16+
17+
<body>
18+
<ion-app>
19+
<ion-content class="ion-padding">
20+
<h5 class="ion-padding-start ion-padding-top">Search - Default</h5>
21+
<ion-searchbar></ion-searchbar>
22+
23+
<h5 class="ion-padding-start ion-padding-top">Search - Round</h5>
24+
<ion-searchbar shape="round"></ion-searchbar>
25+
26+
<h5 class="ion-padding-start ion-padding-top">Search - Soft</h5>
27+
<ion-searchbar shape="soft"></ion-searchbar>
28+
29+
<h5 class="ion-padding-start ion-padding-top">Search - Rectangular</h5>
30+
<ion-searchbar shape="rectangular"></ion-searchbar>
31+
</ion-content>
32+
</ion-app>
33+
</body>
34+
</html>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { expect } from '@playwright/test';
2+
import { configs, test } from '@utils/test/playwright';
3+
4+
/**
5+
* This behavior only applies to the `ionic` theme.
6+
* This behavior does not vary across directions.
7+
*/
8+
configs({ directions: ['ltr'], modes: ['ionic-md'] }).forEach(({ title, screenshot, config }) => {
9+
test.describe(title('searchbar: shape'), () => {
10+
['soft', 'round', 'rectangular'].forEach((shape) => {
11+
test(`${shape} - should not have visual regressions`, async ({ page }) => {
12+
await page.setContent(
13+
`
14+
<style>
15+
/* Background styles to show the border radius */
16+
:root {
17+
background: #000;
18+
}
19+
</style>
20+
21+
<ion-searchbar shape="${shape}"></ion-searchbar>
22+
`,
23+
config
24+
);
25+
26+
const searchbar = page.locator('ion-searchbar');
27+
28+
await expect(searchbar).toHaveScreenshot(screenshot(`searchbar-shape-${shape}`));
29+
});
30+
});
31+
});
32+
});
Loading
Loading
Loading
Loading

0 commit comments

Comments
 (0)