Skip to content

Commit eec1af3

Browse files
committed
1.5.1
Update action-handler
1 parent 7f481e3 commit eec1af3

File tree

5 files changed

+196
-161
lines changed

5 files changed

+196
-161
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "radial-menu",
3-
"version": "1.5.0",
3+
"version": "1.5.1",
44
"description": "Lovelace radial-menu",
55
"keywords": [
66
"home-assistant",
@@ -15,7 +15,7 @@
1515
"author": "Ian Richardson <[email protected]>",
1616
"license": "MIT",
1717
"dependencies": {
18-
"custom-card-helpers": "^1.3.9",
18+
"custom-card-helpers": "^1.6.4",
1919
"home-assistant-js-websocket": "^4.4.0",
2020
"lit-element": "^2.2.1",
2121
"lit-html": "^1.1.2"

src/action-handler-directive.ts

Lines changed: 44 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,37 @@
11
import { directive, PropertyPart } from 'lit-html';
2-
import { fireEvent, ActionHandlerOptions } from 'custom-card-helpers';
2+
3+
import { fireEvent, ActionHandlerDetail, ActionHandlerOptions } from 'custom-card-helpers';
34

45
const isTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;
56

67
interface ActionHandler extends HTMLElement {
78
holdTime: number;
89
bind(element: Element, options): void;
910
}
10-
interface ActionHandlerElement extends Element {
11+
interface ActionHandlerElement extends HTMLElement {
1112
actionHandler?: boolean;
1213
}
1314

15+
declare global {
16+
interface HASSDomEvents {
17+
action: ActionHandlerDetail;
18+
}
19+
}
20+
1421
class ActionHandler extends HTMLElement implements ActionHandler {
15-
public holdTime: number;
16-
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
22+
public holdTime = 500;
23+
1724
public ripple: any;
18-
protected timer: number | undefined;
19-
protected held: boolean;
20-
protected cooldownStart: boolean;
21-
protected cooldownEnd: boolean;
22-
private dblClickTimeout: number | undefined;
25+
26+
protected timer?: number;
27+
28+
protected held = false;
29+
30+
private dblClickTimeout?: number;
2331

2432
constructor() {
2533
super();
26-
this.holdTime = 500;
2734
this.ripple = document.createElement('mwc-ripple');
28-
this.timer = undefined;
29-
this.held = false;
30-
this.cooldownStart = false;
31-
this.cooldownEnd = false;
3235
}
3336

3437
public connectedCallback(): void {
@@ -38,6 +41,7 @@ class ActionHandler extends HTMLElement implements ActionHandler {
3841
height: isTouch ? '100px' : '50px',
3942
transform: 'translate(-50%, -50%)',
4043
pointerEvents: 'none',
44+
zIndex: '999',
4145
});
4246

4347
this.appendChild(this.ripple);
@@ -72,13 +76,10 @@ class ActionHandler extends HTMLElement implements ActionHandler {
7276
}
7377
e.cancelBubble = true;
7478
e.returnValue = false;
75-
return;
79+
return false;
7680
});
7781

78-
const clickStart = (ev: Event): void => {
79-
if (this.cooldownStart) {
80-
return;
81-
}
82+
const start = (ev: Event): void => {
8283
this.held = false;
8384
let x;
8485
let y;
@@ -94,56 +95,50 @@ class ActionHandler extends HTMLElement implements ActionHandler {
9495
this.startAnimation(x, y);
9596
this.held = true;
9697
}, this.holdTime);
97-
98-
this.cooldownStart = true;
99-
window.setTimeout(() => (this.cooldownStart = false), 100);
10098
};
10199

102-
const clickEnd = (ev: Event): void => {
103-
if (this.cooldownEnd || (['touchend', 'touchcancel'].includes(ev.type) && this.timer === undefined)) {
100+
const end = (ev: Event): void => {
101+
// Prevent mouse event if touch event
102+
ev.preventDefault();
103+
if (['touchend', 'touchcancel'].includes(ev.type) && this.timer === undefined) {
104104
return;
105105
}
106106
clearTimeout(this.timer);
107107
this.stopAnimation();
108108
this.timer = undefined;
109109
if (this.held) {
110-
fireEvent(element as HTMLElement, 'action', { action: 'hold' });
111-
} else if (options.hasDoubleTap) {
112-
if ((ev as MouseEvent).detail === 1 || ev.type === 'keyup') {
110+
fireEvent(element, 'action', { action: 'hold' });
111+
} else if (options.hasDoubleClick) {
112+
if ((ev.type === 'click' && (ev as MouseEvent).detail < 2) || !this.dblClickTimeout) {
113113
this.dblClickTimeout = window.setTimeout(() => {
114-
fireEvent(element as HTMLElement, 'action', { action: 'tap' });
114+
this.dblClickTimeout = undefined;
115+
fireEvent(element, 'action', { action: 'tap' });
115116
}, 250);
116117
} else {
117118
clearTimeout(this.dblClickTimeout);
118-
fireEvent(element as HTMLElement, 'action', { action: 'double_tap' });
119+
this.dblClickTimeout = undefined;
120+
fireEvent(element, 'action', { action: 'double_tap' });
119121
}
120122
} else {
121-
fireEvent(element as HTMLElement, 'action', { action: 'tap' });
123+
fireEvent(element, 'action', { action: 'tap' });
122124
}
123-
this.cooldownEnd = true;
124-
window.setTimeout(() => (this.cooldownEnd = false), 100);
125125
};
126126

127-
const handleEnter = (ev: Event): void => {
128-
if ((ev as KeyboardEvent).keyCode === 13) {
129-
return clickEnd(ev);
127+
const handleEnter = (ev: KeyboardEvent): void => {
128+
if (ev.keyCode !== 13) {
129+
return;
130130
}
131+
end(ev);
131132
};
132133

133-
element.addEventListener('touchstart', clickStart, { passive: true });
134-
element.addEventListener('touchend', clickEnd);
135-
element.addEventListener('touchcancel', clickEnd);
136-
element.addEventListener('keyup', handleEnter);
134+
element.addEventListener('touchstart', start, { passive: true });
135+
element.addEventListener('touchend', end);
136+
element.addEventListener('touchcancel', end);
137137

138-
// iOS 13 sends a complete normal touchstart-touchend series of events followed by a mousedown-click series.
139-
// That might be a bug, but until it's fixed, this should make action-handler work.
140-
// If it's not a bug that is fixed, this might need updating with the next iOS version.
141-
// Note that all events (both touch and mouse) must be listened for in order to work on computers with both mouse and touchscreen.
142-
const isIOS13 = /iPhone OS 13_/.test(window.navigator.userAgent);
143-
if (!isIOS13) {
144-
element.addEventListener('mousedown', clickStart, { passive: true });
145-
element.addEventListener('click', clickEnd);
146-
}
138+
element.addEventListener('mousedown', start, { passive: true });
139+
element.addEventListener('click', end);
140+
141+
element.addEventListener('keyup', handleEnter);
147142
}
148143

149144
private startAnimation(x: number, y: number): void {
@@ -187,5 +182,5 @@ export const actionHandlerBind = (element: ActionHandlerElement, options: Action
187182
};
188183

189184
export const actionHandler = directive((options: ActionHandlerOptions = {}) => (part: PropertyPart): void => {
190-
actionHandlerBind(part.committer.element, options);
185+
actionHandlerBind(part.committer.element as ActionHandlerElement, options);
191186
});

src/const.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export const CARD_VERSION = '1.5.0';
1+
export const CARD_VERSION = '1.5.1';

src/radial-menu.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export class RadialMenu extends LitElement {
9292
@action=${this._handleAction}
9393
.actionHandler=${actionHandler({
9494
hasHold: hasAction(item.hold_action),
95-
hasDoubleTap: hasAction(item.double_tap_action),
95+
hasDoubleClick: hasAction(item.double_tap_action),
9696
})}
9797
.config=${item}
9898
.stateObj=${{
@@ -113,7 +113,7 @@ export class RadialMenu extends LitElement {
113113
@action=${this._handleAction}
114114
.actionHandler=${actionHandler({
115115
hasHold: hasAction(item.hold_action),
116-
hasDoubleTap: hasAction(item.double_tap_action),
116+
hasDoubleClick: hasAction(item.double_tap_action),
117117
})}
118118
.config=${item}
119119
.icon=${item.icon}
@@ -133,7 +133,7 @@ export class RadialMenu extends LitElement {
133133
@action=${this._handleAction}
134134
.actionHandler=${actionHandler({
135135
hasHold: hasAction(this._config.hold_action),
136-
hasDoubleTap: hasAction(this._config.double_tap_action),
136+
hasDoubleClick: hasAction(this._config.double_tap_action),
137137
})}
138138
.config=${this._config}
139139
.stateObj=${{
@@ -151,7 +151,7 @@ export class RadialMenu extends LitElement {
151151
@action=${this._handleAction}
152152
.actionHandler=${actionHandler({
153153
hasHold: hasAction(this._config.hold_action),
154-
hasDoubleTap: hasAction(this._config.double_tap_action),
154+
hasDoubleClick: hasAction(this._config.double_tap_action),
155155
})}
156156
.icon=${this._config.icon}
157157
.title=${this._config.name}

0 commit comments

Comments
 (0)