feat(select): add sizes for ionic theme (#30018)

Co-authored-by: Brandy Carney <brandyscarney@users.noreply.github.com>
This commit is contained in:
Maria Hutt
2024-11-15 10:52:41 -08:00
committed by GitHub
parent bc3d30c3d2
commit 5bf48cb57a
17 changed files with 155 additions and 4 deletions

View File

@ -2065,6 +2065,7 @@ ion-select,prop,okText,string,'OK',false,false
ion-select,prop,placeholder,string | undefined,undefined,false,false
ion-select,prop,selectedText,null | string | undefined,undefined,false,false
ion-select,prop,shape,"rectangular" | "round" | "soft" | undefined,undefined,false,false
ion-select,prop,size,"large" | "medium" | "small" | undefined,undefined,false,false
ion-select,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-select,prop,toggleIcon,string | undefined,undefined,false,false
ion-select,prop,value,any,undefined,false,false

View File

@ -3283,6 +3283,10 @@ export namespace Components {
* Set to `"soft"` for a select with slightly rounded corners, `"round"` for a select with fully rounded corners, or `"rectangular"` for a select without rounded corners. Defaults to `"round"` for the `"ionic"` theme, undefined for all other themes.
*/
"shape"?: 'soft' | 'round' | 'rectangular';
/**
* The size of the select. If "large" it will increase the height of the select, while "small" and "medium" provide progressively smaller heights. Defaults to `"medium"` for the ionic theme, and undefined for all other themes.
*/
"size"?: 'small' | 'medium' | 'large';
/**
* The theme determines the visual appearance of the component.
*/
@ -8707,6 +8711,10 @@ declare namespace LocalJSX {
* Set to `"soft"` for a select with slightly rounded corners, `"round"` for a select with fully rounded corners, or `"rectangular"` for a select without rounded corners. Defaults to `"round"` for the `"ionic"` theme, undefined for all other themes.
*/
"shape"?: 'soft' | 'round' | 'rectangular';
/**
* The size of the select. If "large" it will increase the height of the select, while "small" and "medium" provide progressively smaller heights. Defaults to `"medium"` for the ionic theme, and undefined for all other themes.
*/
"size"?: 'small' | 'medium' | 'large';
/**
* The theme determines the visual appearance of the component.
*/

View File

@ -84,8 +84,6 @@
position: relative;
height: globals.$ion-scale-1200;
background: var(--background);
box-sizing: border-box;
@ -197,3 +195,18 @@
:host(.select-shape-rectangular) {
--border-radius: #{globals.$ion-border-radius-0};
}
// Sizes
// ----------------------------------------------------------------
:host(.select-size-small) .select-wrapper-inner {
height: globals.$ion-scale-1000;
}
:host(.select-size-medium) .select-wrapper-inner {
height: globals.$ion-scale-1200;
}
:host(.select-size-large) .select-wrapper-inner {
height: globals.$ion-scale-1400;
}

View File

@ -204,6 +204,14 @@ export class Select implements ComponentInterface {
*/
@Prop({ mutable: true }) value?: any | null;
/**
* The size of the select. If "large" it will increase the height of the select, while
* "small" and "medium" provide progressively smaller heights.
*
* Defaults to `"medium"` for the ionic theme, and undefined for all other themes.
*/
@Prop() size?: 'small' | 'medium' | 'large';
/**
* Emitted when the value has changed.
*
@ -820,6 +828,22 @@ export class Select implements ComponentInterface {
this.ionBlur.emit();
};
private getSize(): string | undefined {
const theme = getIonTheme(this);
const { size } = this;
// TODO(ROU-11370): Remove theme check when sizes are defined for all themes.
if (theme !== 'ionic') {
return undefined;
}
if (size === undefined) {
return 'medium';
}
return size;
}
private renderLabel() {
const { label } = this;
@ -1071,6 +1095,7 @@ export class Select implements ComponentInterface {
const justifyEnabled = !hasFloatingOrStackedLabel && justify !== undefined;
const rtl = isRTL(el) ? 'rtl' : 'ltr';
const inItem = hostContext('ion-item', this.el);
const size = this.getSize();
const shouldRenderHighlight = theme === 'md' && fill !== 'outline' && !inItem;
const hasValue = this.hasValue();
@ -1117,6 +1142,7 @@ export class Select implements ComponentInterface {
[`select-justify-${justify}`]: justifyEnabled,
[`select-shape-${shape}`]: shape !== undefined,
[`select-label-placement-${labelPlacement}`]: true,
[`select-size-${size}`]: size !== undefined,
})}
>
<label class="select-wrapper" id="select-label">

View File

@ -0,0 +1,69 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Select - Size</title>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
<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>
h2 {
font-size: 12px;
font-weight: normal;
color: #6f7378;
margin-top: 10px;
}
</style>
</head>
<body>
<ion-app>
<ion-header>
<ion-toolbar>
<ion-title>Select - Size</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<div class="grid">
<div class="grid-item">
<h2>Default</h2>
<ion-select fill="outline" label="Label" label-placement="stacked" value="filledText">
<ion-select-option value="filledText">Filled text</ion-select-option>
</ion-select>
</div>
<div class="grid-item">
<h2>Small</h2>
<ion-select size="small" fill="outline" label="Label" label-placement="stacked" value="filledText">
<ion-select-option value="filledText">Filled text</ion-select-option>
</ion-select>
</div>
<div class="grid-item">
<h2>Medium</h2>
<ion-select size="medium" fill="outline" label="Label" label-placement="stacked" value="filledText">
<ion-select-option value="filledText">Filled text</ion-select-option>
</ion-select>
</div>
<div class="grid-item">
<h2>Large</h2>
<ion-select size="large" fill="outline" label="Label" label-placement="stacked" value="filledText">
<ion-select-option value="filledText">Filled text</ion-select-option>
</ion-select>
</div>
</div>
</ion-content>
</ion-app>
</body>
</html>

View File

@ -0,0 +1,33 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
/**
* This behavior does not vary across directions.
* This behavior is only in the `ionic` theme.
*/
configs({ modes: ['ionic-md'], directions: ['ltr'] }).forEach(({ config, screenshot, title }) => {
test.describe(title('select: size'), () => {
['small', 'medium', 'large'].forEach((size) => {
test(`${size} - should not have visual regressions`, async ({ page }) => {
await page.setContent(
`
<ion-select
size="${size}"
fill="outline"
label="Label"
label-placement="stacked"
value="filledText"
>
<ion-select-option value="filledText">Filled text</ion-select-option>
</ion-select>
`,
config
);
const select = page.locator('ion-select');
await expect(select).toHaveScreenshot(screenshot(`select-size-${size}`));
});
});
});
});

View File

@ -2066,7 +2066,7 @@ export declare interface IonSegmentView extends Components.IonSegmentView {
@ProxyCmp({
inputs: ['cancelText', 'color', 'compareWith', 'disabled', 'expandedIcon', 'fill', 'interface', 'interfaceOptions', 'justify', 'label', 'labelPlacement', 'mode', 'multiple', 'name', 'okText', 'placeholder', 'selectedText', 'shape', 'theme', 'toggleIcon', 'value'],
inputs: ['cancelText', 'color', 'compareWith', 'disabled', 'expandedIcon', 'fill', 'interface', 'interfaceOptions', 'justify', 'label', 'labelPlacement', 'mode', 'multiple', 'name', 'okText', 'placeholder', 'selectedText', 'shape', 'size', 'theme', 'toggleIcon', 'value'],
methods: ['open']
})
@Component({
@ -2074,7 +2074,7 @@ export declare interface IonSegmentView extends Components.IonSegmentView {
changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['cancelText', 'color', 'compareWith', 'disabled', 'expandedIcon', 'fill', 'interface', 'interfaceOptions', 'justify', 'label', 'labelPlacement', 'mode', 'multiple', 'name', 'okText', 'placeholder', 'selectedText', 'shape', 'theme', 'toggleIcon', 'value'],
inputs: ['cancelText', 'color', 'compareWith', 'disabled', 'expandedIcon', 'fill', 'interface', 'interfaceOptions', 'justify', 'label', 'labelPlacement', 'mode', 'multiple', 'name', 'okText', 'placeholder', 'selectedText', 'shape', 'size', 'theme', 'toggleIcon', 'value'],
})
export class IonSelect {
protected el: HTMLElement;

View File

@ -800,6 +800,7 @@ export const IonSelect = /*@__PURE__*/ defineContainer<JSX.IonSelect, JSX.IonSel
'expandedIcon',
'shape',
'value',
'size',
'ionChange',
'ionCancel',
'ionDismiss',