mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
Merge branch 'ROU-11112-select' into ROU-11112
This commit is contained in:
@@ -3,6 +3,26 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [8.4.3](https://github.com/ionic-team/ionic-framework/compare/v8.4.2...v8.4.3) (2025-01-29)
|
||||
|
||||
**Note:** Version bump only for package @ionic/core
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.4.2](https://github.com/ionic-team/ionic-framework/compare/v8.4.1...v8.4.2) (2025-01-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **segment:** add logic to connect to segment-view in `componentDidLoad()` callback ([#30060](https://github.com/ionic-team/ionic-framework/issues/30060)) ([000f553](https://github.com/ionic-team/ionic-framework/commit/000f55303e459c583e642337fb1894f419f37d48)), closes [#30000](https://github.com/ionic-team/ionic-framework/issues/30000)
|
||||
* **select-modal:** match radio styles to iOS native ([#30119](https://github.com/ionic-team/ionic-framework/issues/30119)) ([3f8346e](https://github.com/ionic-team/ionic-framework/commit/3f8346e718ae3a6eb5008d739f10b6898b84ca9b))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [8.4.1](https://github.com/ionic-team/ionic-framework/compare/v8.4.0...v8.4.1) (2024-11-27)
|
||||
|
||||
|
||||
|
||||
@@ -2004,4 +2004,7 @@ ion-toolbar,css-prop,--padding-end,md
|
||||
ion-toolbar,css-prop,--padding-start,ios
|
||||
ion-toolbar,css-prop,--padding-start,md
|
||||
ion-toolbar,css-prop,--padding-top,ios
|
||||
ion-toolbar,css-prop,--padding-top,md
|
||||
ion-toolbar,css-prop,--padding-top,md
|
||||
ion-toolbar,part,background
|
||||
ion-toolbar,part,container
|
||||
ion-toolbar,part,content
|
||||
4
core/package-lock.json
generated
4
core/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "8.4.1",
|
||||
"version": "8.4.3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/core",
|
||||
"version": "8.4.1",
|
||||
"version": "8.4.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@stencil/core": "4.20.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "8.4.1",
|
||||
"version": "8.4.3",
|
||||
"description": "Base components for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
|
||||
4
core/src/components.d.ts
vendored
4
core/src/components.d.ts
vendored
@@ -2817,7 +2817,7 @@ export namespace Components {
|
||||
*/
|
||||
"placeholder"?: string;
|
||||
/**
|
||||
* If `true`, the user must fill in a value before submitting a form.
|
||||
* If true, screen readers will announce it as a required field. This property works only for accessibility purposes, it will not prevent the form from submitting if the value is invalid.
|
||||
*/
|
||||
"required": boolean;
|
||||
/**
|
||||
@@ -7665,7 +7665,7 @@ declare namespace LocalJSX {
|
||||
*/
|
||||
"placeholder"?: string;
|
||||
/**
|
||||
* If `true`, the user must fill in a value before submitting a form.
|
||||
* If true, screen readers will announce it as a required field. This property works only for accessibility purposes, it will not prevent the form from submitting if the value is invalid.
|
||||
*/
|
||||
"required"?: boolean;
|
||||
/**
|
||||
|
||||
@@ -197,7 +197,9 @@ export class Select implements ComponentInterface {
|
||||
@Prop({ mutable: true }) value?: any | null;
|
||||
|
||||
/**
|
||||
* If `true`, the user must fill in a value before submitting a form.
|
||||
* If true, screen readers will announce it as a required field. This property
|
||||
* works only for accessibility purposes, it will not prevent the form from
|
||||
* submitting if the value is invalid.
|
||||
*/
|
||||
@Prop() required = false;
|
||||
|
||||
|
||||
@@ -125,3 +125,35 @@ describe('select: slot interactivity', () => {
|
||||
expect(divSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('ion-select: required', () => {
|
||||
it('should have a aria-required attribute as true in inner button', async () => {
|
||||
const page = await newSpecPage({
|
||||
components: [Select],
|
||||
html: `
|
||||
<ion-select required="true"></ion-select>
|
||||
`,
|
||||
});
|
||||
|
||||
const select = page.body.querySelector('ion-select')!;
|
||||
|
||||
const nativeButton = select.shadowRoot!.querySelector('button')!;
|
||||
|
||||
expect(nativeButton.getAttribute('aria-required')).toBe('true');
|
||||
});
|
||||
|
||||
it('should not have a aria-required attribute as false in inner button', async () => {
|
||||
const page = await newSpecPage({
|
||||
components: [Select],
|
||||
html: `
|
||||
<ion-select required="false"></ion-select>
|
||||
`,
|
||||
});
|
||||
|
||||
const select = page.body.querySelector('ion-select')!;
|
||||
|
||||
const nativeButton = select.shadowRoot!.querySelector('button')!;
|
||||
|
||||
expect(nativeButton.getAttribute('aria-required')).toBe('false');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,6 +13,10 @@ import type { Color, CssClassMap, StyleEventDetail } from '../../interface';
|
||||
* @slot secondary - Content is placed to the left of the toolbar text in `ios` mode, and directly to the right in `md` mode.
|
||||
* @slot primary - Content is placed to the right of the toolbar text in `ios` mode, and to the far right in `md` mode.
|
||||
* @slot end - Content is placed to the right of the toolbar text in LTR, and to the left in RTL.
|
||||
*
|
||||
* @part background - The background of the toolbar, covering the entire area behind the toolbar content.
|
||||
* @part container - The container that wraps all toolbar content, including the default slot and named slot content.
|
||||
* @part content - The container for the default slot, wrapping content provided without a named slot.
|
||||
*/
|
||||
@Component({
|
||||
tag: 'ion-toolbar',
|
||||
@@ -97,11 +101,11 @@ export class Toolbar implements ComponentInterface {
|
||||
}),
|
||||
}}
|
||||
>
|
||||
<div class="toolbar-background"></div>
|
||||
<div class="toolbar-container">
|
||||
<div class="toolbar-background" part="background"></div>
|
||||
<div class="toolbar-container" part="container">
|
||||
<slot name="start"></slot>
|
||||
<slot name="secondary"></slot>
|
||||
<div class="toolbar-content">
|
||||
<div class="toolbar-content" part="content">
|
||||
<slot></slot>
|
||||
</div>
|
||||
<slot name="primary"></slot>
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { SpinnerTypes } from '../components/spinner/spinner-configs';
|
||||
import type { TabButtonLayout } from '../components/tab-bar/tab-bar-interface';
|
||||
import type { AnimationBuilder, Mode } from '../interface';
|
||||
|
||||
import type { LogLevel } from './logging';
|
||||
import type { PlatformConfig } from './platform';
|
||||
|
||||
export interface IonicConfig {
|
||||
@@ -220,6 +221,15 @@ export interface IonicConfig {
|
||||
*/
|
||||
experimentalCloseWatcher?: boolean;
|
||||
|
||||
/**
|
||||
* Configures the logging level for Ionic Framework:
|
||||
*
|
||||
* - `'OFF'`: No errors or warnings are logged.
|
||||
* - `'ERROR'`: Logs only errors.
|
||||
* - `'WARN'`: Logs errors and warnings.
|
||||
*/
|
||||
logLevel?: LogLevel;
|
||||
|
||||
// PRIVATE configs
|
||||
keyboardHeight?: number;
|
||||
inputShims?: boolean;
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
import { config } from '@global/config';
|
||||
|
||||
export const enum LogLevel {
|
||||
OFF = 'OFF',
|
||||
ERROR = 'ERROR',
|
||||
WARN = 'WARN',
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a warning to the console with an Ionic prefix
|
||||
* to indicate the library that is warning the developer.
|
||||
@@ -5,18 +13,24 @@
|
||||
* @param message - The string message to be logged to the console.
|
||||
*/
|
||||
export const printIonWarning = (message: string, ...params: any[]) => {
|
||||
return console.warn(`[Ionic Warning]: ${message}`, ...params);
|
||||
const logLevel = config.get('logLevel', LogLevel.WARN);
|
||||
if ([LogLevel.WARN].includes(logLevel)) {
|
||||
return console.warn(`[Ionic Warning]: ${message}`, ...params);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
/**
|
||||
* Logs an error to the console with an Ionic prefix
|
||||
* to indicate the library that is warning the developer.
|
||||
*
|
||||
* @param message - The string message to be logged to the console.
|
||||
* @param params - Additional arguments to supply to the console.error.
|
||||
*/
|
||||
export const printIonError = (message: string, ...params: any) => {
|
||||
return console.error(`[Ionic Error]: ${message}`, ...params);
|
||||
export const printIonError = (message: string, ...params: any[]) => {
|
||||
const logLevel = config.get('logLevel', LogLevel.ERROR);
|
||||
if ([LogLevel.ERROR, LogLevel.WARN].includes(logLevel)) {
|
||||
return console.error(`[Ionic Error]: ${message}`, ...params);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
114
core/src/utils/logging/test/logging.spec.ts
Normal file
114
core/src/utils/logging/test/logging.spec.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import { config } from '@global/config';
|
||||
import { LogLevel } from '../index';
|
||||
|
||||
import { printIonError, printIonWarning } from '../index';
|
||||
|
||||
describe('Logging', () => {
|
||||
describe('#printIonWarning', () => {
|
||||
let consoleWarnSpy: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
consoleWarnSpy = jest.spyOn(console, 'warn');
|
||||
// Suppress console.warn output from polluting the test output
|
||||
consoleWarnSpy.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
consoleWarnSpy.mockRestore();
|
||||
});
|
||||
|
||||
describe('when the logLevel configuration is not set', () => {
|
||||
it('logs a warning to the console', () => {
|
||||
config.set('logLevel', undefined);
|
||||
|
||||
printIonWarning('This is a warning message');
|
||||
|
||||
expect(consoleWarnSpy).toHaveBeenCalledWith('[Ionic Warning]: This is a warning message');
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the logLevel configuration is set to 'WARN'", () => {
|
||||
it('logs a warning to the console', () => {
|
||||
config.set('logLevel', LogLevel.WARN);
|
||||
|
||||
printIonWarning('This is a warning message');
|
||||
|
||||
expect(consoleWarnSpy).toHaveBeenCalledWith('[Ionic Warning]: This is a warning message');
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the logLevel configuration is set to 'ERROR'", () => {
|
||||
it('does not log a warning to the console', () => {
|
||||
config.set('logLevel', LogLevel.ERROR);
|
||||
|
||||
printIonWarning('This is a warning message');
|
||||
|
||||
expect(consoleWarnSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the logLevel configuration is set to 'OFF'", () => {
|
||||
it('does not log a warning to the console', () => {
|
||||
config.set('logLevel', LogLevel.OFF);
|
||||
|
||||
printIonWarning('This is a warning message');
|
||||
|
||||
expect(consoleWarnSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#printIonError', () => {
|
||||
let consoleErrorSpy: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
consoleErrorSpy = jest.spyOn(console, 'error');
|
||||
// Suppress console.error output from polluting the test output
|
||||
consoleErrorSpy.mockImplementation(() => {});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
consoleErrorSpy.mockRestore();
|
||||
});
|
||||
|
||||
describe('when the logLevel configuration is not set', () => {
|
||||
it('logs an error to the console', () => {
|
||||
config.set('logLevel', undefined);
|
||||
|
||||
printIonError('This is an error message');
|
||||
|
||||
expect(consoleErrorSpy).toHaveBeenCalledWith('[Ionic Error]: This is an error message');
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the logLevel configuration is set to 'ERROR'", () => {
|
||||
it('logs an error to the console', () => {
|
||||
config.set('logLevel', LogLevel.ERROR);
|
||||
|
||||
printIonError('This is an error message');
|
||||
|
||||
expect(consoleErrorSpy).toHaveBeenCalledWith('[Ionic Error]: This is an error message');
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the logLevel configuration is set to 'WARN'", () => {
|
||||
it('logs an error to the console', () => {
|
||||
config.set('logLevel', LogLevel.WARN);
|
||||
|
||||
printIonError('This is an error message');
|
||||
|
||||
expect(consoleErrorSpy).toHaveBeenCalledWith('[Ionic Error]: This is an error message');
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the logLevel configuration is set to 'OFF'", () => {
|
||||
it('does not log an error to the console', () => {
|
||||
config.set('logLevel', LogLevel.OFF);
|
||||
|
||||
printIonError('This is an error message');
|
||||
|
||||
expect(consoleErrorSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user