@operato/input 0.2.36 → 0.2.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -42,7 +42,13 @@ export class OxInputAngle extends OxFormField {
42
42
  _onChangeValue(e: Event) {
43
43
  this.value = this._toRadian(this.input.value)
44
44
 
45
- this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }))
45
+ this.dispatchEvent(
46
+ new CustomEvent('change', {
47
+ bubbles: true,
48
+ composed: true,
49
+ detail: this.value
50
+ })
51
+ )
46
52
  }
47
53
 
48
54
  _toDegree(value: string | number | undefined) {
@@ -0,0 +1,209 @@
1
+ import '@operato/popup'
2
+
3
+ import { css, html } from 'lit'
4
+ import { customElement, property, query, state } from 'lit/decorators.js'
5
+
6
+ import { BrowserMultiFormatReader } from '@zxing/library'
7
+ import { OxFormField } from './ox-formfield'
8
+ import { OxPopup } from '@operato/popup'
9
+
10
+ const barcodeIcon = `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAYBAMAAAAfR1CMAAADKGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDUgNzkuMTYzNDk5LCAyMDE4LzA4LzEzLTE2OjQwOjIyICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOSAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpFNjM4RURDQkQ1OUExMUU5QkExMkQ4NUY3NkMxNzBFOSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpFNjM4RURDQ0Q1OUExMUU5QkExMkQ4NUY3NkMxNzBFOSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkU2MzhFREM5RDU5QTExRTlCQTEyRDg1Rjc2QzE3MEU5IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkU2MzhFRENBRDU5QTExRTlCQTEyRDg1Rjc2QzE3MEU5Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+55pr/QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAAkUExURQAAAEdwTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEus/7UCWQwAAAALdFJOU9YAg3wKBFBDSz9PnvQNDgAAAE9JREFUGNNjEEQFDKLJSnCOklkgg9QUJFn3RgZhRyS+iCGDEIp2RSBfQICRkRGIgTSQL4jCF6ScvxsZYOFT2T50/6D7Fz080MMLPTzRwhsAHVspfelur08AAAAASUVORK5CYII=`
11
+
12
+ @customElement('ox-input-barcode')
13
+ export class OxInputBarcode extends OxFormField {
14
+ static styles = [
15
+ css`
16
+ :host {
17
+ display: flex;
18
+ align-items: center;
19
+ border: none;
20
+ overflow: hidden;
21
+ background-color: #fff;
22
+
23
+ padding: var(--custom-input-barcode-field-padding) !important;
24
+ }
25
+
26
+ * {
27
+ align-self: stretch;
28
+ }
29
+
30
+ *:focus {
31
+ outline: none;
32
+ }
33
+
34
+ input {
35
+ flex: 1 !important;
36
+ border: none;
37
+ font: var(--custom-input-barcode-field-font);
38
+ width: 10px;
39
+ flex-grow: 1;
40
+ }
41
+
42
+ #scan-button {
43
+ display: block;
44
+ width: 30px;
45
+ height: 100%;
46
+ min-height: 24px;
47
+ border: none;
48
+ background-color: transparent;
49
+ background-repeat: no-repeat;
50
+ background-position: center;
51
+ background-image: var(--barcodescan-input-button-icon);
52
+ }
53
+
54
+ #scan-button[hidden] {
55
+ display: none;
56
+ }
57
+
58
+ ox-popup {
59
+ position: fixed;
60
+
61
+ width: 80vw;
62
+ height: 80vh;
63
+ transform: translate(10%, 10%);
64
+ }
65
+
66
+ video {
67
+ width: 100%;
68
+ height: 100%;
69
+ }
70
+
71
+ @media screen and (max-width: 460px) {
72
+ ox-popup {
73
+ position: fixed;
74
+ left: 0;
75
+ top: 0;
76
+ width: 100vw;
77
+ height: 100vh;
78
+ transform: translate(0%, 0%);
79
+ }
80
+ }
81
+ `
82
+ ]
83
+
84
+ @property({ type: String, attribute: true }) name?: string
85
+ @property({ type: Boolean }) scannable?: boolean
86
+ @property({ attribute: 'without-enter', type: Boolean }) withoutEnter?: boolean
87
+ @property({ type: String }) value?: string
88
+
89
+ @state() stream?: MediaStream
90
+ @state() reader?: BrowserMultiFormatReader
91
+
92
+ @query('input') input!: HTMLInputElement
93
+ @query('ox-popup') popup!: OxPopup
94
+ @query('video') video!: HTMLVideoElement
95
+
96
+ connectedCallback() {
97
+ super.connectedCallback()
98
+
99
+ this.scannable = false
100
+
101
+ if (navigator.mediaDevices) {
102
+ ;(async () => {
103
+ try {
104
+ var stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } })
105
+ if (stream) {
106
+ stream.getTracks().forEach(track => track.stop())
107
+ this.scannable = true
108
+ }
109
+ } catch (e) {
110
+ console.warn('this device not support camera for barcode scan', e)
111
+ }
112
+ })()
113
+ }
114
+ }
115
+
116
+ disconnectedCallback() {
117
+ this.stopScan()
118
+ }
119
+
120
+ render() {
121
+ this.style.setProperty('--barcodescan-input-button-icon', `url(${barcodeIcon})`)
122
+
123
+ return html`
124
+ <input
125
+ type="text"
126
+ .value=${this.value || ''}
127
+ maxlength="50"
128
+ @change=${(e: Event) => this.onChange(e)}
129
+ @keypress=${(e: Event) => this.onChange(e)}
130
+ />
131
+ <button
132
+ ?hidden=${!this.scannable}
133
+ id="scan-button"
134
+ @click=${(e: MouseEvent) => {
135
+ this.scan(e)
136
+ }}
137
+ ></button>
138
+
139
+ <ox-popup
140
+ @focusout=${() => {
141
+ this.stopScan()
142
+ }}
143
+ >
144
+ <video></video>
145
+ </ox-popup>
146
+ `
147
+ }
148
+
149
+ onChange(e: Event) {
150
+ e.stopPropagation()
151
+ this.value = (e.target as HTMLInputElement)?.value
152
+ //@ts-ignore
153
+ this.dispatchEvent(new e.constructor(e.type, e))
154
+ }
155
+
156
+ async scan(e: MouseEvent) {
157
+ try {
158
+ this.popup.open({})
159
+
160
+ /* template.video가 생성된 후에 접근하기 위해서, 한 프레임을 강제로 건너뛴다. */
161
+ await this.updateComplete
162
+
163
+ var constraints = { video: { facingMode: 'environment' } } /* backside camera first */
164
+ this.stream = await navigator.mediaDevices.getUserMedia(constraints)
165
+
166
+ this.reader = new BrowserMultiFormatReader()
167
+ if (getComputedStyle(this.popup).display !== 'none' /* popup not hidden */ && this.stream) {
168
+ var result = await this.reader.decodeOnceFromStream(this.stream, this.video)
169
+ var input = this.input
170
+ input.focus()
171
+ this.value = input.value = String(result)
172
+
173
+ if (!this.withoutEnter) {
174
+ input.dispatchEvent(new KeyboardEvent('keypress', { keyCode: 0x0d }))
175
+ input.dispatchEvent(
176
+ new CustomEvent('change', {
177
+ bubbles: true,
178
+ composed: true,
179
+ detail: this.value
180
+ })
181
+ )
182
+ }
183
+ } else {
184
+ /* popup이 비동기 진행 중에 close된 경우라면, stopScan()을 처리하지 못하게 되므로, 다시한번 clear해준다. */
185
+ this.stopScan()
186
+ }
187
+ } catch (err) {
188
+ /*
189
+ * 1. stream device 문제로 예외 발생한 경우.
190
+ * 2. 뒤로가기 등으로 popup이 종료된 경우에도 NotFoundException: Video stream has ended before any code could be detected. 이 발생한다.
191
+ */
192
+ console.warn(err)
193
+ } finally {
194
+ this.popup.close()
195
+
196
+ this.stopScan()
197
+ }
198
+ }
199
+
200
+ stopScan() {
201
+ this.video.pause()
202
+
203
+ this.stream && this.stream.getTracks().forEach(track => track.stop())
204
+ this.reader && this.reader.reset()
205
+
206
+ delete this.stream
207
+ delete this.reader
208
+ }
209
+ }
@@ -72,7 +72,13 @@ export default class OxInputStack extends OxFormField {
72
72
  _notifyChange() {
73
73
  this.value = this.stack
74
74
 
75
- this.dispatchEvent(new CustomEvent('change', { detail: this.value, bubbles: true, composed: true }))
75
+ this.dispatchEvent(
76
+ new CustomEvent('change', {
77
+ detail: this.value,
78
+ bubbles: true,
79
+ composed: true
80
+ })
81
+ )
76
82
  }
77
83
 
78
84
  _onClickAddFloor(e: Event) {
package/src/ox-select.ts CHANGED
@@ -6,11 +6,12 @@ import '@material/mwc-icon'
6
6
  import '@operato/popup'
7
7
 
8
8
  import { css, html } from 'lit'
9
- import { customElement, property, query } from 'lit/decorators.js'
9
+ import { customElement, property } from 'lit/decorators.js'
10
10
 
11
- import { OxFormField } from './ox-formfield'
12
11
  import { OxPopupList } from '@operato/popup'
13
12
 
13
+ import { OxFormField } from './ox-formfield'
14
+
14
15
  @customElement('ox-select')
15
16
  export class Select extends OxFormField {
16
17
  static styles = [