I've developed a unique block-cursor date/time input field that utilizes Angular states and animations to showcase various ongoing or transitional states. These input fields are live on this website:
export const BACKGROUND_ANIMATIONS = trigger('displayState', [
state('error', style({ backgroundColor: getBackgroundColor(ERROR_BACKGROUND, '#F67') })),
state('normal', style({ backgroundColor: getBackgroundColor(NORMAL_BACKGROUND, 'white') })),
state('confirm', style({ backgroundColor: getBackgroundColor(CONFIRM_BACKGROUND, '#6C6') })),
state('warning', style({ backgroundColor: getBackgroundColor(WARNING_BACKGROUND, '#FC6') })),
state('view-only', style({ backgroundColor: getBackgroundColor(VIEW_ONLY_BACKGROUND, 'black') })),
state('disabled', style({ backgroundColor: getBackgroundColor(DISABLED_BACKGROUND, '#CCC') })),
state('dark-error', style({ backgroundColor: getBackgroundColor(ERROR_BACKGROUND, '#C36', true) })),
state('dark-normal', style({ backgroundColor: getBackgroundColor(NORMAL_BACKGROUND, '#333', true) })),
state('dark-confirm', style({ backgroundColor: getBackgroundColor(CONFIRM_BACKGROUND, '#292', true) })),
state('dark-warning', style({ backgroundColor: getBackgroundColor(WARNING_BACKGROUND, '#B80', true) })),
state('dark-view-only', style({ backgroundColor: getBackgroundColor(VIEW_ONLY_BACKGROUND, '#0A0', true) })),
state('dark-disabled', style({ backgroundColor: getBackgroundColor(DISABLED_BACKGROUND, '#444', true) })),
transition('normal => error', animate(FLASH_DURATION)),
transition('error => normal', animate(FLASH_DURATION)),
transition('normal => confirm', animate(FLASH_DURATION)),
transition('confirm => normal', animate(FLASH_DURATION)),
transition('warning => error', animate(FLASH_DURATION)),
transition('error => warning', animate(FLASH_DURATION)),
transition('dark-normal => dark-error', animate(FLASH_DURATION)),
transition('dark-error => dark-normal', animate(FLASH_DURATION)),
transition('dark-normal => dark-confirm', animate(FLASH_DURATION)),
transition('dark-confirm => dark-normal', animate(FLASH_DURATION)),
transition('dark-warning => dark-error', animate(FLASH_DURATION)),
transition('dark-error => dark-warning', animate(FLASH_DURATION))
]);
All the above animations are defined within an abstract superclass for flexible usage in concrete subclasses:
@Component({
selector: 'tbw-time-editor',
animations: [BACKGROUND_ANIMATIONS],
templateUrl: '../digit-sequence-editor/digit-sequence-editor.directive.html',
styleUrls: ['../digit-sequence-editor/digit-sequence-editor.directive.scss', './time-editor.component.scss'],
providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TimeEditorComponent), multi: true },
{ provide: NG_VALIDATORS, useExisting: forwardRef(() => TimeEditorComponent), multi: true }]
})
export class TimeEditorComponent extends DigitSequenceEditorDirective<number> implements OnInit {
...
My goal is to reduce the number of display states by half and eliminate the need for prefixed dark_
states. Ideally, I want color updates to be automatic based on the addition of the tbw-dark-mode
class to the HTML body.
Presently, my design is limited to supporting only light and dark modes with customization options. Creating additional modes beyond these two presets seems unfeasible at the moment.
An issue arises with timing as the color definitions are generated during application initialization, lacking a way to update them later using Angular APIs.
The function getBackgroundColor()
helps initially define colors, but it's not without flaws such as iOS Safari misinterpreting transparency leading to fixed fallback values.
Though I devised a workaround for dynamic color updates, using a custom DynamicColor
class enforced type coercion and screen refreshing to implement changes.
Is there a more efficient method? Perhaps leveraging CSS classes instead of predefined styles or uncovering an undiscovered Angular API to alter animations installed by the @Component
decorator?