[infra-sk] Add multi-input-sk module
Behaves similarly to <input type="text"> but has string[] as its value.
Change-Id: Ia8741dc7c0ce085cc57c0189c55e1ce0b3fd9c1c
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/328898
Commit-Queue: Eric Boren <borenet@google.com>
Reviewed-by: Weston Tracey <westont@google.com>
diff --git a/infra-sk/modules/multi-input-sk/index.ts b/infra-sk/modules/multi-input-sk/index.ts
new file mode 100644
index 0000000..eb72365
--- /dev/null
+++ b/infra-sk/modules/multi-input-sk/index.ts
@@ -0,0 +1,2 @@
+import './multi-input-sk';
+import './multi-input-sk.scss';
diff --git a/infra-sk/modules/multi-input-sk/multi-input-sk-demo.html b/infra-sk/modules/multi-input-sk/multi-input-sk-demo.html
new file mode 100644
index 0000000..c500009
--- /dev/null
+++ b/infra-sk/modules/multi-input-sk/multi-input-sk-demo.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>multi-input-sk</title>
+ <meta charset="utf-8" />
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ </head>
+ <body>
+ <h1>multi-input-sk</h1>
+ <multi-input-sk></multi-input-sk>
+
+ <h2>Events</h2>
+ <pre id="events"></pre>
+ </body>
+</html>
diff --git a/infra-sk/modules/multi-input-sk/multi-input-sk-demo.ts b/infra-sk/modules/multi-input-sk/multi-input-sk-demo.ts
new file mode 100644
index 0000000..84a8916
--- /dev/null
+++ b/infra-sk/modules/multi-input-sk/multi-input-sk-demo.ts
@@ -0,0 +1,8 @@
+import './index';
+
+document.querySelector('multi-input-sk')!.addEventListener('change', (e) => {
+ console.log(e);
+ const pre = document.createElement('pre');
+ pre.innerText = JSON.stringify(e, null, ' ');
+ document.querySelector('#events')!.appendChild(pre);
+});
diff --git a/infra-sk/modules/multi-input-sk/multi-input-sk.scss b/infra-sk/modules/multi-input-sk/multi-input-sk.scss
new file mode 100644
index 0000000..d353561
--- /dev/null
+++ b/infra-sk/modules/multi-input-sk/multi-input-sk.scss
@@ -0,0 +1,42 @@
+@import '~elements-sk/themes/themes';
+
+multi-input-sk {
+ .input-container {
+ border: 1px solid black;
+ border-radius: 4px;
+ display: flex;
+ justify-content: flex-start;
+ flex-direction: row;
+ align-items: stretch;
+ padding: 4px;
+ height: 24px;
+ }
+
+ .input-item {
+ background-color: var(--surface-1dp);
+ border-radius: 4px;
+ padding: 5px;
+ margin-right: 4px;
+ user-select: none;
+ white-space: nowrap;
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+
+ a {
+ cursor: pointer;
+ text-decoration: none;
+ }
+
+ close-icon-sk svg.icon-sk-svg {
+ width: 12px;
+ height: 12px;
+ }
+ }
+
+ input {
+ border: none;
+ outline: none;
+ flex: 1;
+ }
+}
diff --git a/infra-sk/modules/multi-input-sk/multi-input-sk.ts b/infra-sk/modules/multi-input-sk/multi-input-sk.ts
new file mode 100644
index 0000000..26bf5f7
--- /dev/null
+++ b/infra-sk/modules/multi-input-sk/multi-input-sk.ts
@@ -0,0 +1,64 @@
+/**
+ * @module modules/multi-input-sk
+ * @description <h2><code>multi-input-sk</code></h2>
+ *
+ * multi-input-sk behaves similarly to <input type="text"> but its value is a
+ * string[].
+ */
+import { define } from 'elements-sk/define';
+import { html } from 'lit-html';
+import { ElementSk } from '../../../infra-sk/modules/ElementSk';
+import { $$ } from 'common-sk/modules/dom';
+import 'elements-sk/icon/close-icon-sk';
+
+export class MultiInputSk extends ElementSk {
+ private static template = (ele: MultiInputSk) => html`
+ <div class="input-container">
+ ${ele._values.map(
+ (value: string, index: number) => html`
+ <div class="input-item">
+ ${value}
+ <a
+ @click=${() => {
+ ele._values.splice(index, 1);
+ ele._render();
+ ele.dispatchEvent(new Event('change', { bubbles: true }));
+ }}
+ >
+ <close-icon-sk></close-icon-sk>
+ </a>
+ </div>
+ `
+ )}
+ <input type="text" @change=${(ev: Event) => {
+ ev.stopPropagation();
+ const inp = $$<HTMLInputElement>('input', ele)!;
+ ele._values.push(inp.value);
+ inp.value = '';
+ ele._render();
+ ele.dispatchEvent(new Event('change', { bubbles: true }));
+ }}></input>
+ </div>
+ `;
+
+ private _values: string[] = [];
+
+ get values(): string[] {
+ return this._values.slice();
+ }
+ set values(values: string[]) {
+ this._values = values.slice();
+ this._render();
+ }
+
+ constructor() {
+ super(MultiInputSk.template);
+ }
+
+ connectedCallback() {
+ super.connectedCallback();
+ this._render();
+ }
+}
+
+define('multi-input-sk', MultiInputSk);
diff --git a/infra-sk/modules/multi-input-sk/multi-input-sk_puppeteer_test.ts b/infra-sk/modules/multi-input-sk/multi-input-sk_puppeteer_test.ts
new file mode 100644
index 0000000..65a0012
--- /dev/null
+++ b/infra-sk/modules/multi-input-sk/multi-input-sk_puppeteer_test.ts
@@ -0,0 +1,38 @@
+import * as path from 'path';
+import { expect } from 'chai';
+import {
+ setUpPuppeteerAndDemoPageServer,
+ takeScreenshot,
+} from '../../../puppeteer-tests/util';
+
+describe('multi-input-sk', () => {
+ const testBed = setUpPuppeteerAndDemoPageServer(
+ path.join(__dirname, '..', '..', 'webpack.config.ts')
+ );
+
+ beforeEach(async () => {
+ await testBed.page.goto(`${testBed.baseUrl}/multi-input-sk.html`);
+ await testBed.page.setViewport({ width: 400, height: 400 });
+ });
+
+ it('should render the demo page (smoke test)', async () => {
+ expect(await testBed.page.$$('multi-input-sk')).to.have.length(1);
+ });
+
+ describe('screenshots', () => {
+ it('shows the default view', async () => {
+ await takeScreenshot(testBed.page, 'infra-sk', 'multi-input-sk');
+ });
+ it('type to add values', async () => {
+ await testBed.page.type('input', 'blahblah');
+ await takeScreenshot(testBed.page, 'infra-sk', 'multi-input-sk_typing');
+ await testBed.page.click('h2');
+ await takeScreenshot(testBed.page, 'infra-sk', 'multi-input-sk_added');
+ await testBed.page.type('input', 'another item');
+ await testBed.page.click('h2');
+ await takeScreenshot(testBed.page, 'infra-sk', 'multi-input-sk_added2');
+ await testBed.page.click('close-icon-sk');
+ await takeScreenshot(testBed.page, 'infra-sk', 'multi-input-sk_removed');
+ });
+ });
+});
diff --git a/infra-sk/modules/multi-input-sk/multi-input-sk_test.ts b/infra-sk/modules/multi-input-sk/multi-input-sk_test.ts
new file mode 100644
index 0000000..cc5cf03
--- /dev/null
+++ b/infra-sk/modules/multi-input-sk/multi-input-sk_test.ts
@@ -0,0 +1,30 @@
+import './index';
+import { MultiInputSk } from './multi-input-sk';
+
+import { setUpElementUnderTest } from '../../../infra-sk/modules/test_util';
+import { expect } from 'chai';
+import { $ } from 'common-sk/modules/dom';
+
+describe('multi-input-sk', () => {
+ const newInstance = setUpElementUnderTest<MultiInputSk>('multi-input-sk');
+
+ let ele: MultiInputSk;
+ beforeEach(() => {
+ ele = newInstance();
+ });
+
+ describe('input behavior', () => {
+ it('gets and sets values', () => {
+ expect(ele.values.length).to.equal(0);
+ expect($('.input-item', ele).length).to.equal(0);
+ ele.values = ['abc', '123'];
+ expect(ele.values.length).to.equal(2);
+ expect(ele.values[0]).to.equal('abc');
+ expect(ele.values[1]).to.equal('123');
+ const inputItems = $<HTMLDivElement>('.input-item', ele);
+ expect(inputItems.length).to.equal(2);
+ expect(inputItems[0].innerText).to.equal('abc ');
+ expect(inputItems[1].innerText).to.equal('123 ');
+ });
+ });
+});