Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions BREAKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ This is a comprehensive list of the breaking changes introduced in the major ver
- [Item Divider](#version-9x-item-divider)
- [Radio Group](#version-9x-radio-group)
- [Spinner](#version-9x-spinner)
- [Text](#version-9x-text)
- [Textarea](#version-9x-textarea)

<h2 id="version-9x-global-styles">Global Styles</h2>
Expand Down Expand Up @@ -289,6 +290,28 @@ Additionally, the `radio-group-wrapper` div element has been removed, causing sl
- `.spinner-[spinner-name]` → `.spinner-name-[spinner-name]`
- Specific theme classes (e.g., `ion-spinner.md`) are no longer supported. Style modifications based on the active theme must be implemented using theme tokens rather than direct class targeting.

<h4 id="version-9x-text">Text</h4>

The following breaking changes apply to `ion-text`:

1. The color applied by the `color` prop is now driven by the centralized Ionic Theming system, scoped to the new `hue` property.
2. Theme classes (`ion-text.md`, `ion-text.ios`) are no longer supported.

<h5>New `hue` property and color tokens</h5>

A new `hue` property selects between vibrant and muted color variants. It defaults to `"bold"`, which preserves prior behavior when `color` is set.

When `color` is set, the text color now reads from a token instead of `--ion-color-base` directly. Global overrides should use the theme tokens; component-specific overrides use the corresponding CSS variables:

| Hue | Token (global) | CSS variable (component-specific) |
|---|---|---|
| `bold` | `IonText.hue.bold.semantic.default.color` | `--ion-text-hue-bold-semantic-default-color` |
| `subtle` | `IonText.hue.subtle.semantic.default.color` | `--ion-text-hue-subtle-semantic-default-color` |

<h5>Theme classes</h5>

Remove any instances that target the theme classes: `ion-text.md`, `ion-text.ios`.

<h4 id="version-9x-textarea">Textarea</h4>

Converted `ion-textarea` to use [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM).
Expand Down
4 changes: 3 additions & 1 deletion core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2699,8 +2699,10 @@ ion-tabs,event,ionTabsWillChange,{ tab: string; },false

ion-text,shadow
ion-text,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-text,prop,hue,"bold" | "subtle" | undefined,undefined,false,false
ion-text,prop,mode,"ios" | "md",undefined,false,false
ion-text,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-text,css-prop,--ion-text-hue-bold-semantic-default-color
ion-text,css-prop,--ion-text-hue-subtle-semantic-default-color

ion-textarea,shadow
ion-textarea,prop,autoGrow,boolean,false,false,true
Expand Down
19 changes: 11 additions & 8 deletions core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { SelectModalOption } from "./components/select-modal/select-modal-interf
import { SelectPopoverOption } from "./components/select-popover/select-popover-interface";
import { SpinnerSize } from "./components/spinner/spinner.interfaces";
import { TabBarChangedEventDetail, TabButtonClickEventDetail, TabButtonLayout } from "./components/tab-bar/tab-bar-interface";
import { IonTextHue } from "./components/text/text.interfaces";
import { TextareaChangeEventDetail, TextareaInputEventDetail } from "./components/textarea/textarea-interface";
import { ToastButton, ToastDismissOptions, ToastLayout, ToastPosition, ToastPresentOptions, ToastSwipeGestureDirection } from "./components/toast/toast-interface";
import { ToggleChangeEventDetail } from "./components/toggle/toggle-interface";
Expand Down Expand Up @@ -86,6 +87,7 @@ export { SelectModalOption } from "./components/select-modal/select-modal-interf
export { SelectPopoverOption } from "./components/select-popover/select-popover-interface";
export { SpinnerSize } from "./components/spinner/spinner.interfaces";
export { TabBarChangedEventDetail, TabButtonClickEventDetail, TabButtonLayout } from "./components/tab-bar/tab-bar-interface";
export { IonTextHue } from "./components/text/text.interfaces";
export { TextareaChangeEventDetail, TextareaInputEventDetail } from "./components/textarea/textarea-interface";
export { ToastButton, ToastDismissOptions, ToastLayout, ToastPosition, ToastPresentOptions, ToastSwipeGestureDirection } from "./components/toast/toast-interface";
export { ToggleChangeEventDetail } from "./components/toggle/toggle-interface";
Expand Down Expand Up @@ -4075,13 +4077,13 @@ export namespace Components {
*/
"color"?: Color;
/**
* The mode determines the platform behaviors of the component.
* Set to `"bold"` for a text with vibrant, bold colors or to `"subtle"` for a text with muted, subtle colors. Defaults to `"bold"` if both the hue property and theme config are unset.
*/
"mode"?: "ios" | "md";
"hue"?: IonTextHue;
/**
* The theme determines the visual appearance of the component.
* The mode determines the platform behaviors of the component.
*/
"theme"?: "ios" | "md" | "ionic";
"mode"?: "ios" | "md";
}
interface IonTextarea {
/**
Expand Down Expand Up @@ -10155,13 +10157,13 @@ declare namespace LocalJSX {
*/
"color"?: Color;
/**
* The mode determines the platform behaviors of the component.
* Set to `"bold"` for a text with vibrant, bold colors or to `"subtle"` for a text with muted, subtle colors. Defaults to `"bold"` if both the hue property and theme config are unset.
*/
"mode"?: "ios" | "md";
"hue"?: IonTextHue;
/**
* The theme determines the visual appearance of the component.
* The mode determines the platform behaviors of the component.
*/
"theme"?: "ios" | "md" | "ionic";
"mode"?: "ios" | "md";
}
interface IonTextarea {
/**
Expand Down Expand Up @@ -11313,6 +11315,7 @@ declare namespace LocalJSX {
}
interface IonTextAttributes {
"color": Color;
"hue": IonTextHue;
}
interface IonTextareaAttributes {
"color": Color;
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 61 additions & 0 deletions core/src/components/text/test/hue/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Text - Hue</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>
ion-text {
display: block;
margin-bottom: 4px;
}
</style>
</head>

<body>
<ion-app>
<ion-header>
<ion-toolbar>
<ion-title>Text - Hue</ion-title>
</ion-toolbar>
</ion-header>

<ion-content class="ion-padding">
<h2>Text Hue: Bold</h2>

<ion-text hue="bold">The quick brown fox jumps over the lazy dog</ion-text>
<ion-text hue="bold" color="primary">The quick brown fox jumps over the lazy dog</ion-text>
<ion-text hue="bold" color="secondary">The quick brown fox jumps over the lazy dog</ion-text>
<ion-text hue="bold" color="tertiary">The quick brown fox jumps over the lazy dog</ion-text>
<ion-text hue="bold" color="success">The quick brown fox jumps over the lazy dog</ion-text>
<ion-text hue="bold" color="warning">The quick brown fox jumps over the lazy dog</ion-text>
<ion-text hue="bold" color="danger">The quick brown fox jumps over the lazy dog</ion-text>
<ion-text hue="bold" color="light">The quick brown fox jumps over the lazy dog</ion-text>
<ion-text hue="bold" color="medium">The quick brown fox jumps over the lazy dog</ion-text>
<ion-text hue="bold" color="dark">The quick brown fox jumps over the lazy dog</ion-text>

<h2>Text Hue: Subtle</h2>

<ion-text hue="subtle">The quick brown fox jumps over the lazy dog</ion-text>
<ion-text hue="subtle" color="primary">The quick brown fox jumps over the lazy dog</ion-text>
<ion-text hue="subtle" color="secondary">The quick brown fox jumps over the lazy dog</ion-text>
<ion-text hue="subtle" color="tertiary">The quick brown fox jumps over the lazy dog</ion-text>
<ion-text hue="subtle" color="success">The quick brown fox jumps over the lazy dog</ion-text>
<ion-text hue="subtle" color="warning">The quick brown fox jumps over the lazy dog</ion-text>
<ion-text hue="subtle" color="danger">The quick brown fox jumps over the lazy dog</ion-text>
<ion-text hue="subtle" color="light">The quick brown fox jumps over the lazy dog</ion-text>
<ion-text hue="subtle" color="medium">The quick brown fox jumps over the lazy dog</ion-text>
<ion-text hue="subtle" color="dark">The quick brown fox jumps over the lazy dog</ion-text>
</ion-content>
</ion-app>
</body>
</html>
18 changes: 18 additions & 0 deletions core/src/components/text/text.interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export type IonTextRecipe = {
hue?: {
[K in IonTextHue]?: {
/** Any of the semantic colors like primary, secondary, etc. */
semantic?: {
default?: {
color?: string;
};
};
};
};
};

export type IonTextConfig = {
hue?: IonTextHue;
};

export type IonTextHue = 'bold' | 'subtle';
21 changes: 16 additions & 5 deletions core/src/components/text/text.scss
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
@import "../../themes/native/native.globals";

// Text
// Text: Common Styles
// --------------------------------------------------

:host(.ion-color) {
color: current-color(base);
:host {
/**
* @prop --ion-text-hue-bold-semantic-default-color: Color of the `bold` hue when a semantic color is applied
* @prop --ion-text-hue-subtle-semantic-default-color: Color of the `subtle` hue when a semantic color is applied
*/

color: inherit;
}

:host(.text-hue-bold.ion-color) {
color: var(--ion-text-hue-bold-semantic-default-color);
}

:host(.text-hue-subtle.ion-color) {
color: var(--ion-text-hue-subtle-semantic-default-color);
}
27 changes: 23 additions & 4 deletions core/src/components/text/text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import type { ComponentInterface } from '@stencil/core';
import { Component, Host, Prop, h } from '@stencil/core';
import { createColorClasses } from '@utils/theme';

import { getIonTheme } from '../../global/ionic-global';
import { config } from '../../global/config';
import type { Color } from '../../interface';

import type { IonTextHue } from './text.interfaces';

/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
* @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component.
*/
@Component({
tag: 'ion-text',
Expand All @@ -22,12 +23,30 @@ export class Text implements ComponentInterface {
*/
@Prop({ reflect: true }) color?: Color;

/**
* Set to `"bold"` for a text with vibrant, bold colors or to `"subtle"` for
* a text with muted, subtle colors.
*
* Defaults to `"bold"` if both the hue property and theme config are unset.
*/
@Prop() hue?: IonTextHue;

/**
* Gets the text hue. Uses the `hue` property if set, otherwise
* checks the theme config and falls back to 'bold' if neither is provided.
*/
get hueValue(): IonTextHue {
const hueConfig = config.getObjectValue('IonText.hue', 'bold') as IonTextHue;

return this.hue || hueConfig;
}

render() {
const theme = getIonTheme(this);
const { hueValue } = this;
return (
<Host
class={createColorClasses(this.color, {
[theme]: true,
[`text-hue-${hueValue}`]: true,
})}
>
<slot></slot>
Expand Down
24 changes: 24 additions & 0 deletions core/src/themes/ionic/default.tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ export const defaultTheme: DefaultTheme = {
IonSpinner: {
size: 'xsmall',
},

IonText: {
hue: 'bold',
},
},
},

Expand Down Expand Up @@ -830,5 +834,25 @@ export const defaultTheme: DefaultTheme = {
},
},
},

IonText: {
hue: {
bold: {
semantic: {
default: {
color: currentColor('foreground'),
},
},
},

subtle: {
semantic: {
default: {
color: currentColor('foreground', { subtle: true }),
},
},
},
},
},
},
};
24 changes: 24 additions & 0 deletions core/src/themes/ios/default.tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export const defaultTheme: DefaultTheme = {
IonSpinner: {
size: 'medium',
},

IonText: {
hue: 'bold',
},
},
},

Expand Down Expand Up @@ -858,5 +862,25 @@ export const defaultTheme: DefaultTheme = {
},
},
},

IonText: {
hue: {
bold: {
semantic: {
default: {
color: currentColor('foreground'),
},
},
},

subtle: {
semantic: {
default: {
color: currentColor('foreground', { subtle: true }),
},
},
},
},
},
},
};
24 changes: 24 additions & 0 deletions core/src/themes/md/default.tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ export const defaultTheme: DefaultTheme = {
IonSpinner: {
size: 'medium',
},

IonText: {
hue: 'bold',
},
},
},

