Skip to content

Commit 8040396

Browse files
committed
First pass at new dynamic state color handling.
1 parent ae43888 commit 8040396

4 files changed

Lines changed: 64 additions & 71 deletions

File tree

package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"@angular/router": "~12.1.3",
2525
"@tubular/math": "^3.1.0",
2626
"@tubular/time": "^3.3.1",
27-
"@tubular/util": "^4.2.2",
27+
"@tubular/util": "^4.3.1",
2828
"rxjs": "~6.6.0",
2929
"tslib": "^2.1.0",
3030
"zone.js": "~0.11.4"

projects/tubular-ng-widgets/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"@angular/core": "^12.1.3",
77
"@tubular/math": "^3.1.0",
88
"@tubular/time": "^3.3.1",
9-
"@tubular/util": "^4.2.2"
9+
"@tubular/util": "^4.3.1"
1010
},
1111
"dependencies": {
1212
"tslib": "^2.1.0"

projects/tubular-ng-widgets/src/lib/digit-sequence-editor/digit-sequence-editor.directive.ts

Lines changed: 55 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { animate, AnimationMetadata, state, style, transition, trigger } from '@angular/animations';
1+
import { animate, state, style, transition, trigger } from '@angular/animations';
22
import {
33
AfterViewInit, ChangeDetectorRef, Directive, ElementRef, EventEmitter, Input, NgZone, OnDestroy, OnInit, Output, ViewChild
44
} from '@angular/core';
55
import { abs, floor, max, min, Point, random, round, sign } from '@tubular/math';
66
import {
7-
eventToKey, getCssValue, htmlEscape, isAndroid, isChrome, isChromeOS, isEdge, isEqual, isIOS, isNumber, isSamsung,
8-
isString, noop, processMillis, toBoolean, toNumber
7+
eventToKey, getCssRuleValue, getCssValue, htmlEscape, isAndroid, isChrome, isChromeOS, isEdge, isEqual, isIOS,
8+
isNumber, isSamsung, isString, noop, processMillis, toBoolean, toNumber
99
} from '@tubular/util';
1010
import { Subscription, timer } from 'rxjs';
1111
import { getClientXYForTouchEvent, getPageXYForTouchEvent } from '../util/touch-events';
@@ -80,7 +80,7 @@ function getBackgroundColor(className: string, defaultColor: string, darkMode =
8080
document.body.appendChild(outer);
8181
elem.classList.add(className);
8282
outer.appendChild(elem);
83-
let result = getCssValue(elem, 'background-color');
83+
let result = getCssRuleValue(elem, 'background-color');
8484
document.body.removeChild(outer);
8585

8686
if (result === 'transparent' || result === 'rgba(0, 0, 0, 0)')
@@ -129,42 +129,37 @@ const WARNING_BACKGROUND = 'tbw-warning-background';
129129

130130
const DOT_DOT_TYPING_INTERVAL = 500;
131131

132-
const stateDefinitions: AnimationMetadata[] = [];
133-
let stateDefinitionsRefreshed = false;
134-
135-
function updateStateDefinitions(): void {
136-
stateDefinitions.length = 0;
137-
stateDefinitions.push(...[
138-
state('error', style({ backgroundColor: getBackgroundColor(ERROR_BACKGROUND, '#F67') })),
139-
state('normal', style({ backgroundColor: getBackgroundColor(NORMAL_BACKGROUND, 'white') })),
140-
state('confirm', style({ backgroundColor: getBackgroundColor(CONFIRM_BACKGROUND, '#6C6') })),
141-
state('warning', style({ backgroundColor: getBackgroundColor(WARNING_BACKGROUND, '#FC6') })),
142-
state('view-only', style({ backgroundColor: getBackgroundColor(VIEW_ONLY_BACKGROUND, 'black') })),
143-
state('disabled', style({ backgroundColor: getBackgroundColor(DISABLED_BACKGROUND, '#CCC') })),
144-
state('dark-error', style({ backgroundColor: getBackgroundColor(ERROR_BACKGROUND, '#C36', true) })),
145-
state('dark-normal', style({ backgroundColor: getBackgroundColor(NORMAL_BACKGROUND, '#333', true) })),
146-
state('dark-confirm', style({ backgroundColor: getBackgroundColor(CONFIRM_BACKGROUND, '#292', true) })),
147-
state('dark-warning', style({ backgroundColor: getBackgroundColor(WARNING_BACKGROUND, '#B80', true) })),
148-
state('dark-view-only', style({ backgroundColor: getBackgroundColor(VIEW_ONLY_BACKGROUND, '#0A0', true) })),
149-
state('dark-disabled', style({ backgroundColor: getBackgroundColor(DISABLED_BACKGROUND, '#444', true) })),
150-
transition('normal => error', animate(FLASH_DURATION)),
151-
transition('error => normal', animate(FLASH_DURATION)),
152-
transition('normal => confirm', animate(FLASH_DURATION)),
153-
transition('confirm => normal', animate(FLASH_DURATION)),
154-
transition('warning => error', animate(FLASH_DURATION)),
155-
transition('error => warning', animate(FLASH_DURATION)),
156-
transition('dark-normal => dark-error', animate(FLASH_DURATION)),
157-
transition('dark-error => dark-normal', animate(FLASH_DURATION)),
158-
transition('dark-normal => dark-confirm', animate(FLASH_DURATION)),
159-
transition('dark-confirm => dark-normal', animate(FLASH_DURATION)),
160-
transition('dark-warning => dark-error', animate(FLASH_DURATION)),
161-
transition('dark-error => dark-warning', animate(FLASH_DURATION))
162-
]);
163-
}
132+
class DynamicColor {
133+
private static colorMap: Record<string, string> = {};
134+
135+
static update(key: string, darkMode = false): void {
136+
DynamicColor.colorMap[key] = getBackgroundColor(key, DynamicColor.colorMap[key], darkMode);
137+
}
164138

165-
updateStateDefinitions();
139+
constructor(private key: string, defaultColor: string) {
140+
DynamicColor.colorMap[key] = defaultColor;
141+
}
142+
143+
toString(): string {
144+
return DynamicColor.colorMap[this.key];
145+
}
146+
}
166147

167-
export const BACKGROUND_ANIMATIONS = trigger('displayState', stateDefinitions);
148+
export const BACKGROUND_ANIMATIONS = trigger('displayState', [
149+
state('error', style({ backgroundColor: new DynamicColor(ERROR_BACKGROUND, '#F67') as unknown as string })),
150+
state('normal', style({ backgroundColor: new DynamicColor(NORMAL_BACKGROUND, 'white') as unknown as string })),
151+
state('refresh', style({ backgroundColor: 'gray' })),
152+
state('confirm', style({ backgroundColor: new DynamicColor(CONFIRM_BACKGROUND, '#6C6') as unknown as string })),
153+
state('warning', style({ backgroundColor: new DynamicColor(WARNING_BACKGROUND, '#FC6') as unknown as string })),
154+
state('view-only', style({ backgroundColor: new DynamicColor(VIEW_ONLY_BACKGROUND, 'black') as unknown as string })),
155+
state('disabled', style({ backgroundColor: new DynamicColor(DISABLED_BACKGROUND, '#CCC') as unknown as string })),
156+
transition('normal => error', animate(FLASH_DURATION)),
157+
transition('error => normal', animate(FLASH_DURATION)),
158+
transition('normal => confirm', animate(FLASH_DURATION)),
159+
transition('confirm => normal', animate(FLASH_DURATION)),
160+
transition('warning => error', animate(FLASH_DURATION)),
161+
transition('error => warning', animate(FLASH_DURATION)),
162+
]);
168163

169164
export function getThePoint(evt: MouseEvent | TouchEvent): Point {
170165
if ((evt as any).pageX != null)
@@ -360,11 +355,6 @@ export abstract class DigitSequenceEditorDirective<T> implements
360355
}
361356

362357
ngAfterViewInit(): void {
363-
if (!stateDefinitionsRefreshed) {
364-
updateStateDefinitions();
365-
stateDefinitionsRefreshed = true;
366-
}
367-
368358
this.checkDarkMode();
369359

370360
setTimeout(() => {
@@ -805,10 +795,10 @@ export abstract class DigitSequenceEditorDirective<T> implements
805795
if (this.confirmTimer)
806796
return;
807797

808-
this.displayState = (this.darkMode ? 'dark-' : '') + 'confirm';
798+
this.displayState = 'confirm';
809799
this.confirmTimer = timer(FLASH_DURATION).subscribe(() => {
810800
this.confirmTimer = undefined;
811-
this.displayState = (this.darkMode ? 'dark-' : '') + 'normal';
801+
this.displayState = 'normal';
812802
});
813803
}
814804

@@ -817,22 +807,22 @@ export abstract class DigitSequenceEditorDirective<T> implements
817807
return;
818808

819809
if (!this.errorTimer)
820-
this.displayState = (this.darkMode ? 'dark-' : '') + 'warning';
810+
this.displayState = 'warning';
821811

822812
this.warningTimer = timer(longer ? LONG_WARNING_DURATION : FLASH_DURATION).subscribe(() => {
823813
this.warningTimer = undefined;
824-
this.displayState = (this.darkMode ? 'dark-' : '') + (this.errorTimer ? 'error' : 'normal');
814+
this.displayState = (this.errorTimer ? 'error' : 'normal');
825815
});
826816
}
827817

828818
protected errorFlash(): void {
829819
if (this.errorTimer)
830820
return;
831821

832-
this.displayState = (this.darkMode ? 'dark-' : '') + 'error';
822+
this.displayState = 'error';
833823
this.errorTimer = timer(FLASH_DURATION).subscribe(() => {
834824
this.errorTimer = undefined;
835-
this.displayState = (this.darkMode ? 'dark-' : '') + (this.warningTimer ? 'warning' : 'normal');
825+
this.displayState = (this.warningTimer ? 'warning' : 'normal');
836826
});
837827
}
838828

@@ -1540,27 +1530,30 @@ export abstract class DigitSequenceEditorDirective<T> implements
15401530
}
15411531
}
15421532

1543-
protected checkDarkMode(immediate = false): void {
1544-
let newState: string;
1533+
protected checkDarkMode(_immediate = false): void {
1534+
const lastMode = this.darkMode;
15451535

15461536
this.darkMode = (getBackgroundLevel(this.wrapper?.parentElement) < 128);
15471537

1548-
if (this.darkMode && !this.displayState.startsWith('dark-'))
1549-
newState = 'dark-' + this.displayState;
1550-
else if (!this.darkMode && this.displayState.startsWith('dark-'))
1551-
newState = this.displayState.substr(5);
1538+
if (this.darkMode !== lastMode) {
1539+
DynamicColor.update(ERROR_BACKGROUND, this.darkMode);
1540+
DynamicColor.update(NORMAL_BACKGROUND, this.darkMode);
1541+
DynamicColor.update(CONFIRM_BACKGROUND, this.darkMode);
1542+
DynamicColor.update(WARNING_BACKGROUND, this.darkMode);
1543+
DynamicColor.update(VIEW_ONLY_BACKGROUND, this.darkMode);
1544+
DynamicColor.update(DISABLED_BACKGROUND, this.darkMode);
15521545

1553-
if (newState) {
1554-
if (immediate)
1555-
this.displayState = newState;
1556-
else
1557-
setTimeout(() => this.displayState = newState);
1546+
const currentState = this.displayState;
1547+
1548+
setTimeout(() => {
1549+
this.displayState = 'refresh';
1550+
setTimeout(() => this.displayState = currentState);
1551+
});
15581552
}
15591553
}
15601554

15611555
protected adjustState(): void {
1562-
this.displayState = (this.darkMode ? 'dark-' : '') +
1563-
(this._viewOnly ? 'view-only' : (this._disabled ? 'disabled' : 'normal'));
1556+
this.displayState = (this._viewOnly ? 'view-only' : (this._disabled ? 'disabled' : 'normal'));
15641557

15651558
if (this.hiddenInput) {
15661559
const disabled = (this._floating || this._disabled || this._viewOnly);

0 commit comments

Comments
 (0)