feat(theming): add new color variant for the ionic theme

This commit is contained in:
Brandy Carney
2024-11-12 11:32:22 -05:00
parent a1f3fcc23b
commit 703f765482
9 changed files with 149 additions and 89 deletions

View File

@ -553,6 +553,10 @@ export namespace Components {
* Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered.
*/
"href": string | undefined;
/**
* Set to `"bold"` for a button with vibrant, bold colors or to `"subtle"` for a button with muted, subtle colors.
*/
"hue"?: 'bold' | 'subtle';
/**
* The mode determines the platform behaviors of the component.
*/
@ -5916,6 +5920,10 @@ declare namespace LocalJSX {
* Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered.
*/
"href"?: string | undefined;
/**
* Set to `"bold"` for a button with vibrant, bold colors or to `"subtle"` for a button with muted, subtle colors.
*/
"hue"?: 'bold' | 'subtle';
/**
* The mode determines the platform behaviors of the component.
*/

View File

@ -52,6 +52,11 @@
--ripple-color: var(--background-activated);
}
:host(.button-solid.button-subtle) {
--background: #{globals.ion-color(primary, subtle)};
--color: #{globals.ion-color(primary, base)};
}
// Outline Button
// --------------------------------------------------
@ -81,6 +86,11 @@
// Ripple Effect
// -------------------------------------------------------------------------------
:host(.button-solid.button-subtle.ion-color) .button-native {
background: globals.current-color(subtle);
color: globals.current-color(base);
}
:host(.button-solid.ion-color) ion-ripple-effect {
color: globals.current-color(shade);
}

View File

@ -75,6 +75,12 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
*/
@Prop({ reflect: true }) expand?: 'full' | 'block';
/**
* Set to `"bold"` for a button with vibrant, bold colors or to `"subtle"` for
* a button with muted, subtle colors.
*/
@Prop() hue?: 'bold' | 'subtle' = 'bold';
/**
* Set to `"clear"` for a transparent button that resembles a flat button, to `"outline"`
* for a transparent button with a border, or to `"solid"` for a button with a filled background.
@ -349,8 +355,20 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
};
render() {
const { buttonType, type, disabled, rel, target, href, color, expand, hasIconOnly, strong, inheritedAttributes } =
this;
const {
buttonType,
type,
disabled,
rel,
target,
href,
color,
expand,
hue,
hasIconOnly,
strong,
inheritedAttributes,
} = this;
const theme = getIonTheme(this);
const mode = getIonMode(this);
@ -394,6 +412,7 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
[theme]: true,
[buttonType]: true,
[`${buttonType}-${expand}`]: expand !== undefined,
[`${buttonType}-${hue}`]: hue !== undefined,
[`${buttonType}-${size}`]: size !== undefined,
[`${buttonType}-${shape}`]: true,
[`${buttonType}-${fill}`]: true,

View File

@ -12,6 +12,12 @@
<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>
ion-button {
margin: 8px 4px;
}
</style>
</head>
<body>
@ -23,6 +29,8 @@
</ion-header>
<ion-content class="ion-padding ion-text-center" id="content" no-bounce>
<h2>Bold (default) Buttons</h2>
<p>
<ion-button id="default">Default</ion-button>
<ion-button class="ion-focused">Default.focused</ion-button>
@ -83,48 +91,68 @@
<ion-button class="ion-activated" color="dark">Dark.activated</ion-button>
</p>
<h2>Subtle Buttons</h2>
<p>
<ion-button style="--opacity: 0.2">Opacity: 0.2</ion-button>
<ion-button hue="subtle" id="default">Default</ion-button>
<ion-button hue="subtle" class="ion-focused">Default.focused</ion-button>
<ion-button hue="subtle" class="ion-activated">Default.activated</ion-button>
</p>
<p>
<ion-button expand="block" id="disabledButton" disabled>Button Disabled</ion-button>
<ion-button expand="block" color="secondary" disabled>Secondary Disabled</ion-button>
<ion-button expand="block" color="tertiary" style="--opacity: 1" disabled>Disabled opacity: 1</ion-button>
<ion-button hue="subtle" color="primary">Primary</ion-button>
<ion-button hue="subtle" color="primary" class="ion-focused">Primary.focused</ion-button>
<ion-button hue="subtle" color="primary" class="ion-activated">Primary.activated</ion-button>
</p>
<p>
<ion-button expand="block" onclick="toggleDisabled()">Toggle Disabled</ion-button>
<ion-button hue="subtle" color="secondary">Secondary</ion-button>
<ion-button hue="subtle" class="ion-focused" color="secondary">Secondary.focused</ion-button>
<ion-button hue="subtle" class="ion-activated" color="secondary">Secondary.activated</ion-button>
</p>
<p>
<ion-button id="dynamicColor1" onclick="changeColor(event)">Change Color</ion-button>
<ion-button id="dynamicColor2" onclick="changeColor(event)" fill="outline">Change Color</ion-button>
<ion-button hue="subtle" color="tertiary">Tertiary</ion-button>
<ion-button hue="subtle" class="ion-focused" color="tertiary">Tertiary.focused</ion-button>
<ion-button hue="subtle" class="ion-activated" color="tertiary">Tertiary.activated</ion-button>
</p>
<p>
<ion-button hue="subtle" color="success">Success</ion-button>
<ion-button hue="subtle" color="success" class="ion-focused">Success.focused</ion-button>
<ion-button hue="subtle" color="success" class="ion-activated">Success.activated</ion-button>
</p>
<p>
<ion-button hue="subtle" color="warning">Warning</ion-button>
<ion-button hue="subtle" color="warning" class="ion-focused">Warning.focused</ion-button>
<ion-button hue="subtle" color="warning" class="ion-activated">Warning.activated</ion-button>
</p>
<p>
<ion-button hue="subtle" color="danger">Danger</ion-button>
<ion-button hue="subtle" color="danger" class="ion-focused">Danger.focused</ion-button>
<ion-button hue="subtle" color="danger" class="ion-activated">Danger.activated</ion-button>
</p>
<p>
<ion-button hue="subtle" color="light">Light</ion-button>
<ion-button hue="subtle" color="light" class="ion-focused">Light.focused</ion-button>
<ion-button hue="subtle" color="light" class="ion-activated">Light.activated</ion-button>
</p>
<p>
<ion-button hue="subtle" color="medium">Medium</ion-button>
<ion-button hue="subtle" color="medium" class="ion-focused">Medium.focused</ion-button>
<ion-button hue="subtle" color="medium" class="ion-activated">Medium.activated</ion-button>
</p>
<p>
<ion-button hue="subtle" color="dark">Dark</ion-button>
<ion-button hue="subtle" color="dark" class="ion-focused">Dark.focused</ion-button>
<ion-button hue="subtle" color="dark" class="ion-activated">Dark.activated</ion-button>
</p>
</ion-content>
</ion-app>
<script>
testingColors = ['primary', 'secondary', 'danger', 'dark'];
testingColorIndex = {
dynamicColor1: 0,
dynamicColor2: 0,
};
function changeColor(ev) {
el = ev.currentTarget;
testingColorIndex[el.id] =
testingColorIndex[el.id] >= testingColors.length - 1 ? 0 : testingColorIndex[el.id] + 1;
newColor = testingColors[testingColorIndex[el.id]];
el.color = newColor;
}
function toggleDisabled() {
var buttonEl = document.getElementById('disabledButton');
buttonEl.disabled = !buttonEl.disabled;
}
</script>
</body>
</html>

View File

@ -93,6 +93,7 @@
$contrast: map-get($value, contrast);
$shade: map-get($value, shade);
$tint: map-get($value, tint);
$subtle: map-get($value, subtle);
--ion-color-base: var(--ion-color-#{$color-name}, #{$base}) !important;
--ion-color-base-rgb: var(--ion-color-#{$color-name}-rgb, #{color-to-rgb-list($base)}) !important;
@ -100,6 +101,7 @@
--ion-color-contrast-rgb: var(--ion-color-#{$color-name}-contrast-rgb, #{color-to-rgb-list($contrast)}) !important;
--ion-color-shade: var(--ion-color-#{$color-name}-shade, #{$shade}) !important;
--ion-color-tint: var(--ion-color-#{$color-name}-tint, #{$tint}) !important;
--ion-color-subtle: var(--ion-color-#{$color-name}-subtle, #{$subtle}) !important;
}
// Generates the CSS variables for each color

View File

@ -17,77 +17,69 @@
// TODO(ROU-10778, ROU-10875): Sync the color names to the design system of
// ios and md. This will allow us to have a single color map.
$primary: #105cef;
$secondary: initial;
$tertiary: initial;
$success: #1fbd3b;
$warning: #e18300;
$danger: #bf2222;
$light: #f2f4fd;
$medium: initial;
$neutral: #626262;
$dark: initial;
$ionic-colors: (
primary: (
base: $primary,
contrast: #fff,
shade: color.get-color-shade($primary),
tint: color.get-color-tint($primary),
base: globals.$ion-semantics-primary-base,
contrast: globals.$ion-primitives-base-white,
shade: globals.$ion-semantics-primary-800,
tint: globals.$ion-semantics-primary-500,
subtle: globals.$ion-semantics-primary-100,
),
secondary: (
base: $secondary,
contrast: $secondary,
shade: color.get-color-shade($secondary),
tint: color.get-color-tint($secondary),
base: globals.$ion-semantics-info-base,
contrast: globals.$ion-primitives-base-white,
shade: globals.$ion-semantics-info-800,
tint: globals.$ion-semantics-info-500,
subtle: globals.$ion-semantics-info-100,
),
tertiary: (
base: $tertiary,
contrast: $tertiary,
shade: color.get-color-shade($tertiary),
tint: color.get-color-tint($tertiary),
base: globals.$ion-primitives-violet-700,
contrast: globals.$ion-primitives-base-white,
shade: globals.$ion-primitives-violet-800,
tint: globals.$ion-primitives-violet-500,
subtle: globals.$ion-primitives-violet-100,
),
success: (
base: $success,
contrast: #000,
shade: color.get-color-shade($success),
tint: color.get-color-tint($success),
base: globals.$ion-semantics-success-base,
contrast: globals.$ion-primitives-base-white,
shade: globals.$ion-semantics-success-800,
tint: globals.$ion-semantics-success-500,
subtle: globals.$ion-semantics-success-100,
),
warning: (
base: $warning,
contrast: #000,
shade: color.get-color-shade($warning),
tint: color.get-color-tint($warning),
base: globals.$ion-semantics-warning-base,
contrast: globals.$ion-primitives-base-white,
shade: globals.$ion-semantics-warning-800,
tint: globals.$ion-semantics-warning-500,
subtle: globals.$ion-semantics-warning-100,
),
danger: (
base: $danger,
contrast: #fff,
shade: color.get-color-shade($danger),
tint: color.get-color-tint($danger),
base: globals.$ion-semantics-danger-base,
contrast: globals.$ion-primitives-base-white,
shade: globals.$ion-semantics-danger-800,
tint: globals.$ion-semantics-danger-500,
subtle: globals.$ion-semantics-danger-100,
),
light: (
base: $light,
contrast: #000,
shade: color.get-color-shade($light),
tint: color.get-color-tint($light),
base: globals.$ion-primitives-neutral-200,
contrast: globals.$ion-primitives-base-black,
shade: globals.$ion-primitives-neutral-300,
tint: globals.$ion-primitives-neutral-100,
subtle: globals.$ion-primitives-neutral-100,
),
medium: (
base: $medium,
contrast: $medium,
shade: color.get-color-shade($medium),
tint: color.get-color-tint($medium),
),
neutral: (
base: $neutral,
contrast: #fff,
shade: color.get-color-shade($neutral),
tint: color.get-color-tint($neutral),
base: globals.$ion-primitives-neutral-700,
contrast: globals.$ion-primitives-base-white,
shade: globals.$ion-primitives-neutral-800,
tint: globals.$ion-primitives-neutral-500,
subtle: globals.$ion-primitives-neutral-100,
),
dark: (
base: $dark,
contrast: $dark,
shade: color.get-color-shade($dark),
tint: color.get-color-tint($dark),
base: globals.$ion-primitives-neutral-1100,
contrast: globals.$ion-primitives-base-white,
shade: globals.$ion-primitives-neutral-1200,
tint: globals.$ion-primitives-neutral-900,
subtle: globals.$ion-primitives-neutral-100,
),
);

View File

@ -345,14 +345,14 @@ export declare interface IonBreadcrumbs extends Components.IonBreadcrumbs {
@ProxyCmp({
inputs: ['buttonType', 'color', 'disabled', 'download', 'expand', 'fill', 'form', 'href', 'mode', 'rel', 'routerAnimation', 'routerDirection', 'shape', 'size', 'strong', 'target', 'theme', 'type']
inputs: ['buttonType', 'color', 'disabled', 'download', 'expand', 'fill', 'form', 'href', 'hue', 'mode', 'rel', 'routerAnimation', 'routerDirection', 'shape', 'size', 'strong', 'target', 'theme', 'type']
})
@Component({
selector: 'ion-button',
changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['buttonType', 'color', 'disabled', 'download', 'expand', 'fill', 'form', 'href', 'mode', 'rel', 'routerAnimation', 'routerDirection', 'shape', 'size', 'strong', 'target', 'theme', 'type'],
inputs: ['buttonType', 'color', 'disabled', 'download', 'expand', 'fill', 'form', 'href', 'hue', 'mode', 'rel', 'routerAnimation', 'routerDirection', 'shape', 'size', 'strong', 'target', 'theme', 'type'],
})
export class IonButton {
protected el: HTMLElement;

View File

@ -439,14 +439,14 @@ export declare interface IonBreadcrumbs extends Components.IonBreadcrumbs {
@ProxyCmp({
defineCustomElementFn: defineIonButton,
inputs: ['buttonType', 'color', 'disabled', 'download', 'expand', 'fill', 'form', 'href', 'mode', 'rel', 'routerAnimation', 'routerDirection', 'shape', 'size', 'strong', 'target', 'theme', 'type']
inputs: ['buttonType', 'color', 'disabled', 'download', 'expand', 'fill', 'form', 'href', 'hue', 'mode', 'rel', 'routerAnimation', 'routerDirection', 'shape', 'size', 'strong', 'target', 'theme', 'type']
})
@Component({
selector: 'ion-button',
changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['buttonType', 'color', 'disabled', 'download', 'expand', 'fill', 'form', 'href', 'mode', 'rel', 'routerAnimation', 'routerDirection', 'shape', 'size', 'strong', 'target', 'theme', 'type'],
inputs: ['buttonType', 'color', 'disabled', 'download', 'expand', 'fill', 'form', 'href', 'hue', 'mode', 'rel', 'routerAnimation', 'routerDirection', 'shape', 'size', 'strong', 'target', 'theme', 'type'],
standalone: true
})
export class IonButton {

View File

@ -162,6 +162,7 @@ export const IonButton = /*@__PURE__*/ defineContainer<JSX.IonButton>('ion-butto
'buttonType',
'disabled',
'expand',
'hue',
'fill',
'routerDirection',
'routerAnimation',