Expand Down Expand Up @@ -983,5 +987,25 @@ export const defaultTheme: DefaultTheme = {
},
},
},

IonText: {
hue: {
bold: {
semantic: {
default: {
color: currentColor('foreground'),
},
},
},

subtle: {
semantic: {
default: {
color: currentColor('foreground', { subtle: true }),
},
},
},
},
},
},
};
3 changes: 3 additions & 0 deletions core/src/themes/themes.interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { IonContentRecipe } from '../components/content/content.interfaces'
import type { IonItemDividerRecipe } from '../components/item-divider/item-divider.interfaces';
import type { IonProgressBarConfig, IonProgressBarRecipe } from '../components/progress-bar/progress-bar.interfaces';
import type { IonSpinnerConfig, IonSpinnerRecipe } from '../components/spinner/spinner.interfaces';
import type { IonTextConfig, IonTextRecipe } from '../components/text/text.interfaces';
import type { IonicConfig as IonicGlobalConfig } from '../utils/config';

// Platform-specific theme
Expand Down Expand Up @@ -249,6 +250,7 @@ export type IonicConfig = IonicGlobalConfig & {
IonChip?: IonChipConfig;
IonProgressBar?: IonProgressBarConfig;
IonSpinner?: IonSpinnerConfig;
IonText?: IonTextConfig;
};
};

Expand Down Expand Up @@ -292,6 +294,7 @@ type Components = {
IonItemDivider?: IonItemDividerRecipe;
IonProgressBar?: IonProgressBarRecipe;
IonSpinner?: IonSpinnerRecipe;
IonText?: IonTextRecipe;

IonCard?: any;
IonItem?: any;
Expand Down
Loading