├── .editorconfig
├── .github
├── CONTRIBUTING.md
└── ISSUE_TEMPLATE.md
├── .gitignore
├── .npmignore
├── LICENSE
├── TODO.md
├── demo
├── basic.html
└── events.html
├── dist
├── collection
│ ├── collection-manifest.json
│ ├── components
│ │ └── konami-listener
│ │ │ ├── konami-listener.css
│ │ │ └── konami-listener.js
│ ├── index.js
│ ├── interface.js
│ └── main.css
├── esm
│ ├── es5
│ │ ├── konami-listener.components.js
│ │ ├── konami-listener.core.js
│ │ ├── konami-listener.define.js
│ │ ├── konami-listener.global.js
│ │ ├── konami-listener.js
│ │ ├── konami-listener.sc.js
│ │ └── polyfills
│ │ │ ├── array.js
│ │ │ ├── dom.js
│ │ │ ├── fetch.js
│ │ │ ├── object.js
│ │ │ ├── promise.js
│ │ │ └── string.js
│ └── index.js
├── index.js
├── konami-listener.js
├── konami-listener
│ ├── es5-build-disabled.js
│ ├── konami-listener.core.js
│ ├── konami-listener.global.js
│ ├── konami-listener.js
│ └── konami-listener.sc.js
└── types
│ ├── components.d.ts
│ ├── components
│ └── konami-listener
│ │ └── konami-listener.d.ts
│ ├── index.d.ts
│ └── stencil.core.d.ts
├── package-lock.json
├── package.json
├── readme.md
├── src
├── components.d.ts
├── components
│ └── konami-listener
│ │ ├── konami-listener.css
│ │ ├── konami-listener.spec.ts
│ │ └── konami-listener.tsx
├── index.d.ts
├── index.html
├── index.ts
└── main.css
├── stencil.config.ts
├── tsconfig.json
└── www
├── build
├── konami-listener.js
└── konami-listener
│ ├── es5-build-disabled.js
│ ├── konami-listener.core.js
│ ├── konami-listener.global.js
│ ├── konami-listener.js
│ ├── konami-listener.registry.json
│ └── konami-listener.sc.js
├── index.html
└── main.css
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | indent_style = space
8 | indent_size = 2
9 | end_of_line = lf
10 | insert_final_newline = true
11 | trim_trailing_whitespace = true
12 |
13 | [*.md]
14 | insert_final_newline = false
15 | trim_trailing_whitespace = false
16 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Thanks for your interest in contributing to the Stencil Component Starter! :tada:
4 |
5 |
6 | ## Contributing Etiquette
7 |
8 | Please see our [Contributor Code of Conduct](https://github.com/ionic-team/stencil/blob/master/CODE_OF_CONDUCT.md) for information on our rules of conduct.
9 |
10 |
11 | ## Creating an Issue
12 |
13 | * If you have a question about using Stencil, please ask in the [Stencil Worldwide Slack](https://join.slack.com/t/stencil-worldwide/shared_invite/enQtMjQ2MzkyMTY0MTk0LTQ4ODgzYjFjNjdkNDY3YWVhMmNlMTljMWQxNTM3Yjg0ZTIyZTM1MmU2YWE5YzNjNzE1MmQ3ZTk2NjQ1YzM5ZDM group.
14 |
15 | * It is required that you clearly describe the steps necessary to reproduce the issue you are running into. Although we would love to help our users as much as possible, diagnosing issues without clear reproduction steps is extremely time-consuming and simply not sustainable.
16 |
17 | * The issue list of this repository is exclusively for bug reports and feature requests. Non-conforming issues will be closed immediately.
18 |
19 | * Issues with no clear steps to reproduce will not be triaged. If an issue is labeled with "needs reply" and receives no further replies from the author of the issue for more than 5 days, it will be closed.
20 |
21 | * If you think you have found a bug, or have a new feature idea, please start by making sure it hasn't already been [reported](https://github.com/ionic-team/stencil/issues?utf8=%E2%9C%93&q=is%3Aissue). You can search through existing issues to see if there is a similar one reported. Include closed issues as it may have been closed with a solution.
22 |
23 | * Next, [create a new issue](https://github.com/ionic-team/stencil-component-starter/issues/new) that thoroughly explains the problem. Please fill out the populated issue form before submitting the issue.
24 |
25 |
26 | ## Creating a Pull Request
27 |
28 | * We appreciate you taking the time to contribute! Before submitting a pull request, we ask that you please [create an issue](#creating-an-issue) that explains the bug or feature request and let us know that you plan on creating a pull request for it. If an issue already exists, please comment on that issue letting us know you would like to submit a pull request for it. This helps us to keep track of the pull request and make sure there isn't duplicated effort.
29 |
30 | * Looking for an issue to fix? Make sure to look through our issues with the [help wanted](https://github.com/ionic-team/stencil-component-starter/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) label!
31 |
32 | ### Setup
33 |
34 | 1. Fork the repo.
35 | 2. Clone your fork.
36 | 3. Make a branch for your change.
37 | 4. Run `npm install` (make sure you have [node](https://nodejs.org/en/) and [npm](http://blog.npmjs.org/post/85484771375/how-to-install-npm) installed first)
38 |
39 |
40 | #### Updates
41 |
42 | 1. Unit test. Unit test. Unit test. Please take a look at how other unit tests are written, and you can't write too many tests.
43 | 2. If there is a `*.spec.ts` file located in the components folder, update it to include a test for your change, if needed. If this file doesn't exist, please notify us.
44 | 3. Run `npm run test` or `npm run test.watch` to make sure all tests are working, regardless if a test was added.
45 |
46 |
47 | ## Commit Message Format
48 |
49 | We have very precise rules over how our git commit messages should be formatted. This leads to readable messages that are easy to follow when looking through the project history. We also use the git commit messages to generate our changelog. (Ok you got us, it's basically Angular's commit message format).
50 |
51 | `type(scope): subject`
52 |
53 | #### Type
54 | Must be one of the following:
55 |
56 | * **feat**: A new feature
57 | * **fix**: A bug fix
58 | * **docs**: Documentation only changes
59 | * **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
60 | * **refactor**: A code change that neither fixes a bug nor adds a feature
61 | * **perf**: A code change that improves performance
62 | * **test**: Adding missing tests
63 | * **chore**: Changes to the build process or auxiliary tools and libraries such as documentation generation
64 |
65 | #### Scope
66 | The scope can be anything specifying place of the commit change. For example `renderer`, `compiler`, etc.
67 |
68 | #### Subject
69 | The subject contains succinct description of the change:
70 |
71 | * use the imperative, present tense: "change" not "changed" nor "changes"
72 | * do not capitalize first letter
73 | * do not place a period `.` at the end
74 | * entire length of the commit message must not go over 50 characters
75 | * describe what the commit does, not what issue it relates to or fixes
76 | * **be brief, yet descriptive** - we should have a good understanding of what the commit does by reading the subject
77 |
78 |
79 | #### Adding Documentation
80 |
81 | Please see the [stencil-site](https://github.com/ionic-team/stencil-site) repo to update documentation.
82 |
83 |
84 | ## License
85 |
86 | By contributing your code to the ionic-team/stencil GitHub Repository, you agree to license your contribution under the MIT license.
87 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | **Resources:**
2 | Before submitting an issue, please consult our [docs](https://stenciljs.com/).
3 |
4 | **Stencil version:** (run `npm list @stencil/core` from a terminal/cmd prompt and paste output below):
5 |
6 | ```
7 | insert the output from npm list @stencil/core here
8 | ```
9 |
10 | **I'm submitting a ...** (check one with "x")
11 | [ ] bug report
12 | [ ] feature request
13 | [ ] support request => Please do not submit support requests here, use one of these channels: https://forum.ionicframework.com/ or https://stencil-worldwide.slack.com
14 |
15 | **Current behavior:**
16 |
17 |
18 | **Expected behavior:**
19 |
20 |
21 | **Steps to reproduce:**
22 |
24 |
25 | **Related code:**
26 |
27 | ```
28 | insert any relevant code here
29 | ```
30 |
31 | **Other information:**
32 |
33 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | *.sw[mnpcod]
3 | *.log
4 | *.lock
5 | *.tmp
6 | *.tmp.*
7 | log.txt
8 | *.sublime-project
9 | *.sublime-workspace
10 |
11 | .idea/
12 | .vscode/
13 | .sass-cache/
14 | .versions/
15 | node_modules/
16 | $RECYCLE.BIN/
17 |
18 | .DS_Store
19 | Thumbs.db
20 | UserInterfaceState.xcuserstate
21 | .env
22 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/natemoo-re/konami-listener/a83012a8d2544cae6e8fc1179259cb78085a0bf1/.npmignore
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Ionic
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 | # TODO
2 |
3 | - [ ] Write tests
4 | - [x] Publish to NPM
5 | - [ ] Enable interaction on touch devices (without using Hammer)
--------------------------------------------------------------------------------
/demo/basic.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Stencil Component Starter
7 |
8 |
9 |
10 |
11 |
12 |
13 | ↑ + ↑ + ↓ + ↓ + ← + → + ← + → + B + A
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/demo/events.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Stencil Component Starter
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/dist/collection/collection-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "components": [
3 | {
4 | "tag": "konami-listener",
5 | "dependencies": [],
6 | "componentClass": "KonamiListener",
7 | "componentPath": "components/konami-listener/konami-listener.js",
8 | "styles": {
9 | "$": {
10 | "stylePaths": [
11 | "components/konami-listener/konami-listener.css"
12 | ]
13 | }
14 | },
15 | "states": [
16 | {
17 | "name": "inputs"
18 | }
19 | ],
20 | "listeners": [
21 | {
22 | "event": "document:keydown",
23 | "method": "handleKey",
24 | "passive": false,
25 | "capture": false
26 | }
27 | ],
28 | "hostElement": {
29 | "name": "el"
30 | },
31 | "events": [
32 | {
33 | "event": "input"
34 | },
35 | {
36 | "event": "match"
37 | }
38 | ],
39 | "shadow": true
40 | }
41 | ],
42 | "collections": [],
43 | "compiler": {
44 | "name": "@stencil/core",
45 | "version": "0.11.4",
46 | "typescriptVersion": "2.9.2"
47 | },
48 | "bundles": []
49 | }
--------------------------------------------------------------------------------
/dist/collection/components/konami-listener/konami-listener.css:
--------------------------------------------------------------------------------
1 | :host {
2 | display: none;
3 | position: absolute;
4 | top: 0;
5 | left: 0;
6 | bottom: 0;
7 | right: 0;
8 | }
9 |
10 | :host(.active) {
11 | display: block;
12 | }
13 |
--------------------------------------------------------------------------------
/dist/collection/components/konami-listener/konami-listener.js:
--------------------------------------------------------------------------------
1 | export class KonamiListener {
2 | constructor() {
3 | this.keys = ["ArrowUp", "ArrowUp", "ArrowDown", "ArrowDown", "ArrowLeft", "ArrowRight", "ArrowLeft", "ArrowRight", "b", "a"];
4 | this.accepted = [...new Set(this.keys)];
5 | this.inputs = [];
6 | }
7 | handleKey(e) {
8 | let { key } = e;
9 | if (!this.accepted.includes(key))
10 | return;
11 | (this.keys[this.inputs.length] === key)
12 | ? this.handleInput(key)
13 | : this.reset();
14 | }
15 | handleInput(key) {
16 | this.inputs.push(key);
17 | this.input.emit({ key, index: this.inputs.length - 1 });
18 | if (this.inputs.length === 10) {
19 | this.handleMatch();
20 | }
21 | }
22 | handleMatch() {
23 | this.match.emit();
24 | this.el.classList.add('active');
25 | this.reset();
26 | }
27 | reset() {
28 | if (this.inputs.length) {
29 | this.inputs = [];
30 | this.input.emit({ reset: true });
31 | }
32 | }
33 | render() {
34 | return h("slot", null);
35 | }
36 | static get is() { return "konami-listener"; }
37 | static get encapsulation() { return "shadow"; }
38 | static get properties() { return {
39 | "el": {
40 | "elementRef": true
41 | },
42 | "inputs": {
43 | "state": true
44 | }
45 | }; }
46 | static get events() { return [{
47 | "name": "input",
48 | "method": "input",
49 | "bubbles": true,
50 | "cancelable": true,
51 | "composed": true
52 | }, {
53 | "name": "match",
54 | "method": "match",
55 | "bubbles": true,
56 | "cancelable": true,
57 | "composed": true
58 | }]; }
59 | static get listeners() { return [{
60 | "name": "document:keydown",
61 | "method": "handleKey"
62 | }]; }
63 | static get style() { return "/**style-placeholder:konami-listener:**/"; }
64 | }
65 |
--------------------------------------------------------------------------------
/dist/collection/index.js:
--------------------------------------------------------------------------------
1 | export * from './components';
2 |
--------------------------------------------------------------------------------
/dist/collection/interface.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/natemoo-re/konami-listener/a83012a8d2544cae6e8fc1179259cb78085a0bf1/dist/collection/interface.js
--------------------------------------------------------------------------------
/dist/collection/main.css:
--------------------------------------------------------------------------------
1 | @keyframes fade {
2 | 0% {
3 | opacity: 0.5;
4 | }
5 | 100% {
6 | opacity: 0;
7 | }
8 | }
9 |
10 | :root {
11 | --color-red: #f4511e;
12 | --header-size: 200px;
13 | --footer-size: 56px;
14 | }
15 |
16 | html, body {
17 | padding: 0;
18 | margin: 0;
19 | }
20 |
21 | header {
22 | box-sizing: border-box;
23 | width: 100%;
24 | height: var(--header-size);
25 | display: flex;
26 | flex-flow: column nowrap;
27 | align-items: center;
28 | justify-content: center;
29 | text-align: center;
30 | padding: 0 12px;
31 | max-width: 570px;
32 | margin: 0 auto;
33 | }
34 | header h1 {
35 | margin: 0;
36 | font-family: 'Press Start 2P', sans-serif;
37 | line-height: 1.2;
38 | }
39 | header p {
40 | font-family: sans-serif;
41 | color: rgba(0,0,0,0.54);
42 | }
43 | header code {
44 | box-sizing: border-box;
45 | padding: 1px 4px 0 4px;
46 | line-height: 1;
47 | background-color: rgba(0, 0, 0, 0.12);
48 | border-radius: 4px;
49 | white-space: nowrap;
50 | }
51 |
52 |
53 | footer {
54 | box-sizing: border-box;
55 | height: var(--footer-size);
56 | background-color: red;
57 | width: 100%;
58 | display: flex;
59 | align-items: center;
60 | }
61 | footer .inner {
62 | box-sizing: border-box;
63 | width: 100%;
64 | display: flex;
65 | align-items: center;
66 | justify-content: space-between;
67 | max-width: 570px;
68 | margin: 0 auto;
69 | }
70 | footer .inner div {
71 | box-sizing: border-box;
72 | text-align: center;
73 | padding: 0 12px;
74 | }
75 | footer h4 {
76 | margin: 0;
77 | font-family: sans-serif;
78 | font-weight: 400;
79 | color: #FFF;
80 | }
81 | footer a {
82 | font-family: 'Press Start 2P', sans-serif;
83 | font-size: 14px;
84 | color: #FFF;
85 | }
86 |
87 | main, .prize {
88 | height: calc(calc(100vh - var(--header-size)) - var(--footer-size));
89 | width: 100%;
90 | max-width: calc(1000px / 4);
91 |
92 | display: flex;
93 | align-items: center;
94 | justify-content: center;
95 | margin: 0 auto;
96 | }
97 |
98 | main.hidden {
99 | opacity: 0;
100 | }
101 |
102 | .prize {
103 | flex-flow: column nowrap;
104 | align-items: center;
105 | justify-content: center;
106 | height: 100vh;
107 | font-size: 126px;
108 | }
109 | .prize h2 {
110 | font-size: 32px;
111 | font-family: 'Press Start 2P', sans-serif;
112 | color: var(--color-red);
113 | margin: 0;
114 | line-height: 1;
115 |
116 | }
117 |
118 | .inputs {
119 | width: 100%;
120 | flex-flow: row wrap;
121 | display: flex;
122 | align-items: center;
123 | justify-content: space-between;
124 | transform: scale(.7);
125 | }
126 |
127 | .inputs > div {
128 | --size: 100px;
129 | margin: 12px;
130 | width: var(--size);
131 | height: var(--size);
132 | }
133 |
134 | .inputs > div > svg > path.fixed {
135 | fill: rgba(0,0,0,0.32);
136 | /* stroke-width: 4px; */
137 | z-index: 1;
138 | }
139 | .inputs > div > svg > path:not(.fixed) {
140 | transition: 250ms ease-out all;
141 | fill: none;
142 | stroke-width: 2px;
143 | opacity: 0.5;
144 | z-index: -1;
145 | stroke: var(--color-red);
146 |
147 | opacity: 0;
148 | transform-origin: center center;
149 | }
150 |
151 | .inputs > div > svg {
152 | overflow: visible;
153 | }
154 |
155 | .inputs > div.active > svg > path.fixed {
156 | fill: var(--color-red);
157 | stroke: transparent;
158 | }
159 | .inputs > div.active > svg > path:not(.fixed) {
160 | display: block;
161 | opacity: 1;
162 | transform: scale(1.5);
163 | animation: 150ms 100ms fade forwards;
164 | }
165 |
166 | div.up.active > svg > path:not(.fixed) {
167 | transform: translateY(-70px);
168 | }
169 | div.down.active > svg > path:not(.fixed) {
170 | transform: translateY(70px);
171 | }
172 | div.left.active > svg > path:not(.fixed) {
173 | transform: translateX(-70px);
174 | }
175 | div.right.active > svg > path:not(.fixed) {
176 | transform: translateX(70px);
177 | }
178 | div.B.active > svg > path:not(.fixed) {
179 | transform: scale(1.75);
180 | }
181 | div.A.active > svg > path:not(.fixed) {
182 | transform: scale(1.75);
183 | }
184 | @media only screen and (min-width: 555px) {
185 | header {
186 | margin-bottom: calc(var(--header-size) / -4);
187 | }
188 | main {
189 | padding-bottom: calc(var(--header-size) / 4);
190 | }
191 | }
192 |
193 | @media only screen and (min-width: 1180px) {
194 | main {
195 | max-width: 1180px;
196 | }
197 | footer {
198 | justify-content: center;
199 | }
200 | .inputs {
201 | transform: scale(1);
202 | }
203 |
204 | .inputs > div {
205 | margin: 0;
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/dist/esm/es5/konami-listener.components.js:
--------------------------------------------------------------------------------
1 | // KonamiListener: Host Data, ES Module/ES5 Target
2 |
3 | export var KonamiListener = ["konami-listener",function(o){return(o.scoped?import("./konami-listener.sc.js"):import("./konami-listener.js")).then(function(m){return m.KonamiListener})},1,[["el",7],["inputs",5]],1,[["document:keydown","handleKey"]]];
--------------------------------------------------------------------------------
/dist/esm/es5/konami-listener.define.js:
--------------------------------------------------------------------------------
1 | // KonamiListener: Custom Elements Define Library, ES Module/ES5 Target
2 | import { defineCustomElement } from './konami-listener.core.js';
3 | import {
4 | KonamiListener
5 | } from './konami-listener.components.js';
6 |
7 | export function defineCustomElements(window, opts) {
8 | defineCustomElement(window, [
9 | KonamiListener
10 | ], opts);
11 | }
--------------------------------------------------------------------------------
/dist/esm/es5/konami-listener.global.js:
--------------------------------------------------------------------------------
1 | /*! Built with http://stenciljs.com */
2 | export default function appGlobal(namespace, Context, window, document, resourcesUrl, hydratedCssClass) {
3 | }
--------------------------------------------------------------------------------
/dist/esm/es5/konami-listener.js:
--------------------------------------------------------------------------------
1 | /*! Built with http://stenciljs.com */
2 | import { h } from './konami-listener.core.js';
3 | var KonamiListener = /** @class */ (function () {
4 | function KonamiListener() {
5 | this.keys = ["ArrowUp", "ArrowUp", "ArrowDown", "ArrowDown", "ArrowLeft", "ArrowRight", "ArrowLeft", "ArrowRight", "b", "a"];
6 | this.accepted = new Set(this.keys).slice();
7 | this.inputs = [];
8 | }
9 | KonamiListener.prototype.handleKey = function (e) {
10 | var key = e.key;
11 | if (!this.accepted.includes(key))
12 | return;
13 | (this.keys[this.inputs.length] === key)
14 | ? this.handleInput(key)
15 | : this.reset();
16 | };
17 | KonamiListener.prototype.handleInput = function (key) {
18 | this.inputs.push(key);
19 | this.input.emit({ key: key, index: this.inputs.length - 1 });
20 | if (this.inputs.length === 10) {
21 | this.handleMatch();
22 | }
23 | };
24 | KonamiListener.prototype.handleMatch = function () {
25 | this.match.emit();
26 | this.el.classList.add('active');
27 | this.reset();
28 | };
29 | KonamiListener.prototype.reset = function () {
30 | if (this.inputs.length) {
31 | this.inputs = [];
32 | this.input.emit({ reset: true });
33 | }
34 | };
35 | KonamiListener.prototype.render = function () {
36 | return h("slot", null);
37 | };
38 | Object.defineProperty(KonamiListener, "is", {
39 | get: function () { return "konami-listener"; },
40 | enumerable: true,
41 | configurable: true
42 | });
43 | Object.defineProperty(KonamiListener, "encapsulation", {
44 | get: function () { return "shadow"; },
45 | enumerable: true,
46 | configurable: true
47 | });
48 | Object.defineProperty(KonamiListener, "properties", {
49 | get: function () {
50 | return {
51 | "el": {
52 | "elementRef": true
53 | },
54 | "inputs": {
55 | "state": true
56 | }
57 | };
58 | },
59 | enumerable: true,
60 | configurable: true
61 | });
62 | Object.defineProperty(KonamiListener, "events", {
63 | get: function () {
64 | return [{
65 | "name": "input",
66 | "method": "input",
67 | "bubbles": true,
68 | "cancelable": true,
69 | "composed": true
70 | }, {
71 | "name": "match",
72 | "method": "match",
73 | "bubbles": true,
74 | "cancelable": true,
75 | "composed": true
76 | }];
77 | },
78 | enumerable: true,
79 | configurable: true
80 | });
81 | Object.defineProperty(KonamiListener, "listeners", {
82 | get: function () {
83 | return [{
84 | "name": "document:keydown",
85 | "method": "handleKey"
86 | }];
87 | },
88 | enumerable: true,
89 | configurable: true
90 | });
91 | Object.defineProperty(KonamiListener, "style", {
92 | get: function () { return ":host {\n display: none;\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n right: 0;\n}\n\n:host(.active) {\n display: block;\n}"; },
93 | enumerable: true,
94 | configurable: true
95 | });
96 | return KonamiListener;
97 | }());
98 | export { KonamiListener };
99 |
--------------------------------------------------------------------------------
/dist/esm/es5/konami-listener.sc.js:
--------------------------------------------------------------------------------
1 | /*! Built with http://stenciljs.com */
2 | import { h } from './konami-listener.core.js';
3 | var KonamiListener = /** @class */ (function () {
4 | function KonamiListener() {
5 | this.keys = ["ArrowUp", "ArrowUp", "ArrowDown", "ArrowDown", "ArrowLeft", "ArrowRight", "ArrowLeft", "ArrowRight", "b", "a"];
6 | this.accepted = new Set(this.keys).slice();
7 | this.inputs = [];
8 | }
9 | KonamiListener.prototype.handleKey = function (e) {
10 | var key = e.key;
11 | if (!this.accepted.includes(key))
12 | return;
13 | (this.keys[this.inputs.length] === key)
14 | ? this.handleInput(key)
15 | : this.reset();
16 | };
17 | KonamiListener.prototype.handleInput = function (key) {
18 | this.inputs.push(key);
19 | this.input.emit({ key: key, index: this.inputs.length - 1 });
20 | if (this.inputs.length === 10) {
21 | this.handleMatch();
22 | }
23 | };
24 | KonamiListener.prototype.handleMatch = function () {
25 | this.match.emit();
26 | this.el.classList.add('active');
27 | this.reset();
28 | };
29 | KonamiListener.prototype.reset = function () {
30 | if (this.inputs.length) {
31 | this.inputs = [];
32 | this.input.emit({ reset: true });
33 | }
34 | };
35 | KonamiListener.prototype.render = function () {
36 | return h("slot", null);
37 | };
38 | Object.defineProperty(KonamiListener, "is", {
39 | get: function () { return "konami-listener"; },
40 | enumerable: true,
41 | configurable: true
42 | });
43 | Object.defineProperty(KonamiListener, "encapsulation", {
44 | get: function () { return "shadow"; },
45 | enumerable: true,
46 | configurable: true
47 | });
48 | Object.defineProperty(KonamiListener, "properties", {
49 | get: function () {
50 | return {
51 | "el": {
52 | "elementRef": true
53 | },
54 | "inputs": {
55 | "state": true
56 | }
57 | };
58 | },
59 | enumerable: true,
60 | configurable: true
61 | });
62 | Object.defineProperty(KonamiListener, "events", {
63 | get: function () {
64 | return [{
65 | "name": "input",
66 | "method": "input",
67 | "bubbles": true,
68 | "cancelable": true,
69 | "composed": true
70 | }, {
71 | "name": "match",
72 | "method": "match",
73 | "bubbles": true,
74 | "cancelable": true,
75 | "composed": true
76 | }];
77 | },
78 | enumerable: true,
79 | configurable: true
80 | });
81 | Object.defineProperty(KonamiListener, "listeners", {
82 | get: function () {
83 | return [{
84 | "name": "document:keydown",
85 | "method": "handleKey"
86 | }];
87 | },
88 | enumerable: true,
89 | configurable: true
90 | });
91 | Object.defineProperty(KonamiListener, "style", {
92 | get: function () { return "\n.sc-konami-listener-h {\n display: none;\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n right: 0;\n}\n\n.active.sc-konami-listener-h {\n display: block;\n}\n"; },
93 | enumerable: true,
94 | configurable: true
95 | });
96 | return KonamiListener;
97 | }());
98 | export { KonamiListener };
99 |
--------------------------------------------------------------------------------
/dist/esm/es5/polyfills/array.js:
--------------------------------------------------------------------------------
1 | export function applyPolyfill(window, document) {
2 | /*!
3 | Array.prototype.find
4 | */
5 | Array.prototype.find||Object.defineProperty(Array.prototype,"find",{writable:!0,configurable:!0,value:function(c,e){if(null==this)throw new TypeError('"this" is null or not defined');var b=Object(this),f=b.length>>>0;if("function"!==typeof c)throw new TypeError("predicate must be a function");for(var a=0;a>>0;if(0===n)return!1;var i,o,a=0|e,u=Math.max(0<=a?a:n-Math.abs(a),0);for(;u1)&&Zt(this)}}}),ot(u,h,{value:function(e){-1<_.call(a,e)&&o[h].apply(this,arguments)}}),o[d]&&ot(u,p,{value:o[d]}),o[v]&&ot(u,g,{value:o[v]}),i&&(f[c]=i),e=e.toUpperCase(),G[e]={constructor:t,create:i?[i,et(e)]:[e]},Z.set(t,e),n[s](e.toLowerCase(),f),en(e),Y[e].r()}function Gt(e){var t=G[e.toUpperCase()];return t&&t.constructor}function Yt(e){return typeof e=="string"?e:e&&e.is||""}function Zt(e){var t=e[h],n=t?e.attributes:j,r=n.length,i;while(r--)i=n[r],t.call(e,i.name||i.nodeName,null,i.value||i.nodeValue)}function en(e){return e=e.toUpperCase(),e in Y||(Y[e]={},Y[e].p=new K(function(t){Y[e].r=t})),Y[e].p}function tn(){X&&delete e.customElements,B(e,"customElements",{configurable:!0,value:new Kt}),B(e,"CustomElementRegistry",{configurable:!0,value:Kt});for(var t=function(t){var r=e[t];if(r){e[t]=function(t){var i,s;return t||(t=this),t[W]||(Q=!0,i=G[Z.get(t.constructor)],s=V&&i.create.length===1,t=s?Reflect.construct(r,j,i.constructor):n.createElement.apply(n,i.create),t[W]=!0,Q=!1,s||Zt(t)),t},e[t].prototype=r.prototype;try{r.prototype.constructor=e[t]}catch(i){z=!0,B(r,W,{value:e[t]})}}},r=i.get(/^HTML[A-Z]*[a-z]/),o=r.length;o--;t(r[o]));n.createElement=function(e,t){var n=Yt(t);return n?gt.call(this,e,et(n)):gt.call(this,e)},St||(Tt=!0,n[s](""))}var n=e.document,r=e.Object,i=function(e){var t=/^[A-Z]+[a-z]/,n=function(e){var t=[],n;for(n in s)e.test(n)&&t.push(n);return t},i=function(e,t){t=t.toLowerCase(),t in s||(s[e]=(s[e]||[]).concat(t),s[t]=s[t.toUpperCase()]=e)},s=(r.create||r)(null),o={},u,a,f,l;for(a in e)for(l in e[a]){f=e[a][l],s[l]=f;for(u=0;u>0),u="addEventListener",a="attached",f="Callback",l="detached",c="extends",h="attributeChanged"+f,p=a+f,d="connected"+f,v="disconnected"+f,m="created"+f,g=l+f,y="ADDITION",b="MODIFICATION",w="REMOVAL",E="DOMAttrModified",S="DOMContentLoaded",x="DOMSubtreeModified",T="<",N="=",C=/^[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)+$/,k=["ANNOTATION-XML","COLOR-PROFILE","FONT-FACE","FONT-FACE-SRC","FONT-FACE-URI","FONT-FACE-FORMAT","FONT-FACE-NAME","MISSING-GLYPH"],L=[],A=[],O="",M=n.documentElement,_=L.indexOf||function(e){for(var t=this.length;t--&&this[t]!==e;);return t},D=r.prototype,P=D.hasOwnProperty,H=D.isPrototypeOf,B=r.defineProperty,j=[],F=r.getOwnPropertyDescriptor,I=r.getOwnPropertyNames,q=r.getPrototypeOf,R=r.setPrototypeOf,U=!!r.__proto__,z=!1,W="__dreCEv1",X=e.customElements,V=!/^force/.test(t.type)&&!!(X&&X.define&&X.get&&X.whenDefined),$=r.create||r,J=e.Map||function(){var t=[],n=[],r;return{get:function(e){return n[_.call(t,e)]},set:function(e,i){r=_.call(t,e),r<0?n[t.push(e)-1]=i:n[r]=i}}},K=e.Promise||function(e){function i(e){n=!0;while(t.length)t.shift()(e)}var t=[],n=!1,r={"catch":function(){return r},then:function(e){return t.push(e),n&&setTimeout(i,1),r}};return e(i),r},Q=!1,G=$(null),Y=$(null),Z=new J,et=function(e){return e.toLowerCase()},tt=r.create||function sn(e){return e?(sn.prototype=e,new sn):this},nt=R||(U?function(e,t){return e.__proto__=t,e}:I&&F?function(){function e(e,t){for(var n,r=I(t),i=0,s=r.length;ithis.status;this.statusText="statusText"in b?b.statusText:"OK";this.headers=new d(b.headers);this.url=b.url||"";this._initBody(a)}if(!e.fetch){var D="Symbol"in e&&"iterator"in Symbol,m;if(m="FileReader"in e&&"Blob"in e)try{new Blob,m=!0}catch(a){m=!1}var g={searchParams:"URLSearchParams"in e,iterable:D,
16 | blob:m,formData:"FormData"in e,arrayBuffer:"ArrayBuffer"in e};if(g.arrayBuffer){var E="[object Int8Array];[object Uint8Array];[object Uint8ClampedArray];[object Int16Array];[object Uint16Array];[object Int32Array];[object Uint32Array];[object Float32Array];[object Float64Array]".split(";");var y=function(a){return a&&DataView.prototype.isPrototypeOf(a)};var z=ArrayBuffer.isView||function(a){return a&&-1this.length)a=this.length;return this.substring(a-b.length,a)===b}});
6 | /*!
7 | String.prototype.includes
8 | */
9 | String.prototype.includes||(String.prototype.includes=function(b,a){"number"!==typeof a&&(a=0);return a+b.length>this.length?!1:-1!==this.indexOf(b,a)});
10 | /*!
11 | String.prototype.startsWith
12 | */
13 | String.prototype.startsWith||Object.defineProperty(String.prototype,"startsWith",{writable:!0,configurable:!0,value:function(b,a){return this.substr(!a||0>a?0:+a,b.length)===b}});
14 | }
--------------------------------------------------------------------------------
/dist/esm/index.js:
--------------------------------------------------------------------------------
1 | // KonamiListener: ES Module
2 | export * from './es5/konami-listener.define.js';
3 | export * from '../collection/index.js';
--------------------------------------------------------------------------------
/dist/index.js:
--------------------------------------------------------------------------------
1 | // KonamiListener: CommonJS Main
--------------------------------------------------------------------------------
/dist/konami-listener.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Built with http://stenciljs.com
3 | * 2018-08-19T13:38:16
4 | */
5 | (function(win, doc, namespace, fsNamespace, resourcesUrl, appCore, appCoreSsr, appCorePolyfilled, hydratedCssClass, components) {
6 |
7 | function init(win, doc, namespace, fsNamespace, resourcesUrl, appCore, appCorePolyfilled, hydratedCssClass, components, HTMLElementPrototype, App, x, y, scriptElm) {
8 | // create global namespace if it doesn't already exist
9 | App = win[namespace] = win[namespace] || {};
10 | App.components = components;
11 | y = components.filter(function (c) { return c[2]; }).map(function (c) { return c[0]; });
12 | if (y.length) {
13 | // auto hide components until they been fully hydrated
14 | // reusing the "x" and "i" variables from the args for funzies
15 | x = doc.createElement('style');
16 | x.innerHTML = y.join() + '{visibility:hidden}.' + hydratedCssClass + '{visibility:inherit}';
17 | x.setAttribute('data-styles', '');
18 | doc.head.insertBefore(x, doc.head.firstChild);
19 | }
20 | createComponentOnReadyPrototype(win, namespace, HTMLElementPrototype);
21 | resourcesUrl = resourcesUrl || App.resourcesUrl;
22 | // figure out the script element for this current script
23 | y = doc.querySelectorAll('script');
24 | for (x = y.length - 1; x >= 0; x--) {
25 | scriptElm = y[x];
26 | if (scriptElm.src || scriptElm.hasAttribute('data-resources-url')) {
27 | break;
28 | }
29 | }
30 | // get the resource path attribute on this script element
31 | y = scriptElm.getAttribute('data-resources-url');
32 | if (!resourcesUrl && y) {
33 | // the script element has a data-resources-url attribute, always use that
34 | resourcesUrl = y;
35 | }
36 | if (!resourcesUrl && scriptElm.src) {
37 | // we don't have an exact resourcesUrl, so let's
38 | // figure it out relative to this script's src and app's filesystem namespace
39 | y = scriptElm.src.split('/').slice(0, -1);
40 | resourcesUrl = (y.join('/')) + (y.length ? '/' : '') + fsNamespace + '/';
41 | }
42 | // request the core this browser needs
43 | // test for native support of custom elements and fetch
44 | // if either of those are not supported, then use the core w/ polyfills
45 | // also check if the page was build with ssr or not
46 | x = doc.createElement('script');
47 | if (usePolyfills(win, win.location, x, 'import("")')) {
48 | // requires the es5/polyfilled core
49 | x.src = resourcesUrl + appCorePolyfilled;
50 | }
51 | else {
52 | // let's do this!
53 | x.src = resourcesUrl + appCore;
54 | x.setAttribute('type', 'module');
55 | x.setAttribute('crossorigin', true);
56 | }
57 | x.setAttribute('data-resources-url', resourcesUrl);
58 | x.setAttribute('data-namespace', fsNamespace);
59 | doc.head.appendChild(x);
60 | }
61 | function usePolyfills(win, location, scriptElm, dynamicImportTest) {
62 | // fyi, dev mode has verbose if/return statements
63 | // but it minifies to a nice 'lil one-liner ;)
64 | if (location.search.indexOf('core=esm') > 0) {
65 | // force esm build
66 | return false;
67 | }
68 | if ((location.search.indexOf('core=es5') > 0) ||
69 | (location.protocol === 'file:') ||
70 | (!(win.customElements && win.customElements.define)) ||
71 | (!win.fetch) ||
72 | (!(win.CSS && win.CSS.supports && win.CSS.supports('color', 'var(--c)'))) ||
73 | (!('noModule' in scriptElm))) {
74 | // es5 build w/ polyfills
75 | return true;
76 | }
77 | // final test to see if this browser support dynamic imports
78 | return doesNotSupportsDynamicImports(dynamicImportTest);
79 | }
80 | function doesNotSupportsDynamicImports(dynamicImportTest) {
81 | try {
82 | new Function(dynamicImportTest);
83 | return false;
84 | }
85 | catch (e) { }
86 | return true;
87 | }
88 | function createComponentOnReadyPrototype(win, namespace, HTMLElementPrototype) {
89 | (win['s-apps'] = win['s-apps'] || []).push(namespace);
90 | if (!HTMLElementPrototype.componentOnReady) {
91 | HTMLElementPrototype.componentOnReady = function componentOnReady() {
92 | /*tslint:disable*/
93 | var elm = this;
94 | function executor(resolve) {
95 | if (elm.nodeName.indexOf('-') > 0) {
96 | // window hasn't loaded yet and there's a
97 | // good chance this is a custom element
98 | var apps = win['s-apps'];
99 | var appsReady = 0;
100 | // loop through all the app namespaces
101 | for (var i = 0; i < apps.length; i++) {
102 | // see if this app has "componentOnReady" setup
103 | if (win[apps[i]].componentOnReady) {
104 | // this app's core has loaded call its "componentOnReady"
105 | if (win[apps[i]].componentOnReady(elm, resolve)) {
106 | // this component does belong to this app and would
107 | // have fired off the resolve fn
108 | // let's stop here, we're good
109 | return;
110 | }
111 | appsReady++;
112 | }
113 | }
114 | if (appsReady < apps.length) {
115 | // not all apps are ready yet
116 | // add it to the queue to be figured out when they are
117 | (win['s-cr'] = win['s-cr'] || []).push([elm, resolve]);
118 | return;
119 | }
120 | }
121 | // not a recognized app component
122 | resolve(null);
123 | }
124 | // callback wasn't provided, let's return a promise
125 | if (win.Promise) {
126 | // use native/polyfilled promise
127 | return new win.Promise(executor);
128 | }
129 | // promise may not have been polyfilled yet
130 | return { then: executor };
131 | };
132 | }
133 | }
134 |
135 |
136 | init(win, doc, namespace, fsNamespace, resourcesUrl, appCore, appCoreSsr, appCorePolyfilled, hydratedCssClass, components);
137 |
138 | })(window, document, "KonamiListener","konami-listener",0,"konami-listener.core.js","es5-build-disabled.js","hydrated",[["konami-listener","konami-listener",1,[["el",7],["inputs",5]],1,[["document:keydown","handleKey"]]]],HTMLElement.prototype);
--------------------------------------------------------------------------------
/dist/konami-listener/es5-build-disabled.js:
--------------------------------------------------------------------------------
1 | setTimeout(function(){
2 | document.body.innerHTML = ' This Stencil app is disabled for this browser. Developers: ES5 builds are disabled during development to take advantage of 2x faster build times. Please see the example below or our config docs if you would like to develop on a browser that does not fully support ES2017 and custom elements. Note that by default, ES5 builds and polyfills are enabled during production builds. When testing browsers it is recommended to always test in production mode, and ES5 builds should always be enabled during production builds. This is only an experiement and if it slows down app development then we will revert this and enable ES5 builds during dev. Enabling ES5 builds during development: npm run dev --es5 For stencil-component-starter, use:
npm start --es5 Enabling full production builds during development: npm run dev --prod For stencil-component-starter, use:
npm start --prod Current Browser\'s Support: Current Browser: ';
3 |
4 | document.getElementById('current-browser-output').textContent = window.navigator.userAgent;
5 | document.getElementById('es-modules-test').textContent = !!('noModule' in document.createElement('script'));
6 | document.getElementById('custom-elements-test').textContent = !!(window.customElements);
7 | document.getElementById('css-variables-test').textContent = !!(window.CSS && window.CSS.supports && window.CSS.supports('color', 'var(--c)'));
8 | document.getElementById('fetch-test').textContent = !!(window.fetch);
9 | }, 10)
--------------------------------------------------------------------------------
/dist/konami-listener/konami-listener.global.js:
--------------------------------------------------------------------------------
1 | /*! Built with http://stenciljs.com */
2 | (function(namespace,resourcesUrl){"use strict";
3 |
4 | })("KonamiListener");
--------------------------------------------------------------------------------
/dist/konami-listener/konami-listener.js:
--------------------------------------------------------------------------------
1 | /*! Built with http://stenciljs.com */
2 | const { h } = window.KonamiListener;
3 |
4 | class KonamiListener {
5 | constructor() {
6 | this.keys = ["ArrowUp", "ArrowUp", "ArrowDown", "ArrowDown", "ArrowLeft", "ArrowRight", "ArrowLeft", "ArrowRight", "b", "a"];
7 | this.accepted = [...new Set(this.keys)];
8 | this.inputs = [];
9 | }
10 | handleKey(e) {
11 | let { key } = e;
12 | if (!this.accepted.includes(key))
13 | return;
14 | (this.keys[this.inputs.length] === key)
15 | ? this.handleInput(key)
16 | : this.reset();
17 | }
18 | handleInput(key) {
19 | this.inputs.push(key);
20 | this.input.emit({ key, index: this.inputs.length - 1 });
21 | if (this.inputs.length === 10) {
22 | this.handleMatch();
23 | }
24 | }
25 | handleMatch() {
26 | this.match.emit();
27 | this.el.classList.add('active');
28 | this.reset();
29 | }
30 | reset() {
31 | if (this.inputs.length) {
32 | this.inputs = [];
33 | this.input.emit({ reset: true });
34 | }
35 | }
36 | render() {
37 | return h("slot", null);
38 | }
39 | static get is() { return "konami-listener"; }
40 | static get encapsulation() { return "shadow"; }
41 | static get properties() { return {
42 | "el": {
43 | "elementRef": true
44 | },
45 | "inputs": {
46 | "state": true
47 | }
48 | }; }
49 | static get events() { return [{
50 | "name": "input",
51 | "method": "input",
52 | "bubbles": true,
53 | "cancelable": true,
54 | "composed": true
55 | }, {
56 | "name": "match",
57 | "method": "match",
58 | "bubbles": true,
59 | "cancelable": true,
60 | "composed": true
61 | }]; }
62 | static get listeners() { return [{
63 | "name": "document:keydown",
64 | "method": "handleKey"
65 | }]; }
66 | static get style() { return ":host {\n display: none;\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n right: 0;\n}\n\n:host(.active) {\n display: block;\n}"; }
67 | }
68 |
69 | export { KonamiListener };
70 |
--------------------------------------------------------------------------------
/dist/konami-listener/konami-listener.sc.js:
--------------------------------------------------------------------------------
1 | /*! Built with http://stenciljs.com */
2 | const { h } = window.KonamiListener;
3 |
4 | class KonamiListener {
5 | constructor() {
6 | this.keys = ["ArrowUp", "ArrowUp", "ArrowDown", "ArrowDown", "ArrowLeft", "ArrowRight", "ArrowLeft", "ArrowRight", "b", "a"];
7 | this.accepted = [...new Set(this.keys)];
8 | this.inputs = [];
9 | }
10 | handleKey(e) {
11 | let { key } = e;
12 | if (!this.accepted.includes(key))
13 | return;
14 | (this.keys[this.inputs.length] === key)
15 | ? this.handleInput(key)
16 | : this.reset();
17 | }
18 | handleInput(key) {
19 | this.inputs.push(key);
20 | this.input.emit({ key, index: this.inputs.length - 1 });
21 | if (this.inputs.length === 10) {
22 | this.handleMatch();
23 | }
24 | }
25 | handleMatch() {
26 | this.match.emit();
27 | this.el.classList.add('active');
28 | this.reset();
29 | }
30 | reset() {
31 | if (this.inputs.length) {
32 | this.inputs = [];
33 | this.input.emit({ reset: true });
34 | }
35 | }
36 | render() {
37 | return h("slot", null);
38 | }
39 | static get is() { return "konami-listener"; }
40 | static get encapsulation() { return "shadow"; }
41 | static get properties() { return {
42 | "el": {
43 | "elementRef": true
44 | },
45 | "inputs": {
46 | "state": true
47 | }
48 | }; }
49 | static get events() { return [{
50 | "name": "input",
51 | "method": "input",
52 | "bubbles": true,
53 | "cancelable": true,
54 | "composed": true
55 | }, {
56 | "name": "match",
57 | "method": "match",
58 | "bubbles": true,
59 | "cancelable": true,
60 | "composed": true
61 | }]; }
62 | static get listeners() { return [{
63 | "name": "document:keydown",
64 | "method": "handleKey"
65 | }]; }
66 | static get style() { return "\n.sc-konami-listener-h {\n display: none;\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n right: 0;\n}\n\n.active.sc-konami-listener-h {\n display: block;\n}\n"; }
67 | }
68 |
69 | export { KonamiListener };
70 |
--------------------------------------------------------------------------------
/dist/types/components.d.ts:
--------------------------------------------------------------------------------
1 | import './stencil.core';
2 | /**
3 | * This is an autogenerated file created by the Stencil compiler.
4 | * It contains typing information for all components that exist in this project.
5 | */
6 | /* tslint:disable */
7 |
8 | import './stencil.core';
9 |
10 |
11 |
12 |
13 | declare global {
14 | interface HTMLElement {
15 | componentOnReady?: () => Promise;
16 | }
17 |
18 | interface HTMLStencilElement extends HTMLElement {
19 | componentOnReady(): Promise;
20 |
21 | forceUpdate(): void;
22 | }
23 |
24 | interface HTMLAttributes {}
25 |
26 | namespace StencilComponents {
27 |
28 | interface KonamiListener {
29 |
30 | }
31 | }
32 |
33 |
34 | interface HTMLKonamiListenerElement extends StencilComponents.KonamiListener, HTMLStencilElement {}
35 |
36 | var HTMLKonamiListenerElement: {
37 | prototype: HTMLKonamiListenerElement;
38 | new (): HTMLKonamiListenerElement;
39 | };
40 |
41 |
42 | namespace JSX {
43 | interface Element {}
44 | export interface IntrinsicElements {
45 | 'konami-listener': JSXElements.KonamiListenerAttributes;
46 | }
47 | }
48 |
49 | namespace JSXElements {
50 |
51 | export interface KonamiListenerAttributes extends HTMLAttributes {
52 | 'onInput'?: (event: CustomEvent) => void;
53 | 'onMatch'?: (event: CustomEvent) => void;
54 | }
55 | }
56 |
57 | interface HTMLElementTagNameMap {
58 | 'konami-listener': HTMLKonamiListenerElement
59 | }
60 |
61 | interface ElementTagNameMap {
62 | 'konami-listener': HTMLKonamiListenerElement;
63 | }
64 | }
65 | declare global { namespace JSX { interface StencilJSX {} } }
66 |
67 | export declare function defineCustomElements(window: any): void;
--------------------------------------------------------------------------------
/dist/types/components/konami-listener/konami-listener.d.ts:
--------------------------------------------------------------------------------
1 | import '../../stencil.core';
2 | import { EventEmitter } from '../../stencil.core';
3 | export declare class KonamiListener {
4 | private keys;
5 | private accepted;
6 | el: HTMLElement;
7 | inputs: string[];
8 | input: EventEmitter;
9 | match: EventEmitter;
10 | handleKey(e: KeyboardEvent): void;
11 | handleInput(key: string): void;
12 | handleMatch(): void;
13 | reset(): void;
14 | render(): JSX.Element;
15 | }
16 |
--------------------------------------------------------------------------------
/dist/types/index.d.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/natemoo-re/konami-listener/a83012a8d2544cae6e8fc1179259cb78085a0bf1/dist/types/index.d.ts
--------------------------------------------------------------------------------
/dist/types/stencil.core.d.ts:
--------------------------------------------------------------------------------
1 |
2 | export interface ComponentWillLoad {
3 | componentWillLoad: () => Promise | void;
4 | }
5 |
6 | export interface ComponentDidLoad {
7 | componentDidLoad: () => void;
8 | }
9 |
10 | export interface ComponentWillUpdate {
11 | componentWillUpdate: () => Promise | void;
12 | }
13 |
14 | export interface ComponentDidUpdate {
15 | componentDidUpdate: () => void;
16 | }
17 |
18 | export interface ComponentDidUnload {
19 | componentDidUnload: () => void;
20 | }
21 |
22 | export interface EventEmitter {
23 | emit: (data?: T) => void;
24 | }
25 |
26 | export interface EventListenerEnable {
27 | (instance: any, eventName: string, enabled: boolean, attachTo?: string|Element, passive?: boolean): void;
28 | }
29 |
30 | export interface QueueApi {
31 | tick: (cb: RafCallback) => void;
32 | read: (cb: RafCallback) => void;
33 | write: (cb: RafCallback) => void;
34 | clear?: () => void;
35 | flush?: (cb?: () => void) => void;
36 | }
37 |
38 | export interface RafCallback {
39 | (timeStamp: number): void;
40 | }
41 |
42 | declare global {
43 | namespace JSX {
44 | interface Element {}
45 | export interface IntrinsicElements {}
46 | }
47 | namespace JSXElements {}
48 |
49 | interface HTMLStencilElement extends HTMLElement {
50 | componentOnReady(): Promise;
51 | }
52 |
53 | interface HTMLAttributes {}
54 | }
55 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "konami-listener",
3 | "version": "0.3.0",
4 | "description": "Konami Code listener as a Vanilla Web Component",
5 | "module": "dist/esm/index.js",
6 | "main": "dist/index.js",
7 | "types": "dist/types/components.d.ts",
8 | "collection": "dist/collection/collection-manifest.json",
9 | "files": [
10 | "dist/"
11 | ],
12 | "scripts": {
13 | "build": "stencil build",
14 | "start": "stencil build --dev --watch --serve",
15 | "test": "jest",
16 | "test.watch": "jest --watch"
17 | },
18 | "devDependencies": {
19 | "@stencil/core": "^0.11.0",
20 | "@types/jest": "^23.3.1",
21 | "jest": "^23.4.2"
22 | },
23 | "repository": {
24 | "type": "git",
25 | "url": "git+https://github.com/natemoo-re/konami-listener.git"
26 | },
27 | "author": "Nate Moore",
28 | "license": "MIT",
29 | "bugs": {
30 | "url": "https://github.com/natemoo-re/konami-listener"
31 | },
32 | "homepage": "http://projects.natemoo.re/konami-listener",
33 | "jest": {
34 | "transform": {
35 | "^.+\\.(ts|tsx)$": "/node_modules/@stencil/core/testing/jest.preprocessor.js"
36 | },
37 | "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$",
38 | "moduleFileExtensions": [
39 | "ts",
40 | "tsx",
41 | "js",
42 | "json",
43 | "jsx"
44 | ]
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | 
2 | 
3 |
4 | # Konami Listener
5 |
6 | `` is a web component that listens for the Konami Code. When a match is triggered, it will automatically show any content placed inside of the component, like so ` Hello world! `
7 |
8 | See the demo at [http://projects.natemoo.re/konami-listener](http://projects.natemoo.re/konami-listener)
9 |
10 | ## Getting Started
11 |
12 | ### Script tag
13 |
14 | - Add the javascript module in the head of your index.html file
15 | ```html
16 |
17 | ```
18 | - Use ` ` anywhere in your templates, JSX, html, etc
19 |
20 | ### Node Modules
21 | - Run `npm install konami-listener --save`
22 | - Add the javascript module in the head of your index.html file
23 | ```html
24 |
25 | ```
26 | - Use ` ` anywhere in your templates, JSX, html, etc
27 |
28 | ### In a stencil-starter app
29 | - Run `npm install konami-listener --save`
30 | - Add `{ name: 'konami-listener' }` to your [collections](https://github.com/ionic-team/stencil-starter/blob/master/stencil.config.js#L5)
31 | - Use ` ` anywhere in your templates, JSX, html, etc
32 |
33 | ## API
34 | ### Simple Usage
35 | `` allows you to place any content inside of it. It will then be shown when the code is matched. By default, the container is absolutely positioned over the entire page, so style the internal markup accordingly.
36 | ```html
37 |
38 | 💩
39 |
40 | ```
41 |
42 | ### Events
43 | `` emits the following custom events
44 | | Event Name | Description | Data |
45 | | ----------- | ------------------------------------------------ | -------------------------------- |
46 | | input | Emitted on each keydown as the code progresses | `{ key: string, index: number }` |
47 | | match | Emitted on the final match | none |
48 |
49 | To listen for events, just use `addEventListener`. Since it uses custom HTML events, the data payload is bound to `event.detail`.
50 | ```js
51 | const konami = document.querySelector('konami-listener');
52 | konami.addEventListener('match', () => {
53 | console.log('Konami Code matched!');
54 | })
55 | konami.addEventListener('input', (e) => {
56 | const { key, index } = e.detail;
57 | console.log('Konami Code progress', { key, index });
58 | })
59 | ```
60 |
61 | ## Framework Integration
62 | If you'd like to drop this component into Angular, React, or any other framework, take a look at Stencil's [Framework Integration guide](https://stenciljs.com/docs/framework-integration)
--------------------------------------------------------------------------------
/src/components.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This is an autogenerated file created by the Stencil compiler.
3 | * It contains typing information for all components that exist in this project.
4 | */
5 | /* tslint:disable */
6 |
7 | import '@stencil/core';
8 |
9 |
10 |
11 |
12 | declare global {
13 | interface HTMLElement {
14 | componentOnReady?: () => Promise;
15 | }
16 |
17 | interface HTMLStencilElement extends HTMLElement {
18 | componentOnReady(): Promise;
19 |
20 | forceUpdate(): void;
21 | }
22 |
23 | interface HTMLAttributes {}
24 |
25 | namespace StencilComponents {
26 |
27 | interface KonamiListener {
28 |
29 | }
30 | }
31 |
32 |
33 | interface HTMLKonamiListenerElement extends StencilComponents.KonamiListener, HTMLStencilElement {}
34 |
35 | var HTMLKonamiListenerElement: {
36 | prototype: HTMLKonamiListenerElement;
37 | new (): HTMLKonamiListenerElement;
38 | };
39 |
40 |
41 | namespace JSX {
42 | interface Element {}
43 | export interface IntrinsicElements {
44 | 'konami-listener': JSXElements.KonamiListenerAttributes;
45 | }
46 | }
47 |
48 | namespace JSXElements {
49 |
50 | export interface KonamiListenerAttributes extends HTMLAttributes {
51 | 'onInput'?: (event: CustomEvent) => void;
52 | 'onMatch'?: (event: CustomEvent) => void;
53 | }
54 | }
55 |
56 | interface HTMLElementTagNameMap {
57 | 'konami-listener': HTMLKonamiListenerElement
58 | }
59 |
60 | interface ElementTagNameMap {
61 | 'konami-listener': HTMLKonamiListenerElement;
62 | }
63 | }
64 | declare global { namespace JSX { interface StencilJSX {} } }
65 |
66 | export declare function defineCustomElements(window: any): void;
--------------------------------------------------------------------------------
/src/components/konami-listener/konami-listener.css:
--------------------------------------------------------------------------------
1 | :host {
2 | display: none;
3 | position: absolute;
4 | top: 0;
5 | left: 0;
6 | bottom: 0;
7 | right: 0;
8 | }
9 |
10 | :host(.active) {
11 | display: block;
12 | }
13 |
--------------------------------------------------------------------------------
/src/components/konami-listener/konami-listener.spec.ts:
--------------------------------------------------------------------------------
1 | import { flush, render } from '@stencil/core/testing';
2 | import { KonamiListener } from './konami-listener';
3 |
4 | describe('konami-listener', () => {
5 | it('should build', () => {
6 | expect(new KonamiListener()).toBeTruthy();
7 | });
8 |
9 | describe('keyboard', () => {
10 | let element: HTMLElement;
11 |
12 | let press = function(key) {
13 | let event = new KeyboardEvent('keydown', { key });
14 | document.dispatchEvent(event);
15 | }
16 |
17 | beforeEach(async () => {
18 | element = await render({
19 | components: [KonamiListener],
20 | html: ' '
21 | });
22 | });
23 |
24 | it('should recognize ArrowUp', () => {
25 | // press('ArrowUp');
26 | expect(element).toBeTruthy();
27 | });
28 | })
29 |
30 | // describe('rendering', () => {
31 | // let element;
32 | // beforeEach(async () => {
33 | // element = await render({
34 | // components: [KonamiListener],
35 | // html: ' '
36 | // });
37 | // });
38 |
39 | // it('should work without parameters', () => {
40 | // expect(element..trim()).toEqual('Hello, World! I\'m');
41 | // });
42 |
43 | // it('should work with a first name', async () => {
44 | // element.first = 'Peter';
45 | // await flush(element);
46 | // expect(element.textContent.trim()).toEqual('Hello, World! I\'m Peter');
47 | // });
48 |
49 | // it('should work with a last name', async () => {
50 | // element.last = 'Parker';
51 | // await flush(element);
52 | // expect(element.textContent.trim()).toEqual('Hello, World! I\'m Parker');
53 | // });
54 |
55 | // it('should work with both a first and a last name', async () => {
56 | // element.first = 'Peter'
57 | // element.last = 'Parker';
58 | // await flush(element);
59 | // expect(element.textContent.trim()).toEqual('Hello, World! I\'m Peter Parker');
60 | // });
61 | // });
62 | });
--------------------------------------------------------------------------------
/src/components/konami-listener/konami-listener.tsx:
--------------------------------------------------------------------------------
1 | import { Component, State, Listen, Event, EventEmitter, Element } from '@stencil/core';
2 |
3 | @Component({
4 | tag: 'konami-listener',
5 | styleUrl: 'konami-listener.css',
6 | shadow: true
7 | })
8 | export class KonamiListener {
9 |
10 | private keys = ["ArrowUp", "ArrowUp", "ArrowDown", "ArrowDown", "ArrowLeft", "ArrowRight", "ArrowLeft", "ArrowRight", "b", "a"];
11 | private accepted = [...new Set(this.keys)];
12 |
13 | @Element() el: HTMLElement;
14 |
15 | @State() inputs: string[] = [];
16 |
17 | @Event() input: EventEmitter;
18 | @Event() match: EventEmitter;
19 |
20 | @Listen('document:keydown')
21 | handleKey(e: KeyboardEvent) {
22 | let { key } = e;
23 | if (!this.accepted.includes(key)) return;
24 |
25 | (this.keys[this.inputs.length] === key)
26 | ? this.handleInput(key)
27 | : this.reset();
28 | }
29 |
30 | handleInput(key: string) {
31 | this.inputs.push(key);
32 | this.input.emit({ key, index: this.inputs.length - 1 });
33 |
34 | if (this.inputs.length === 10) {
35 | this.handleMatch();
36 | }
37 | }
38 |
39 | handleMatch() {
40 | this.match.emit();
41 | this.el.classList.add('active');
42 | this.reset();
43 | }
44 |
45 | reset() {
46 | if (this.inputs.length) {
47 | this.inputs = [];
48 | this.input.emit({ reset: true });
49 | }
50 | }
51 |
52 | render() {
53 | return
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/index.d.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/natemoo-re/konami-listener/a83012a8d2544cae6e8fc1179259cb78085a0bf1/src/index.d.ts
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Stencil Component Starter
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
22 |
23 |
24 |
86 |
87 |
88 |
94 |
95 |
96 |
100 |
101 |
102 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './components';
2 |
--------------------------------------------------------------------------------
/src/main.css:
--------------------------------------------------------------------------------
1 | @keyframes fade {
2 | 0% {
3 | opacity: 0.5;
4 | }
5 | 100% {
6 | opacity: 0;
7 | }
8 | }
9 |
10 | :root {
11 | --color-red: #f4511e;
12 | --header-size: 200px;
13 | --footer-size: 56px;
14 | }
15 |
16 | html, body {
17 | padding: 0;
18 | margin: 0;
19 | }
20 |
21 | header {
22 | box-sizing: border-box;
23 | width: 100%;
24 | height: var(--header-size);
25 | display: flex;
26 | flex-flow: column nowrap;
27 | align-items: center;
28 | justify-content: center;
29 | text-align: center;
30 | padding: 0 12px;
31 | max-width: 570px;
32 | margin: 0 auto;
33 | }
34 | header h1 {
35 | margin: 0;
36 | font-family: 'Press Start 2P', sans-serif;
37 | line-height: 1.2;
38 | }
39 | header p {
40 | font-family: sans-serif;
41 | color: rgba(0,0,0,0.54);
42 | }
43 | header code {
44 | box-sizing: border-box;
45 | padding: 1px 4px 0 4px;
46 | line-height: 1;
47 | background-color: rgba(0, 0, 0, 0.12);
48 | border-radius: 4px;
49 | white-space: nowrap;
50 | }
51 |
52 |
53 | footer {
54 | box-sizing: border-box;
55 | height: var(--footer-size);
56 | background-color: red;
57 | width: 100%;
58 | display: flex;
59 | align-items: center;
60 | }
61 | footer .inner {
62 | box-sizing: border-box;
63 | width: 100%;
64 | display: flex;
65 | align-items: center;
66 | justify-content: space-between;
67 | max-width: 570px;
68 | margin: 0 auto;
69 | }
70 | footer .inner div {
71 | box-sizing: border-box;
72 | text-align: center;
73 | padding: 0 12px;
74 | }
75 | footer h4 {
76 | margin: 0;
77 | font-family: sans-serif;
78 | font-weight: 400;
79 | color: #FFF;
80 | }
81 | footer a {
82 | font-family: 'Press Start 2P', sans-serif;
83 | font-size: 14px;
84 | color: #FFF;
85 | }
86 |
87 | main, .prize {
88 | height: calc(calc(100vh - var(--header-size)) - var(--footer-size));
89 | width: 100%;
90 | max-width: calc(1000px / 4);
91 |
92 | display: flex;
93 | align-items: center;
94 | justify-content: center;
95 | margin: 0 auto;
96 | }
97 |
98 | main.hidden {
99 | opacity: 0;
100 | }
101 |
102 | .prize {
103 | flex-flow: column nowrap;
104 | align-items: center;
105 | justify-content: center;
106 | height: 100vh;
107 | font-size: 126px;
108 | }
109 | .prize h2 {
110 | font-size: 32px;
111 | font-family: 'Press Start 2P', sans-serif;
112 | color: var(--color-red);
113 | margin: 0;
114 | line-height: 1;
115 |
116 | }
117 |
118 | .inputs {
119 | width: 100%;
120 | flex-flow: row wrap;
121 | display: flex;
122 | align-items: center;
123 | justify-content: space-between;
124 | transform: scale(.7);
125 | }
126 |
127 | .inputs > div {
128 | --size: 100px;
129 | margin: 12px;
130 | width: var(--size);
131 | height: var(--size);
132 | }
133 |
134 | .inputs > div > svg > path.fixed {
135 | fill: rgba(0,0,0,0.32);
136 | /* stroke-width: 4px; */
137 | z-index: 1;
138 | }
139 | .inputs > div > svg > path:not(.fixed) {
140 | transition: 250ms ease-out all;
141 | fill: none;
142 | stroke-width: 2px;
143 | opacity: 0.5;
144 | z-index: -1;
145 | stroke: var(--color-red);
146 |
147 | opacity: 0;
148 | transform-origin: center center;
149 | }
150 |
151 | .inputs > div > svg {
152 | overflow: visible;
153 | }
154 |
155 | .inputs > div.active > svg > path.fixed {
156 | fill: var(--color-red);
157 | stroke: transparent;
158 | }
159 | .inputs > div.active > svg > path:not(.fixed) {
160 | display: block;
161 | opacity: 1;
162 | transform: scale(1.5);
163 | animation: 150ms 100ms fade forwards;
164 | }
165 |
166 | div.up.active > svg > path:not(.fixed) {
167 | transform: translateY(-70px);
168 | }
169 | div.down.active > svg > path:not(.fixed) {
170 | transform: translateY(70px);
171 | }
172 | div.left.active > svg > path:not(.fixed) {
173 | transform: translateX(-70px);
174 | }
175 | div.right.active > svg > path:not(.fixed) {
176 | transform: translateX(70px);
177 | }
178 | div.B.active > svg > path:not(.fixed) {
179 | transform: scale(1.75);
180 | }
181 | div.A.active > svg > path:not(.fixed) {
182 | transform: scale(1.75);
183 | }
184 | @media only screen and (min-width: 555px) {
185 | header {
186 | margin-bottom: calc(var(--header-size) / -4);
187 | }
188 | main {
189 | padding-bottom: calc(var(--header-size) / 4);
190 | }
191 | }
192 |
193 | @media only screen and (min-width: 1180px) {
194 | main {
195 | max-width: 1180px;
196 | }
197 | footer {
198 | justify-content: center;
199 | }
200 | .inputs {
201 | transform: scale(1);
202 | }
203 |
204 | .inputs > div {
205 | margin: 0;
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/stencil.config.ts:
--------------------------------------------------------------------------------
1 | import { Config } from '@stencil/core';
2 |
3 | export const config: Config = {
4 | namespace: 'konami-listener',
5 | outputTargets: [
6 | { type: 'dist' },
7 | {
8 | type: 'www',
9 | serviceWorker: null
10 | }
11 | ],
12 | copy: [
13 | { src: 'main.css' }
14 | ]
15 | };
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "allowUnreachableCode": false,
5 | "declaration": false,
6 | "experimentalDecorators": true,
7 | "lib": [
8 | "dom",
9 | "es2017"
10 | ],
11 | "moduleResolution": "node",
12 | "module": "es2015",
13 | "target": "es2017",
14 | "noUnusedLocals": true,
15 | "noUnusedParameters": true,
16 | "jsx": "react",
17 | "jsxFactory": "h"
18 | },
19 | "include": [
20 | "src",
21 | "types/jsx.d.ts"
22 | ],
23 | "exclude": [
24 | "node_modules"
25 | ]
26 | }
--------------------------------------------------------------------------------
/www/build/konami-listener.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Built with http://stenciljs.com
3 | * 2018-08-19T13:38:16
4 | */
5 | (function(win, doc, namespace, fsNamespace, resourcesUrl, appCore, appCoreSsr, appCorePolyfilled, hydratedCssClass, components) {
6 |
7 | function init(win, doc, namespace, fsNamespace, resourcesUrl, appCore, appCorePolyfilled, hydratedCssClass, components, HTMLElementPrototype, App, x, y, scriptElm) {
8 | // create global namespace if it doesn't already exist
9 | App = win[namespace] = win[namespace] || {};
10 | App.components = components;
11 | y = components.filter(function (c) { return c[2]; }).map(function (c) { return c[0]; });
12 | if (y.length) {
13 | // auto hide components until they been fully hydrated
14 | // reusing the "x" and "i" variables from the args for funzies
15 | x = doc.createElement('style');
16 | x.innerHTML = y.join() + '{visibility:hidden}.' + hydratedCssClass + '{visibility:inherit}';
17 | x.setAttribute('data-styles', '');
18 | doc.head.insertBefore(x, doc.head.firstChild);
19 | }
20 | createComponentOnReadyPrototype(win, namespace, HTMLElementPrototype);
21 | resourcesUrl = resourcesUrl || App.resourcesUrl;
22 | // figure out the script element for this current script
23 | y = doc.querySelectorAll('script');
24 | for (x = y.length - 1; x >= 0; x--) {
25 | scriptElm = y[x];
26 | if (scriptElm.src || scriptElm.hasAttribute('data-resources-url')) {
27 | break;
28 | }
29 | }
30 | // get the resource path attribute on this script element
31 | y = scriptElm.getAttribute('data-resources-url');
32 | if (!resourcesUrl && y) {
33 | // the script element has a data-resources-url attribute, always use that
34 | resourcesUrl = y;
35 | }
36 | if (!resourcesUrl && scriptElm.src) {
37 | // we don't have an exact resourcesUrl, so let's
38 | // figure it out relative to this script's src and app's filesystem namespace
39 | y = scriptElm.src.split('/').slice(0, -1);
40 | resourcesUrl = (y.join('/')) + (y.length ? '/' : '') + fsNamespace + '/';
41 | }
42 | // request the core this browser needs
43 | // test for native support of custom elements and fetch
44 | // if either of those are not supported, then use the core w/ polyfills
45 | // also check if the page was build with ssr or not
46 | x = doc.createElement('script');
47 | if (usePolyfills(win, win.location, x, 'import("")')) {
48 | // requires the es5/polyfilled core
49 | x.src = resourcesUrl + appCorePolyfilled;
50 | }
51 | else {
52 | // let's do this!
53 | x.src = resourcesUrl + appCore;
54 | x.setAttribute('type', 'module');
55 | x.setAttribute('crossorigin', true);
56 | }
57 | x.setAttribute('data-resources-url', resourcesUrl);
58 | x.setAttribute('data-namespace', fsNamespace);
59 | doc.head.appendChild(x);
60 | }
61 | function usePolyfills(win, location, scriptElm, dynamicImportTest) {
62 | // fyi, dev mode has verbose if/return statements
63 | // but it minifies to a nice 'lil one-liner ;)
64 | if (location.search.indexOf('core=esm') > 0) {
65 | // force esm build
66 | return false;
67 | }
68 | if ((location.search.indexOf('core=es5') > 0) ||
69 | (location.protocol === 'file:') ||
70 | (!(win.customElements && win.customElements.define)) ||
71 | (!win.fetch) ||
72 | (!(win.CSS && win.CSS.supports && win.CSS.supports('color', 'var(--c)'))) ||
73 | (!('noModule' in scriptElm))) {
74 | // es5 build w/ polyfills
75 | return true;
76 | }
77 | // final test to see if this browser support dynamic imports
78 | return doesNotSupportsDynamicImports(dynamicImportTest);
79 | }
80 | function doesNotSupportsDynamicImports(dynamicImportTest) {
81 | try {
82 | new Function(dynamicImportTest);
83 | return false;
84 | }
85 | catch (e) { }
86 | return true;
87 | }
88 | function createComponentOnReadyPrototype(win, namespace, HTMLElementPrototype) {
89 | (win['s-apps'] = win['s-apps'] || []).push(namespace);
90 | if (!HTMLElementPrototype.componentOnReady) {
91 | HTMLElementPrototype.componentOnReady = function componentOnReady() {
92 | /*tslint:disable*/
93 | var elm = this;
94 | function executor(resolve) {
95 | if (elm.nodeName.indexOf('-') > 0) {
96 | // window hasn't loaded yet and there's a
97 | // good chance this is a custom element
98 | var apps = win['s-apps'];
99 | var appsReady = 0;
100 | // loop through all the app namespaces
101 | for (var i = 0; i < apps.length; i++) {
102 | // see if this app has "componentOnReady" setup
103 | if (win[apps[i]].componentOnReady) {
104 | // this app's core has loaded call its "componentOnReady"
105 | if (win[apps[i]].componentOnReady(elm, resolve)) {
106 | // this component does belong to this app and would
107 | // have fired off the resolve fn
108 | // let's stop here, we're good
109 | return;
110 | }
111 | appsReady++;
112 | }
113 | }
114 | if (appsReady < apps.length) {
115 | // not all apps are ready yet
116 | // add it to the queue to be figured out when they are
117 | (win['s-cr'] = win['s-cr'] || []).push([elm, resolve]);
118 | return;
119 | }
120 | }
121 | // not a recognized app component
122 | resolve(null);
123 | }
124 | // callback wasn't provided, let's return a promise
125 | if (win.Promise) {
126 | // use native/polyfilled promise
127 | return new win.Promise(executor);
128 | }
129 | // promise may not have been polyfilled yet
130 | return { then: executor };
131 | };
132 | }
133 | }
134 |
135 |
136 | init(win, doc, namespace, fsNamespace, resourcesUrl, appCore, appCoreSsr, appCorePolyfilled, hydratedCssClass, components);
137 |
138 | })(window, document, "KonamiListener","konami-listener",0,"konami-listener.core.js","es5-build-disabled.js","hydrated",[["konami-listener","konami-listener",1,[["el",7],["inputs",5]],1,[["document:keydown","handleKey"]]]],HTMLElement.prototype);
--------------------------------------------------------------------------------
/www/build/konami-listener/es5-build-disabled.js:
--------------------------------------------------------------------------------
1 | setTimeout(function(){
2 | document.body.innerHTML = ' This Stencil app is disabled for this browser. Developers: ES5 builds are disabled during development to take advantage of 2x faster build times. Please see the example below or our config docs if you would like to develop on a browser that does not fully support ES2017 and custom elements. Note that by default, ES5 builds and polyfills are enabled during production builds. When testing browsers it is recommended to always test in production mode, and ES5 builds should always be enabled during production builds. This is only an experiement and if it slows down app development then we will revert this and enable ES5 builds during dev. Enabling ES5 builds during development: npm run dev --es5 For stencil-component-starter, use:
npm start --es5 Enabling full production builds during development: npm run dev --prod For stencil-component-starter, use:
npm start --prod Current Browser\'s Support: Current Browser: ';
3 |
4 | document.getElementById('current-browser-output').textContent = window.navigator.userAgent;
5 | document.getElementById('es-modules-test').textContent = !!('noModule' in document.createElement('script'));
6 | document.getElementById('custom-elements-test').textContent = !!(window.customElements);
7 | document.getElementById('css-variables-test').textContent = !!(window.CSS && window.CSS.supports && window.CSS.supports('color', 'var(--c)'));
8 | document.getElementById('fetch-test').textContent = !!(window.fetch);
9 | }, 10)
--------------------------------------------------------------------------------
/www/build/konami-listener/konami-listener.global.js:
--------------------------------------------------------------------------------
1 | /*! Built with http://stenciljs.com */
2 | (function(namespace,resourcesUrl){"use strict";
3 |
4 | })("KonamiListener");
--------------------------------------------------------------------------------
/www/build/konami-listener/konami-listener.js:
--------------------------------------------------------------------------------
1 | /*! Built with http://stenciljs.com */
2 | const { h } = window.KonamiListener;
3 |
4 | class KonamiListener {
5 | constructor() {
6 | this.keys = ["ArrowUp", "ArrowUp", "ArrowDown", "ArrowDown", "ArrowLeft", "ArrowRight", "ArrowLeft", "ArrowRight", "b", "a"];
7 | this.accepted = [...new Set(this.keys)];
8 | this.inputs = [];
9 | }
10 | handleKey(e) {
11 | let { key } = e;
12 | if (!this.accepted.includes(key))
13 | return;
14 | (this.keys[this.inputs.length] === key)
15 | ? this.handleInput(key)
16 | : this.reset();
17 | }
18 | handleInput(key) {
19 | this.inputs.push(key);
20 | this.input.emit({ key, index: this.inputs.length - 1 });
21 | if (this.inputs.length === 10) {
22 | this.handleMatch();
23 | }
24 | }
25 | handleMatch() {
26 | this.match.emit();
27 | this.el.classList.add('active');
28 | this.reset();
29 | }
30 | reset() {
31 | if (this.inputs.length) {
32 | this.inputs = [];
33 | this.input.emit({ reset: true });
34 | }
35 | }
36 | render() {
37 | return h("slot", null);
38 | }
39 | static get is() { return "konami-listener"; }
40 | static get encapsulation() { return "shadow"; }
41 | static get properties() { return {
42 | "el": {
43 | "elementRef": true
44 | },
45 | "inputs": {
46 | "state": true
47 | }
48 | }; }
49 | static get events() { return [{
50 | "name": "input",
51 | "method": "input",
52 | "bubbles": true,
53 | "cancelable": true,
54 | "composed": true
55 | }, {
56 | "name": "match",
57 | "method": "match",
58 | "bubbles": true,
59 | "cancelable": true,
60 | "composed": true
61 | }]; }
62 | static get listeners() { return [{
63 | "name": "document:keydown",
64 | "method": "handleKey"
65 | }]; }
66 | static get style() { return ":host {\n display: none;\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n right: 0;\n}\n\n:host(.active) {\n display: block;\n}"; }
67 | }
68 |
69 | export { KonamiListener };
70 |
--------------------------------------------------------------------------------
/www/build/konami-listener/konami-listener.registry.json:
--------------------------------------------------------------------------------
1 | {
2 | "namespace": "KonamiListener",
3 | "fsNamespace": "konami-listener",
4 | "loader": "../konami-listener.js",
5 | "corePolyfilled": "es5-build-disabled.js",
6 | "global": "konami-listener.global.js",
7 | "core": "konami-listener.core.js",
8 | "components": {
9 | "konami-listener": {
10 | "bundleIds": {
11 | "$": "konami-listener"
12 | },
13 | "encapsulation": "shadow"
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/www/build/konami-listener/konami-listener.sc.js:
--------------------------------------------------------------------------------
1 | /*! Built with http://stenciljs.com */
2 | const { h } = window.KonamiListener;
3 |
4 | class KonamiListener {
5 | constructor() {
6 | this.keys = ["ArrowUp", "ArrowUp", "ArrowDown", "ArrowDown", "ArrowLeft", "ArrowRight", "ArrowLeft", "ArrowRight", "b", "a"];
7 | this.accepted = [...new Set(this.keys)];
8 | this.inputs = [];
9 | }
10 | handleKey(e) {
11 | let { key } = e;
12 | if (!this.accepted.includes(key))
13 | return;
14 | (this.keys[this.inputs.length] === key)
15 | ? this.handleInput(key)
16 | : this.reset();
17 | }
18 | handleInput(key) {
19 | this.inputs.push(key);
20 | this.input.emit({ key, index: this.inputs.length - 1 });
21 | if (this.inputs.length === 10) {
22 | this.handleMatch();
23 | }
24 | }
25 | handleMatch() {
26 | this.match.emit();
27 | this.el.classList.add('active');
28 | this.reset();
29 | }
30 | reset() {
31 | if (this.inputs.length) {
32 | this.inputs = [];
33 | this.input.emit({ reset: true });
34 | }
35 | }
36 | render() {
37 | return h("slot", null);
38 | }
39 | static get is() { return "konami-listener"; }
40 | static get encapsulation() { return "shadow"; }
41 | static get properties() { return {
42 | "el": {
43 | "elementRef": true
44 | },
45 | "inputs": {
46 | "state": true
47 | }
48 | }; }
49 | static get events() { return [{
50 | "name": "input",
51 | "method": "input",
52 | "bubbles": true,
53 | "cancelable": true,
54 | "composed": true
55 | }, {
56 | "name": "match",
57 | "method": "match",
58 | "bubbles": true,
59 | "cancelable": true,
60 | "composed": true
61 | }]; }
62 | static get listeners() { return [{
63 | "name": "document:keydown",
64 | "method": "handleKey"
65 | }]; }
66 | static get style() { return "\n.sc-konami-listener-h {\n display: none;\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n right: 0;\n}\n\n.active.sc-konami-listener-h {\n display: block;\n}\n"; }
67 | }
68 |
69 | export { KonamiListener };
70 |
--------------------------------------------------------------------------------
/www/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Stencil Component Starter
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
20 |
21 |
22 |
84 |
85 |
86 |
92 |
93 |
94 |
98 |
99 |
100 |
117 |
118 |
119 |
129 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/www/main.css:
--------------------------------------------------------------------------------
1 | @keyframes fade {
2 | 0% {
3 | opacity: 0.5;
4 | }
5 | 100% {
6 | opacity: 0;
7 | }
8 | }
9 |
10 | :root {
11 | --color-red: #f4511e;
12 | --header-size: 200px;
13 | --footer-size: 56px;
14 | }
15 |
16 | html, body {
17 | padding: 0;
18 | margin: 0;
19 | }
20 |
21 | header {
22 | box-sizing: border-box;
23 | width: 100%;
24 | height: var(--header-size);
25 | display: flex;
26 | flex-flow: column nowrap;
27 | align-items: center;
28 | justify-content: center;
29 | text-align: center;
30 | padding: 0 12px;
31 | max-width: 570px;
32 | margin: 0 auto;
33 | }
34 | header h1 {
35 | margin: 0;
36 | font-family: 'Press Start 2P', sans-serif;
37 | line-height: 1.2;
38 | }
39 | header p {
40 | font-family: sans-serif;
41 | color: rgba(0,0,0,0.54);
42 | }
43 | header code {
44 | box-sizing: border-box;
45 | padding: 1px 4px 0 4px;
46 | line-height: 1;
47 | background-color: rgba(0, 0, 0, 0.12);
48 | border-radius: 4px;
49 | white-space: nowrap;
50 | }
51 |
52 |
53 | footer {
54 | box-sizing: border-box;
55 | height: var(--footer-size);
56 | background-color: red;
57 | width: 100%;
58 | display: flex;
59 | align-items: center;
60 | }
61 | footer .inner {
62 | box-sizing: border-box;
63 | width: 100%;
64 | display: flex;
65 | align-items: center;
66 | justify-content: space-between;
67 | max-width: 570px;
68 | margin: 0 auto;
69 | }
70 | footer .inner div {
71 | box-sizing: border-box;
72 | text-align: center;
73 | padding: 0 12px;
74 | }
75 | footer h4 {
76 | margin: 0;
77 | font-family: sans-serif;
78 | font-weight: 400;
79 | color: #FFF;
80 | }
81 | footer a {
82 | font-family: 'Press Start 2P', sans-serif;
83 | font-size: 14px;
84 | color: #FFF;
85 | }
86 |
87 | main, .prize {
88 | height: calc(calc(100vh - var(--header-size)) - var(--footer-size));
89 | width: 100%;
90 | max-width: calc(1000px / 4);
91 |
92 | display: flex;
93 | align-items: center;
94 | justify-content: center;
95 | margin: 0 auto;
96 | }
97 |
98 | main.hidden {
99 | opacity: 0;
100 | }
101 |
102 | .prize {
103 | flex-flow: column nowrap;
104 | align-items: center;
105 | justify-content: center;
106 | height: 100vh;
107 | font-size: 126px;
108 | }
109 | .prize h2 {
110 | font-size: 32px;
111 | font-family: 'Press Start 2P', sans-serif;
112 | color: var(--color-red);
113 | margin: 0;
114 | line-height: 1;
115 |
116 | }
117 |
118 | .inputs {
119 | width: 100%;
120 | flex-flow: row wrap;
121 | display: flex;
122 | align-items: center;
123 | justify-content: space-between;
124 | transform: scale(.7);
125 | }
126 |
127 | .inputs > div {
128 | --size: 100px;
129 | margin: 12px;
130 | width: var(--size);
131 | height: var(--size);
132 | }
133 |
134 | .inputs > div > svg > path.fixed {
135 | fill: rgba(0,0,0,0.32);
136 | /* stroke-width: 4px; */
137 | z-index: 1;
138 | }
139 | .inputs > div > svg > path:not(.fixed) {
140 | transition: 250ms ease-out all;
141 | fill: none;
142 | stroke-width: 2px;
143 | opacity: 0.5;
144 | z-index: -1;
145 | stroke: var(--color-red);
146 |
147 | opacity: 0;
148 | transform-origin: center center;
149 | }
150 |
151 | .inputs > div > svg {
152 | overflow: visible;
153 | }
154 |
155 | .inputs > div.active > svg > path.fixed {
156 | fill: var(--color-red);
157 | stroke: transparent;
158 | }
159 | .inputs > div.active > svg > path:not(.fixed) {
160 | display: block;
161 | opacity: 1;
162 | transform: scale(1.5);
163 | animation: 150ms 100ms fade forwards;
164 | }
165 |
166 | div.up.active > svg > path:not(.fixed) {
167 | transform: translateY(-70px);
168 | }
169 | div.down.active > svg > path:not(.fixed) {
170 | transform: translateY(70px);
171 | }
172 | div.left.active > svg > path:not(.fixed) {
173 | transform: translateX(-70px);
174 | }
175 | div.right.active > svg > path:not(.fixed) {
176 | transform: translateX(70px);
177 | }
178 | div.B.active > svg > path:not(.fixed) {
179 | transform: scale(1.75);
180 | }
181 | div.A.active > svg > path:not(.fixed) {
182 | transform: scale(1.75);
183 | }
184 | @media only screen and (min-width: 555px) {
185 | header {
186 | margin-bottom: calc(var(--header-size) / -4);
187 | }
188 | main {
189 | padding-bottom: calc(var(--header-size) / 4);
190 | }
191 | }
192 |
193 | @media only screen and (min-width: 1180px) {
194 | main {
195 | max-width: 1180px;
196 | }
197 | footer {
198 | justify-content: center;
199 | }
200 | .inputs {
201 | transform: scale(1);
202 | }
203 |
204 | .inputs > div {
205 | margin: 0;
206 | }
207 | }
208 |
--------------------------------------------------------------------------------