Skip to content

Commit

Permalink
feat(kit): Time & DateTime support AM / PM formats
Browse files Browse the repository at this point in the history
  • Loading branch information
nsbarsukov committed Sep 27, 2024
1 parent 732013e commit b8e741d
Show file tree
Hide file tree
Showing 42 changed files with 1,242 additions and 134 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ module.exports = {
rules: {
'react/display-name': 'off',
'react/react-in-jsx-scope': 'off',
'no-irregular-whitespace': 'off',
},
},
],
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('DateTime | Separator', () => {
it('rejects dot as separator', () => {
cy.get('@input')
.type('1412.')
.should('have.value', '14/12')
.should('have.value', '14/12/')
.type('2000')
.should('have.value', '14/12/2000');
});
Expand Down Expand Up @@ -57,7 +57,7 @@ describe('DateTime | Separator', () => {
.type('14')
.should('have.value', '14')
.type('12.')
.should('have.value', '14-12');
.should('have.value', '14-12-');
});
});
});
375 changes: 375 additions & 0 deletions projects/demo-integrations/src/tests/kit/time/time-meridiem.cy.ts

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ describe('Time', () => {

describe('max hours 11', () => {
beforeEach(() => {
cy.visit(`/${DemoPath.Time}/API?mode=HH&timeSegmentMaxValues$=1`);
cy.visit(`/${DemoPath.Time}/API?mode=HH&timeSegmentMaxValues$=2`);
cy.get('#demo-content input')
.should('be.visible')
.first()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import {DemoPath} from '@demo/constants';

import {range} from '../../utils';

describe('Time | [timeSegmentMaxValues] property', () => {
describe('{hours: 5, minutes: 5, seconds: 5, milliseconds: 5}', () => {
beforeEach(() => {
cy.visit(`/${DemoPath.Time}/API?mode=HH:MM&timeSegmentMaxValues$=2`);
cy.visit(`/${DemoPath.Time}/API?mode=HH:MM&timeSegmentMaxValues$=3`);
cy.get('#demo-content input')
.should('be.visible')
.first()
Expand Down Expand Up @@ -152,7 +154,3 @@ describe('Time | [timeSegmentMaxValues] property', () => {
});
});
});

function range(from: number, to: number): number[] {
return new Array(to - from + 1).fill(null).map((_, i) => from + i);
}
7 changes: 7 additions & 0 deletions projects/demo-integrations/src/tests/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function range(from: number, to: number): number[] {
return new Array(to - from + 1).fill(null).map((_, i) => from + i);
}

export function withCaretLabel(value: string, caretIndex: number): string {
return `${value.slice(0, caretIndex)}|${value.slice(caretIndex)}`;
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ export default class SupportedInputTypesDocPageComponent {
};

protected getInput(type: HTMLInputElement['type']): string {
// eslint-disable-next-line no-irregular-whitespace
return `<input type="${type}" />`;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,11 @@ export default class DateTimeMaskDocComponent implements GeneratorOptions {

protected readonly timeModeOptions = [
'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 MaskitoTimeMode[];

protected readonly minMaxOptions = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import mask from './mask';
[style.max-width.rem]="20"
[(ngModel)]="value"
>
HH:MM:SS
Enter 24-hour time format
<input
inputmode="decimal"
tuiTextfieldLegacy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ import mask from './mask';
template: `
<tui-input
tuiTextfieldCustomContent="@tui.clock"
tuiTextfieldFiller="hh:mm"
tuiTextfieldFiller="HH:MM AA"
[style.max-width.rem]="20"
[tuiTextfieldLabelOutside]="true"
[(ngModel)]="value"
>
Enter 12-hour time format
<input
inputmode="decimal"
tuiTextfieldLegacy
Expand All @@ -32,6 +32,6 @@ import mask from './mask';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TimeMaskDocExample2 {
protected value = '11:59';
protected readonly mask = mask;
protected value = '03:30 PM';
}
18 changes: 18 additions & 0 deletions projects/demo/src/pages/kit/time/examples/2-am-pm/mask.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {type MaskitoOptions, maskitoUpdateElement} from '@maskito/core';
import {maskitoEventHandler, maskitoTimeOptionsGenerator} from '@maskito/kit';

const timeOptions = maskitoTimeOptionsGenerator({
mode: 'HH:MM AA',
});

export default {
...timeOptions,
plugins: [
...timeOptions.plugins,
maskitoEventHandler('blur', (element) => {
if (element.value.length >= 'HH:MM'.length && !element.value.endsWith('M')) {
maskitoUpdateElement(element, `${element.value} AM`);
}
}),
],
} satisfies MaskitoOptions;

This file was deleted.

20 changes: 18 additions & 2 deletions projects/demo/src/pages/kit/time/examples/3-step/mask.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
import {maskitoTimeOptionsGenerator} from '@maskito/kit';
import {type MaskitoOptions, maskitoUpdateElement} from '@maskito/core';
import {maskitoEventHandler, maskitoTimeOptionsGenerator} from '@maskito/kit';

export default maskitoTimeOptionsGenerator({
const timeOptions = maskitoTimeOptionsGenerator({
mode: 'HH:MM:SS',
step: 1,
});

export default {
...timeOptions,
plugins: [
...timeOptions.plugins,
maskitoEventHandler('blur', (element) => {
const [hh = '', mm = '', ss = ''] = element.value.split(':');

maskitoUpdateElement(
element,
[hh, mm, ss].map((segment) => segment.padEnd(2, '0')).join(':'),
);
}),
],
} satisfies MaskitoOptions;
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {ChangeDetectionStrategy, Component} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {MaskitoDirective} from '@maskito/angular';
import {TuiTextfield} from '@taiga-ui/core';
import {TuiSegmented} from '@taiga-ui/kit';

import mask from './mask';

@Component({
standalone: true,
selector: 'time-mask-doc-example-4',
imports: [FormsModule, MaskitoDirective, TuiSegmented, TuiTextfield],
template: `
<!-- TODO: remove (input)="(0)" (Taiga UI CD bug) -->
<tui-textfield
filler="HH:MM"
[style.max-width.rem]="20"
[tuiTextfieldCleaner]="false"
(input)="(0)"
>
<input
inputmode="decimal"
tuiTextfield
[maskito]="mask"
[(ngModel)]="value"
/>
<tui-segmented>
<button type="button">AM</button>
<button type="button">PM</button>
</tui-segmented>
</tui-textfield>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TimeMaskDocExample4 {
protected value = '03:30';
protected readonly mask = mask;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {maskitoTimeOptionsGenerator} from '@maskito/kit';

export default maskitoTimeOptionsGenerator({
mode: 'HH:MM',
timeSegmentMaxValues: {hours: 12},
timeSegmentMinValues: {hours: 1},
});
31 changes: 24 additions & 7 deletions projects/demo/src/pages/kit/time/time-mask-doc.component.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import {ChangeDetectionStrategy, Component} from '@angular/core';
import {FormControl, ReactiveFormsModule} from '@angular/forms';
import {DocExamplePrimaryTab} from '@demo/constants';
import {RouterLink} from '@angular/router';
import {DemoPath, DocExamplePrimaryTab} from '@demo/constants';
import {MaskitoDirective} from '@maskito/angular';
import type {MaskitoOptions} from '@maskito/core';
import type {MaskitoTimeMode, MaskitoTimeSegments} from '@maskito/kit';
import {maskitoTimeOptionsGenerator} from '@maskito/kit';
import type {TuiRawLoaderContent} from '@taiga-ui/addon-doc';
import {TuiAddonDoc} from '@taiga-ui/addon-doc';
import {TuiNotification} from '@taiga-ui/core';
import {TuiLink, TuiNotification} from '@taiga-ui/core';
import {TuiInputModule, TuiTextfieldControllerModule} from '@taiga-ui/legacy';

import {TimeMaskDocExample1} from './examples/1-modes/component';
import {TimeMaskDocExample2} from './examples/2-twelve-hour-format/component';
import {TimeMaskDocExample2} from './examples/2-am-pm/component';
import {TimeMaskDocExample3} from './examples/3-step/component';
import {TimeMaskDocExample4} from './examples/4-time-segments-min-max/component';

type GeneratorOptions = Required<Parameters<typeof maskitoTimeOptionsGenerator>[0]>;

Expand All @@ -22,11 +24,14 @@ type GeneratorOptions = Required<Parameters<typeof maskitoTimeOptionsGenerator>[
imports: [
MaskitoDirective,
ReactiveFormsModule,
RouterLink,
TimeMaskDocExample1,
TimeMaskDocExample2,
TimeMaskDocExample3,
TimeMaskDocExample4,
TuiAddonDoc,
TuiInputModule,
TuiLink,
TuiNotification,
TuiTextfieldControllerModule,
],
Expand All @@ -35,6 +40,8 @@ type GeneratorOptions = Required<Parameters<typeof maskitoTimeOptionsGenerator>[
changeDetection: ChangeDetectionStrategy.OnPush,
})
export default class TimeMaskDocComponent implements GeneratorOptions {
protected pages = DemoPath;

protected readonly maskitoParseStringifyTimeDemo = import(
'./examples/maskito-parse-stringify-time-demo.md?raw'
);
Expand All @@ -43,34 +50,44 @@ export default class TimeMaskDocComponent implements GeneratorOptions {
[DocExamplePrimaryTab.MaskitoOptions]: import('./examples/1-modes/mask.ts?raw'),
};

protected readonly modeExample2: Record<string, TuiRawLoaderContent> = {
[DocExamplePrimaryTab.MaskitoOptions]: import(
'./examples/2-twelve-hour-format/mask.ts?raw'
),
protected readonly amPmExample2: Record<string, TuiRawLoaderContent> = {
[DocExamplePrimaryTab.MaskitoOptions]: import('./examples/2-am-pm/mask.ts?raw'),
};

protected readonly stepExample3: Record<string, TuiRawLoaderContent> = {
[DocExamplePrimaryTab.MaskitoOptions]: import('./examples/3-step/mask.ts?raw'),
};

protected readonly timeSegmentsMinMaxExample4: Record<string, TuiRawLoaderContent> = {
[DocExamplePrimaryTab.MaskitoOptions]: import(
'./examples/4-time-segments-min-max/mask.ts?raw'
),
};

protected apiPageControl = new FormControl('');

protected readonly modeOptions = [
'HH:MM',
'HH:MM AA',
'HH:MM:SS',
'HH:MM:SS AA',
'HH:MM:SS.MSS',
'HH:MM:SS.MSS AA',
'HH',
'HH AA',
'MM:SS.MSS',
'SS.MSS',
] as const satisfies readonly MaskitoTimeMode[];

protected readonly timeSegmentMaxValuesOptions = [
{},
{hours: 23, minutes: 59, seconds: 59, milliseconds: 999},
{hours: 11},
{hours: 5, minutes: 5, seconds: 5, milliseconds: 5},
] as const satisfies ReadonlyArray<Partial<MaskitoTimeSegments<number>>>;

public mode: MaskitoTimeMode = this.modeOptions[0];
public timeSegmentMinValues = {};
public timeSegmentMaxValues: Partial<MaskitoTimeSegments<number>> =
this.timeSegmentMaxValuesOptions[0];

Expand Down
Loading

0 comments on commit b8e741d

Please sign in to comment.