From 0f67a78475ef771ac95d03b5abcff568b299d5eb Mon Sep 17 00:00:00 2001 From: Nikita Barsukov Date: Thu, 24 Oct 2024 16:13:20 +0300 Subject: [PATCH] feat(legacy): `InputTime` & `InputDateTime` support `AM` / `PM` formats (#9595) --- projects/cdk/date-time/test/time.spec.ts | 74 +++++-- projects/cdk/date-time/time.ts | 48 ++++- projects/cdk/date-time/types.ts | 8 +- .../input-date-time/input-date-time.spec.ts | 31 ++- .../legacy/input-time/input-time.spec.ts | 186 +++++++++++++----- projects/demo/src/modules/app/app.const.ts | 1 + .../input-date-time/examples/6/index.html | 9 + .../input-date-time/examples/6/index.ts | 21 ++ .../components/input-date-time/index.html | 16 ++ .../components/input-date-time/index.ts | 9 +- .../input-time/examples/5/index.html | 24 +-- .../components/input-time/examples/5/index.ts | 34 +--- .../modules/components/input-time/index.html | 15 +- .../modules/components/input-time/index.ts | 3 + projects/i18n/languages/belarusian/kit.ts | 3 + projects/i18n/languages/chinese/kit.ts | 3 + projects/i18n/languages/dutch/kit.ts | 3 + projects/i18n/languages/english/kit.ts | 3 + projects/i18n/languages/french/kit.ts | 3 + projects/i18n/languages/german/kit.ts | 3 + projects/i18n/languages/hebrew/kit.ts | 3 + projects/i18n/languages/italian/kit.ts | 3 + projects/i18n/languages/japan/kit.ts | 3 + projects/i18n/languages/kazakh/kit.ts | 3 + projects/i18n/languages/korean/kit.ts | 3 + projects/i18n/languages/lithuanian/kit.ts | 3 + projects/i18n/languages/malay/kit.ts | 3 + projects/i18n/languages/polish/kit.ts | 3 + projects/i18n/languages/portuguese/kit.ts | 3 + projects/i18n/languages/russian/kit.ts | 3 + projects/i18n/languages/spanish/kit.ts | 3 + projects/i18n/languages/turkish/kit.ts | 3 + projects/i18n/languages/ukrainian/kit.ts | 3 + projects/i18n/languages/vietnamese/kit.ts | 3 + projects/i18n/types/language.ts | 3 + .../input-time/input-time.component.ts | 15 +- .../input-time/input-time.options.ts | 5 +- 37 files changed, 430 insertions(+), 132 deletions(-) create mode 100644 projects/demo/src/modules/components/input-date-time/examples/6/index.html create mode 100644 projects/demo/src/modules/components/input-date-time/examples/6/index.ts diff --git a/projects/cdk/date-time/test/time.spec.ts b/projects/cdk/date-time/test/time.spec.ts index 007742a7da1e..b3fb25fcca5f 100644 --- a/projects/cdk/date-time/test/time.spec.ts +++ b/projects/cdk/date-time/test/time.spec.ts @@ -127,6 +127,35 @@ describe('TuiTime', () => { expect(time.seconds).toBe(0); expect(time.ms).toBe(888); }); + + describe('mode with AM / PM', () => { + ( + [ + ['12:00 AM', {hours: 0, minutes: 0}], + ['12:34 AM', {hours: 0, minutes: 34}], + ['12:59 AM', {hours: 0, minutes: 59}], + ['01:00 AM', {hours: 1, minutes: 0}], + ['11:00 AM', {hours: 11, minutes: 0}], + ['11:59 AM', {hours: 11, minutes: 59}], + ['12:00 PM', {hours: 12, minutes: 0}], + ['12:01 PM', {hours: 12, minutes: 1}], + ['12:59 PM', {hours: 12, minutes: 59}], + ['01:00 PM', {hours: 13, minutes: 0}], + ['11:00 PM', {hours: 23, minutes: 0}], + ['11:59 PM', {hours: 23, minutes: 59}], + ['04:59', {hours: 4, minutes: 59}], + ] as const + ).forEach(([timeString, {hours, minutes}]) => { + it(`from ${timeString}`, () => { + const time = TuiTime.fromString(timeString); + + expect(time.hours).toBe(hours); + expect(time.minutes).toBe(minutes); + expect(time.seconds).toBe(0); + expect(time.ms).toBe(0); + }); + }); + }); }); describe('current', () => { @@ -334,22 +363,45 @@ describe('TuiTime', () => { }); }); - it('stringify', () => { - const time = new TuiTime(6, 36, 1, 1); + describe('toString(mode) method', () => { + it('without mode parameter', () => { + const time = new TuiTime(6, 36, 1, 1); - expect(time.toString()).toBe('06:36:01.001'); - }); + expect(time.toString()).toBe('06:36:01.001'); + }); - it('stringify and fill zeros for seconds', () => { - const time = new TuiTime(6, 36, 0, 0); + it('stringify and fill zeros for seconds', () => { + const time = new TuiTime(6, 36, 0, 0); - expect(time.toString('HH:MM:SS')).toBe('06:36:00'); - }); + expect(time.toString('HH:MM:SS')).toBe('06:36:00'); + }); - it('stringify and fill zeros for seconds and ms', () => { - const time = new TuiTime(6, 36, 0, 0); + it('stringify and fill zeros for seconds and ms', () => { + const time = new TuiTime(6, 36, 0, 0); - expect(time.toString('HH:MM:SS.MSS')).toBe('06:36:00.000'); + expect(time.toString('HH:MM:SS.MSS')).toBe('06:36:00.000'); + }); + + describe('HH:MM AA', () => { + ( + [ + [new TuiTime(0, 0), '12:00 AM'], + [new TuiTime(0, 30), '12:30 AM'], + [new TuiTime(0, 59), '12:59 AM'], + [new TuiTime(1, 1), '01:01 AM'], + [new TuiTime(11, 11), '11:11 AM'], + [new TuiTime(11, 59), '11:59 AM'], + [new TuiTime(12, 0), '12:00 PM'], + [new TuiTime(13, 0), '01:00 PM'], + [new TuiTime(16, 0), '04:00 PM'], + [new TuiTime(23, 59), '11:59 PM'], + ] as const + ).forEach(([time, timeString]) => { + it(`{hours: ${time.hours}, minutes: ${time.minutes}} => ${timeString}`, () => { + expect(time.toString('HH:MM AA')).toBe(timeString); + }); + }); + }); }); describe('valueOf returns', () => { diff --git a/projects/cdk/date-time/time.ts b/projects/cdk/date-time/time.ts index 6637027977d1..d1257674baf2 100644 --- a/projects/cdk/date-time/time.ts +++ b/projects/cdk/date-time/time.ts @@ -1,5 +1,6 @@ /// +import {CHAR_NO_BREAK_SPACE} from '@taiga-ui/cdk/constants'; import {tuiInRange} from '@taiga-ui/cdk/utils/math'; import { @@ -113,7 +114,7 @@ export class TuiTime implements TuiTimeLike { * Parses string into TuiTime object */ public static fromString(time: string): TuiTime { - const hours = Number(time.slice(0, 2)); + const hours = this.parseHours(time); const minutes = Number(time.slice(3, 5)) || 0; const seconds = Number(time.slice(6, 8)) || 0; const ms = Number(time.slice(9, 12)) || 0; @@ -134,6 +135,29 @@ export class TuiTime implements TuiTimeLike { ); } + private static parseMeridiemPeriod(time: string): 'AM' | 'PM' | null { + return ( + (/[AP]M/.exec(time.toUpperCase().replaceAll(/\W/g, ''))?.[0] as + | 'AM' + | 'PM') || null + ); + } + + private static parseHours(time: string): number { + const hours = Number(time.slice(0, 2)); + const meridiem = this.parseMeridiemPeriod(time); + + if (!meridiem) { + return hours; + } + + if (hours === 12) { + return meridiem === 'AM' ? 0 : 12; + } + + return meridiem === 'PM' ? hours + 12 : hours; + } + /** * Shifts time by hours and minutes */ @@ -165,14 +189,18 @@ export class TuiTime implements TuiTimeLike { * Converts TuiTime to string */ public toString(mode?: TuiTimeMode): string { - const needAddMs = mode === 'HH:MM:SS.MSS' || (!mode && this.ms > 0); + const needAddMs = mode?.startsWith('HH:MM:SS.MSS') || (!mode && this.ms > 0); const needAddSeconds = - needAddMs || mode === 'HH:MM:SS' || (!mode && this.seconds > 0); - const hhMm = `${this.formatTime(this.hours)}:${this.formatTime(this.minutes)}`; + needAddMs || mode?.startsWith('HH:MM:SS') || (!mode && this.seconds > 0); + const {hours = this.hours, meridiem = ''} = mode?.includes('AA') + ? this.toTwelveHour(this.hours) + : {}; + const hhMm = `${this.formatTime(hours)}:${this.formatTime(this.minutes)}`; const ss = needAddSeconds ? `:${this.formatTime(this.seconds)}` : ''; const mss = needAddMs ? `.${this.formatTime(this.ms, 3)}` : ''; + const aa = meridiem && `${CHAR_NO_BREAK_SPACE}${meridiem}`; - return `${hhMm}${ss}${mss}`; + return `${hhMm}${ss}${mss}${aa}`; } public valueOf(): number { @@ -203,4 +231,14 @@ export class TuiTime implements TuiTimeLike { private formatTime(time: number, digits = 2): string { return String(time).padStart(digits, '0'); } + + private toTwelveHour(hours: number): {hours: number; meridiem: string} { + const meridiem = hours >= 12 ? 'PM' : 'AM'; + + if (hours === 0 || hours === 12) { + return {meridiem, hours: 12}; + } + + return {meridiem, hours: hours % 12}; + } } diff --git a/projects/cdk/date-time/types.ts b/projects/cdk/date-time/types.ts index bb17f30ff2b1..6e96f90de78c 100644 --- a/projects/cdk/date-time/types.ts +++ b/projects/cdk/date-time/types.ts @@ -4,7 +4,13 @@ * * YMD - yyyy.mm.dd */ export type TuiDateMode = 'DMY' | 'MDY' | 'YMD'; -export type TuiTimeMode = 'HH:MM:SS.MSS' | 'HH:MM:SS' | 'HH:MM'; +export type TuiTimeMode = + | 'HH:MM AA' + | 'HH:MM:SS AA' + | 'HH:MM:SS.MSS AA' + | 'HH:MM:SS.MSS' + | 'HH:MM:SS' + | 'HH:MM'; /** * Optionally has year and/or month and/or day diff --git a/projects/demo-playwright/tests/legacy/input-date-time/input-date-time.spec.ts b/projects/demo-playwright/tests/legacy/input-date-time/input-date-time.spec.ts index fe3469f2b4ce..5bc1cc41da16 100644 --- a/projects/demo-playwright/tests/legacy/input-date-time/input-date-time.spec.ts +++ b/projects/demo-playwright/tests/legacy/input-date-time/input-date-time.spec.ts @@ -174,13 +174,19 @@ test.describe('InputDateTime', () => { ); await timeModeSelect.textfield.click(); - await timeModeSelect.selectOptions([1]); + await timeModeSelect.selectOptions([2]); + + await expect(timeModeSelect.textfield).toHaveValue('HH:MM:SS'); + await inputDateTime.textfield.focus(); await expect(inputDateTime.host).toHaveScreenshot('03-timeMode=HH:MM.SS.png'); await timeModeSelect.textfield.click(); - await timeModeSelect.selectOptions([2]); + await timeModeSelect.selectOptions([4]); + + await expect(timeModeSelect.textfield).toHaveValue('HH:MM:SS.MSS'); + await inputDateTime.textfield.focus(); await expect(inputDateTime.host).toHaveScreenshot( @@ -196,6 +202,27 @@ test.describe('InputDateTime', () => { await expect(inputDateTime.textfield).toHaveValue('07.06.2024, 23:59:00.000'); }); + + test.describe('AM / PM', () => { + test.beforeEach(async ({page}) => { + await tuiGoto(page, `${DemoRoute.InputDateTime}/API?timeMode=HH:MM%20AA`); + await inputDateTime.textfield.pressSequentially('2092020'); + + await expect(inputDateTime.textfield).toHaveValue('20.09.2020'); + }); + + test('330a => 03:30 AM', async () => { + await inputDateTime.textfield.pressSequentially('330a'); + + await expect(inputDateTime.textfield).toHaveValue('20.09.2020, 03:30 AM'); + }); + + test('330p => 03:30 PM', async () => { + await inputDateTime.textfield.pressSequentially('330p'); + + await expect(inputDateTime.textfield).toHaveValue('20.09.2020, 03:30 PM'); + }); + }); }); test.describe('invalid date', () => { diff --git a/projects/demo-playwright/tests/legacy/input-time/input-time.spec.ts b/projects/demo-playwright/tests/legacy/input-time/input-time.spec.ts index 28bea16dd3e1..36dd6fffd588 100644 --- a/projects/demo-playwright/tests/legacy/input-time/input-time.spec.ts +++ b/projects/demo-playwright/tests/legacy/input-time/input-time.spec.ts @@ -52,9 +52,16 @@ test.describe('InputTime', () => { inputTime = new TuiInputTimePO(apiPageExample.locator('tui-input-time')); }); - ['HH:MM', 'HH:MM:SS', 'HH:MM:SS.MSS'].forEach((mode) => { + [ + 'HH:MM', + 'HH:MM AA', + 'HH:MM:SS', + 'HH:MM:SS AA', + 'HH:MM:SS.MSS', + 'HH:MM:SS.MSS AA', + ].forEach((mode) => { test(`the input is configured for ${mode} mode`, async ({page}) => { - await tuiGoto(page, `components/input-time/API?mode=${mode}`, { + await tuiGoto(page, `${DemoRoute.InputTime}/API?mode=${mode}`, { date: MOCK_DATE, }); @@ -82,7 +89,7 @@ test.describe('InputTime', () => { }) => { await tuiGoto( page, - 'components/input-time/API?disabledItemHandler$=1&items$=1', + `${DemoRoute.InputTime}/API?disabledItemHandler$=1&items$=1`, { date: MOCK_DATE, }, @@ -100,7 +107,7 @@ test.describe('InputTime', () => { test(`the dropdown is configured for ${size} size`, async ({page}) => { await tuiGoto( page, - `components/input-time/API?items$=1&itemSize=${size}`, + `${DemoRoute.InputTime}/API?items$=1&itemSize=${size}`, { date: MOCK_DATE, }, @@ -130,61 +137,125 @@ test.describe('InputTime', () => { }); test.describe('Basic typing from keyboard', () => { - test.beforeEach(async ({page}) => { - await tuiGoto(page, `${DemoRoute.InputTime}/API?mode=HH:MM`); - await inputTime.textfield.clear(); + test.describe('HH:MM', () => { + test.beforeEach(async ({page}) => { + await tuiGoto(page, `${DemoRoute.InputTime}/API?mode=HH:MM`); + await inputTime.textfield.clear(); - await expect(inputTime.textfield).toHaveValue(''); - }); + await expect(inputTime.textfield).toHaveValue(''); + }); - test('3 => 03', async () => { - await inputTime.textfield.pressSequentially('3'); + test('3 => 03', async () => { + await inputTime.textfield.pressSequentially('3'); - await expect(inputTime.textfield).toHaveValue('03'); - await expect(inputTime.textfield).toHaveJSProperty('selectionStart', 2); - await expect(inputTime.textfield).toHaveJSProperty('selectionEnd', 2); - }); + await expect(inputTime.textfield).toHaveValue('03'); + await expect(inputTime.textfield).toHaveJSProperty( + 'selectionStart', + 2, + ); + await expect(inputTime.textfield).toHaveJSProperty('selectionEnd', 2); + }); - test('1111 => 11:11', async () => { - await inputTime.textfield.pressSequentially('1111'); + test('1111 => 11:11', async () => { + await inputTime.textfield.pressSequentially('1111'); - await expect(inputTime.textfield).toHaveValue('11:11'); - await expect(inputTime.textfield).toHaveJSProperty( - 'selectionStart', - '11:11'.length, - ); - await expect(inputTime.textfield).toHaveJSProperty( - 'selectionEnd', - '11:11'.length, - ); - }); + await expect(inputTime.textfield).toHaveValue('11:11'); + await expect(inputTime.textfield).toHaveJSProperty( + 'selectionStart', + '11:11'.length, + ); + await expect(inputTime.textfield).toHaveJSProperty( + 'selectionEnd', + '11:11'.length, + ); + }); - test('0130 => 01:30', async () => { - await inputTime.textfield.pressSequentially('0130'); + test('0130 => 01:30', async () => { + await inputTime.textfield.pressSequentially('0130'); - await expect(inputTime.textfield).toHaveValue('01:30'); - await expect(inputTime.textfield).toHaveJSProperty( - 'selectionStart', - '01:30'.length, - ); - await expect(inputTime.textfield).toHaveJSProperty( - 'selectionEnd', - '01:30'.length, - ); + await expect(inputTime.textfield).toHaveValue('01:30'); + await expect(inputTime.textfield).toHaveJSProperty( + 'selectionStart', + '01:30'.length, + ); + await expect(inputTime.textfield).toHaveJSProperty( + 'selectionEnd', + '01:30'.length, + ); + }); + + test('99 => 09:09', async () => { + await inputTime.textfield.pressSequentially('99'); + + await expect(inputTime.textfield).toHaveValue('09:09'); + await expect(inputTime.textfield).toHaveJSProperty( + 'selectionStart', + '09:09'.length, + ); + await expect(inputTime.textfield).toHaveJSProperty( + 'selectionEnd', + '09:09'.length, + ); + }); }); - test('99 => 09:09', async () => { - await inputTime.textfield.pressSequentially('99'); + test.describe('HH:MM AA', () => { + test.beforeEach(async ({page}) => { + await tuiGoto(page, `${DemoRoute.InputTime}/API?mode=HH:MM%20AA`); + await inputTime.textfield.clear(); - await expect(inputTime.textfield).toHaveValue('09:09'); - await expect(inputTime.textfield).toHaveJSProperty( - 'selectionStart', - '09:09'.length, - ); - await expect(inputTime.textfield).toHaveJSProperty( - 'selectionEnd', - '09:09'.length, - ); + await expect(inputTime.textfield).toHaveValue(''); + }); + + test('2 => 02', async () => { + await inputTime.textfield.pressSequentially('2'); + + await expect(inputTime.textfield).toHaveValue('02'); + await expect(inputTime.textfield).toHaveJSProperty( + 'selectionStart', + 2, + ); + await expect(inputTime.textfield).toHaveJSProperty('selectionEnd', 2); + }); + + test('333a => 03:33 AM', async () => { + await inputTime.textfield.pressSequentially('333a'); + + await expect(inputTime.textfield).toHaveValue('03:33 AM'); + await expect(inputTime.textfield).toHaveJSProperty( + 'selectionStart', + '03:33 AM'.length, + ); + await expect(inputTime.textfield).toHaveJSProperty( + 'selectionEnd', + '03:33 AM'.length, + ); + }); + + test('00 => 0', async () => { + await inputTime.textfield.pressSequentially('00'); + + await expect(inputTime.textfield).toHaveValue('0'); + await expect(inputTime.textfield).toHaveJSProperty( + 'selectionStart', + 1, + ); + await expect(inputTime.textfield).toHaveJSProperty('selectionEnd', 1); + }); + + test('1234p => 12:34 PM', async () => { + await inputTime.textfield.pressSequentially('1234p'); + + await expect(inputTime.textfield).toHaveValue('12:34 PM'); + await expect(inputTime.textfield).toHaveJSProperty( + 'selectionStart', + '12:34 PM'.length, + ); + await expect(inputTime.textfield).toHaveJSProperty( + 'selectionEnd', + '12:34 PM'.length, + ); + }); }); }); @@ -204,7 +275,7 @@ test.describe('InputTime', () => { test.describe('HH:MM', () => { test.beforeEach(async ({page}) => { - await tuiGoto(page, 'components/input-time/API?mode=HH:MM'); + await tuiGoto(page, `${DemoRoute.InputTime}/API?mode=HH:MM`); }); check('1', '01:00'); @@ -215,9 +286,20 @@ test.describe('InputTime', () => { check('12:34', '12:34'); }); + test.describe('HH:MM AA', () => { + test.beforeEach(async ({page}) => { + await tuiGoto(page, `${DemoRoute.InputTime}/API?mode=HH:MM%20AA`); + }); + + check('0', '12:00 AM'); + check('01', '01:00 AM'); + check('012', '01:02 AM'); + check('0123', '01:23 AM'); + }); + test.describe('HH:MM:SS', () => { test.beforeEach(async ({page}) => { - await tuiGoto(page, 'components/input-time/API?mode=HH:MM:SS'); + await tuiGoto(page, `${DemoRoute.InputTime}/API?mode=HH:MM:SS`); }); check('1', '01:00:00'); @@ -233,7 +315,7 @@ test.describe('InputTime', () => { test.describe('HH:MM:SS.MSS', () => { test.beforeEach(async ({page}) => { - await tuiGoto(page, 'components/input-time/API?mode=HH:MM:SS.MSS'); + await tuiGoto(page, `${DemoRoute.InputTime}/API?mode=HH:MM:SS.MSS`); }); check('1', '01:00:00.000'); diff --git a/projects/demo/src/modules/app/app.const.ts b/projects/demo/src/modules/app/app.const.ts index da4aff85dc08..25cc5be60210 100644 --- a/projects/demo/src/modules/app/app.const.ts +++ b/projects/demo/src/modules/app/app.const.ts @@ -36,6 +36,7 @@ export const DEFAULT_LANGUAGE_PAGE = new Set([ 'InputCardGroup', 'InputFiles', 'InputPhoneInternational', + 'InputTime', 'MobileCalendar', 'Table', 'TablePagination', diff --git a/projects/demo/src/modules/components/input-date-time/examples/6/index.html b/projects/demo/src/modules/components/input-date-time/examples/6/index.html new file mode 100644 index 000000000000..fd8d6852f267 --- /dev/null +++ b/projects/demo/src/modules/components/input-date-time/examples/6/index.html @@ -0,0 +1,9 @@ + + Enter 12-hour time format + + +

Control value:

+
{{ control.value | json }}
diff --git a/projects/demo/src/modules/components/input-date-time/examples/6/index.ts b/projects/demo/src/modules/components/input-date-time/examples/6/index.ts new file mode 100644 index 000000000000..de4cc59900e6 --- /dev/null +++ b/projects/demo/src/modules/components/input-date-time/examples/6/index.ts @@ -0,0 +1,21 @@ +import {JsonPipe} from '@angular/common'; +import {Component} from '@angular/core'; +import {FormControl, ReactiveFormsModule} from '@angular/forms'; +import {changeDetection} from '@demo/emulate/change-detection'; +import {encapsulation} from '@demo/emulate/encapsulation'; +import {TuiDay, TuiTime} from '@taiga-ui/cdk'; +import {TuiInputDateTimeModule} from '@taiga-ui/legacy'; + +@Component({ + standalone: true, + imports: [JsonPipe, ReactiveFormsModule, TuiInputDateTimeModule], + templateUrl: './index.html', + encapsulation, + changeDetection, +}) +export default class Example { + protected readonly control = new FormControl([ + new TuiDay(2020, 8, 20), + new TuiTime(15, 30), + ] as const); +} diff --git a/projects/demo/src/modules/components/input-date-time/index.html b/projects/demo/src/modules/components/input-date-time/index.html index 3d4024ba6cfd..bce43fee055c 100644 --- a/projects/demo/src/modules/components/input-date-time/index.html +++ b/projects/demo/src/modules/components/input-date-time/index.html @@ -99,6 +99,22 @@

DI-tokens for input-configurations:

Please note that native input datetime only supports HH:MM time mode + + + + Any + timeMode + ending with + AA + is 12-hour time format with meridiem part + + diff --git a/projects/demo/src/modules/components/input-date-time/index.ts b/projects/demo/src/modules/components/input-date-time/index.ts index d1e63e051723..7ca5aebc57bb 100644 --- a/projects/demo/src/modules/components/input-date-time/index.ts +++ b/projects/demo/src/modules/components/input-date-time/index.ts @@ -84,13 +84,16 @@ export default class PageComponent extends AbstractExampleTuiControl { protected items = this.itemsVariants[0]!; - protected readonly modeVariants: readonly TuiTimeMode[] = [ + protected readonly modeVariants = [ 'HH:MM', + 'HH:MM AA', 'HH:MM:SS', + 'HH:MM:SS AA', 'HH:MM:SS.MSS', - ]; + 'HH:MM:SS.MSS AA', + ] as const satisfies readonly TuiTimeMode[]; - protected mode = this.modeVariants[0]!; + protected mode: TuiTimeMode = this.modeVariants[0]; public override cleaner = false; diff --git a/projects/demo/src/modules/components/input-time/examples/5/index.html b/projects/demo/src/modules/components/input-time/examples/5/index.html index 1fa28f6d5bd5..d511f60f1dee 100644 --- a/projects/demo/src/modules/components/input-time/examples/5/index.html +++ b/projects/demo/src/modules/components/input-time/examples/5/index.html @@ -1,15 +1,9 @@ -
- - 12h time - - -
+ + Enter 12-hour time format + + +

Control value:

+
{{ control.value | json }}
diff --git a/projects/demo/src/modules/components/input-time/examples/5/index.ts b/projects/demo/src/modules/components/input-time/examples/5/index.ts index 3d4d7fe9f074..3ef640691dba 100644 --- a/projects/demo/src/modules/components/input-time/examples/5/index.ts +++ b/projects/demo/src/modules/components/input-time/examples/5/index.ts @@ -1,40 +1,18 @@ +import {JsonPipe} from '@angular/common'; import {Component} from '@angular/core'; -import {FormControl, FormGroup, ReactiveFormsModule} from '@angular/forms'; +import {FormControl, ReactiveFormsModule} from '@angular/forms'; import {changeDetection} from '@demo/emulate/change-detection'; import {encapsulation} from '@demo/emulate/encapsulation'; -import type {TuiTime} from '@taiga-ui/cdk'; -import {TuiSwitch} from '@taiga-ui/kit'; -import { - TuiInputTimeModule, - tuiInputTimeOptionsProvider, - TuiTextfieldControllerModule, -} from '@taiga-ui/legacy'; +import {TuiTime} from '@taiga-ui/cdk'; +import {TuiInputTimeModule} from '@taiga-ui/legacy'; @Component({ standalone: true, - imports: [ - ReactiveFormsModule, - TuiInputTimeModule, - TuiSwitch, - TuiTextfieldControllerModule, - ], + imports: [JsonPipe, ReactiveFormsModule, TuiInputTimeModule], templateUrl: './index.html', encapsulation, changeDetection, - providers: [ - tuiInputTimeOptionsProvider({ - mode: 'HH:MM', - maxValues: {HH: 11, MM: 59, SS: 59, MS: 999}, - }), - ], }) export default class Example { - protected readonly testForm = new FormGroup({ - testValue: new FormControl(null), - isPm: new FormControl(false), - }); - - protected get postfix(): string { - return this.testForm.value?.isPm ? 'PM' : 'AM'; - } + protected readonly control = new FormControl(new TuiTime(17, 0)); } diff --git a/projects/demo/src/modules/components/input-time/index.html b/projects/demo/src/modules/components/input-time/index.html index 01af37a33ab9..9609b9be4da8 100644 --- a/projects/demo/src/modules/components/input-time/index.html +++ b/projects/demo/src/modules/components/input-time/index.html @@ -61,11 +61,20 @@

DI-tokens for input-configurations:

/> + [description]="amPmDescription" + > + + Any + mode + ending with + AA + is 12-hour time format with meridiem part + + texts[mode])); } - protected onClick(): void { - this.open = !this.open; - } - protected onFocused(focused: boolean): void { this.updateFocused(focused); @@ -246,8 +242,9 @@ export class TuiInputTimeComponent return maskitoTimeOptionsGenerator({ mode, step: readOnly ? 0 : 1, + // TODO(v5): timeSegmentMaxValues: this.options.timeSegmentMaxValues timeSegmentMaxValues: { - hours: HH, + hours: mode.includes('AA') ? 12 : HH, minutes: MM, seconds: SS, milliseconds: MS, @@ -278,14 +275,10 @@ export class TuiInputTimeComponent return this.items.find((item) => TUI_STRICT_MATCHER(item, value)); } - private close(): void { - this.open = false; - } - private focusInput(preventScroll = false): void { if (this.nativeFocusableElement) { this.nativeFocusableElement.focus({preventScroll}); - this.close(); + this.open = false; } } } diff --git a/projects/legacy/components/input-time/input-time.options.ts b/projects/legacy/components/input-time/input-time.options.ts index 6c5ffef201b7..faadd4829e52 100644 --- a/projects/legacy/components/input-time/input-time.options.ts +++ b/projects/legacy/components/input-time/input-time.options.ts @@ -8,13 +8,16 @@ import type {PolymorpheusContent} from '@taiga-ui/polymorpheus'; export interface TuiInputTimeOptions { readonly icon: PolymorpheusContent>; readonly itemSize: TuiSizeL | TuiSizeS; + // TODO(v5): timeSegmentMaxValues: Partial> readonly maxValues: Record; readonly mode: TuiTimeMode; readonly nativePicker?: boolean; } +// TODO(v5): delete it export type TuiTimeFormatParts = 'HH' | 'MM' | 'MS' | 'SS'; +// TODO(v5): delete it export const MAX_TIME_VALUES: Record = { HH: 23, MM: 59, @@ -25,7 +28,7 @@ export const MAX_TIME_VALUES: Record = { export const TUI_INPUT_TIME_DEFAULT_OPTIONS: TuiInputTimeOptions = { icon: () => '@tui.clock', mode: 'HH:MM', - maxValues: MAX_TIME_VALUES, + maxValues: MAX_TIME_VALUES, // TODO(v5): use empty object itemSize: 'm', nativePicker: false, };