@oicl/openbridge-webcomponents-full-bundle 2.0.0-next.119 → 2.0.0-next.120
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundle/openbridge-webcomponents.bundle.js +96 -0
- package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
- package/custom-elements.json +44 -0
- package/dist/components/alert-button/alert-button.d.ts +3 -0
- package/dist/components/alert-button/alert-button.d.ts.map +1 -1
- package/dist/components/alert-button/alert-button.js +12 -0
- package/dist/components/alert-button/alert-button.js.map +1 -1
- package/dist/components/alert-frame/alert-frame.css.js +1 -0
- package/dist/components/alert-frame/alert-frame.css.js.map +1 -1
- package/dist/components/alert-frame/alert-frame.d.ts +5 -0
- package/dist/components/alert-frame/alert-frame.d.ts.map +1 -1
- package/dist/components/alert-frame/alert-frame.js +24 -0
- package/dist/components/alert-frame/alert-frame.js.map +1 -1
- package/dist/components/alert-icon/alert-icon.d.ts +5 -0
- package/dist/components/alert-icon/alert-icon.d.ts.map +1 -1
- package/dist/components/alert-icon/alert-icon.js +26 -0
- package/dist/components/alert-icon/alert-icon.js.map +1 -1
- package/dist/openbridge.css +0 -73
- package/dist/palettes/blinking.d.ts +6 -0
- package/dist/palettes/blinking.d.ts.map +1 -0
- package/dist/palettes/blinking.js +44 -0
- package/dist/palettes/blinking.js.map +1 -0
- package/package.json +1 -1
- package/src/components/alert-button/alert-button.spec.ts +58 -0
- package/src/components/alert-button/alert-button.ts +16 -0
- package/src/components/alert-frame/alert-frame.css +1 -0
- package/src/components/alert-frame/alert-frame.spec.ts +122 -0
- package/src/components/alert-frame/alert-frame.stories.ts +12 -0
- package/src/components/alert-frame/alert-frame.ts +37 -0
- package/src/components/alert-icon/alert-icon.spec.ts +76 -0
- package/src/components/alert-icon/alert-icon.ts +38 -0
- package/src/palettes/blinking.ts +46 -0
- package/src/palettes/manual.css +0 -42
- package/src/palettes/variables.css +0 -36
package/dist/openbridge.css
CHANGED
|
@@ -14739,36 +14739,6 @@
|
|
|
14739
14739
|
inherits: true;
|
|
14740
14740
|
initial-value: 0;
|
|
14741
14741
|
}
|
|
14742
|
-
@keyframes warning-blink {
|
|
14743
|
-
0% {
|
|
14744
|
-
--warning-blink-on: 1;
|
|
14745
|
-
--warning-blink-off: 0;
|
|
14746
|
-
--alarm-blink-on: 1;
|
|
14747
|
-
--alarm-blink-off: 0;
|
|
14748
|
-
}
|
|
14749
|
-
|
|
14750
|
-
25% {
|
|
14751
|
-
--alarm-blink-on: 0;
|
|
14752
|
-
--alarm-blink-off: 1;
|
|
14753
|
-
}
|
|
14754
|
-
|
|
14755
|
-
50% {
|
|
14756
|
-
--warning-blink-on: 0;
|
|
14757
|
-
--warning-blink-off: 1;
|
|
14758
|
-
--alarm-blink-on: 1;
|
|
14759
|
-
--alarm-blink-off: 0;
|
|
14760
|
-
}
|
|
14761
|
-
|
|
14762
|
-
75% {
|
|
14763
|
-
--alarm-blink-on: 0;
|
|
14764
|
-
--alarm-blink-off: 1;
|
|
14765
|
-
}
|
|
14766
|
-
|
|
14767
|
-
100% {
|
|
14768
|
-
--warning-blink-on: 1;
|
|
14769
|
-
--warning-blink-off: 0;
|
|
14770
|
-
}
|
|
14771
|
-
}
|
|
14772
14742
|
@property --warning-blink-on {
|
|
14773
14743
|
syntax: "<number>";
|
|
14774
14744
|
inherits: true;
|
|
@@ -14779,10 +14749,6 @@
|
|
|
14779
14749
|
inherits: true;
|
|
14780
14750
|
initial-value: 0;
|
|
14781
14751
|
}
|
|
14782
|
-
:root {
|
|
14783
|
-
animation: warning-blink 4s infinite;
|
|
14784
|
-
animation-timing-function: steps(1);
|
|
14785
|
-
}
|
|
14786
14752
|
:root[data-obc-theme="day"] {
|
|
14787
14753
|
--critical-enabled-background-color: rgb(196, 36, 183);
|
|
14788
14754
|
--critical-enabled-border-color: rgb(153, 0, 143);
|
|
@@ -14899,45 +14865,6 @@
|
|
|
14899
14865
|
inherits: true;
|
|
14900
14866
|
initial-value: 0;
|
|
14901
14867
|
}
|
|
14902
|
-
@keyframes critical-blink {
|
|
14903
|
-
0% {
|
|
14904
|
-
--critical-blink-on: 1;
|
|
14905
|
-
--critical-blink-off: 0;
|
|
14906
|
-
}
|
|
14907
|
-
|
|
14908
|
-
50% {
|
|
14909
|
-
--critical-blink-on: 0;
|
|
14910
|
-
--critical-blink-off: 1;
|
|
14911
|
-
}
|
|
14912
|
-
|
|
14913
|
-
100% {
|
|
14914
|
-
--critical-blink-on: 1;
|
|
14915
|
-
--critical-blink-off: 0;
|
|
14916
|
-
}
|
|
14917
|
-
}
|
|
14918
|
-
@keyframes low-blink {
|
|
14919
|
-
0% {
|
|
14920
|
-
--low-blink-on: 1;
|
|
14921
|
-
--low-blink-off: 0;
|
|
14922
|
-
}
|
|
14923
|
-
|
|
14924
|
-
50% {
|
|
14925
|
-
--low-blink-on: 0;
|
|
14926
|
-
--low-blink-off: 1;
|
|
14927
|
-
}
|
|
14928
|
-
|
|
14929
|
-
100% {
|
|
14930
|
-
--low-blink-on: 1;
|
|
14931
|
-
--low-blink-off: 0;
|
|
14932
|
-
}
|
|
14933
|
-
}
|
|
14934
|
-
:root {
|
|
14935
|
-
animation:
|
|
14936
|
-
warning-blink 4s infinite,
|
|
14937
|
-
critical-blink 1s infinite,
|
|
14938
|
-
low-blink 8s infinite;
|
|
14939
|
-
animation-timing-function: steps(1);
|
|
14940
|
-
}
|
|
14941
14868
|
.obc-radio-button {
|
|
14942
14869
|
user-select: none;
|
|
14943
14870
|
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function blinkingCritical(el: HTMLElement): () => void;
|
|
2
|
+
export declare function blinkingAlarm(el: HTMLElement): () => void;
|
|
3
|
+
export declare function blinkingWarning(el: HTMLElement): () => void;
|
|
4
|
+
export declare function blinkingLow(el: HTMLElement): () => void;
|
|
5
|
+
export declare function blinkingAll(el: HTMLElement): () => void;
|
|
6
|
+
//# sourceMappingURL=blinking.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blinking.d.ts","sourceRoot":"","sources":["../../src/palettes/blinking.ts"],"names":[],"mappings":"AAqBA,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,WAAW,GAAG,MAAM,IAAI,CAE5D;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,WAAW,GAAG,MAAM,IAAI,CAEzD;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,WAAW,GAAG,MAAM,IAAI,CAE3D;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,WAAW,GAAG,MAAM,IAAI,CAEvD;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,WAAW,GAAG,MAAM,IAAI,CAQvD"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const CRITICAL_PERIOD = 1e3;
|
|
2
|
+
const ALARM_PERIOD = 2e3;
|
|
3
|
+
const WARNING_PERIOD = 4e3;
|
|
4
|
+
const LOW_PERIOD = 8e3;
|
|
5
|
+
function blinkingInstall(el, period, label) {
|
|
6
|
+
const anim = el.animate(
|
|
7
|
+
[
|
|
8
|
+
{ [label + "-on"]: 1, [label + "-off"]: 0 },
|
|
9
|
+
{ [label + "-on"]: 0, [label + "-off"]: 1 }
|
|
10
|
+
],
|
|
11
|
+
{ duration: period, iterations: Infinity, easing: "steps(2, jump-none)" }
|
|
12
|
+
);
|
|
13
|
+
anim.startTime = 0;
|
|
14
|
+
return () => anim.cancel();
|
|
15
|
+
}
|
|
16
|
+
function blinkingCritical(el) {
|
|
17
|
+
return blinkingInstall(el, CRITICAL_PERIOD, "--critical-blink");
|
|
18
|
+
}
|
|
19
|
+
function blinkingAlarm(el) {
|
|
20
|
+
return blinkingInstall(el, ALARM_PERIOD, "--alarm-blink");
|
|
21
|
+
}
|
|
22
|
+
function blinkingWarning(el) {
|
|
23
|
+
return blinkingInstall(el, WARNING_PERIOD, "--warning-blink");
|
|
24
|
+
}
|
|
25
|
+
function blinkingLow(el) {
|
|
26
|
+
return blinkingInstall(el, LOW_PERIOD, "--low-blink");
|
|
27
|
+
}
|
|
28
|
+
function blinkingAll(el) {
|
|
29
|
+
const animes = [
|
|
30
|
+
blinkingCritical(el),
|
|
31
|
+
blinkingAlarm(el),
|
|
32
|
+
blinkingWarning(el),
|
|
33
|
+
blinkingLow(el)
|
|
34
|
+
];
|
|
35
|
+
return () => animes.forEach((anim) => anim());
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
blinkingAlarm,
|
|
39
|
+
blinkingAll,
|
|
40
|
+
blinkingCritical,
|
|
41
|
+
blinkingLow,
|
|
42
|
+
blinkingWarning
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=blinking.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blinking.js","sources":["../../src/palettes/blinking.ts"],"sourcesContent":["const CRITICAL_PERIOD = 1000; // ms\nconst ALARM_PERIOD = 2000; // ms\nconst WARNING_PERIOD = 4000; // ms\nconst LOW_PERIOD = 8000; // ms\n\nfunction blinkingInstall(\n el: HTMLElement,\n period: number,\n label: string\n): () => void {\n const anim = el.animate(\n [\n {[label + '-on']: 1, [label + '-off']: 0},\n {[label + '-on']: 0, [label + '-off']: 1},\n ],\n {duration: period, iterations: Infinity, easing: 'steps(2, jump-none)'}\n );\n anim.startTime = 0; // Common time origin for all animations, so they blink in sync.\n return () => anim.cancel();\n}\n\nexport function blinkingCritical(el: HTMLElement): () => void {\n return blinkingInstall(el, CRITICAL_PERIOD, '--critical-blink');\n}\n\nexport function blinkingAlarm(el: HTMLElement): () => void {\n return blinkingInstall(el, ALARM_PERIOD, '--alarm-blink');\n}\n\nexport function blinkingWarning(el: HTMLElement): () => void {\n return blinkingInstall(el, WARNING_PERIOD, '--warning-blink');\n}\n\nexport function blinkingLow(el: HTMLElement): () => void {\n return blinkingInstall(el, LOW_PERIOD, '--low-blink');\n}\n\nexport function blinkingAll(el: HTMLElement): () => void {\n const animes = [\n blinkingCritical(el),\n blinkingAlarm(el),\n blinkingWarning(el),\n blinkingLow(el),\n ];\n return () => animes.forEach((anim) => anim());\n}\n"],"names":[],"mappings":"AAAA,MAAM,kBAAkB;AACxB,MAAM,eAAe;AACrB,MAAM,iBAAiB;AACvB,MAAM,aAAa;AAEnB,SAAS,gBACP,IACA,QACA,OACY;AACZ,QAAM,OAAO,GAAG;AAAA,IACd;AAAA,MACE,EAAC,CAAC,QAAQ,KAAK,GAAG,GAAG,CAAC,QAAQ,MAAM,GAAG,EAAA;AAAA,MACvC,EAAC,CAAC,QAAQ,KAAK,GAAG,GAAG,CAAC,QAAQ,MAAM,GAAG,EAAA;AAAA,IAAC;AAAA,IAE1C,EAAC,UAAU,QAAQ,YAAY,UAAU,QAAQ,sBAAA;AAAA,EAAqB;AAExE,OAAK,YAAY;AACjB,SAAO,MAAM,KAAK,OAAA;AACpB;AAEO,SAAS,iBAAiB,IAA6B;AAC5D,SAAO,gBAAgB,IAAI,iBAAiB,kBAAkB;AAChE;AAEO,SAAS,cAAc,IAA6B;AACzD,SAAO,gBAAgB,IAAI,cAAc,eAAe;AAC1D;AAEO,SAAS,gBAAgB,IAA6B;AAC3D,SAAO,gBAAgB,IAAI,gBAAgB,iBAAiB;AAC9D;AAEO,SAAS,YAAY,IAA6B;AACvD,SAAO,gBAAgB,IAAI,YAAY,aAAa;AACtD;AAEO,SAAS,YAAY,IAA6B;AACvD,QAAM,SAAS;AAAA,IACb,iBAAiB,EAAE;AAAA,IACnB,cAAc,EAAE;AAAA,IAChB,gBAAgB,EAAE;AAAA,IAClB,YAAY,EAAE;AAAA,EAAA;AAEhB,SAAO,MAAM,OAAO,QAAQ,CAAC,SAAS,MAAM;AAC9C;"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import {describe, expect, it} from 'vitest';
|
|
2
|
+
import './alert-button.js';
|
|
3
|
+
import {ObcAlertButton} from './alert-button.js';
|
|
4
|
+
import {render} from 'vitest-browser-lit';
|
|
5
|
+
import {html} from 'lit';
|
|
6
|
+
|
|
7
|
+
describe('obc-alert-button blinking lifecycle', () => {
|
|
8
|
+
async function setup() {
|
|
9
|
+
const screen = render(html`<obc-alert-button></obc-alert-button>`);
|
|
10
|
+
const el = screen.baseElement.querySelector(
|
|
11
|
+
'obc-alert-button'
|
|
12
|
+
) as ObcAlertButton;
|
|
13
|
+
await el.updateComplete;
|
|
14
|
+
return el;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
it('installs the blink animations on first render', async () => {
|
|
18
|
+
const el = await setup();
|
|
19
|
+
|
|
20
|
+
expect(el.getAnimations().length).toBeGreaterThan(0);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('cancels the blink animations on disconnect', async () => {
|
|
24
|
+
const el = await setup();
|
|
25
|
+
|
|
26
|
+
el.parentElement!.removeChild(el);
|
|
27
|
+
|
|
28
|
+
expect(el.getAnimations()).toHaveLength(0);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('resumes blinking after disconnect and reconnect', async () => {
|
|
32
|
+
const el = await setup();
|
|
33
|
+
const parent = el.parentElement!;
|
|
34
|
+
const initial = el.getAnimations().length;
|
|
35
|
+
|
|
36
|
+
parent.removeChild(el);
|
|
37
|
+
expect(el.getAnimations()).toHaveLength(0);
|
|
38
|
+
|
|
39
|
+
// Reconnect without touching any property. firstUpdated() will not run
|
|
40
|
+
// again, so this only passes if blinking is reinstalled on update.
|
|
41
|
+
parent.appendChild(el);
|
|
42
|
+
await el.updateComplete;
|
|
43
|
+
|
|
44
|
+
expect(el.getAnimations()).toHaveLength(initial);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('does not accumulate animations across repeated updates', async () => {
|
|
48
|
+
const el = await setup();
|
|
49
|
+
const initial = el.getAnimations().length;
|
|
50
|
+
|
|
51
|
+
el.nAlerts = 3;
|
|
52
|
+
await el.updateComplete;
|
|
53
|
+
el.nAlerts = 5;
|
|
54
|
+
await el.updateComplete;
|
|
55
|
+
|
|
56
|
+
expect(el.getAnimations()).toHaveLength(initial);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
} from '../../alert-severity.js';
|
|
21
21
|
import {classMap} from 'lit/directives/class-map.js';
|
|
22
22
|
import {customElement} from '../../decorator.js';
|
|
23
|
+
import {blinkingAll} from '../../palettes/blinking.js';
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* `ObcAlertButtonType` – Enum for alert button visual and behavioral variants.
|
|
@@ -202,10 +203,14 @@ export class ObcAlertButton extends LitElement {
|
|
|
202
203
|
override connectedCallback() {
|
|
203
204
|
super.connectedCallback();
|
|
204
205
|
window.addEventListener('resize', this.resizeListener);
|
|
206
|
+
if (this.hasUpdated) {
|
|
207
|
+
this.installBlinking();
|
|
208
|
+
}
|
|
205
209
|
}
|
|
206
210
|
|
|
207
211
|
override disconnectedCallback() {
|
|
208
212
|
window.removeEventListener('resize', this.resizeListener);
|
|
213
|
+
this._blinkAnimationCancel?.();
|
|
209
214
|
super.disconnectedCallback();
|
|
210
215
|
}
|
|
211
216
|
|
|
@@ -280,6 +285,17 @@ export class ObcAlertButton extends LitElement {
|
|
|
280
285
|
);
|
|
281
286
|
}
|
|
282
287
|
|
|
288
|
+
private _blinkAnimationCancel?: () => void;
|
|
289
|
+
|
|
290
|
+
private installBlinking() {
|
|
291
|
+
this._blinkAnimationCancel?.();
|
|
292
|
+
this._blinkAnimationCancel = blinkingAll(this);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
override updated() {
|
|
296
|
+
this.installBlinking();
|
|
297
|
+
}
|
|
298
|
+
|
|
283
299
|
override render() {
|
|
284
300
|
const hasAlerts = this.nAlerts > 0;
|
|
285
301
|
const showCounter =
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import {describe, expect, it} from 'vitest';
|
|
2
|
+
import './alert-frame.js';
|
|
3
|
+
import {ObcAlertFrame, ObcAlertFrameMode} from './alert-frame.js';
|
|
4
|
+
import {render} from 'vitest-browser-lit';
|
|
5
|
+
import {html} from 'lit';
|
|
6
|
+
|
|
7
|
+
describe('obc-alert-frame blinking lifecycle', () => {
|
|
8
|
+
async function setup(mode: ObcAlertFrameMode) {
|
|
9
|
+
const screen = render(
|
|
10
|
+
html`<obc-alert-frame .mode=${mode}></obc-alert-frame>`
|
|
11
|
+
);
|
|
12
|
+
const el = screen.baseElement.querySelector(
|
|
13
|
+
'obc-alert-frame'
|
|
14
|
+
) as ObcAlertFrame;
|
|
15
|
+
await el.updateComplete;
|
|
16
|
+
return el;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
it('blinks while mode is unacked-active', async () => {
|
|
20
|
+
const el = await setup(ObcAlertFrameMode.unackedActive);
|
|
21
|
+
|
|
22
|
+
expect(el.getAnimations().length).toBeGreaterThan(0);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('does not blink in other modes', async () => {
|
|
26
|
+
const el = await setup(ObcAlertFrameMode.ackedActive);
|
|
27
|
+
|
|
28
|
+
expect(el.getAnimations()).toHaveLength(0);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('mode transitions', () => {
|
|
32
|
+
it('starts blinking when mode becomes unacked-active', async () => {
|
|
33
|
+
const el = await setup(ObcAlertFrameMode.ackedActive);
|
|
34
|
+
expect(el.getAnimations()).toHaveLength(0);
|
|
35
|
+
|
|
36
|
+
el.mode = ObcAlertFrameMode.unackedActive;
|
|
37
|
+
await el.updateComplete;
|
|
38
|
+
|
|
39
|
+
expect(el.getAnimations().length).toBeGreaterThan(0);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('stops blinking when mode leaves unacked-active', async () => {
|
|
43
|
+
const el = await setup(ObcAlertFrameMode.unackedActive);
|
|
44
|
+
expect(el.getAnimations().length).toBeGreaterThan(0);
|
|
45
|
+
|
|
46
|
+
el.mode = ObcAlertFrameMode.ackedActive;
|
|
47
|
+
await el.updateComplete;
|
|
48
|
+
|
|
49
|
+
expect(el.getAnimations()).toHaveLength(0);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('stops blinking when mode becomes unacked-rectified', async () => {
|
|
53
|
+
const el = await setup(ObcAlertFrameMode.unackedActive);
|
|
54
|
+
|
|
55
|
+
el.mode = ObcAlertFrameMode.unackedRectified;
|
|
56
|
+
await el.updateComplete;
|
|
57
|
+
|
|
58
|
+
expect(el.getAnimations()).toHaveLength(0);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('does not accumulate animations across repeated updates', async () => {
|
|
62
|
+
const el = await setup(ObcAlertFrameMode.unackedActive);
|
|
63
|
+
const initial = el.getAnimations().length;
|
|
64
|
+
|
|
65
|
+
el.fullWidth = true;
|
|
66
|
+
await el.updateComplete;
|
|
67
|
+
el.showIcon = true;
|
|
68
|
+
await el.updateComplete;
|
|
69
|
+
|
|
70
|
+
expect(el.getAnimations()).toHaveLength(initial);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('reconnection', () => {
|
|
75
|
+
it('resumes blinking after disconnect and reconnect', async () => {
|
|
76
|
+
const el = await setup(ObcAlertFrameMode.unackedActive);
|
|
77
|
+
const parent = el.parentElement!;
|
|
78
|
+
expect(el.getAnimations().length).toBeGreaterThan(0);
|
|
79
|
+
|
|
80
|
+
parent.removeChild(el);
|
|
81
|
+
expect(el.getAnimations()).toHaveLength(0);
|
|
82
|
+
|
|
83
|
+
// Reconnect without touching any property. firstUpdated() will not run
|
|
84
|
+
// again, so this only passes if blinking is reinstalled on update.
|
|
85
|
+
parent.appendChild(el);
|
|
86
|
+
await el.updateComplete;
|
|
87
|
+
|
|
88
|
+
expect(el.getAnimations().length).toBeGreaterThan(0);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('does not resume blinking on reconnect when mode is not unacked-active', async () => {
|
|
92
|
+
const el = await setup(ObcAlertFrameMode.ackedActive);
|
|
93
|
+
const parent = el.parentElement!;
|
|
94
|
+
|
|
95
|
+
parent.removeChild(el);
|
|
96
|
+
parent.appendChild(el);
|
|
97
|
+
await el.updateComplete;
|
|
98
|
+
|
|
99
|
+
expect(el.getAnimations()).toHaveLength(0);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('does not blink after disconnection when mode became unacked-active while detached', async () => {
|
|
103
|
+
const el = await setup(ObcAlertFrameMode.ackedActive);
|
|
104
|
+
const parent = el.parentElement!;
|
|
105
|
+
|
|
106
|
+
parent.removeChild(el);
|
|
107
|
+
await el.updateComplete;
|
|
108
|
+
|
|
109
|
+
expect(el.getAnimations().length).toBe(0);
|
|
110
|
+
|
|
111
|
+
el.mode = ObcAlertFrameMode.unackedActive;
|
|
112
|
+
await el.updateComplete;
|
|
113
|
+
|
|
114
|
+
expect(el.getAnimations().length).toBe(0);
|
|
115
|
+
|
|
116
|
+
parent.appendChild(el);
|
|
117
|
+
await el.updateComplete;
|
|
118
|
+
|
|
119
|
+
expect(el.getAnimations().length).toBeGreaterThan(0);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
@@ -261,3 +261,15 @@ export const RectifiedUnactive: Story = {
|
|
|
261
261
|
mode: ObcAlertFrameMode.unackedRectified,
|
|
262
262
|
},
|
|
263
263
|
};
|
|
264
|
+
|
|
265
|
+
export const CriticalUnacked: Story = {
|
|
266
|
+
args: {
|
|
267
|
+
type: ObcAlertFrameType.SmallSideFlip,
|
|
268
|
+
thickness: ObcAlertFrameThickness.Small,
|
|
269
|
+
status: ObcAlertFrameStatus.LevelCritical,
|
|
270
|
+
mode: ObcAlertFrameMode.unackedActive,
|
|
271
|
+
demoWidth: 200,
|
|
272
|
+
showIcon: true,
|
|
273
|
+
showAlertCategoryIcon: true,
|
|
274
|
+
},
|
|
275
|
+
};
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
getAlertBadgeComponent,
|
|
21
21
|
AlertBadgeComponent,
|
|
22
22
|
} from '../../alert-severity.js';
|
|
23
|
+
import {blinkingAll} from '../../palettes/blinking.js';
|
|
23
24
|
|
|
24
25
|
export {AlertType as ObcAlertFrameStatus} from '../../types.js';
|
|
25
26
|
|
|
@@ -256,6 +257,42 @@ export class ObcAlertFrame extends LitElement {
|
|
|
256
257
|
`;
|
|
257
258
|
}
|
|
258
259
|
|
|
260
|
+
private _blinkAnimationCancel?: () => void;
|
|
261
|
+
|
|
262
|
+
private syncBlinking() {
|
|
263
|
+
if (
|
|
264
|
+
this.mode !== ObcAlertFrameMode.unackedActive &&
|
|
265
|
+
this._blinkAnimationCancel
|
|
266
|
+
) {
|
|
267
|
+
this._blinkAnimationCancel();
|
|
268
|
+
this._blinkAnimationCancel = undefined;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (
|
|
272
|
+
this.mode === ObcAlertFrameMode.unackedActive &&
|
|
273
|
+
!this._blinkAnimationCancel
|
|
274
|
+
) {
|
|
275
|
+
this._blinkAnimationCancel = blinkingAll(this);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
override connectedCallback() {
|
|
280
|
+
super.connectedCallback();
|
|
281
|
+
if (this.hasUpdated) {
|
|
282
|
+
this.syncBlinking();
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
override updated() {
|
|
287
|
+
this.syncBlinking();
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
override disconnectedCallback() {
|
|
291
|
+
super.disconnectedCallback();
|
|
292
|
+
this._blinkAnimationCancel?.();
|
|
293
|
+
this._blinkAnimationCancel = undefined;
|
|
294
|
+
}
|
|
295
|
+
|
|
259
296
|
private flap() {
|
|
260
297
|
if (this.type === ObcAlertFrameType.Regular) {
|
|
261
298
|
return nothing;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {describe, expect, it} from 'vitest';
|
|
2
|
+
import './alert-icon.js';
|
|
3
|
+
import {ObcAlertIcon} from './alert-icon.js';
|
|
4
|
+
import {render} from 'vitest-browser-lit';
|
|
5
|
+
import {html} from 'lit';
|
|
6
|
+
import {AlertType} from '../../types.js';
|
|
7
|
+
|
|
8
|
+
describe('obc-alert-icon blinking lifecycle', () => {
|
|
9
|
+
async function setup(acknowledged = false) {
|
|
10
|
+
const screen = render(
|
|
11
|
+
html`<obc-alert-icon
|
|
12
|
+
.alertType=${AlertType.Alarm}
|
|
13
|
+
.acknowledged=${acknowledged}
|
|
14
|
+
></obc-alert-icon>`
|
|
15
|
+
);
|
|
16
|
+
const el = screen.baseElement.querySelector(
|
|
17
|
+
'obc-alert-icon'
|
|
18
|
+
) as ObcAlertIcon;
|
|
19
|
+
await el.updateComplete;
|
|
20
|
+
return el;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function wrapperAnimations(el: ObcAlertIcon) {
|
|
24
|
+
return el.getAnimations();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
it('blinks for an unacknowledged blinking alert type', async () => {
|
|
28
|
+
const el = await setup();
|
|
29
|
+
|
|
30
|
+
expect(wrapperAnimations(el).length).toBeGreaterThan(0);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('does not blink once acknowledged', async () => {
|
|
34
|
+
const el = await setup(true);
|
|
35
|
+
|
|
36
|
+
expect(wrapperAnimations(el)).toHaveLength(0);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('stops blinking when the alert is acknowledged', async () => {
|
|
40
|
+
const el = await setup();
|
|
41
|
+
expect(wrapperAnimations(el).length).toBeGreaterThan(0);
|
|
42
|
+
|
|
43
|
+
el.acknowledged = true;
|
|
44
|
+
await el.updateComplete;
|
|
45
|
+
|
|
46
|
+
expect(wrapperAnimations(el)).toHaveLength(0);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('resumes blinking after disconnect and reconnect', async () => {
|
|
50
|
+
const el = await setup();
|
|
51
|
+
const parent = el.parentElement!;
|
|
52
|
+
const initial = wrapperAnimations(el).length;
|
|
53
|
+
expect(initial).toBeGreaterThan(0);
|
|
54
|
+
|
|
55
|
+
parent.removeChild(el);
|
|
56
|
+
expect(wrapperAnimations(el)).toHaveLength(0);
|
|
57
|
+
|
|
58
|
+
// Reconnect without touching any property, so no Lit update is scheduled.
|
|
59
|
+
parent.appendChild(el);
|
|
60
|
+
await el.updateComplete;
|
|
61
|
+
|
|
62
|
+
expect(wrapperAnimations(el)).toHaveLength(initial);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('does not accumulate animations across repeated updates', async () => {
|
|
66
|
+
const el = await setup();
|
|
67
|
+
const initial = wrapperAnimations(el).length;
|
|
68
|
+
|
|
69
|
+
el.active = true;
|
|
70
|
+
await el.updateComplete;
|
|
71
|
+
el.silenced = true;
|
|
72
|
+
await el.updateComplete;
|
|
73
|
+
|
|
74
|
+
expect(wrapperAnimations(el)).toHaveLength(initial);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
import {lowSilencedA, lowSilencedB} from './icons/icon-low-silenced.js';
|
|
51
51
|
import {lowRectifiedA, lowRectifiedB} from './icons/icon-low-rectified.js';
|
|
52
52
|
import {lowAcknowledged} from './icons/icon-low-acknowledged.js';
|
|
53
|
+
import {blinkingAll} from '../../palettes/blinking.js';
|
|
53
54
|
|
|
54
55
|
enum AlertIconState {
|
|
55
56
|
Silenced = 'silenced',
|
|
@@ -343,6 +344,43 @@ export class ObcAlertIcon extends LitElement {
|
|
|
343
344
|
return html`<div class="wrapper">${this.renderStaticIcon()}</div>`;
|
|
344
345
|
}
|
|
345
346
|
|
|
347
|
+
private _blinkAnimationCancel?: () => void;
|
|
348
|
+
|
|
349
|
+
private syncBlinking(): void {
|
|
350
|
+
if (
|
|
351
|
+
this._blinkAnimationCancel &&
|
|
352
|
+
!supportsBlinking(this._effectiveType, this.acknowledged ?? false)
|
|
353
|
+
) {
|
|
354
|
+
this._blinkAnimationCancel();
|
|
355
|
+
this._blinkAnimationCancel = undefined;
|
|
356
|
+
}
|
|
357
|
+
if (
|
|
358
|
+
!this._blinkAnimationCancel &&
|
|
359
|
+
supportsBlinking(this._effectiveType, this.acknowledged ?? false)
|
|
360
|
+
) {
|
|
361
|
+
this._blinkAnimationCancel = blinkingAll(this);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
override connectedCallback(): void {
|
|
366
|
+
super.connectedCallback();
|
|
367
|
+
if (this.hasUpdated) {
|
|
368
|
+
this.syncBlinking();
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
override updated(): void {
|
|
373
|
+
this.syncBlinking();
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
override disconnectedCallback(): void {
|
|
377
|
+
super.disconnectedCallback();
|
|
378
|
+
if (this._blinkAnimationCancel) {
|
|
379
|
+
this._blinkAnimationCancel();
|
|
380
|
+
this._blinkAnimationCancel = undefined;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
346
384
|
static override styles = css`
|
|
347
385
|
.wrapper {
|
|
348
386
|
height: 100%;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const CRITICAL_PERIOD = 1000; // ms
|
|
2
|
+
const ALARM_PERIOD = 2000; // ms
|
|
3
|
+
const WARNING_PERIOD = 4000; // ms
|
|
4
|
+
const LOW_PERIOD = 8000; // ms
|
|
5
|
+
|
|
6
|
+
function blinkingInstall(
|
|
7
|
+
el: HTMLElement,
|
|
8
|
+
period: number,
|
|
9
|
+
label: string
|
|
10
|
+
): () => void {
|
|
11
|
+
const anim = el.animate(
|
|
12
|
+
[
|
|
13
|
+
{[label + '-on']: 1, [label + '-off']: 0},
|
|
14
|
+
{[label + '-on']: 0, [label + '-off']: 1},
|
|
15
|
+
],
|
|
16
|
+
{duration: period, iterations: Infinity, easing: 'steps(2, jump-none)'}
|
|
17
|
+
);
|
|
18
|
+
anim.startTime = 0; // Common time origin for all animations, so they blink in sync.
|
|
19
|
+
return () => anim.cancel();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function blinkingCritical(el: HTMLElement): () => void {
|
|
23
|
+
return blinkingInstall(el, CRITICAL_PERIOD, '--critical-blink');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function blinkingAlarm(el: HTMLElement): () => void {
|
|
27
|
+
return blinkingInstall(el, ALARM_PERIOD, '--alarm-blink');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function blinkingWarning(el: HTMLElement): () => void {
|
|
31
|
+
return blinkingInstall(el, WARNING_PERIOD, '--warning-blink');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function blinkingLow(el: HTMLElement): () => void {
|
|
35
|
+
return blinkingInstall(el, LOW_PERIOD, '--low-blink');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function blinkingAll(el: HTMLElement): () => void {
|
|
39
|
+
const animes = [
|
|
40
|
+
blinkingCritical(el),
|
|
41
|
+
blinkingAlarm(el),
|
|
42
|
+
blinkingWarning(el),
|
|
43
|
+
blinkingLow(el),
|
|
44
|
+
];
|
|
45
|
+
return () => animes.forEach((anim) => anim());
|
|
46
|
+
}
|
package/src/palettes/manual.css
CHANGED
|
@@ -121,45 +121,3 @@
|
|
|
121
121
|
inherits: true;
|
|
122
122
|
initial-value: 0;
|
|
123
123
|
}
|
|
124
|
-
|
|
125
|
-
@keyframes critical-blink {
|
|
126
|
-
0% {
|
|
127
|
-
--critical-blink-on: 1;
|
|
128
|
-
--critical-blink-off: 0;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
50% {
|
|
132
|
-
--critical-blink-on: 0;
|
|
133
|
-
--critical-blink-off: 1;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
100% {
|
|
137
|
-
--critical-blink-on: 1;
|
|
138
|
-
--critical-blink-off: 0;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
@keyframes low-blink {
|
|
143
|
-
0% {
|
|
144
|
-
--low-blink-on: 1;
|
|
145
|
-
--low-blink-off: 0;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
50% {
|
|
149
|
-
--low-blink-on: 0;
|
|
150
|
-
--low-blink-off: 1;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
100% {
|
|
154
|
-
--low-blink-on: 1;
|
|
155
|
-
--low-blink-off: 0;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
:root {
|
|
160
|
-
animation:
|
|
161
|
-
warning-blink 4s infinite,
|
|
162
|
-
critical-blink 1s infinite,
|
|
163
|
-
low-blink 8s infinite;
|
|
164
|
-
animation-timing-function: steps(1);
|
|
165
|
-
}
|