From 1f3e1344a90c33b1f5ba822026cc26958ff67753 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jose=CC=81=20Rio?=
Date: Tue, 19 Mar 2024 15:53:46 +0000
Subject: [PATCH 01/33] [feat](button): Added new ionic theme and sizes.
---
core/src/components.d.ts | 12 +-
core/src/components/button/button.ionic.scss | 238 ++++++++++++++++++
.../components/button/button.ionic.vars.scss | 154 ++++++++++++
core/src/components/button/button.tsx | 43 +++-
.../button/test/theme-ionic/index.html | 160 ++++++++++++
core/src/themes/ionic.functions.sizes.scss | 13 +
core/src/themes/ionic.globals.scss | 1 +
7 files changed, 607 insertions(+), 14 deletions(-)
create mode 100644 core/src/components/button/button.ionic.scss
create mode 100644 core/src/components/button/button.ionic.vars.scss
create mode 100644 core/src/components/button/test/theme-ionic/index.html
create mode 100644 core/src/themes/ionic.functions.sizes.scss
diff --git a/core/src/components.d.ts b/core/src/components.d.ts
index 820b7cbae7d..a6ebb122385 100644
--- a/core/src/components.d.ts
+++ b/core/src/components.d.ts
@@ -545,11 +545,11 @@ export namespace Components {
/**
* 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. Option`"xsmall"` and `"xlarge"` are only availave for Ionic theme. At ios and md if in they are in use undefined will be assume.
*/
- "size"?: 'small' | 'default' | 'large';
+ "size"?: 'xsmall' | 'small' | 'default' | 'large' | 'xlarge';
/**
* If `true`, activates a button with a heavier font weight.
*/
@@ -5737,11 +5737,11 @@ declare namespace LocalJSX {
/**
* 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. Option`"xsmall"` and `"xlarge"` are only availave for Ionic theme. At ios and md if in they are in use undefined will be assume.
*/
- "size"?: 'small' | 'default' | 'large';
+ "size"?: 'xsmall' | 'small' | 'default' | 'large' | 'xlarge';
/**
* If `true`, activates a button with a heavier font weight.
*/
diff --git a/core/src/components/button/button.ionic.scss b/core/src/components/button/button.ionic.scss
new file mode 100644
index 00000000000..a4f169c6d7d
--- /dev/null
+++ b/core/src/components/button/button.ionic.scss
@@ -0,0 +1,238 @@
+@import "./button";
+@import "./button.ionic.vars";
+
+// Ionic Button
+// -------------------------------------------------------------------------------
+
+:host {
+ --border-radius: #{$button-ionic-default-border-radius};
+
+ --padding-top: #{$button-ionic-default-padding-top};
+ --padding-end: #{$button-ionic-default-padding-end};
+ --padding-bottom: var(--padding-top);
+ --padding-start: var(--padding-end);
+
+ position: relative;
+
+ font-size: #{$button-ionic-default-font-size};
+ min-height: #{$button-ionic-default-min-height};
+
+ // Target area
+ &::after {
+ position: absolute;
+
+ content: "";
+
+ top: 50%;
+ left: 0;
+ right: 0;
+ bottom: 0;
+
+ transform: translateY(-50%);
+
+ min-height: pxToEm(48);
+
+ cursor: pointer;
+
+ z-index: 1;
+ }
+
+ ::slotted(ion-icon[slot=start]) {
+ margin-inline-end: pxToEm(8);
+ }
+
+ ::slotted(ion-icon[slot=end]) {
+ margin-inline-start: pxToEm(8);
+ }
+}
+
+
+// Button Sizes
+// -------------------------------------------------------------------------------
+
+/* Extra Small and Samll Button */
+:host(.button-xsmall),
+:host(.button-small) {
+ ::slotted(ion-icon[slot=start]) {
+ margin-inline-end: pxToEm(4);
+ }
+
+ ::slotted(ion-icon[slot=end]) {
+ margin-inline-start: pxToEm(4);
+ }
+}
+
+/* Extra Small Button */
+:host(.button-xsmall) {
+ --border-radius: #{$button-ionic-default-xsmall-border-radius};
+
+ --padding-top: #{$button-ionic-xsmall-padding-top};
+ --padding-end: #{$button-ionic-xsmall-padding-end};
+
+ font-size: #{$button-ionic-xsmall-font-size};
+ min-height: #{$button-ionic-xsmall-min-height};
+}
+
+/* Small Button */
+:host(.button-small) {
+ --border-radius: #{$button-ionic-default-small-border-radius};
+
+ --padding-top: #{$button-ionic-small-padding-top};
+ --padding-end: #{$button-ionic-small-padding-end};
+
+ font-size: #{$button-ionic-small-font-size};
+ min-height: #{$button-ionic-small-min-height};
+}
+
+/* Large Button */
+:host(.button-large) {
+ --padding-top: #{$button-ionic-large-padding-top};
+ --padding-end: #{$button-ionic-large-padding-end};
+
+ font-size: #{$button-ionic-large-font-size};
+ min-height: #{$button-ionic-large-min-height};
+}
+
+/* Extra Large Button */
+:host(.button-xlarge) {
+ --padding-top: #{$button-ionic-xlarge-padding-top};
+ --padding-end: #{$button-ionic-xlarge-padding-end};
+
+ font-size: #{$button-ionic-xlarge-font-size};
+ min-height: #{$button-ionic-xlarge-min-height};
+}
+
+// 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-ionic-xsmall-padding-top};
+}
+
+/* Button small */
+:host(.button-has-icon-only.button-small) {
+ --padding-end: #{$button-ionic-small-padding-top};
+}
+
+/* Default */
+:host(.button-has-icon-only) {
+ --padding-end: #{$button-ionic-default-padding-top};
+}
+
+/* Button large */
+:host(.button-has-icon-only.button-large) {
+ --padding-end: #{$button-ionic-large-padding-top};
+}
+
+/* Button extra large */
+:host(.button-has-icon-only.button-xlarge) {
+ --padding-end: #{$button-ionic-xlarge-padding-top};
+}
+
+// Button Shapes
+// -------------------------------------------------------------------------------
+
+/* Rectangular */
+:host(.button-rectangular) {
+ --border-radius: #{$button-ionic-default-rectangular-border};
+}
+
+/* Round */
+:host(.button-round) {
+ --border-radius: #{$button-ionic-default-round-border};
+}
+
+// Button States
+// -------------------------------------------------------------------------------
+
+/* Activated */
+:host(.ion-activated) {
+ --background: #{ion-color(primary, shade)};
+}
+
+:host(.button-outline.ion-activated),
+:host(.button-clear.ion-activated) {
+ --color: #{ion-color(primary, base)};
+ --background: #e3e3e3;
+}
+
+/* Focused */
+// Only show the focus ring when the button is focused
+:host(.ion-focused){
+ --overflow: visible;
+
+ .button-native::after {
+ border-radius: inherit;
+ }
+}
+
+.button-focus-ring {
+ --focus-ring-color: #9ec4fd;
+
+ position: absolute;
+
+ content: '';
+
+ top: -4px;
+ left: -4px;
+
+ width: calc(100% + 8px);
+ height: calc(100% + 8px);
+
+ // ToDo: NewTheme, check if this color can be placed as a variable!
+ border: 2px solid var(--focus-ring-color);
+
+ border-radius: inherit;
+ box-sizing: border-box;
+
+ transition: border-color 0.3s;
+}
+
+// Outline
+:host(.button-outline) {
+ --border-width: #{$button-ionic-outline-border-width};
+ --border-style: #{$button-ionic-outline-border-style};
+ --background-activated: #{ion-color(primary, base)};
+ --background-focused: #{ion-color(primary, base)};
+ --background-hover: transparent;
+ --background-focused-opacity: .1;
+ --color-activated: #{ion-color(primary, contrast)};
+}
+
+// Clear
+:host(.button-clear) {
+ --background-activated: transparent;
+ --background-activated-opacity: 0;
+ --background-focused: #{ion-color(primary, base)};
+ --background-hover: transparent;
+ --background-focused-opacity: .1;
+}
+
+/* Hover */
+:host(.button-outline),
+:host(.button-clear) {
+ --background-hover: #121212;
+ --background-hover-opacity: .04;
+}
+
+/* Disabled */
+:host(.button-disabled) {
+ opacity: 1;
+
+ // ToDo: NewTheme, check if this color can be placed as a variable!
+ --color: #c9c9c9;
+ --border-color: var(--color);
+}
+
+:host(.button-solid.button-disabled) {
+ // ToDo: NewTheme, check if this color can be placed as a variable!
+ --background: #f5f5f5;
+}
\ No newline at end of file
diff --git a/core/src/components/button/button.ionic.vars.scss b/core/src/components/button/button.ionic.vars.scss
new file mode 100644
index 00000000000..b1264c235b3
--- /dev/null
+++ b/core/src/components/button/button.ionic.vars.scss
@@ -0,0 +1,154 @@
+@import "../../themes/ionic.globals.ios";
+
+// Ionic Button
+// -------------------------------------------------------------------------------
+
+/* Default Button */
+
+/// @prop - Border radius of the button for the default size
+$button-ionic-default-border-radius: pxToEm(8) !default;
+
+/// @prop - Padding top of the button for the default size
+$button-ionic-default-padding-top: pxToEm(12) !default;
+
+/// @prop - Padding end of the button for the default size
+$button-ionic-default-padding-end: pxToEm(16) !default;
+
+/// @prop - Padding bottom of the button for the default size
+$button-ionic-default-padding-bottom: $button-ionic-default-padding-top !default;
+
+/// @prop - Padding start of the button for the default size
+$button-ionic-default-padding-start: $button-ionic-default-padding-end !default;
+
+/// @prop - Minimum height of the button for the default size
+$button-ionic-default-min-height: pxToEm(40) !default;
+
+/// @prop - Font size of the button text for the default size
+/// 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-default-font-size: dynamic-font-max(14px, 3) !default;
+
+
+// Button Sizes
+// -------------------------------------------------------------------------------
+
+/* Extra Small Button */
+
+/// @prop - Border radius of the button for the extra small size
+$button-ionic-default-xsmall-border-radius: pxToEm(4) !default;
+
+/// @prop - Padding top of the button for the extra small size
+$button-ionic-xsmall-padding-top: pxToEm(4) !default;
+
+/// @prop - Padding end of the button for the extra small size
+$button-ionic-xsmall-padding-end: pxToEm(12) !default;
+
+/// @prop - Padding bottom of the button for the extra small size
+$button-ionic-xsmall-padding-bottom: $button-ionic-xsmall-padding-top !default;
+
+/// @prop - Padding start of the button for the extra small size
+$button-ionic-xsmall-padding-start: $button-ionic-xsmall-padding-end !default;
+
+/// @prop - Minimum height of the button for the extra small size
+$button-ionic-xsmall-min-height: pxToEm(24) !default;
+
+/// @prop - Font size of the button text for the extra small size
+/// 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;
+
+
+/* Small Button */
+
+/// @prop - Border radius of the button for the small size
+$button-ionic-default-small-border-radius: pxToEm(4) !default;
+
+/// @prop - Padding top of the button for the small size
+$button-ionic-small-padding-top: pxToEm(8) !default;
+
+/// @prop - Padding end of the button for the small size
+$button-ionic-small-padding-end: pxToEm(16) !default;
+
+/// @prop - Padding bottom of the button for the small size
+$button-ionic-small-padding-bottom: $button-ionic-small-padding-top !default;
+
+/// @prop - Padding start of the button for the small size
+$button-ionic-small-padding-start: $button-ionic-small-padding-end !default;
+
+/// @prop - Minimum height of the button for the small size
+$button-ionic-small-min-height: pxToEm(32) !default;
+
+/// @prop - Font size of the button text for the small size
+/// 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;
+
+
+/* Large Button */
+
+/// @prop - Padding top of the button for the large size
+$button-ionic-large-padding-top: pxToEm(16) !default;
+
+/// @prop - Padding end of the button for the large size
+$button-ionic-large-padding-end: pxToEm(24) !default;
+
+/// @prop - Padding bottom of the button for the large size
+$button-ionic-large-padding-bottom: $button-ionic-large-padding-top !default;
+
+/// @prop - Padding start of the button for the large size
+$button-ionic-large-padding-start: $button-ionic-large-padding-end !default;
+
+/// @prop - Minimum height of the button for the large size
+$button-ionic-large-min-height: pxToEm(48) !default;
+
+/// @prop - Font size of the button text for the large size
+/// 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;
+
+
+/* Extra Large Button */
+
+/// @prop - Padding top of the button for the xlarge size
+$button-ionic-xlarge-padding-top: pxToEm(20) !default;
+
+/// @prop - Padding end of the button for the xlarge size
+$button-ionic-xlarge-padding-end: pxToEm(32) !default;
+
+/// @prop - Padding bottom of the button for the xlarge size
+$button-ionic-xlarge-padding-bottom: $button-ionic-xlarge-padding-top !default;
+
+/// @prop - Padding start of the button for the xlarge size
+$button-ionic-xlarge-padding-start: $button-ionic-xlarge-padding-end !default;
+
+/// @prop - Minimum height of the button for the xlarge size
+$button-ionic-xlarge-min-height: pxToEm(56) !default;
+
+/// @prop - Font size of the button text for the xlarge size
+/// 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;
+
+
+// Button Shapes
+// -------------------------------------------------------------------------------
+
+/* Rectangular */
+/// @prop - Rectangular border radius of the button
+$button-ionic-default-rectangular-border: 0 !default;
+
+/* Round */
+/// @prop - Round border radius of the button
+$button-ionic-default-round-border: pxToEm(999) !default;
+
+
+// Button Fill
+// -------------------------------------------------------------------------------
+
+/* Outline */
+/// @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;
+
diff --git a/core/src/components/button/button.tsx b/core/src/components/button/button.tsx
index f23aff61e76..29b8335e9e6 100644
--- a/core/src/components/button/button.tsx
+++ b/core/src/components/button/button.tsx
@@ -1,5 +1,5 @@
import type { ComponentInterface, EventEmitter } from '@stencil/core';
-import { Component, Element, Event, Host, Prop, Watch, h } from '@stencil/core';
+import { Component, Element, Event, Host, Prop, State, Watch, h } from '@stencil/core';
import type { AnchorInterface, ButtonInterface } from '@utils/element-interface';
import type { Attributes } from '@utils/helpers';
import { inheritAriaAttributes, hasShadowDom } from '@utils/helpers';
@@ -20,13 +20,14 @@ import type { RouterDirection } from '../router/utils/interface';
* @slot end - Content is placed to the right of the button text in LTR, and to the left in RTL.
*
* @part native - The native HTML button or anchor element that wraps all child elements.
+ * @part focus-ring - The visual indicator that appears as an outline around the button when focused.
*/
@Component({
tag: 'ion-button',
styleUrls: {
ios: 'button.ios.scss',
md: 'button.md.scss',
- ionic: 'button.md.scss',
+ ionic: 'button.ionic.scss',
},
shadow: true,
})
@@ -37,9 +38,11 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
private formButtonEl: HTMLButtonElement | null = null;
private formEl: HTMLFormElement | null = null;
private inheritedAttributes: Attributes = {};
-
+
@Element() el!: HTMLElement;
+ @State() isCircle: boolean = false;
+
/**
* The color to use from your application's color palette.
* Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
@@ -112,7 +115,7 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
/**
* 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"`
@@ -120,8 +123,10 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
* 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.
+ * Option`"xsmall"` and `"xlarge"` are only availave for Ionic theme.
+ * At ios and md if in they are in use undefined will be assume.
*/
- @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.
@@ -211,6 +216,21 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
return 'bounded';
}
+ /**
+ * Check which size has been set, and once at ion & md,
+ * disable xsmall and xlarge styles!
+ */
+ 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
* or element reference provided.
@@ -269,6 +289,13 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
return this.el.closest('form');
}
+ /**
+ * Makes button-has-icon-only class to update when an icon is added or removed from slot="icon-only"
+ */
+ private slotChanged = () => {
+ this.isCircle = this.hasIconOnly;
+ };
+
private submitForm(ev: Event) {
// this button wants to specifically submit a form
// climb up the dom to see if we're in a
-
+
Focused
@@ -118,43 +113,40 @@ States
-
-
-
+