diff --git a/core/src/components.d.ts b/core/src/components.d.ts
index 2cbca79a7a3..550ad28183c 100644
--- a/core/src/components.d.ts
+++ b/core/src/components.d.ts
@@ -12,13 +12,13 @@ import { OverlayEventDetail } from "./utils/overlays-interface";
import { IonicSafeString } from "./utils/sanitization";
import { AlertButton, AlertInput } from "./components/alert/alert-interface";
import { Hue } from "./themes/themes.interfaces";
-import { IonBadgeShape, IonBadgeSize, IonBadgeVerticalPosition } from "./components/badge/badge.interfaces";
+import { IonBadgeShape, IonBadgeSize, IonBadgeVerticalPosition } from "./components/badge/badge.interface";
import { RouteID, RouterDirection, RouterEventDetail, RouteWrite } from "./components/router/utils/interface";
import { BreadcrumbCollapsedClickEventDetail } from "./components/breadcrumb/breadcrumb-interface";
import { CheckboxChangeEventDetail } from "./components/checkbox/checkbox-interface";
-import { IonChipFill, IonChipShape, IonChipSize } from "./components/chip/chip.interfaces";
+import { IonChipFill, IonChipShape, IonChipSize } from "./components/chip/chip.interface";
import { IonColValue } from "./components/col/col.interface";
-import { ScrollBaseDetail, ScrollDetail } from "./components/content/content.interfaces";
+import { ScrollBaseDetail, ScrollDetail } from "./components/content/content.interface";
import { DatetimeChangeEventDetail, DatetimeHighlight, DatetimeHighlightCallback, DatetimeHourCycle, DatetimeParts, DatetimePresentation, FormatOptions, TitleSelectedDatesFormatter } from "./components/datetime/datetime-interface";
import { FooterScrollEffect } from "./components/footer/footer-interface";
import { IonGalleryColumns, IonGalleryGap } from "./components/gallery/gallery.interface";
@@ -33,7 +33,7 @@ import { ViewController } from "./components/nav/view-controller";
import { PickerChangeEventDetail } from "./components/picker/picker-interfaces";
import { PickerColumnChangeEventDetail, PickerColumnValue } from "./components/picker-column/picker-column-interfaces";
import { PopoverSize, PositionAlign, PositionReference, PositionSide, TriggerAction } from "./components/popover/popover-interface";
-import { IonProgressBarShape } from "./components/progress-bar/progress-bar.interfaces";
+import { IonProgressBarShape } from "./components/progress-bar/progress-bar.interface";
import { RadioGroupChangeEventDetail, RadioGroupCompareFn } from "./components/radio-group/radio-group-interface";
import { PinFormatter, RangeChangeEventDetail, RangeKnobMoveEndEventDetail, RangeKnobMoveStartEventDetail, RangeValue } from "./components/range/range-interface";
import { RefresherEventDetail, RefresherPullEndEventDetail } from "./components/refresher/refresher-interface";
@@ -47,7 +47,7 @@ import { SegmentViewScrollEvent } from "./components/segment-view/segment-view-i
import { SelectChangeEventDetail, SelectCompareFn, SelectInterface } from "./components/select/select-interface";
import { SelectModalOption } from "./components/select-modal/select-modal-interface";
import { SelectPopoverOption } from "./components/select-popover/select-popover-interface";
-import { SpinnerSize } from "./components/spinner/spinner.interfaces";
+import { SpinnerSize } from "./components/spinner/spinner.interface";
import { TabBarChangedEventDetail, TabBarScrollEffect, TabButtonClickEventDetail, TabButtonLayout } from "./components/tab-bar/tab-bar-interface";
import { TextareaChangeEventDetail, TextareaInputEventDetail } from "./components/textarea/textarea-interface";
import { IonTitleSize } from "./components/title/title.interface";
@@ -60,13 +60,13 @@ export { OverlayEventDetail } from "./utils/overlays-interface";
export { IonicSafeString } from "./utils/sanitization";
export { AlertButton, AlertInput } from "./components/alert/alert-interface";
export { Hue } from "./themes/themes.interfaces";
-export { IonBadgeShape, IonBadgeSize, IonBadgeVerticalPosition } from "./components/badge/badge.interfaces";
+export { IonBadgeShape, IonBadgeSize, IonBadgeVerticalPosition } from "./components/badge/badge.interface";
export { RouteID, RouterDirection, RouterEventDetail, RouteWrite } from "./components/router/utils/interface";
export { BreadcrumbCollapsedClickEventDetail } from "./components/breadcrumb/breadcrumb-interface";
export { CheckboxChangeEventDetail } from "./components/checkbox/checkbox-interface";
-export { IonChipFill, IonChipShape, IonChipSize } from "./components/chip/chip.interfaces";
+export { IonChipFill, IonChipShape, IonChipSize } from "./components/chip/chip.interface";
export { IonColValue } from "./components/col/col.interface";
-export { ScrollBaseDetail, ScrollDetail } from "./components/content/content.interfaces";
+export { ScrollBaseDetail, ScrollDetail } from "./components/content/content.interface";
export { DatetimeChangeEventDetail, DatetimeHighlight, DatetimeHighlightCallback, DatetimeHourCycle, DatetimeParts, DatetimePresentation, FormatOptions, TitleSelectedDatesFormatter } from "./components/datetime/datetime-interface";
export { FooterScrollEffect } from "./components/footer/footer-interface";
export { IonGalleryColumns, IonGalleryGap } from "./components/gallery/gallery.interface";
@@ -81,7 +81,7 @@ export { ViewController } from "./components/nav/view-controller";
export { PickerChangeEventDetail } from "./components/picker/picker-interfaces";
export { PickerColumnChangeEventDetail, PickerColumnValue } from "./components/picker-column/picker-column-interfaces";
export { PopoverSize, PositionAlign, PositionReference, PositionSide, TriggerAction } from "./components/popover/popover-interface";
-export { IonProgressBarShape } from "./components/progress-bar/progress-bar.interfaces";
+export { IonProgressBarShape } from "./components/progress-bar/progress-bar.interface";
export { RadioGroupChangeEventDetail, RadioGroupCompareFn } from "./components/radio-group/radio-group-interface";
export { PinFormatter, RangeChangeEventDetail, RangeKnobMoveEndEventDetail, RangeKnobMoveStartEventDetail, RangeValue } from "./components/range/range-interface";
export { RefresherEventDetail, RefresherPullEndEventDetail } from "./components/refresher/refresher-interface";
@@ -95,7 +95,7 @@ export { SegmentViewScrollEvent } from "./components/segment-view/segment-view-i
export { SelectChangeEventDetail, SelectCompareFn, SelectInterface } from "./components/select/select-interface";
export { SelectModalOption } from "./components/select-modal/select-modal-interface";
export { SelectPopoverOption } from "./components/select-popover/select-popover-interface";
-export { SpinnerSize } from "./components/spinner/spinner.interfaces";
+export { SpinnerSize } from "./components/spinner/spinner.interface";
export { TabBarChangedEventDetail, TabBarScrollEffect, TabButtonClickEventDetail, TabButtonLayout } from "./components/tab-bar/tab-bar-interface";
export { TextareaChangeEventDetail, TextareaInputEventDetail } from "./components/textarea/textarea-interface";
export { IonTitleSize } from "./components/title/title.interface";
diff --git a/core/src/components/avatar/test/badge/avatar.e2e.ts b/core/src/components/avatar/test/badge/avatar.e2e.ts
index b417dddd25a..ca89867ebee 100644
--- a/core/src/components/avatar/test/badge/avatar.e2e.ts
+++ b/core/src/components/avatar/test/badge/avatar.e2e.ts
@@ -1,7 +1,7 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
-import { ION_BADGE_SIZES, ION_BADGE_VERTICAL_POSITIONS } from '../../../badge/badge.interfaces';
+import { ION_BADGE_SIZES, ION_BADGE_VERTICAL_POSITIONS } from '../../../badge/badge.interface';
configs({ modes: ['md', 'ios', 'ionic-md'] }).forEach(({ config, screenshot, title }) => {
test.describe(title('avatar: badge'), () => {
diff --git a/core/src/components/badge/badge.interfaces.ts b/core/src/components/badge/badge.interface.ts
similarity index 100%
rename from core/src/components/badge/badge.interfaces.ts
rename to core/src/components/badge/badge.interface.ts
diff --git a/core/src/components/badge/badge.tsx b/core/src/components/badge/badge.tsx
index f534030ac3c..b449f933890 100644
--- a/core/src/components/badge/badge.tsx
+++ b/core/src/components/badge/badge.tsx
@@ -6,7 +6,7 @@ import { config } from '../../global/config';
import type { Color } from '../../interface';
import type { Hue } from '../../themes/themes.interfaces';
-import type { IonBadgeShape, IonBadgeSize, IonBadgeVerticalPosition } from './badge.interfaces';
+import type { IonBadgeShape, IonBadgeSize, IonBadgeVerticalPosition } from './badge.interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
diff --git a/core/src/components/badge/test/shape/badge.e2e.ts b/core/src/components/badge/test/shape/badge.e2e.ts
index fe788e93ae4..04a0b7ce445 100644
--- a/core/src/components/badge/test/shape/badge.e2e.ts
+++ b/core/src/components/badge/test/shape/badge.e2e.ts
@@ -1,7 +1,7 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
-import { ION_BADGE_SHAPES } from '../../../badge/badge.interfaces';
+import { ION_BADGE_SHAPES } from '../../../badge/badge.interface';
/**
* This behavior does not vary across directions.
diff --git a/core/src/components/badge/test/size/badge.e2e.ts b/core/src/components/badge/test/size/badge.e2e.ts
index 25d131cd4ad..750fe168078 100644
--- a/core/src/components/badge/test/size/badge.e2e.ts
+++ b/core/src/components/badge/test/size/badge.e2e.ts
@@ -1,7 +1,7 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
-import { ION_BADGE_SIZES } from '../../../badge/badge.interfaces';
+import { ION_BADGE_SIZES } from '../../../badge/badge.interface';
/**
* This behavior does not vary across directions.
diff --git a/core/src/components/button/test/badge/button.e2e.ts b/core/src/components/button/test/badge/button.e2e.ts
index f4854147528..b4c4ad86449 100644
--- a/core/src/components/button/test/badge/button.e2e.ts
+++ b/core/src/components/button/test/badge/button.e2e.ts
@@ -1,7 +1,7 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
-import { ION_BADGE_SIZES, ION_BADGE_VERTICAL_POSITIONS } from '../../../badge/badge.interfaces';
+import { ION_BADGE_SIZES, ION_BADGE_VERTICAL_POSITIONS } from '../../../badge/badge.interface';
configs({ modes: ['md', 'ios', 'ionic-md'] }).forEach(({ config, screenshot, title }) => {
test.describe(title('button: badge'), () => {
diff --git a/core/src/components/chip/chip.interfaces.ts b/core/src/components/chip/chip.interface.ts
similarity index 81%
rename from core/src/components/chip/chip.interfaces.ts
rename to core/src/components/chip/chip.interface.ts
index c66a56a1a3c..da809d6e389 100644
--- a/core/src/components/chip/chip.interfaces.ts
+++ b/core/src/components/chip/chip.interface.ts
@@ -2,7 +2,9 @@ import type { IonPadding, IonMargin, Hue } from '../../themes/themes.interfaces'
export type IonChipRecipe = {
letterSpacing?: string | number;
- lineHeight?: string | number;
+ line?: {
+ height?: string | number;
+ };
margin?: IonMargin;
padding?: IonPadding;
gap?: string | number;
@@ -71,7 +73,9 @@ type IonChipColorDefinition = {
};
type IonChipSizeDefinition = {
- minHeight?: string | number;
+ min?: {
+ height?: string | number;
+ };
font?: {
size?: string | number;
@@ -116,6 +120,9 @@ export type IonChipConfig = {
shape?: IonChipShape;
};
-export type IonChipFill = 'outline' | 'solid';
-export type IonChipSize = 'small' | 'large';
-export type IonChipShape = 'soft' | 'round' | 'rectangular';
+export const ION_CHIP_FILLS = ['solid', 'outline'] as const;
+export type IonChipFill = (typeof ION_CHIP_FILLS)[number];
+export const ION_CHIP_SIZES = ['small', 'large'] as const;
+export type IonChipSize = (typeof ION_CHIP_SIZES)[number];
+export const ION_CHIP_SHAPES = ['soft', 'round', 'rectangular'] as const;
+export type IonChipShape = (typeof ION_CHIP_SHAPES)[number];
diff --git a/core/src/components/chip/chip.tsx b/core/src/components/chip/chip.tsx
index efc5f5266f3..34fabfbe48b 100644
--- a/core/src/components/chip/chip.tsx
+++ b/core/src/components/chip/chip.tsx
@@ -7,7 +7,7 @@ import { config } from '../../global/config';
import type { Color } from '../../interface';
import type { Hue } from '../../themes/themes.interfaces';
-import type { IonChipFill, IonChipSize, IonChipShape } from './chip.interfaces';
+import type { IonChipFill, IonChipSize, IonChipShape } from './chip.interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
diff --git a/core/src/components/chip/test/hue/chip.e2e.ts b/core/src/components/chip/test/hue/chip.e2e.ts
index 18bf32e04c5..5afcca620ae 100644
--- a/core/src/components/chip/test/hue/chip.e2e.ts
+++ b/core/src/components/chip/test/hue/chip.e2e.ts
@@ -1,217 +1,58 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
+import { HUES } from '../../../../themes/themes.interfaces';
+import { ION_CHIP_FILLS } from '../../chip.interface';
+
+const COLORS = [
+ undefined,
+ 'primary',
+ 'secondary',
+ 'tertiary',
+ 'success',
+ 'warning',
+ 'danger',
+ 'light',
+ 'medium',
+ 'dark',
+];
+
/**
* This behavior does not vary across directions.
*/
configs({ directions: ['ltr'], modes: ['ionic-md', 'md', 'ios'] }).forEach(({ config, screenshot, title }) => {
test.describe(title('chip: hue'), () => {
- test('should render subtle chips', async ({ page }) => {
- await page.setContent(
- `
-
-
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
- `,
- config
- );
-
- const container = page.locator('#container');
-
- await expect(container).toHaveScreenshot(screenshot(`chip-hue-subtle`));
- });
-
- test('should render bold chips', async ({ page }) => {
- await page.setContent(
- `
-
-
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
-
- Chip
-
-
- `,
- config
- );
-
- const container = page.locator('#container');
-
- await expect(container).toHaveScreenshot(screenshot(`chip-hue-bold`));
+ HUES.forEach((hue) => {
+ test(`should render ${hue} chips`, async ({ page }) => {
+ const rows = ION_CHIP_FILLS.map((fill) =>
+ COLORS.map(
+ (color) => `
+
+
+ Chip
+
+ `
+ ).join('')
+ ).join('
');
+
+ await page.setContent(
+ `
+
+
+ ${rows}
+ `,
+ config
+ );
+
+ const container = page.locator('#container');
+
+ await expect(container).toHaveScreenshot(screenshot(`chip-hue-${hue}`));
+ });
});
});
});
diff --git a/core/src/components/chip/test/shape/chip.e2e.ts b/core/src/components/chip/test/shape/chip.e2e.ts
index f75df323ea7..8dc19a00ee4 100644
--- a/core/src/components/chip/test/shape/chip.e2e.ts
+++ b/core/src/components/chip/test/shape/chip.e2e.ts
@@ -1,6 +1,8 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
+import { ION_CHIP_SHAPES } from '../../chip.interface';
+
/**
* This behavior does not vary across directions
*/
@@ -10,27 +12,11 @@ configs({ modes: ['ionic-md', 'md', 'ios'], directions: ['ltr'] }).forEach(({ ti
await page.goto(`/src/components/chip/test/shape`, config);
});
- test.describe('soft', () => {
- test('should not have visual regressions', async ({ page }) => {
- const container = page.locator('#soft');
-
- await expect(container).toHaveScreenshot(screenshot(`chip-soft`));
- });
- });
-
- test.describe('round', () => {
- test('should not have visual regressions', async ({ page }) => {
- const container = page.locator('#round');
-
- await expect(container).toHaveScreenshot(screenshot(`chip-round`));
- });
- });
-
- test.describe('rectangular', () => {
- test('should not have visual regressions', async ({ page }) => {
- const container = page.locator('#rectangular');
+ ION_CHIP_SHAPES.forEach((shape) => {
+ test(`should not have visual regressions with ${shape} shape`, async ({ page }) => {
+ const container = page.locator(`#${shape}`);
- await expect(container).toHaveScreenshot(screenshot(`chip-rectangular`));
+ await expect(container).toHaveScreenshot(screenshot(`chip-${shape}`));
});
});
});
diff --git a/core/src/components/chip/test/size/chip.e2e.ts b/core/src/components/chip/test/size/chip.e2e.ts
index aaa26e1effe..2a7ddc16e03 100644
--- a/core/src/components/chip/test/size/chip.e2e.ts
+++ b/core/src/components/chip/test/size/chip.e2e.ts
@@ -1,35 +1,26 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
+import { ION_CHIP_SIZES } from '../../chip.interface';
+
/**
* This behavior does not vary across directions.
*/
configs({ modes: ['ionic-md', 'md', 'ios'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('chip: size'), () => {
- test('should render small chip', async ({ page }) => {
- await page.setContent(
- `
- Small
- `,
- config
- );
-
- const chip = page.locator('ion-chip');
-
- await expect(chip).toHaveScreenshot(screenshot(`chip-size-small`));
- });
-
- test('should render large chip', async ({ page }) => {
- await page.setContent(
- `
- Large
- `,
- config
- );
+ ION_CHIP_SIZES.forEach((size) => {
+ test(`should render ${size} chip`, async ({ page }) => {
+ await page.setContent(
+ `
+ ${size.charAt(0).toUpperCase() + size.slice(1)}
+ `,
+ config
+ );
- const chip = page.locator('ion-chip');
+ const chip = page.locator('ion-chip');
- await expect(chip).toHaveScreenshot(screenshot(`chip-size-large`));
+ await expect(chip).toHaveScreenshot(screenshot(`chip-size-${size}`));
+ });
});
});
});
diff --git a/core/src/components/content/content.interfaces.ts b/core/src/components/content/content.interface.ts
similarity index 100%
rename from core/src/components/content/content.interfaces.ts
rename to core/src/components/content/content.interface.ts
diff --git a/core/src/components/content/content.tsx b/core/src/components/content/content.tsx
index 0c6bce921f8..8522ed8235c 100644
--- a/core/src/components/content/content.tsx
+++ b/core/src/components/content/content.tsx
@@ -25,7 +25,7 @@ import { config } from '../../global/config';
import { getIonMode } from '../../global/ionic-global';
import type { Color, Mode } from '../../interface';
-import type { ScrollBaseDetail, ScrollDetail } from './content.interfaces';
+import type { ScrollBaseDetail, ScrollDetail } from './content.interface';
/**
* How long to wait (in ms) after the last `resize` event before recalculating.
diff --git a/core/src/components/item-divider/item-divider.interfaces.ts b/core/src/components/item-divider/item-divider.interface.ts
similarity index 98%
rename from core/src/components/item-divider/item-divider.interfaces.ts
rename to core/src/components/item-divider/item-divider.interface.ts
index 15e7c3a82ba..4f158c505de 100644
--- a/core/src/components/item-divider/item-divider.interfaces.ts
+++ b/core/src/components/item-divider/item-divider.interface.ts
@@ -3,7 +3,9 @@ import type { IonPadding, IonMargin } from '../../themes/themes.interfaces';
export type IonItemDividerRecipe = {
background?: string;
color?: string;
- minHeight?: string;
+ min?: {
+ height?: string;
+ };
padding?: IonPadding;
diff --git a/core/src/components/progress-bar/progress-bar.interfaces.ts b/core/src/components/progress-bar/progress-bar.interface.ts
similarity index 100%
rename from core/src/components/progress-bar/progress-bar.interfaces.ts
rename to core/src/components/progress-bar/progress-bar.interface.ts
diff --git a/core/src/components/progress-bar/progress-bar.tsx b/core/src/components/progress-bar/progress-bar.tsx
index 1e1fb652693..e4e1d74480b 100644
--- a/core/src/components/progress-bar/progress-bar.tsx
+++ b/core/src/components/progress-bar/progress-bar.tsx
@@ -7,7 +7,7 @@ import { createColorClasses } from '@utils/theme';
import { config } from '../../global/config';
import type { Color } from '../../interface';
-import type { IonProgressBarShape } from './progress-bar.interfaces';
+import type { IonProgressBarShape } from './progress-bar.interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
diff --git a/core/src/components/progress-bar/test/shape/progress-bar.e2e.ts b/core/src/components/progress-bar/test/shape/progress-bar.e2e.ts
index 4e736237cd7..03f8510bfc8 100644
--- a/core/src/components/progress-bar/test/shape/progress-bar.e2e.ts
+++ b/core/src/components/progress-bar/test/shape/progress-bar.e2e.ts
@@ -1,7 +1,7 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
-import { ION_PROGRESS_BAR_SHAPES } from '../../progress-bar.interfaces';
+import { ION_PROGRESS_BAR_SHAPES } from '../../progress-bar.interface';
/**
* This behavior does not vary across directions
diff --git a/core/src/components/skeleton-text/skeleton-text.interface.ts b/core/src/components/skeleton-text/skeleton-text.interface.ts
index 689e785b75e..b832d828c0e 100644
--- a/core/src/components/skeleton-text/skeleton-text.interface.ts
+++ b/core/src/components/skeleton-text/skeleton-text.interface.ts
@@ -25,7 +25,9 @@ export type IonSkeletonTextRecipe = {
};
};
- lineHeight?: string;
+ line?: {
+ height?: string;
+ };
margin?: Omit;
};
diff --git a/core/src/components/spinner/spinner-configs.ts b/core/src/components/spinner/spinner-configs.ts
index 362503d6275..6c9582fc480 100644
--- a/core/src/components/spinner/spinner-configs.ts
+++ b/core/src/components/spinner/spinner-configs.ts
@@ -1,4 +1,4 @@
-import type { SpinnerDefinitions } from './spinner.interfaces';
+import type { SpinnerDefinitions } from './spinner.interface';
const spinners = {
bubbles: {
diff --git a/core/src/components/spinner/spinner.interfaces.ts b/core/src/components/spinner/spinner.interface.ts
similarity index 88%
rename from core/src/components/spinner/spinner.interfaces.ts
rename to core/src/components/spinner/spinner.interface.ts
index 0b45e370de5..15bf74c52cc 100644
--- a/core/src/components/spinner/spinner.interfaces.ts
+++ b/core/src/components/spinner/spinner.interface.ts
@@ -81,4 +81,5 @@ export type IonSpinnerConfig = {
size?: SpinnerSize;
};
-export type SpinnerSize = 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge';
+export const ION_SPINNER_SIZES = ['xsmall', 'small', 'medium', 'large', 'xlarge'] as const;
+export type SpinnerSize = (typeof ION_SPINNER_SIZES)[number];
diff --git a/core/src/components/spinner/spinner.tsx b/core/src/components/spinner/spinner.tsx
index 25232666b3f..3da5f1a5284 100644
--- a/core/src/components/spinner/spinner.tsx
+++ b/core/src/components/spinner/spinner.tsx
@@ -8,7 +8,7 @@ import type { Color } from '../../interface';
import type { SpinnerTypes } from './spinner-configs';
import { SPINNERS } from './spinner-configs';
-import type { SpinnerSize, SpinnerDefinition } from './spinner.interfaces';
+import type { SpinnerSize, SpinnerDefinition } from './spinner.interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component.
diff --git a/core/src/components/spinner/test/size/spinner.e2e.ts b/core/src/components/spinner/test/size/spinner.e2e.ts
index 79452e7b885..1bddaff741c 100644
--- a/core/src/components/spinner/test/size/spinner.e2e.ts
+++ b/core/src/components/spinner/test/size/spinner.e2e.ts
@@ -1,6 +1,8 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
+import { ION_SPINNER_SIZES } from '../../spinner.interface';
+
/**
* This behavior does not vary across directions.
*
@@ -8,69 +10,19 @@ import { configs, test } from '@utils/test/playwright';
*/
configs({ directions: ['ltr'], modes: ['md', 'ionic-md'] }).forEach(({ config, screenshot, title }) => {
test.describe(title('spinner: size'), () => {
- test('should render xsmall spinner', async ({ page }) => {
- await page.setContent(
- `
-
- `,
- config
- );
-
- const spinner = page.locator('ion-spinner');
-
- await expect(spinner).toHaveScreenshot(screenshot(`spinner-size-xsmall`));
- });
-
- test('should render small spinner', async ({ page }) => {
- await page.setContent(
- `
-
- `,
- config
- );
-
- const spinner = page.locator('ion-spinner');
-
- await expect(spinner).toHaveScreenshot(screenshot(`spinner-size-small`));
- });
-
- test('should render medium spinner', async ({ page }) => {
- await page.setContent(
- `
-
- `,
- config
- );
-
- const spinner = page.locator('ion-spinner');
-
- await expect(spinner).toHaveScreenshot(screenshot(`spinner-size-medium`));
- });
-
- test('should render large spinner', async ({ page }) => {
- await page.setContent(
- `
-
- `,
- config
- );
-
- const spinner = page.locator('ion-spinner');
-
- await expect(spinner).toHaveScreenshot(screenshot(`spinner-size-large`));
- });
-
- test('should render xlarge spinner', async ({ page }) => {
- await page.setContent(
- `
-
- `,
- config
- );
-
- const spinner = page.locator('ion-spinner');
-
- await expect(spinner).toHaveScreenshot(screenshot(`spinner-size-xlarge`));
+ ION_SPINNER_SIZES.forEach((size) => {
+ test(`should render ${size} spinner`, async ({ page }) => {
+ await page.setContent(
+ `
+
+ `,
+ config
+ );
+
+ const spinner = page.locator('ion-spinner');
+
+ await expect(spinner).toHaveScreenshot(screenshot(`spinner-size-${size}`));
+ });
});
});
});
diff --git a/core/src/components/tab-button/test/badge/tab-button.e2e.ts b/core/src/components/tab-button/test/badge/tab-button.e2e.ts
index f004c3a7ef3..baf6959949b 100644
--- a/core/src/components/tab-button/test/badge/tab-button.e2e.ts
+++ b/core/src/components/tab-button/test/badge/tab-button.e2e.ts
@@ -1,9 +1,10 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
+import { ION_BADGE_SIZES, ION_BADGE_VERTICAL_POSITIONS } from '../../../badge/badge.interface';
+
configs({ modes: ['md', 'ios', 'ionic-md'] }).forEach(({ config, screenshot, title }) => {
test.describe(title('tab-button: badge'), () => {
- const positions = ['top', 'bottom'];
const layouts = ['icon-top', 'icon-bottom', 'icon-start', 'icon-end', 'icon-hide', 'label-hide'];
const icons = ['star', 'globe', 'logo-facebook', 'chatbox'];
const colors = ['danger', 'primary', 'warning', 'success'];
@@ -15,24 +16,23 @@ configs({ modes: ['md', 'ios', 'ionic-md'] }).forEach(({ config, screenshot, tit
{ label: 'label-only', hasIcon: false, hasLabel: true },
];
- ['small', 'medium', 'large'].forEach((badgeSize) => {
+ ION_BADGE_SIZES.forEach((badgeSize) => {
test(`should not have visual regressions with ${badgeSize} badges`, async ({ page }) => {
- const tabBars = positions
- .map((position) => {
- const combinedLayouts: Record = {
- 'icon-only': layouts.filter((l) => l !== 'icon-hide'),
- 'label-only': layouts.filter((l) => l !== 'label-hide'),
- };
-
- const variantGroups = slotVariants
- .map((variant) => {
- if (variant.label === 'icon-only' || variant.label === 'label-only') {
- const tabs = combinedLayouts[variant.label]
- .map((layout, i) => {
- const label = variant.hasLabel ? `Tab ${i + 1}` : '';
- const icon = variant.hasIcon ? `` : '';
+ const tabBars = ION_BADGE_VERTICAL_POSITIONS.map((position) => {
+ const combinedLayouts: Record = {
+ 'icon-only': layouts.filter((l) => l !== 'icon-hide'),
+ 'label-only': layouts.filter((l) => l !== 'label-hide'),
+ };
+
+ const variantGroups = slotVariants
+ .map((variant) => {
+ if (variant.label === 'icon-only' || variant.label === 'label-only') {
+ const tabs = combinedLayouts[variant.label]
+ .map((layout, i) => {
+ const label = variant.hasLabel ? `Tab ${i + 1}` : '';
+ const icon = variant.hasIcon ? `` : '';
- return `
+ return `
${label}
${icon}
@@ -41,52 +41,51 @@ configs({ modes: ['md', 'ios', 'ionic-md'] }).forEach(({ config, screenshot, tit
}" size="${badgeSize}" vertical="${position}">${contents[i % contents.length]}
`;
- })
- .join('\n');
+ })
+ .join('\n');
- return `
+ return `
${variant.label}
${tabs}
`;
- }
+ }
- const layoutRows = layouts
- .map((layout) => {
- const tabs = contents
- .map((html, i) => {
- const label = variant.hasLabel ? `Tab ${i + 1}` : '';
- const icon = variant.hasIcon ? `` : '';
+ const layoutRows = layouts
+ .map((layout) => {
+ const tabs = contents
+ .map((html, i) => {
+ const label = variant.hasLabel ? `Tab ${i + 1}` : '';
+ const icon = variant.hasIcon ? `` : '';
- return `
+ return `
${label}
${icon}
${html}
`;
- })
- .join('\n');
+ })
+ .join('\n');
- return `
+ return `
${layout}
${tabs}
`;
- })
- .join('\n');
+ })
+ .join('\n');
- return `
+ return `
${variant.label}
${layoutRows}
`;
- })
- .join('\n');
+ })
+ .join('\n');
- return `
+ return `
badge position: ${position}
${variantGroups}
`;
- })
- .join('\n');
+ }).join('\n');
await page.setContent(
`
diff --git a/core/src/components/tabs/tabs.interfaces.ts b/core/src/components/tabs/tabs.interface.ts
similarity index 100%
rename from core/src/components/tabs/tabs.interfaces.ts
rename to core/src/components/tabs/tabs.interface.ts
diff --git a/core/src/components/text/text.interfaces.ts b/core/src/components/text/text.interface.ts
similarity index 100%
rename from core/src/components/text/text.interfaces.ts
rename to core/src/components/text/text.interface.ts
diff --git a/core/src/components/thumbnail/thumbnail.interfaces.ts b/core/src/components/thumbnail/thumbnail.interface.ts
similarity index 100%
rename from core/src/components/thumbnail/thumbnail.interfaces.ts
rename to core/src/components/thumbnail/thumbnail.interface.ts
diff --git a/core/src/components/title/title.interface.ts b/core/src/components/title/title.interface.ts
index 16a8692e0d4..ce9e29fab2c 100644
--- a/core/src/components/title/title.interface.ts
+++ b/core/src/components/title/title.interface.ts
@@ -37,9 +37,7 @@ export type IonTitleRecipe = {
};
};
- letter?: {
- spacing?: string;
- };
+ letterSpacing?: string;
// TODO(FW-6864): remove when ion-toolbar titlePlacement works in every theme (ios center, md start)
position?: {
diff --git a/core/src/interface.d.ts b/core/src/interface.d.ts
index 40afdea3849..4bb53d494e3 100644
--- a/core/src/interface.d.ts
+++ b/core/src/interface.d.ts
@@ -7,7 +7,7 @@ export { AccordionGroupCustomEvent } from './components/accordion-group/accordio
export { AlertOptions } from './components/alert/alert-interface';
export { ActionSheetOptions } from './components/action-sheet/action-sheet-interface';
export { BreadcrumbCustomEvent } from './components/breadcrumb/breadcrumb-interface';
-export { ScrollBaseCustomEvent, ScrollCallback, ScrollCustomEvent } from './components/content/content.interfaces';
+export { ScrollBaseCustomEvent, ScrollCallback, ScrollCustomEvent } from './components/content/content.interface';
export { CheckboxCustomEvent } from './components/checkbox/checkbox-interface';
export { DatetimeCustomEvent, DatetimeHighlightStyle } from './components/datetime/datetime-interface';
export { InfiniteScrollCustomEvent } from './components/infinite-scroll/infinite-scroll-interface';
@@ -32,7 +32,7 @@ export {
export { SearchbarCustomEvent } from './components/searchbar/searchbar-interface';
export { SegmentCustomEvent } from './components/segment/segment-interface';
export { SelectCustomEvent, SelectCompareFn } from './components/select/select-interface';
-export { TabsCustomEvent } from './components/tabs/tabs.interfaces';
+export { TabsCustomEvent } from './components/tabs/tabs.interface';
export { TextareaCustomEvent } from './components/textarea/textarea-interface';
export { ToastOptions } from './components/toast/toast-interface';
export { ToggleCustomEvent } from './components/toggle/toggle-interface';
diff --git a/core/src/themes/ionic/default.tokens.ts b/core/src/themes/ionic/default.tokens.ts
index ce168adb25c..81bd9db51fe 100644
--- a/core/src/themes/ionic/default.tokens.ts
+++ b/core/src/themes/ionic/default.tokens.ts
@@ -314,7 +314,9 @@ export const defaultTheme: DefaultTheme = {
start: 'var(--ion-spacing-sm)',
},
- lineHeight: '100%',
+ line: {
+ height: '100%',
+ },
letterSpacing: '0%',
gap: 'var(--ion-spacing-xxs)',
@@ -325,13 +327,17 @@ export const defaultTheme: DefaultTheme = {
// Sizes
size: {
small: {
- minHeight: 'var(--ion-scaling-xs)',
+ min: {
+ height: 'var(--ion-scaling-xs)',
+ },
font: {
size: 'var(--ion-font-size-xs)',
},
},
large: {
- minHeight: 'var(--ion-scaling-md)',
+ min: {
+ height: 'var(--ion-scaling-md)',
+ },
font: {
size: 'var(--ion-font-size-sm)',
},
@@ -637,7 +643,9 @@ export const defaultTheme: DefaultTheme = {
IonItemDivider: {
background: baseColors.backgroundColor,
color: `var(--ion-text-color-step-600, ${mix(baseColors.white, baseColors.black, '40%')})`,
- minHeight: 'var(--ion-scaling-750)',
+ min: {
+ height: 'var(--ion-scaling-750)',
+ },
padding: {
top: 'var(--ion-spacing-0)',
@@ -926,7 +934,9 @@ export const defaultTheme: DefaultTheme = {
},
},
- lineHeight: 'var(--ion-scaling-250)',
+ line: {
+ height: 'var(--ion-scaling-250)',
+ },
margin: {
bottom: 'var(--ion-spacing-xxs)',
@@ -1060,9 +1070,7 @@ export const defaultTheme: DefaultTheme = {
},
},
- letter: {
- spacing: '0',
- },
+ letterSpacing: '0',
size: {
small: {
diff --git a/core/src/themes/ios/default.tokens.ts b/core/src/themes/ios/default.tokens.ts
index dc0cf5b5712..2f50868d822 100644
--- a/core/src/themes/ios/default.tokens.ts
+++ b/core/src/themes/ios/default.tokens.ts
@@ -328,7 +328,9 @@ export const defaultTheme: DefaultTheme = {
// Sizes
size: {
small: {
- minHeight: 'var(--ion-scaling-xs)',
+ min: {
+ height: 'var(--ion-scaling-xs)',
+ },
font: {
size: clamp(
@@ -340,7 +342,9 @@ export const defaultTheme: DefaultTheme = {
},
large: {
- minHeight: 'var(--ion-scaling-md)',
+ min: {
+ height: 'var(--ion-scaling-md)',
+ },
font: {
size: clamp('13px', `${(components.chip.font.size / global.root).toFixed(2)}rem`, '22px'),
@@ -781,7 +785,9 @@ export const defaultTheme: DefaultTheme = {
IonItemDivider: {
background: `var(--ion-background-color-step-100, ${mix(baseColors.black, baseColors.white, '90%')})`,
color: `var(--ion-text-color-step-150, ${mix(baseColors.white, baseColors.black, '85%')})`,
- minHeight: 'var(--ion-scaling-sm)',
+ min: {
+ height: 'var(--ion-scaling-sm)',
+ },
padding: {
top: 'var(--ion-spacing-0)',
@@ -960,7 +966,9 @@ export const defaultTheme: DefaultTheme = {
},
},
- lineHeight: 'var(--ion-scaling-250)',
+ line: {
+ height: 'var(--ion-scaling-250)',
+ },
margin: {
bottom: 'var(--ion-spacing-xxs)',
diff --git a/core/src/themes/md/default.tokens.ts b/core/src/themes/md/default.tokens.ts
index 06da2f5e884..a05e7543be2 100644
--- a/core/src/themes/md/default.tokens.ts
+++ b/core/src/themes/md/default.tokens.ts
@@ -328,14 +328,18 @@ export const defaultTheme: DefaultTheme = {
// Sizes
size: {
small: {
- minHeight: 'var(--ion-scaling-xs)',
+ min: {
+ height: 'var(--ion-scaling-xs)',
+ },
font: {
size: `${((components.chip.font.size - 2) / global.root).toFixed(2)}rem`,
},
},
large: {
- minHeight: 'var(--ion-scaling-md)',
+ min: {
+ height: 'var(--ion-scaling-md)',
+ },
font: {
size: `${(components.chip.font.size / global.root).toFixed(2)}rem`,
@@ -775,7 +779,9 @@ export const defaultTheme: DefaultTheme = {
IonItemDivider: {
background: baseColors.backgroundColor,
color: `var(--ion-text-color-step-600, ${mix(baseColors.white, baseColors.black, '40%')})`,
- minHeight: 'var(--ion-scaling-750)',
+ min: {
+ height: 'var(--ion-scaling-750)',
+ },
padding: {
top: 'var(--ion-spacing-0)',
@@ -1076,7 +1082,9 @@ export const defaultTheme: DefaultTheme = {
},
},
- lineHeight: 'var(--ion-scaling-250)',
+ line: {
+ height: 'var(--ion-scaling-250)',
+ },
margin: {
bottom: 'var(--ion-spacing-xxs)',
@@ -1206,9 +1214,7 @@ export const defaultTheme: DefaultTheme = {
},
},
- letter: {
- spacing: '0.0075em',
- },
+ letterSpacing: '0.0075em',
size: {
small: {
diff --git a/core/src/themes/themes.interfaces.ts b/core/src/themes/themes.interfaces.ts
index b1b77c7ebad..e759c31bce2 100644
--- a/core/src/themes/themes.interfaces.ts
+++ b/core/src/themes/themes.interfaces.ts
@@ -1,17 +1,17 @@
-import type { IonBadgeConfig, IonBadgeRecipe } from '../components/badge/badge.interfaces';
-import type { IonChipConfig, IonChipRecipe } from '../components/chip/chip.interfaces';
+import type { IonBadgeConfig, IonBadgeRecipe } from '../components/badge/badge.interface';
+import type { IonChipConfig, IonChipRecipe } from '../components/chip/chip.interface';
import type { IonColRecipe } from '../components/col/col.interface';
-import type { IonContentRecipe } from '../components/content/content.interfaces';
+import type { IonContentRecipe } from '../components/content/content.interface';
import type { IonGalleryRecipe } from '../components/gallery/gallery.interface';
import type { IonGridRecipe } from '../components/grid/grid.interface';
-import type { IonItemDividerRecipe } from '../components/item-divider/item-divider.interfaces';
-import type { IonProgressBarConfig, IonProgressBarRecipe } from '../components/progress-bar/progress-bar.interfaces';
+import type { IonItemDividerRecipe } from '../components/item-divider/item-divider.interface';
+import type { IonProgressBarConfig, IonProgressBarRecipe } from '../components/progress-bar/progress-bar.interface';
import type { IonRippleEffectRecipe } from '../components/ripple-effect/ripple-effect.interface';
import type { IonRowRecipe } from '../components/row/row.interface';
import type { IonSkeletonTextRecipe } from '../components/skeleton-text/skeleton-text.interface';
-import type { IonSpinnerConfig, IonSpinnerRecipe } from '../components/spinner/spinner.interfaces';
-import type { IonTextConfig, IonTextRecipe } from '../components/text/text.interfaces';
-import type { IonThumbnailRecipe } from '../components/thumbnail/thumbnail.interfaces';
+import type { IonSpinnerConfig, IonSpinnerRecipe } from '../components/spinner/spinner.interface';
+import type { IonTextConfig, IonTextRecipe } from '../components/text/text.interface';
+import type { IonThumbnailRecipe } from '../components/thumbnail/thumbnail.interface';
import type { IonTitleConfig, IonTitleRecipe } from '../components/title/title.interface';
import type { IonicConfig as IonicGlobalConfig } from '../utils/config';
diff --git a/docs/themes/README.md b/docs/themes/README.md
index 88af9ab9770..7eb1d21005c 100644
--- a/docs/themes/README.md
+++ b/docs/themes/README.md
@@ -36,6 +36,20 @@ core/
└── mixins.scss # Sass mixins
```
+## Component Files
+
+A component that uses the theme system keeps its recipe and config types next to its source:
+
+```bash
+core/src/components/my-component/
+├── my-component.tsx # Reads config defaults and renders CSS custom properties
+├── my-component.scss # Single base stylesheet for every theme
+├── my-component.interface.ts # Recipe and config types, plus const arrays for prop values
+└── my-component.constant.ts # Optional shared values, such as defaults
+```
+
+- Back each prop union with a `const` array, such as `ION_CHIP_SIZES`, so tests can loop over every value.
+
## Available Themes
### iOS Theme (`@ionic/theme/ios`)