Skip to content

Commit 328098a

Browse files
committed
feat: add membrane-keypad element
1 parent 58a3932 commit 328098a

File tree

3 files changed

+169
-0
lines changed

3 files changed

+169
-0
lines changed

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ export { LEDElement } from './led-element';
77
export { NeoPixelElement } from './neopixel-element';
88
export { PushbuttonElement } from './pushbutton-element';
99
export { ResistorElement } from './resistor-element';
10+
export { MembraneKeypadElement } from './membrane-keypad-element';
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { withActions, action } from '@storybook/addon-actions';
2+
import { storiesOf } from '@storybook/web-components';
3+
import { html } from 'lit-html';
4+
import './membrane-keypad-element';
5+
6+
storiesOf('Membrane Keypad', module)
7+
.addDecorator(withActions())
8+
.add(
9+
'Default',
10+
() => html`
11+
<wokwi-membrane-keypad
12+
@button-press=${action('button-press')}
13+
@button-release=${action('button-release')}
14+
></wokwi-membrane-keypad>
15+
`
16+
)
17+
.add(
18+
'Three Columns',
19+
() => html`
20+
<wokwi-membrane-keypad
21+
.threeColumns="${true}"
22+
@button-press=${action('button-press')}
23+
@button-release=${action('button-release')}
24+
></wokwi-membrane-keypad>
25+
`
26+
);

src/membrane-keypad-element.ts

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import { customElement, html, LitElement, property, svg } from 'lit-element';
2+
3+
const SPACE_KEY = 32;
4+
5+
@customElement('wokwi-membrane-keypad')
6+
export class MembraneKeypadElement extends LitElement {
7+
@property() threeColumns = false;
8+
9+
private pressedKeys = new Set<string>();
10+
11+
renderKey(text: string, x: number, y: number) {
12+
return svg`<g
13+
transform="translate(${x} ${y})"
14+
tabindex="0"
15+
@mousedown=${() => this.down(text)}
16+
@mouseup=${() => this.up(text)}
17+
@touchstart=${() => this.down(text)}
18+
@touchend=${() => this.up(text)}
19+
@keydown=${(e: KeyboardEvent) => e.keyCode === SPACE_KEY && this.down(text)}
20+
@keyup=${(e: KeyboardEvent) => e.keyCode === SPACE_KEY && this.up(text)}
21+
>
22+
<use xlink:href="#key" />
23+
<text x="5.6" y="8.1">${text}</text>
24+
</g>`;
25+
}
26+
27+
render() {
28+
const fourColumns = !this.threeColumns;
29+
const columnWidth = 14.647;
30+
const width = fourColumns ? 70.336 : 70.336 - columnWidth;
31+
32+
return html`
33+
<style>
34+
text {
35+
fill: #c2e4fd;
36+
user-select: none;
37+
}
38+
39+
g[tabindex] {
40+
cursor: pointer;
41+
}
42+
43+
g[tabindex]:focus {
44+
fill: #4e50d7;
45+
stroke: white;
46+
outline: none;
47+
}
48+
49+
g[tabindex]:focus text {
50+
fill: white;
51+
stroke: none;
52+
}
53+
</style>
54+
55+
<svg
56+
width="${width}mm"
57+
height="76mm"
58+
version="1.1"
59+
viewBox="0 0 ${width} 76"
60+
font-family="sans-serif"
61+
font-size="8.2px"
62+
text-anchor="middle"
63+
xmlns="http://www.w3.org/2000/svg"
64+
>
65+
<defs>
66+
<rect
67+
id="key"
68+
width="11.2"
69+
height="11"
70+
rx="1.4"
71+
ry="1.4"
72+
stroke="#b3c7db"
73+
stroke-width=".75"
74+
/>
75+
</defs>
76+
77+
<!-- Keypad outline -->
78+
<rect x="0" y="0" width="${width}" height="76" rx="5" ry="5" fill="#454449" />
79+
<rect
80+
x="2.78"
81+
y="3.25"
82+
width="${fourColumns ? 65 : 65 - columnWidth}"
83+
height="68.6"
84+
rx="3.5"
85+
ry="3.5"
86+
fill="none"
87+
stroke="#b3c7db"
88+
stroke-width="1"
89+
/>
90+
91+
<!-- Blue keys -->
92+
<g fill="#4e90d7">
93+
<g>${this.renderKey('1', 7, 10.7)}</g>
94+
<g>${this.renderKey('2', 22, 10.7)}</g>
95+
<g>${this.renderKey('3', 37, 10.7)}</g>
96+
<g>${this.renderKey('4', 7, 25)}</g>
97+
<g>${this.renderKey('5', 22, 25)}</g>
98+
<g>${this.renderKey('6', 37, 25)}</g>
99+
<g>${this.renderKey('7', 7, 39.3)}</g>
100+
<g>${this.renderKey('8', 22, 39.3)}</g>
101+
<g>${this.renderKey('9', 37, 39.3)}</g>
102+
<g>${this.renderKey('0', 22, 53.6)}</g>
103+
</g>
104+
105+
<!-- Red keys -->
106+
<g fill="#e94541">
107+
<g>${this.renderKey('*', 7, 53.6)}</g>
108+
<g>${this.renderKey('#', 37, 53.6)}</g>
109+
${fourColumns &&
110+
svg`
111+
<g>${this.renderKey('A', 52, 10.7)}</g>
112+
<g>${this.renderKey('B', 52, 25)}</g>
113+
<g>${this.renderKey('C', 52, 39.3)}</g>
114+
<g>${this.renderKey('D', 52, 53.6)}</g>
115+
`}
116+
</g>
117+
</svg>
118+
`;
119+
}
120+
121+
private down(key: string) {
122+
if (!this.pressedKeys.has(key)) {
123+
this.pressedKeys.add(key);
124+
this.dispatchEvent(
125+
new CustomEvent('button-press', {
126+
detail: { key }
127+
})
128+
);
129+
}
130+
}
131+
132+
private up(key: string) {
133+
if (this.pressedKeys.has(key)) {
134+
this.pressedKeys.delete(key);
135+
this.dispatchEvent(
136+
new CustomEvent('button-release', {
137+
detail: { key }
138+
})
139+
);
140+
}
141+
}
142+
}

0 commit comments

Comments
 (0)