Skip to content
Merged
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
37 changes: 37 additions & 0 deletions BREAKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ This is a comprehensive list of the breaking changes introduced in the major ver
- [Input Otp](#version-10x-input-otp)
- [Item Divider](#version-10x-item-divider)
- [Menu Toggle](#version-10x-menu-toggle)
- [Note](#version-10x-note)
- [Radio Group](#version-10x-radio-group)
- [Ripple Effect](#version-10x-ripple-effect)
- [Router Link](#version-10x-router-link)
Expand Down Expand Up @@ -456,6 +457,42 @@ The following breaking changes apply to `ion-menu-toggle`:

Remove any instances that target the mode classes: `ion-menu-toggle.md`, `ion-menu-toggle.ios`.

<h4 id="version-10x-note">Note</h4>

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

1. `--color` has been replaced. <sup>[1](#version-10x-note-replaced-css-variables)</sup>
2. The color applied by the `color` prop is now driven by the centralized Ionic Theming system, scoped to the new `hue` property. <sup>[2](#version-10x-note-hue)</sup>
3. Mode classes (`ion-note.md`, `ion-note.ios`) are no longer supported. <sup>[3](#version-10x-note-mode-classes)</sup>

<h5 id="version-10x-note-replaced-css-variables">Replaced CSS variables</h5>

Use the new token structure for global styles, or the corresponding CSS variable for component-specific overrides:

| Old (9.x) | New token (global) | New CSS variable (component-specific) |
|---|---|---|
| `--color` | `IonNote.hue.bold.default.color` | `--ion-note-hue-bold-default-color` |

> [!NOTE]
> A note with `hue="subtle"` reads `IonNote.hue.subtle.default.color` for global styles, or `--ion-note-hue-subtle-default-color` for component-specific styles.

<h5 id="version-10x-note-hue">New <code>hue</code> property and color tokens</h5>

A new `hue` property selects between vibrant and muted color variants. It defaults to `"bold"`.

When `color` is set, a bold note now uses the color's `foreground` variant instead of `base`, which is darker so the text stays readable on the page. To revert to the previous appearance, set `IonNote.hue.bold.semantic.default.color` to `var(--ion-color-base)` for global styles, or `--ion-note-hue-bold-semantic-default-color` for component-specific styles.

When `color` is set, the note 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` | `IonNote.hue.bold.semantic.default.color` | `--ion-note-hue-bold-semantic-default-color` |
| `subtle` | `IonNote.hue.subtle.semantic.default.color` | `--ion-note-hue-subtle-semantic-default-color` |

<h5 id="version-10x-note-mode-classes">Mode classes</h5>

Remove any instances that target the mode classes: `ion-note.md`, `ion-note.ios`.

<h4 id="version-10x-radio-group">Radio Group</h4>

Converted `ion-radio-group` to use [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM).
Expand Down
11 changes: 7 additions & 4 deletions core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1899,11 +1899,14 @@ ion-nav-link,prop,theme,"ios" | "md" | "ionic",undefined,false,false

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

ion-picker,shadow
ion-picker,prop,mode,"ios" | "md",undefined,false,false
Expand Down
17 changes: 9 additions & 8 deletions core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2703,13 +2703,13 @@ export namespace Components {
*/
"color"?: Color;
/**
* The mode determines the platform behaviors of the component.
* Set to `"bold"` for a note with vibrant, bold colors or to `"subtle"` for a note with muted, subtle colors. Defaults to `"bold"` if both the hue property and theme config are unset.
*/
"mode"?: "ios" | "md";
"hue"?: Hue;
/**
* 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 IonPicker {
"exitInputMode": () => Promise<void>;
Expand Down Expand Up @@ -8560,13 +8560,13 @@ declare namespace LocalJSX {
*/
"color"?: Color;
/**
* The mode determines the platform behaviors of the component.
* Set to `"bold"` for a note with vibrant, bold colors or to `"subtle"` for a note with muted, subtle colors. Defaults to `"bold"` if both the hue property and theme config are unset.
*/
"mode"?: "ios" | "md";
"hue"?: Hue;
/**
* 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 IonPicker {
/**
Expand Down Expand Up @@ -10897,6 +10897,7 @@ declare namespace LocalJSX {
}
interface IonNoteAttributes {
"color": Color;
"hue": Hue;
}
interface IonPickerColumnAttributes {
"disabled": boolean;
Expand Down
8 changes: 8 additions & 0 deletions core/src/components/note/_note.docs.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* @prop --ion-note-font-family: Font family of the note
* @prop --ion-note-font-size: Font size of the note
* @prop --ion-note-hue-bold-default-color: Text color of the `bold` hue
* @prop --ion-note-hue-bold-semantic-default-color: Text color of the `bold` hue when a semantic color is applied
* @prop --ion-note-hue-subtle-default-color: Text color of the `subtle` hue
* @prop --ion-note-hue-subtle-semantic-default-color: Text color of the `subtle` hue when a semantic color is applied
*/
27 changes: 27 additions & 0 deletions core/src/components/note/note.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { Hue } from '../../themes/themes.interfaces';

export type IonNoteRecipe = {
font?: {
family?: string;
size?: string;
};

hue?: {
[K in Hue]?: {
default?: {
color?: string;
};

/** Any of the semantic colors like primary, secondary, etc. */
semantic?: {
default?: {
color?: string;
};
};
};
};
};

export type IonNoteConfig = {
hue?: Hue;
};
11 changes: 0 additions & 11 deletions core/src/components/note/note.ios.scss

This file was deleted.

10 changes: 0 additions & 10 deletions core/src/components/note/note.ios.vars.scss

This file was deleted.

11 changes: 0 additions & 11 deletions core/src/components/note/note.md.scss

This file was deleted.

10 changes: 0 additions & 10 deletions core/src/components/note/note.md.vars.scss

This file was deleted.

31 changes: 21 additions & 10 deletions core/src/components/note/note.scss
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
@import "./note.ios.vars";
@use "./note.docs";

// iOS Note
// Note
// --------------------------------------------------

:host {
/**
* @prop --color: Color of the note
*/
color: var(--color);
box-sizing: border-box;

font-family: $font-family-base;
font-family: var(--ion-note-font-family, inherit);
font-size: var(--ion-note-font-size);
}

box-sizing: border-box;
// Note: Hue
// --------------------------------------------------

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

:host(.note-hue-subtle) {
color: var(--ion-note-hue-subtle-default-color);
}

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

:host(.ion-color) {
color: #{current-color(base)};
:host(.note-hue-subtle.ion-color) {
color: var(--ion-note-hue-subtle-semantic-default-color);
}
35 changes: 25 additions & 10 deletions core/src/components/note/note.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,16 @@ 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 { Hue } from '../../themes/themes.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-note',
styleUrls: {
ios: 'note.ios.scss',
md: 'note.md.scss',
ionic: 'note.md.scss',
},
styleUrl: 'note.scss',
shadow: true,
})
export class Note implements ComponentInterface {
Expand All @@ -26,12 +22,31 @@ export class Note implements ComponentInterface {
*/
@Prop({ reflect: true }) color?: Color;

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

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

return this.hue || hueConfig;
}

render() {
const theme = getIonTheme(this);
const { color, hueValue } = this;

return (
<Host
class={createColorClasses(this.color, {
[theme]: true,
class={createColorClasses(color, {
[`note-hue-${hueValue}`]: true,
})}
>
<slot></slot>
Expand Down
11 changes: 0 additions & 11 deletions core/src/components/note/test/basic/note.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,6 @@ configs({ modes: ['ios', 'md', 'ionic-md'], directions: ['ltr'] }).forEach(({ ti
const note = page.locator('ion-note');
await expect(note).toHaveScreenshot(screenshot(`note-diff`));
});

test('should render color correctly', async ({ page }) => {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to the hue tests

await page.setContent(
`
<ion-note color="danger">99</ion-note>
`,
config
);
const note = page.locator('ion-note');
await expect(note).toHaveScreenshot(screenshot(`note-color`));
});
});
});

Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
35 changes: 35 additions & 0 deletions core/src/components/note/test/hue/note.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';

import { HUES } from '../../../../themes/themes.interfaces';

/**
* This behavior does not vary across directions.
*/
configs({ directions: ['ltr'], modes: ['ionic-md', 'md', 'ios'] }).forEach(({ config, screenshot, title }) => {
test.describe(title('note: hue'), () => {
HUES.forEach((hue) => {
test(`should render ${hue} notes`, async ({ page }) => {
await page.setContent(
`
<style>
.container {
width: max-content;
}
</style>

<div class="container">
<ion-note hue="${hue}">Default</ion-note>
<ion-note hue="${hue}" color="danger">Danger</ion-note>
</div>
`,
config
);

const container = page.locator('.container');

await expect(container).toHaveScreenshot(screenshot(`note-hue-${hue}`));
});
});
});
});
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.
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.
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.
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.
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.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading