Skip to content

Commit

Permalink
feat(angular): add angular compatibility layer for new date and time …
Browse files Browse the repository at this point in the history
…picker (#498)

* chore: init copy

* chore: rework component structure and hierarchy

* chore: cleanup

* chore: add docs

* fix: prettier

* chore: cleanup

* chore: final touches

* chore: angular

* chore: stuff

* chore: time limit

* chore: cleanup

* chore: cleanup

* chore: cleanup

* chore: update pnpm

* chore: cleanup
  • Loading branch information
fynnfeldpausch committed Apr 22, 2024
1 parent 0321ba8 commit 304c226
Show file tree
Hide file tree
Showing 20 changed files with 11,899 additions and 10,583 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/angular.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 8
version: 9
run_install: false
- name: Get pnpm store directory
shell: bash
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 8
version: 9
run_install: false
- name: Get pnpm store directory
shell: bash
Expand Down Expand Up @@ -55,7 +55,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 8
version: 9
run_install: false
- name: Get pnpm store directory
shell: bash
Expand Down Expand Up @@ -87,7 +87,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 8
version: 9
run_install: false
- name: Get pnpm store directory
shell: bash
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 8
version: 9
- name: Setup Node
uses: actions/setup-node@v4
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/react.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 8
version: 9
run_install: false
- name: Get pnpm store directory
shell: bash
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 8
version: 9
run_install: false
if: ${{ steps.release.outputs.release_created }}
- name: Get pnpm store directory
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tokens.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v3
with:
version: 8
version: 9
run_install: false
- name: Get pnpm store directory
shell: bash
Expand Down
8 changes: 7 additions & 1 deletion angular/projects/catalyst/src/lib/catalyst.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@ import { CatDialogActionsComponent } from './dialog/dialog-actions.component';
import { CatDialogHeaderComponent } from './dialog/dialog-header.component';
import { CatDialogComponent } from './dialog/dialog.component';
import { BooleanValueAccessor } from './directives/boolean-value-accessor';
import { DateValueAccessor } from './directives/date-value-accessor';
import * as Components from './directives/proxies';
import { RadioValueAccessor } from './directives/radio-value-accessor';
import { SelectValueAccessor } from './directives/select-value-accessor';
import { SelectValueAccessorDecorator } from './directives/select-value-accessor-decorator';
import { TextValueAccessor } from './directives/text-value-accessor';
import { TimeValueAccessor } from './directives/time-value-accessor';
import { ValueAccessorDecorator } from './directives/value-accessor-decorator';
import { DatetimeComponent } from './datetime/datetime.component';

const CatComponents = [
Components.CatAlert,
Expand Down Expand Up @@ -51,11 +54,14 @@ const CatComponents = [

const CatDirectives = [
BooleanValueAccessor,
DateValueAccessor,
RadioValueAccessor,
SelectValueAccessor,
SelectValueAccessorDecorator,
TextValueAccessor,
ValueAccessorDecorator
TimeValueAccessor,
ValueAccessorDecorator,
DatetimeComponent
];

export const CAT_LOG_TOKEN = new InjectionToken<RootLogger>('CAT_LOG', {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { DatetimeComponent } from './datetime.component';

describe('DatetimeComponent', () => {
let component: DatetimeComponent;
let fixture: ComponentFixture<DatetimeComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [DatetimeComponent]
})
.overrideTemplate(DatetimeComponent, '')
.compileComponents();

fixture = TestBed.createComponent(DatetimeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
137 changes: 137 additions & 0 deletions angular/projects/catalyst/src/lib/datetime/datetime.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { AfterContentInit, Component, ContentChild, Input, ViewEncapsulation } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { DateValueAccessor } from '../directives/date-value-accessor';
import { TimeValueAccessor } from '../directives/time-value-accessor';

@Component({
selector: 'cat-datetime',
template: '<ng-content></ng-content>',
styles: ['cat-datetime { display: contents; }'],
encapsulation: ViewEncapsulation.None,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: DatetimeComponent,
multi: true
}
]
})
export class DatetimeComponent implements AfterContentInit, ControlValueAccessor {
protected lastValue: any;
protected lastDateValue: any;
protected lastTimeValue: any;

@ContentChild(DateValueAccessor) dateInput?: DateValueAccessor;
@ContentChild(TimeValueAccessor) timeInput?: TimeValueAccessor;

private _min?: Date | null;
get min(): Date | null {
return this._min ?? null;
}
@Input() set min(value: Date | null | undefined) {
this._min = value;
setTimeout(() => {
const min = value ? this.toLocalISODate(value) : undefined;
this.dateInput?.nativeElement.setAttribute('min', min);
this.limitTime('min');
});
}

private _max?: Date | null;
get max(): Date | null {
return this._max ?? null;
}
@Input() set max(value: Date | null | undefined) {
this._max = value;
setTimeout(() => {
const max = value ? this.toLocalISODate(value) : undefined;
this.dateInput?.nativeElement.setAttribute('max', max);
this.limitTime('max');
});
}

ngAfterContentInit(): void {
if (!this.dateInput) {
throw new Error('Missing child element <cat-date></cat-date>');
}
if (!this.timeInput) {
throw new Error('Missing child element <cat-time></cat-time>');
}
}

writeValue(value: any): void {
this.lastValue = this.lastDateValue = this.lastTimeValue = value;
setTimeout(() => {
this.dateInput?.writeValue(value);
this.timeInput?.writeValue(value);
});
}

registerOnChange(fn: (value: any) => void) {
setTimeout(() => {
this.dateInput?.registerOnChange((value: any) => {
this.lastDateValue = value;
this.limitTime('min');
this.limitTime('max');
fn(this.value);
});
this.timeInput?.registerOnChange((value: any) => {
this.lastTimeValue = value;
fn(this.value);
});
});
}

registerOnTouched(fn: () => void) {
setTimeout(() => {
this.dateInput?.registerOnTouched(fn);
this.timeInput?.registerOnTouched(fn);
});
}

setDisabledState?(isDisabled: boolean): void {
setTimeout(() => {
this.dateInput?.setDisabledState(isDisabled);
this.timeInput?.setDisabledState(isDisabled);
});
}

private get value() {
if (this.lastDateValue && this.lastTimeValue) {
const result = new Date(this.lastDateValue);
result.setHours(
this.lastTimeValue.getHours(),
this.lastTimeValue.getMinutes(),
this.lastTimeValue.getSeconds(),
this.lastTimeValue.getMilliseconds()
);
return result;
}
return null;
}

private limitTime(mode: 'min' | 'max') {
const limit = mode === 'min' ? this.min : this.max;
const limitIso = limit ? this.toLocalISODate(limit) : undefined;
const dateIso = this.lastDateValue ? this.toLocalISODate(this.lastDateValue) : undefined;
const attr = limit && limitIso === dateIso ? this.toLocalISOTime(limit) : undefined;
if (attr) {
this.timeInput?.nativeElement.setAttribute(mode, attr);
} else {
this.timeInput?.nativeElement.removeAttribute(mode);
}
}

private toLocalISODate(value: Date) {
const year = value.getFullYear();
const month = (value.getMonth() + 1).toString().padStart(2, '0');
const day = value.getDate().toString().padStart(2, '0');
return `${year}-${month}-${day}`;
}

private toLocalISOTime(value: Date) {
const hours = value.getHours().toString().padStart(2, '0');
const mins = value.getMinutes().toString().padStart(2, '0');
return `${hours}:${mins}`;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Directive, ElementRef } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';

import { ValueAccessor } from './value-accessor';

@Directive({
/* tslint:disable-next-line:directive-selector */
selector: 'cat-date, cat-date-inline',
host: {
'(catChange)': 'handleChangeEvent($event.target.value)'
},
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: DateValueAccessor,
multi: true
}
]
})
export class DateValueAccessor extends ValueAccessor {
constructor(el: ElementRef) {
super(el);
}
get nativeElement() {
return this.el.nativeElement;
}
writeValue(value: any) {
if (value && value instanceof Date) {
const year = value.getFullYear();
const month = (value.getMonth() + 1).toString().padStart(2, '0');
const day = value.getDate().toString().padStart(2, '0');
return super.writeValue(`${year}-${month}-${day}`);
}
return super.writeValue(undefined);
}
handleChangeEvent(value: any) {
const [match, year, month, day] = value?.match(/^(\d{4})-(\d{2})-(\d{2})/) ?? [];
return super.handleChangeEvent(match ? new Date(Number(year), Number(month) - 1, Number(day)) : null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ValueAccessor } from './value-accessor';

@Directive({
/* tslint:disable-next-line:directive-selector */
selector: 'cat-input, cat-textarea, cat-datepicker, cat-datepicker-inline, cat-date, cat-date-inline, cat-time',
selector: 'cat-input, cat-textarea, cat-datepicker, cat-datepicker-inline',
host: {
'(catChange)': 'handleChangeEvent($event.target.value)'
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Directive, ElementRef } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';

import { ValueAccessor } from './value-accessor';

@Directive({
/* tslint:disable-next-line:directive-selector */
selector: 'cat-time',
host: {
'(catChange)': 'handleChangeEvent($event.target.value)'
},
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: TimeValueAccessor,
multi: true
}
]
})
export class TimeValueAccessor extends ValueAccessor {
constructor(el: ElementRef) {
super(el);
}
get nativeElement() {
return this.el.nativeElement;
}
writeValue(value: any) {
if (value && value instanceof Date) {
const hours = value.getHours().toString().padStart(2, '0');
const mins = value.getMinutes().toString().padStart(2, '0');
return super.writeValue(`${hours}:${mins}`);
}
return super.writeValue(undefined);
}
handleChangeEvent(value: any) {
const [match, hours, mins] = value?.match(/^(\d{2}):(\d{2})/) ?? [];
if (match) {
const date = new Date();
date.setHours(Number(hours), Number(mins), 0, 0);
return super.handleChangeEvent(date);
}
return super.handleChangeEvent(null);
}
}
3 changes: 3 additions & 0 deletions angular/projects/catalyst/src/public-api.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
export * from './lib/catalyst.module';
export * from './lib/datetime/datetime.component';
export { CatDialogActionsComponent } from './lib/dialog/dialog-actions.component';
export { CatDialogHeaderComponent } from './lib/dialog/dialog-header.component';
export { CatDialogComponent } from './lib/dialog/dialog.component';
export { CatDialogConfig, CatDialogService } from './lib/dialog/dialog.service';
export * from './lib/directives/boolean-value-accessor';
export * from './lib/directives/date-value-accessor';
export * from './lib/directives/proxies';
export * from './lib/directives/radio-value-accessor';
export * from './lib/directives/select-value-accessor';
export * from './lib/directives/select-value-accessor-decorator';
export * from './lib/directives/text-value-accessor';
export * from './lib/directives/time-value-accessor';
export * from './lib/directives/value-accessor';
export * from './lib/directives/value-accessor-decorator';

0 comments on commit 304c226

Please sign in to comment.