Merge branch 'next' into ROU-4822

This commit is contained in:
João Ferreira
2024-03-28 14:36:26 +00:00
committed by GitHub
133 changed files with 1294 additions and 106 deletions

View File

@ -30,6 +30,7 @@ This is a comprehensive list of the breaking changes introduced in the major ver
- [Progress bar](#version-8x-progress-bar) - [Progress bar](#version-8x-progress-bar)
- [Radio](#version-8x-radio) - [Radio](#version-8x-radio)
- [Range](#version-8x-range) - [Range](#version-8x-range)
- [Searchbar](#version-8x-searchbar)
- [Select](#version-8x-select) - [Select](#version-8x-select)
- [Textarea](#version-8x-textarea) - [Textarea](#version-8x-textarea)
- [Toggle](#version-8x-toggle) - [Toggle](#version-8x-toggle)
@ -264,6 +265,10 @@ For more information on styling toast buttons, refer to the [Toast Theming docum
- The `legacy` property and support for the legacy syntax, which involved placing an `ion-range` inside of an `ion-item` with an `ion-label`, have been removed. Ionic will also no longer attempt to automatically associate form controls with sibling `<label>` elements as these label elements are now used inside the form control. Developers should provide a label (either visible text or `aria-label`) directly to the form control. For more information on migrating from the legacy range syntax, refer to the [Range documentation](https://ionicframework.com/docs/api/range#migrating-from-legacy-range-syntax). - The `legacy` property and support for the legacy syntax, which involved placing an `ion-range` inside of an `ion-item` with an `ion-label`, have been removed. Ionic will also no longer attempt to automatically associate form controls with sibling `<label>` elements as these label elements are now used inside the form control. Developers should provide a label (either visible text or `aria-label`) directly to the form control. For more information on migrating from the legacy range syntax, refer to the [Range documentation](https://ionicframework.com/docs/api/range#migrating-from-legacy-range-syntax).
<h4 id="version-8x-searchbar">Searchbar</h4>
- The `autocapitalize` property now defaults to `'off'`.
<h4 id="version-8x-select">Select</h4> <h4 id="version-8x-select">Select</h4>
- The `legacy` property and support for the legacy syntax, which involved placing an `ion-select` inside of an `ion-item` with an `ion-label`, have been removed. Ionic will also no longer attempt to automatically associate form controls with sibling `<label>` elements as these label elements are now used inside the form control. Developers should provide a label (either visible text or `aria-label`) directly to the form control. For more information on migrating from the legacy select syntax, refer to the [Select documentation](https://ionicframework.com/docs/api/select#migrating-from-legacy-select-syntax). - The `legacy` property and support for the legacy syntax, which involved placing an `ion-select` inside of an `ion-item` with an `ion-label`, have been removed. Ionic will also no longer attempt to automatically associate form controls with sibling `<label>` elements as these label elements are now used inside the form control. Developers should provide a label (either visible text or `aria-label`) directly to the form control. For more information on migrating from the legacy select syntax, refer to the [Select documentation](https://ionicframework.com/docs/api/select#migrating-from-legacy-select-syntax).

View File

@ -234,8 +234,8 @@ ion-button,prop,mode,"ios" | "md",undefined,false,false
ion-button,prop,rel,string | undefined,undefined,false,false ion-button,prop,rel,string | undefined,undefined,false,false
ion-button,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false ion-button,prop,routerAnimation,((baseEl: any, opts?: any) => Animation) | undefined,undefined,false,false
ion-button,prop,routerDirection,"back" | "forward" | "root",'forward',false,false ion-button,prop,routerDirection,"back" | "forward" | "root",'forward',false,false
ion-button,prop,shape,"round" | undefined,undefined,false,true ion-button,prop,shape,"rectangular" | "round" | undefined,undefined,false,true
ion-button,prop,size,"default" | "large" | "small" | undefined,undefined,false,true ion-button,prop,size,"default" | "large" | "small" | "xlarge" | "xsmall" | undefined,undefined,false,true
ion-button,prop,strong,boolean,false,false,false ion-button,prop,strong,boolean,false,false,false
ion-button,prop,target,string | undefined,undefined,false,false ion-button,prop,target,string | undefined,undefined,false,false
ion-button,prop,theme,"ios" | "md" | "ionic",undefined,false,false ion-button,prop,theme,"ios" | "md" | "ionic",undefined,false,false
@ -607,7 +607,7 @@ ion-input,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secon
ion-input,prop,counter,boolean,false,false,false ion-input,prop,counter,boolean,false,false,false
ion-input,prop,counterFormatter,((inputLength: number, maxLength: number) => string) | undefined,undefined,false,false ion-input,prop,counterFormatter,((inputLength: number, maxLength: number) => string) | undefined,undefined,false,false
ion-input,prop,debounce,number | undefined,undefined,false,false ion-input,prop,debounce,number | undefined,undefined,false,false
ion-input,prop,disabled,boolean,false,false,false ion-input,prop,disabled,boolean,false,false,true
ion-input,prop,enterkeyhint,"done" | "enter" | "go" | "next" | "previous" | "search" | "send" | undefined,undefined,false,false ion-input,prop,enterkeyhint,"done" | "enter" | "go" | "next" | "previous" | "search" | "send" | undefined,undefined,false,false
ion-input,prop,errorText,string | undefined,undefined,false,false ion-input,prop,errorText,string | undefined,undefined,false,false
ion-input,prop,fill,"outline" | "solid" | undefined,undefined,false,false ion-input,prop,fill,"outline" | "solid" | undefined,undefined,false,false
@ -624,7 +624,7 @@ ion-input,prop,multiple,boolean | undefined,undefined,false,false
ion-input,prop,name,string,this.inputId,false,false ion-input,prop,name,string,this.inputId,false,false
ion-input,prop,pattern,string | undefined,undefined,false,false ion-input,prop,pattern,string | undefined,undefined,false,false
ion-input,prop,placeholder,string | undefined,undefined,false,false ion-input,prop,placeholder,string | undefined,undefined,false,false
ion-input,prop,readonly,boolean,false,false,false ion-input,prop,readonly,boolean,false,false,true
ion-input,prop,required,boolean,false,false,false ion-input,prop,required,boolean,false,false,false
ion-input,prop,shape,"round" | undefined,undefined,false,false ion-input,prop,shape,"round" | undefined,undefined,false,false
ion-input,prop,spellcheck,boolean,false,false,false ion-input,prop,spellcheck,boolean,false,false,false
@ -657,6 +657,12 @@ ion-input,css-prop,--placeholder-font-style
ion-input,css-prop,--placeholder-font-weight ion-input,css-prop,--placeholder-font-weight
ion-input,css-prop,--placeholder-opacity ion-input,css-prop,--placeholder-opacity
ion-input-password-toggle,shadow
ion-input-password-toggle,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-input-password-toggle,prop,hideIcon,string | undefined,undefined,false,false
ion-input-password-toggle,prop,mode,"ios" | "md",undefined,false,false
ion-input-password-toggle,prop,showIcon,string | undefined,undefined,false,false
ion-item,shadow ion-item,shadow
ion-item,prop,button,boolean,false,false,false ion-item,prop,button,boolean,false,false,false
ion-item,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true ion-item,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
@ -1269,7 +1275,7 @@ ion-row,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-searchbar,scoped ion-searchbar,scoped
ion-searchbar,prop,animated,boolean,false,false,false ion-searchbar,prop,animated,boolean,false,false,false
ion-searchbar,prop,autocapitalize,string,undefined,true,false ion-searchbar,prop,autocapitalize,string,'off',false,false
ion-searchbar,prop,autocomplete,"name" | "email" | "tel" | "url" | "on" | "off" | "honorific-prefix" | "given-name" | "additional-name" | "family-name" | "honorific-suffix" | "nickname" | "username" | "new-password" | "current-password" | "one-time-code" | "organization-title" | "organization" | "street-address" | "address-line1" | "address-line2" | "address-line3" | "address-level4" | "address-level3" | "address-level2" | "address-level1" | "country" | "country-name" | "postal-code" | "cc-name" | "cc-given-name" | "cc-additional-name" | "cc-family-name" | "cc-number" | "cc-exp" | "cc-exp-month" | "cc-exp-year" | "cc-csc" | "cc-type" | "transaction-currency" | "transaction-amount" | "language" | "bday" | "bday-day" | "bday-month" | "bday-year" | "sex" | "tel-country-code" | "tel-national" | "tel-area-code" | "tel-local" | "tel-extension" | "impp" | "photo",'off',false,false ion-searchbar,prop,autocomplete,"name" | "email" | "tel" | "url" | "on" | "off" | "honorific-prefix" | "given-name" | "additional-name" | "family-name" | "honorific-suffix" | "nickname" | "username" | "new-password" | "current-password" | "one-time-code" | "organization-title" | "organization" | "street-address" | "address-line1" | "address-line2" | "address-line3" | "address-level4" | "address-level3" | "address-level2" | "address-level1" | "country" | "country-name" | "postal-code" | "cc-name" | "cc-given-name" | "cc-additional-name" | "cc-family-name" | "cc-number" | "cc-exp" | "cc-exp-month" | "cc-exp-year" | "cc-csc" | "cc-type" | "transaction-currency" | "transaction-amount" | "language" | "bday" | "bday-day" | "bday-month" | "bday-year" | "sex" | "tel-country-code" | "tel-national" | "tel-area-code" | "tel-local" | "tel-extension" | "impp" | "photo",'off',false,false
ion-searchbar,prop,autocorrect,"off" | "on",'off',false,false ion-searchbar,prop,autocorrect,"off" | "on",'off',false,false
ion-searchbar,prop,cancelButtonIcon,string,config.get('backButtonIcon', arrowBackSharp) as string,false,false ion-searchbar,prop,cancelButtonIcon,string,config.get('backButtonIcon', arrowBackSharp) as string,false,false

View File

@ -545,11 +545,11 @@ export namespace Components {
/** /**
* Set to `"round"` for a button with more rounded corners. * Set to `"round"` for a button with more rounded corners.
*/ */
"shape"?: 'round'; "shape"?: 'round' | 'rectangular';
/** /**
* Set to `"small"` for a button with less height and padding, to `"default"` for a button with the default height and padding, or to `"large"` for a button with more height and padding. By default the size is unset, unless the button is inside of an item, where the size is `"small"` by default. Set the size to `"default"` inside of an item to make it a standard size button. * Set to `"small"` for a button with less height and padding, to `"default"` for a button with the default height and padding, or to `"large"` for a button with more height and padding. By default the size is unset, unless the button is inside of an item, where the size is `"small"` by default. Set the size to `"default"` inside of an item to make it a standard size button.
*/ */
"size"?: 'small' | 'default' | 'large'; "size"?: 'xsmall' | 'small' | 'default' | 'large' | 'xlarge';
/** /**
* If `true`, activates a button with a heavier font weight. * If `true`, activates a button with a heavier font weight.
*/ */
@ -1483,6 +1483,25 @@ export namespace Components {
*/ */
"value"?: string | number | null; "value"?: string | number | null;
} }
interface IonInputPasswordToggle {
/**
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
*/
"color"?: Color;
/**
* The icon that can be used to represent hiding a password. If not set, the "eyeOff" Ionicon will be used.
*/
"hideIcon"?: string;
/**
* The mode determines which platform styles to use.
*/
"mode"?: "ios" | "md";
/**
* The icon that can be used to represent showing a password. If not set, the "eye" Ionicon will be used.
*/
"showIcon"?: string;
"type": TextFieldTypes;
}
interface IonItem { interface IonItem {
/** /**
* If `true`, a button tag will be rendered and the item will be tappable. * If `true`, a button tag will be rendered and the item will be tappable.
@ -4335,6 +4354,12 @@ declare global {
prototype: HTMLIonInputElement; prototype: HTMLIonInputElement;
new (): HTMLIonInputElement; new (): HTMLIonInputElement;
}; };
interface HTMLIonInputPasswordToggleElement extends Components.IonInputPasswordToggle, HTMLStencilElement {
}
var HTMLIonInputPasswordToggleElement: {
prototype: HTMLIonInputPasswordToggleElement;
new (): HTMLIonInputPasswordToggleElement;
};
interface HTMLIonItemElement extends Components.IonItem, HTMLStencilElement { interface HTMLIonItemElement extends Components.IonItem, HTMLStencilElement {
} }
var HTMLIonItemElement: { var HTMLIonItemElement: {
@ -5159,6 +5184,7 @@ declare global {
"ion-infinite-scroll": HTMLIonInfiniteScrollElement; "ion-infinite-scroll": HTMLIonInfiniteScrollElement;
"ion-infinite-scroll-content": HTMLIonInfiniteScrollContentElement; "ion-infinite-scroll-content": HTMLIonInfiniteScrollContentElement;
"ion-input": HTMLIonInputElement; "ion-input": HTMLIonInputElement;
"ion-input-password-toggle": HTMLIonInputPasswordToggleElement;
"ion-item": HTMLIonItemElement; "ion-item": HTMLIonItemElement;
"ion-item-divider": HTMLIonItemDividerElement; "ion-item-divider": HTMLIonItemDividerElement;
"ion-item-group": HTMLIonItemGroupElement; "ion-item-group": HTMLIonItemGroupElement;
@ -5747,11 +5773,11 @@ declare namespace LocalJSX {
/** /**
* Set to `"round"` for a button with more rounded corners. * Set to `"round"` for a button with more rounded corners.
*/ */
"shape"?: 'round'; "shape"?: 'round' | 'rectangular';
/** /**
* Set to `"small"` for a button with less height and padding, to `"default"` for a button with the default height and padding, or to `"large"` for a button with more height and padding. By default the size is unset, unless the button is inside of an item, where the size is `"small"` by default. Set the size to `"default"` inside of an item to make it a standard size button. * Set to `"small"` for a button with less height and padding, to `"default"` for a button with the default height and padding, or to `"large"` for a button with more height and padding. By default the size is unset, unless the button is inside of an item, where the size is `"small"` by default. Set the size to `"default"` inside of an item to make it a standard size button.
*/ */
"size"?: 'small' | 'default' | 'large'; "size"?: 'xsmall' | 'small' | 'default' | 'large' | 'xlarge';
/** /**
* If `true`, activates a button with a heavier font weight. * If `true`, activates a button with a heavier font weight.
*/ */
@ -6713,6 +6739,25 @@ declare namespace LocalJSX {
*/ */
"value"?: string | number | null; "value"?: string | number | null;
} }
interface IonInputPasswordToggle {
/**
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
*/
"color"?: Color;
/**
* The icon that can be used to represent hiding a password. If not set, the "eyeOff" Ionicon will be used.
*/
"hideIcon"?: string;
/**
* The mode determines which platform styles to use.
*/
"mode"?: "ios" | "md";
/**
* The icon that can be used to represent showing a password. If not set, the "eye" Ionicon will be used.
*/
"showIcon"?: string;
"type"?: TextFieldTypes;
}
interface IonItem { interface IonItem {
/** /**
* If `true`, a button tag will be rendered and the item will be tappable. * If `true`, a button tag will be rendered and the item will be tappable.
@ -8145,7 +8190,7 @@ declare namespace LocalJSX {
/** /**
* Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user. Available options: `"off"`, `"none"`, `"on"`, `"sentences"`, `"words"`, `"characters"`. * Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user. Available options: `"off"`, `"none"`, `"on"`, `"sentences"`, `"words"`, `"characters"`.
*/ */
"autocapitalize": string; "autocapitalize"?: string;
/** /**
* Set the input's autocomplete property. * Set the input's autocomplete property.
*/ */
@ -9088,6 +9133,7 @@ declare namespace LocalJSX {
"ion-infinite-scroll": IonInfiniteScroll; "ion-infinite-scroll": IonInfiniteScroll;
"ion-infinite-scroll-content": IonInfiniteScrollContent; "ion-infinite-scroll-content": IonInfiniteScrollContent;
"ion-input": IonInput; "ion-input": IonInput;
"ion-input-password-toggle": IonInputPasswordToggle;
"ion-item": IonItem; "ion-item": IonItem;
"ion-item-divider": IonItemDivider; "ion-item-divider": IonItemDivider;
"ion-item-group": IonItemGroup; "ion-item-group": IonItemGroup;
@ -9186,6 +9232,7 @@ declare module "@stencil/core" {
"ion-infinite-scroll": LocalJSX.IonInfiniteScroll & JSXBase.HTMLAttributes<HTMLIonInfiniteScrollElement>; "ion-infinite-scroll": LocalJSX.IonInfiniteScroll & JSXBase.HTMLAttributes<HTMLIonInfiniteScrollElement>;
"ion-infinite-scroll-content": LocalJSX.IonInfiniteScrollContent & JSXBase.HTMLAttributes<HTMLIonInfiniteScrollContentElement>; "ion-infinite-scroll-content": LocalJSX.IonInfiniteScrollContent & JSXBase.HTMLAttributes<HTMLIonInfiniteScrollContentElement>;
"ion-input": LocalJSX.IonInput & JSXBase.HTMLAttributes<HTMLIonInputElement>; "ion-input": LocalJSX.IonInput & JSXBase.HTMLAttributes<HTMLIonInputElement>;
"ion-input-password-toggle": LocalJSX.IonInputPasswordToggle & JSXBase.HTMLAttributes<HTMLIonInputPasswordToggleElement>;
"ion-item": LocalJSX.IonItem & JSXBase.HTMLAttributes<HTMLIonItemElement>; "ion-item": LocalJSX.IonItem & JSXBase.HTMLAttributes<HTMLIonItemElement>;
"ion-item-divider": LocalJSX.IonItemDivider & JSXBase.HTMLAttributes<HTMLIonItemDividerElement>; "ion-item-divider": LocalJSX.IonItemDivider & JSXBase.HTMLAttributes<HTMLIonItemDividerElement>;
"ion-item-group": LocalJSX.IonItemGroup & JSXBase.HTMLAttributes<HTMLIonItemGroupElement>; "ion-item-group": LocalJSX.IonItemGroup & JSXBase.HTMLAttributes<HTMLIonItemGroupElement>;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,220 @@
@import "./button";
@import "./button.ionic.vars";
// Ionic Button
// -------------------------------------------------------------------------------
:host {
--border-radius: #{$button-ionic-border-radius};
--padding-bottom: var(--padding-top);
--padding-end: #{$button-ionic-padding-end};
--padding-start: var(--padding-end);
--padding-top: #{$button-ionic-padding-top};
--focus-ring-color: #9ec4fd;
--focus-ring-width: 2px;
position: relative;
min-height: #{$button-ionic-min-height};
font-size: #{$button-ionic-font-size};
// Target area
&::after {
@include position(50%, 0, null, 0);
position: absolute;
height: 100%;
min-height: px-to-rem(48);
transform: translateY(-50%);
content: "";
cursor: pointer;
z-index: 1;
}
::slotted(ion-icon[slot="start"]) {
@include margin-horizontal(null, px-to-rem(8));
}
::slotted(ion-icon[slot="end"]) {
@include margin-horizontal(px-to-rem(8), null);
}
}
// Button Sizes
// -------------------------------------------------------------------------------
/* Extra Small and Small Button */
:host(.button-xsmall),
:host(.button-small) {
::slotted(ion-icon[slot="start"]) {
@include margin-horizontal(null, px-to-rem(4));
}
::slotted(ion-icon[slot="end"]) {
@include margin-horizontal(px-to-rem(4), null);
}
}
/* Extra Small Button */
:host(.button-xsmall) {
--border-radius: #{$button-ionic-xsmall-border-radius};
--padding-top: #{$button-ionic-xsmall-padding-top};
--padding-end: #{$button-ionic-xsmall-padding-end};
min-height: #{$button-ionic-xsmall-min-height};
font-size: #{$button-ionic-xsmall-font-size};
}
/* Small Button */
:host(.button-small) {
--border-radius: #{$button-ionic-small-border-radius};
--padding-top: #{$button-ionic-small-padding-top};
--padding-end: #{$button-ionic-small-padding-end};
min-height: #{$button-ionic-small-min-height};
font-size: #{$button-ionic-small-font-size};
}
/* Large Button */
:host(.button-large) {
--padding-top: #{$button-ionic-large-padding-top};
--padding-end: #{$button-ionic-large-padding-end};
min-height: #{$button-ionic-large-min-height};
font-size: #{$button-ionic-large-font-size};
}
/* Extra Large Button */
:host(.button-xlarge) {
--padding-top: #{$button-ionic-xlarge-padding-top};
--padding-end: #{$button-ionic-xlarge-padding-end};
min-height: #{$button-ionic-xlarge-min-height};
font-size: #{$button-ionic-xlarge-font-size};
}
// Button with Icons
// -------------------------------------------------------------------------------
/* Button containing only an icon */
::slotted(ion-icon[slot="start"]),
::slotted(ion-icon[slot="end"]),
::slotted(ion-icon[slot="icon-only"]) {
font-size: 1em;
}
/* Button extra small */
:host(.button-has-icon-only.button-xsmall) {
--padding-end: #{$button-has-icon-only-padding-end-xsmall};
}
/* Button small */
:host(.button-has-icon-only.button-small) {
--padding-end: #{$button-has-icon-only-padding-end-small};
}
/* Default */
:host(.button-has-icon-only) {
--padding-end: #{$button-has-icon-only-padding-end};
}
/* Button large */
:host(.button-has-icon-only.button-large) {
--padding-end: #{$button-has-icon-only-padding-end-large};
}
/* Button extra large */
:host(.button-has-icon-only.button-xlarge) {
--padding-end: #{$button-has-icon-only-padding-end-xlarge};
}
// Button Shapes
// -------------------------------------------------------------------------------
// Button Shape Rectangular
// -------------------------------------------------------------------------------
:host(.button-rectangular) {
--border-radius: #{$button-ionic-rectangular-border};
}
// Button Shape Round
// -------------------------------------------------------------------------------
:host(.button-round) {
--border-radius: #{$button-ionic-round-border};
}
// Button Focused
// -------------------------------------------------------------------------------
// Only show the focus ring when the button is focused
:host(.ion-focused) .button-native {
outline: var(--focus-ring-width) solid var(--focus-ring-color);
outline-offset: 2px;
}
// Fill Solid Button
// -------------------------------------------------------------------------------
:host(.button-solid) {
--background-activated: #{ion-color(primary, shade)};
}
// Fill Outline Button
// --------------------------------------------------
:host(.button-outline) {
--border-width: #{$button-ionic-outline-border-width};
--border-style: #{$button-ionic-outline-border-style};
--background-activated: #e3e3e3;
--background-activated-opacity: 1;
--background-focused: transparent;
--background-hover: transparent;
--background-focused-opacity: 0.1;
--color-activated: #{ion-color(primary, base)};
}
:host(.button-outline.ion-focused) {
--border-color: transparent;
}
// Fill Clear Button
// --------------------------------------------------
:host(.button-clear) {
--background-activated: #e3e3e3;
--background-activated-opacity: 1;
--background-focused: transparent;
--background-hover: transparent;
}
// Button Hover
// --------------------------------------------------
:host(.button-outline),
:host(.button-clear) {
--background-hover: #121212;
--background-hover-opacity: 0.04;
}
// Button: Disabled
// --------------------------------------------------
:host(.button-disabled) {
--color: #c9c9c9;
--border-color: var(--color);
opacity: 1;
}
:host(.button-solid.button-disabled) {
--background: #f5f5f5;
}

View File

@ -0,0 +1,164 @@
@import "../../themes/ionic.globals.ios";
// Ionic Button
// -------------------------------------------------------------------------------
/// @prop - Border radius of the button
$button-ionic-border-radius: px-to-rem(8) !default;
/// @prop - Padding top of the button
$button-ionic-padding-top: px-to-rem(12) !default;
/// @prop - Padding end of the button
$button-ionic-padding-end: px-to-rem(16) !default;
/// @prop - Padding bottom of the button
$button-ionic-padding-bottom: $button-ionic-padding-top !default;
/// @prop - Padding start of the button
$button-ionic-padding-start: $button-ionic-padding-end !default;
/// @prop - Minimum height of the button
$button-ionic-min-height: px-to-rem(40) !default;
/// @prop - Font size of the button text
/// The maximum font size is calculated by taking the default font size
/// and multiplying it by 3, since 310% of the default is the maximum
$button-ionic-font-size: dynamic-font-max(14px, 3) !default;
// Ionic Extra Small Button
// -------------------------------------------------------------------------------
/// @prop - Border radius of the extra small button
$button-ionic-xsmall-border-radius: px-to-rem(4) !default;
/// @prop - Padding top of the extra small button
$button-ionic-xsmall-padding-top: px-to-rem(4) !default;
/// @prop - Padding end of the extra small button
$button-ionic-xsmall-padding-end: px-to-rem(12) !default;
/// @prop - Padding bottom of the extra small button
$button-ionic-xsmall-padding-bottom: $button-ionic-xsmall-padding-top !default;
/// @prop - Padding start of the extra small button
$button-ionic-xsmall-padding-start: $button-ionic-xsmall-padding-end !default;
/// @prop - Minimum height of the extra small button
$button-ionic-xsmall-min-height: px-to-rem(24) !default;
/// @prop - Font size of the extra small button text
/// The maximum font size is calculated by taking the default font size
/// and multiplying it by 3, since 310% of the default is the maximum
$button-ionic-xsmall-font-size: dynamic-font-max(12px, 3) !default;
// Ionic Small Button
// -------------------------------------------------------------------------------
/// @prop - Border radius of the small button
$button-ionic-small-border-radius: px-to-rem(4) !default;
/// @prop - Padding top of the small button
$button-ionic-small-padding-top: px-to-rem(8) !default;
/// @prop - Padding end of the small button
$button-ionic-small-padding-end: px-to-rem(16) !default;
/// @prop - Padding bottom of the small button
$button-ionic-small-padding-bottom: $button-ionic-small-padding-top !default;
/// @prop - Padding start of the small button
$button-ionic-small-padding-start: $button-ionic-small-padding-end !default;
/// @prop - Minimum height of the small button
$button-ionic-small-min-height: px-to-rem(32) !default;
/// @prop - Font size of the small button text
/// The maximum font size is calculated by taking the default font size
/// and multiplying it by 3, since 310% of the default is the maximum
$button-ionic-small-font-size: dynamic-font-max(12px, 3) !default;
// Ionic Large Button
// -------------------------------------------------------------------------------
/// @prop - Padding top of the large button
$button-ionic-large-padding-top: px-to-rem(16) !default;
/// @prop - Padding end of the large button
$button-ionic-large-padding-end: px-to-rem(24) !default;
/// @prop - Padding bottom of the large button
$button-ionic-large-padding-bottom: $button-ionic-large-padding-top !default;
/// @prop - Padding start of the large button
$button-ionic-large-padding-start: $button-ionic-large-padding-end !default;
/// @prop - Minimum height of the large button
$button-ionic-large-min-height: px-to-rem(48) !default;
/// @prop - Font size of the large button text
/// The maximum font size is calculated by taking the default font size
/// and multiplying it by 3, since 310% of the default is the maximum
$button-ionic-large-font-size: dynamic-font-max(16px, 3) !default;
// Ionic Extra Large Button
// -------------------------------------------------------------------------------
/// @prop - Padding top of the extra large button
$button-ionic-xlarge-padding-top: px-to-rem(16) !default;
/// @prop - Padding end of the extra large button
$button-ionic-xlarge-padding-end: px-to-rem(32) !default;
/// @prop - Padding bottom of the extra large button
$button-ionic-xlarge-padding-bottom: $button-ionic-xlarge-padding-top !default;
/// @prop - Padding start of the extra large button
$button-ionic-xlarge-padding-start: $button-ionic-xlarge-padding-end !default;
/// @prop - Minimum height of the extra large button
$button-ionic-xlarge-min-height: px-to-rem(56) !default;
/// @prop - Font size of the extra large button text
/// The maximum font size is calculated by taking the default font size
/// and multiplying it by 3, since 310% of the default is the maximum
$button-ionic-xlarge-font-size: dynamic-font-max(20px, 3) !default;
// Ionic Rectangular Button
// -------------------------------------------------------------------------------
/// @prop - Border radius of the rectangular button
$button-ionic-rectangular-border: 0 !default;
// Ionic Round Button
// -------------------------------------------------------------------------------
/// @prop - Border radius of the round button
$button-ionic-round-border: px-to-rem(999) !default;
// Ionic Outline Button
// -------------------------------------------------------------------------------
/// @prop - Border width of the outline button
$button-ionic-outline-border-width: 1px !default;
/// @prop - Border style of the outline button
$button-ionic-outline-border-style: solid !default;
// Ionic Icon Only Button
// -------------------------------------------------------------------------------
/// @prop - Padding end of the icon only button
$button-has-icon-only-padding-end: px-to-rem(13) !default;
/// @prop - Padding end of the icon only extra small button
$button-has-icon-only-padding-end-xsmall: px-to-rem(6) !default;
/// @prop - Padding end of the icon only small button
$button-has-icon-only-padding-end-small: px-to-rem(10) !default;
/// @prop - Padding end of the icon only large button
$button-has-icon-only-padding-end-large: px-to-rem(16) !default;
/// @prop - Padding end of the icon only extra large button
$button-has-icon-only-padding-end-xlarge: px-to-rem(18) !default;

View File

@ -26,7 +26,7 @@ import type { RouterDirection } from '../router/utils/interface';
styleUrls: { styleUrls: {
ios: 'button.ios.scss', ios: 'button.ios.scss',
md: 'button.md.scss', md: 'button.md.scss',
ionic: 'button.md.scss', ionic: 'button.ionic.scss',
}, },
shadow: true, shadow: true,
}) })
@ -117,7 +117,7 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
/** /**
* Set to `"round"` for a button with more rounded corners. * Set to `"round"` for a button with more rounded corners.
*/ */
@Prop({ reflect: true }) shape?: 'round'; @Prop({ reflect: true }) shape?: 'round' | 'rectangular';
/** /**
* Set to `"small"` for a button with less height and padding, to `"default"` * Set to `"small"` for a button with less height and padding, to `"default"`
@ -126,7 +126,7 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
* is inside of an item, where the size is `"small"` by default. Set the size to * is inside of an item, where the size is `"small"` by default. Set the size to
* `"default"` inside of an item to make it a standard size button. * `"default"` inside of an item to make it a standard size button.
*/ */
@Prop({ reflect: true }) size?: 'small' | 'default' | 'large'; @Prop({ reflect: true }) size?: 'xsmall' | 'small' | 'default' | 'large' | 'xlarge';
/** /**
* If `true`, activates a button with a heavier font weight. * If `true`, activates a button with a heavier font weight.
@ -216,6 +216,24 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
return 'bounded'; return 'bounded';
} }
/**
* Disable the "xsmall" and "xlarge" sizes if the theme is "ios" or "md"
*/
private getSize(): string | undefined {
const theme = getIonTheme(this);
const { size } = this;
if (size === undefined && this.inItem) {
return 'small';
}
if ((theme === 'ios' || theme === 'md') && (size === 'xsmall' || size === 'xlarge')) {
return undefined;
}
return size;
}
/** /**
* Finds the form element based on the provided `form` selector * Finds the form element based on the provided `form` selector
* or element reference provided. * or element reference provided.
@ -321,7 +339,6 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
disabled, disabled,
rel, rel,
target, target,
size,
href, href,
color, color,
expand, expand,
@ -332,7 +349,7 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
} = this; } = this;
const theme = getIonTheme(this); const theme = getIonTheme(this);
const finalSize = size === undefined && this.inItem ? 'small' : size; const finalSize = this.getSize();
const TagType = href === undefined ? 'button' : ('a' as any); const TagType = href === undefined ? 'button' : ('a' as any);
const attrs = const attrs =
TagType === 'button' TagType === 'button'

View File

@ -1,14 +1,17 @@
import { expect } from '@playwright/test'; import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright'; import { configs, test } from '@utils/test/playwright';
configs().forEach(({ title, config, screenshot }) => { /**
test.describe(title('button: clear'), () => { * Fill="clear" does not render differently based on the direction.
*/
configs({ directions: ['ltr'], themes: ['ios', 'md', 'ionic'] }).forEach(({ title, config, screenshot }) => {
test.describe(title('button: fill: clear'), () => {
test('should not have visual regressions', async ({ page }) => { test('should not have visual regressions', async ({ page }) => {
await page.goto(`/src/components/button/test/clear`, config); await page.goto(`/src/components/button/test/clear`, config);
await page.setIonViewport(); await page.setIonViewport();
await expect(page).toHaveScreenshot(screenshot(`button-clear`)); await expect(page).toHaveScreenshot(screenshot(`button-fill-clear`));
}); });
}); });
}); });

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -1,69 +0,0 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
/**
* All content takes up the full width, so RTL has no effect.
*/
configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('button: round'), () => {
test.describe('default', () => {
test('should not have visual regressions', async ({ page }) => {
await page.goto(`/src/components/button/test/round`, config);
await page.setIonViewport();
const container = page.locator('#default');
await expect(container).toHaveScreenshot(screenshot(`button-round`));
});
});
test.describe('outline', () => {
test('should not have visual regressions', async ({ page }) => {
await page.goto(`/src/components/button/test/round`, config);
await page.setIonViewport();
const container = page.locator('#outline');
await expect(container).toHaveScreenshot(screenshot(`button-outline-round`));
});
});
test.describe('clear', () => {
test('should not have visual regressions', async ({ page }) => {
await page.goto(`/src/components/button/test/round`, config);
await page.setIonViewport();
const container = page.locator('#clear');
await expect(container).toHaveScreenshot(screenshot(`button-clear-round`));
});
});
test.describe('color', () => {
test('should not have visual regressions', async ({ page }) => {
await page.goto(`/src/components/button/test/round`, config);
await page.setIonViewport();
const container = page.locator('#color');
await expect(container).toHaveScreenshot(screenshot(`button-color-round`));
});
});
test.describe('expand', () => {
test('should not have visual regressions', async ({ page }) => {
await page.goto(`/src/components/button/test/round`, config);
await page.setIonViewport();
const container = page.locator('#expand');
await expect(container).toHaveScreenshot(screenshot(`button-expand-round`));
});
});
});
});

View File

@ -0,0 +1,111 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
/**
* All content takes up the full width, so RTL has no effect.
*/
// TODO: FW-6077 - Add ionic theme on MD mode to this test.
configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('button: shape'), () => {
test.describe('round', () => {
test.describe('default', () => {
test('should not have visual regressions', async ({ page }) => {
await page.goto(`/src/components/button/test/shape`, config);
await page.setIonViewport();
const container = page.locator('#default');
await expect(container).toHaveScreenshot(screenshot(`button-round`));
});
});
test.describe('outline', () => {
test('should not have visual regressions', async ({ page }) => {
await page.goto(`/src/components/button/test/shape`, config);
await page.setIonViewport();
const container = page.locator('#outline');
await expect(container).toHaveScreenshot(screenshot(`button-outline-round`));
});
});
test.describe('clear', () => {
test('should not have visual regressions', async ({ page }) => {
await page.goto(`/src/components/button/test/shape`, config);
await page.setIonViewport();
const container = page.locator('#clear');
await expect(container).toHaveScreenshot(screenshot(`button-clear-round`));
});
});
test.describe('color', () => {
test('should not have visual regressions', async ({ page }) => {
await page.goto(`/src/components/button/test/shape`, config);
await page.setIonViewport();
const container = page.locator('#color');
await expect(container).toHaveScreenshot(screenshot(`button-color-round`));
});
});
test.describe('expand', () => {
test('should not have visual regressions', async ({ page }) => {
await page.goto(`/src/components/button/test/shape`, config);
await page.setIonViewport();
const container = page.locator('#expand');
await expect(container).toHaveScreenshot(screenshot(`button-expand-round`));
});
});
});
});
});
/**
* Shape="rectangular" is only available in the Ionic theme.
*/
configs({ directions: ['ltr'], themes: ['ionic'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('button: shape'), () => {
test.describe('rectangular', () => {
test('should not have visual regressions', async ({ page }) => {
await page.setContent(
`
<style>
ion-button {
margin: 8px;
}
</style>
<div id="container">
<ion-button shape="rectangular" fill="solid">Rectangular Button, Solid</ion-button>
<ion-button class="ion-focused" shape="rectangular" fill="solid">Rectangular Button, Solid, Focused</ion-button>
<ion-button class="ion-activated" shape="rectangular" fill="solid">Rectangular Button, Solid, Activated</ion-button>
<ion-button shape="rectangular" fill="outline">Rectangular Button, Outline</ion-button>
<ion-button class="ion-focused" shape="rectangular" fill="outline">Rectangular Button, Outline, Focused</ion-button>
<ion-button class="ion-activated" shape="rectangular" fill="outline">Rectangular Button, Outline, Activated</ion-button>
<ion-button shape="rectangular" fill="clear">Rectangular Button</ion-button>
<ion-button class="ion-focused" shape="rectangular" fill="clear">Rectangular Button, Focused</ion-button>
<ion-button class="ion-activated" shape="rectangular" fill="clear">Rectangular Button, Activated</ion-button>
</div>
`,
config
);
const container = page.locator('#container');
await expect(container).toHaveScreenshot(screenshot(`button-shape-rectangular`));
});
});
});
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,7 +1,8 @@
import { expect } from '@playwright/test'; import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright'; import { configs, test } from '@utils/test/playwright';
configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => { // TODO: FW-6077 - Limit this test to just the Ionic theme on MD mode.
configs({ directions: ['ltr'], themes: ['ionic', 'md', 'ios'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('button: size'), () => { test.describe(title('button: size'), () => {
test('should render small buttons', async ({ page }) => { test('should render small buttons', async ({ page }) => {
await page.setContent( await page.setContent(
@ -60,3 +61,26 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
}); });
}); });
}); });
/**
* The following tests are specific to the Ionic theme and do not depend on the text direction.
*/
configs({ directions: ['ltr'], themes: ['ionic'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('button: size'), () => {
test('should render xsmall buttons', async ({ page }) => {
await page.setContent(`<ion-button size="xsmall" fill="solid">X-Small Button</ion-button>`, config);
const wrapper = page.locator('ion-button');
await expect(wrapper).toHaveScreenshot(screenshot(`button-size-x-small`));
});
test('should render xlarge buttons', async ({ page }) => {
await page.setContent(`<ion-button size="xlarge" fill="solid">X-Large Button</ion-button>`, config);
const wrapper = page.locator('ion-button');
await expect(wrapper).toHaveScreenshot(screenshot(`button-size-x-large`));
});
});
});

Some files were not shown because too many files have changed in this diff Show More