@operato/ocr 0.2.10 → 0.2.21

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.
Files changed (45) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/demo/index.html +699 -25
  3. package/dist/src/index.d.ts +1 -1
  4. package/dist/src/index.js +1 -1
  5. package/dist/src/index.js.map +1 -1
  6. package/dist/src/{camera-capturer.d.ts → ox-camera-capturer.d.ts} +0 -0
  7. package/dist/src/{camera-capturer.js → ox-camera-capturer.js} +19 -11
  8. package/dist/src/ox-camera-capturer.js.map +1 -0
  9. package/dist/src/{ocr-helper.d.ts → ox-ocr-helper.d.ts} +8 -4
  10. package/dist/src/{ocr-helper.js → ox-ocr-helper.js} +47 -51
  11. package/dist/src/ox-ocr-helper.js.map +1 -0
  12. package/dist/src/ox-ocr-result-image.d.ts +37 -0
  13. package/dist/src/ox-ocr-result-image.js +279 -0
  14. package/dist/src/ox-ocr-result-image.js.map +1 -0
  15. package/dist/src/type.d.ts +15 -0
  16. package/dist/src/type.js +6 -0
  17. package/dist/src/type.js.map +1 -0
  18. package/dist/src/{file-drop-helper.d.ts → utils/file-drop-helper.d.ts} +0 -0
  19. package/dist/src/{file-drop-helper.js → utils/file-drop-helper.js} +0 -0
  20. package/dist/src/utils/file-drop-helper.js.map +1 -0
  21. package/dist/src/utils/touch-to-mouse-event.d.ts +1 -0
  22. package/dist/src/utils/touch-to-mouse-event.js +34 -0
  23. package/dist/src/utils/touch-to-mouse-event.js.map +1 -0
  24. package/dist/stories/index.stories.d.ts +1 -1
  25. package/dist/stories/index.stories.js +10 -14
  26. package/dist/stories/index.stories.js.map +1 -1
  27. package/dist/test/ox-ocr-helper.test.d.ts +1 -0
  28. package/dist/test/{ocr-helper.test.js → ox-ocr-helper.test.js} +7 -7
  29. package/dist/test/ox-ocr-helper.test.js.map +1 -0
  30. package/dist/tsconfig.tsbuildinfo +1 -1
  31. package/package.json +4 -3
  32. package/src/index.ts +1 -1
  33. package/src/{camera-capturer.ts → ox-camera-capturer.ts} +18 -10
  34. package/src/{ocr-helper.ts → ox-ocr-helper.ts} +43 -49
  35. package/src/ox-ocr-result-image.ts +303 -0
  36. package/src/type.ts +13 -0
  37. package/src/{file-drop-helper.ts → utils/file-drop-helper.ts} +0 -0
  38. package/src/utils/touch-to-mouse-event.ts +39 -0
  39. package/stories/index.stories.ts +29 -37
  40. package/test/{ocr-helper.test.ts → ox-ocr-helper.test.ts} +8 -7
  41. package/dist/src/camera-capturer.js.map +0 -1
  42. package/dist/src/file-drop-helper.js.map +0 -1
  43. package/dist/src/ocr-helper.js.map +0 -1
  44. package/dist/test/ocr-helper.test.d.ts +0 -1
  45. package/dist/test/ocr-helper.test.js.map +0 -1
@@ -1,12 +1,13 @@
1
- import './camera-capturer'
2
1
  import '@material/mwc-button'
2
+ import './ox-camera-capturer'
3
+ import './ox-ocr-result-image'
3
4
 
4
- import { LitElement, css, html } from 'lit'
5
- import { customElement, property, query } from 'lit/decorators.js'
5
+ import { css, html, LitElement } from 'lit'
6
+ import { customElement, property, query, state } from 'lit/decorators.js'
6
7
 
7
- import { gql } from 'graphql-tag'
8
+ import { NOTHING_RESULT, ScanResult } from './type'
8
9
 
9
- @customElement('ocr-helper')
10
+ @customElement('ox-ocr-helper')
10
11
  export class OcrHelper extends LitElement {
11
12
  static styles = [
12
13
  css`
@@ -23,7 +24,7 @@ export class OcrHelper extends LitElement {
23
24
 
24
25
  #images {
25
26
  flex: 1;
26
- background-color: black;
27
+ background-color: var(--main-section-background-color, #f4f7fb);
27
28
  color: white;
28
29
 
29
30
  display: flex;
@@ -37,46 +38,41 @@ export class OcrHelper extends LitElement {
37
38
 
38
39
  [i] {
39
40
  min-width: 50px;
40
- background-color: black;
41
+ background-color: var(--secondary-color, #394e64);
42
+ border-right: 1px solid rgba(0, 0, 0, 0.2);
43
+ padding: var(--padding-narrow, 4px);
41
44
  text-align: center;
45
+ height: 1.4em;
42
46
  }
43
47
 
44
48
  [i][active] {
45
- background-color: red;
49
+ background-color: var(--primary-color, #22a6a7);
50
+ font-weight: bold;
46
51
  }
47
52
 
48
- [image] {
53
+ ox-ocr-result-image {
49
54
  flex: 1;
50
-
51
- display: flex;
52
- flex-direction: column;
53
- justify-content: center;
54
- }
55
-
56
- img {
57
- style=width: 100%;
58
55
  }
59
56
  `
60
57
  ]
61
58
 
62
- @property({ type: Array }) _files: any
63
- @property({ type: Number }) index: number = 0
59
+ @property({ type: Array }) result: ScanResult[] = []
60
+
61
+ @state() _files: any
62
+ @state() _index: number = 0
64
63
 
65
64
  @query('#capturer') fileUploader!: any
66
- @query('#result') result!: any
65
+ @query('#copied') copied!: HTMLElement
67
66
 
68
67
  render() {
69
68
  const files = this._files || []
70
- const index = this.index || 0
69
+ const index = this._index || 0
71
70
  const file = files[index]
72
- const image = file && URL.createObjectURL(file)
73
- if (image) {
74
- requestAnimationFrame(() => URL.revokeObjectURL(image))
75
- }
71
+ const result = this.result?.[index] || NOTHING_RESULT
76
72
 
77
73
  return html`
78
74
  <div attachment-wrap>
79
- <camera-capturer
75
+ <ox-camera-capturer
80
76
  name="scanner"
81
77
  id="capturer"
82
78
  label="Capture Images"
@@ -85,10 +81,10 @@ export class OcrHelper extends LitElement {
85
81
  ?hidden=${false}
86
82
  custom-input
87
83
  @files-change=${(e: Event) => this.fileschange(e)}
88
- ></camera-capturer>
84
+ ></ox-camera-capturer>
89
85
  </div>
90
86
  <div buttons>
91
- <mwc-button @click=${(e: Event) => this.upload()}>submit</mwc-button>
87
+ <mwc-button @click=${(e: Event) => this.submit()}>submit</mwc-button>
92
88
  <mwc-button @click=${(e: Event) => this.reset()}>reset</mwc-button>
93
89
  </div>
94
90
  <div id="images">
@@ -98,15 +94,20 @@ export class OcrHelper extends LitElement {
98
94
  const item = (e.target as HTMLElement)?.closest('[i]')
99
95
  const children = (e.currentTarget as HTMLElement)?.querySelectorAll('[i]')
100
96
  if (item) {
101
- this.index = Array.from(children).indexOf(item)
97
+ this._index = Array.from(children).indexOf(item)
102
98
  }
103
99
  }}
104
100
  >
105
101
  ${files.map((file: any, idx: number) => html`<div i ?active=${idx === index}>${idx}</div>`)}
106
102
  </div>
107
- <div image>${file ? html` <img src=${URL.createObjectURL(file)} /> ` : html``}</div>
103
+ <ox-ocr-result-image
104
+ .file=${file}
105
+ @selected=${(e: CustomEvent) => this.onSelected(e)}
106
+ .result=${result}
107
+ ></ox-ocr-result-image>
108
108
  </div>
109
- <div id="result"></div>
109
+
110
+ <div id="copied"></div>
110
111
  `
111
112
  }
112
113
 
@@ -116,25 +117,18 @@ export class OcrHelper extends LitElement {
116
117
 
117
118
  reset() {
118
119
  this.fileUploader.reset()
119
- this.result.textContent = ''
120
+ this.copied.textContent = ''
121
+ }
122
+
123
+ onSelected(e: CustomEvent) {
124
+ navigator.clipboard.writeText(e.detail)
120
125
  }
121
126
 
122
- async upload() {
123
- // const response = await client.query({
124
- // query: gql`
125
- // query ocrRequest($images: [Upload!]!) {
126
- // ocrRequest(images: $images)
127
- // }
128
- // `,
129
- // variables: {
130
- // images: this.fileUploader?.files
131
- // },
132
- // context: { hasUpload: true }
133
- // })
134
- // if (!response.errors) {
135
- // this.result.textContent = response.data.ocrRequest
136
- // } else {
137
- // this.result.textContent = 'error'
138
- // }
127
+ async submit() {
128
+ this.dispatchEvent(
129
+ new CustomEvent('attached', {
130
+ detail: this.fileUploader?.files
131
+ })
132
+ )
139
133
  }
140
134
  }
@@ -0,0 +1,303 @@
1
+ import { css, html, LitElement, PropertyValues } from 'lit'
2
+ import { customElement, property, query, state } from 'lit/decorators.js'
3
+
4
+ import { NOTHING_RESULT, ScanResult } from './type'
5
+ import { touch2mouse } from './utils/touch-to-mouse-event'
6
+
7
+ @customElement('ox-ocr-result-image')
8
+ export class OcrResultImage extends LitElement {
9
+ static styles = [
10
+ css`
11
+ :host {
12
+ display: block;
13
+ position: relative;
14
+ }
15
+
16
+ img {
17
+ display: block;
18
+ flex: 1;
19
+ border: 0;
20
+ padding: 0;
21
+ margin: 0;
22
+ max-width: 100%;
23
+ max-height: 100%;
24
+ }
25
+
26
+ [overlay] {
27
+ position: absolute;
28
+ top: 0;
29
+ left: 0;
30
+ width: 100%;
31
+ height: 100%;
32
+
33
+ border: 0;
34
+ padding: 0;
35
+ margin: 0;
36
+ opacity: 50%;
37
+ }
38
+
39
+ [notice] {
40
+ position: absolute;
41
+ bottom: 0;
42
+ background-color: var(--primary-color, #38a25b);
43
+ padding: var(--padding-default, 9px) var(--padding-wide, 15px);
44
+ opacity: 0.95;
45
+
46
+ overflow-wrap: anywhere;
47
+
48
+ color: #fff;
49
+ font-size: 1.5em;
50
+ }
51
+ `
52
+ ]
53
+
54
+ @property({ type: Array }) file: any
55
+ @property({ type: Array }) result: ScanResult = NOTHING_RESULT
56
+
57
+ @state() _ratio: { x: number; y: number } = { x: 1, y: 1 }
58
+ @state() _image!: string
59
+ @state() _resizeObserver!: ResizeObserver
60
+ @state() _trails: Array<Array<{ x: number; y: number }>> = []
61
+ @state() _tracking: boolean = false
62
+ @state() _selections: Array<number> = []
63
+ @state() _text: string = ''
64
+
65
+ @query('img') _img!: HTMLImageElement
66
+ @query('[overlay]') _overlay!: HTMLCanvasElement
67
+
68
+ render() {
69
+ return html`
70
+ <img src=${this._image} @load=${() => this.calculateRatio()} />
71
+ <canvas overlay></canvas>
72
+
73
+ ${this._text ? html` <div notice>${this._text} copied!</div> ` : html``}
74
+ `
75
+ }
76
+
77
+ renderOverlay() {
78
+ const { boundaries } = this.result
79
+
80
+ const context = this._overlay.getContext('2d')
81
+ if (!context) {
82
+ return
83
+ }
84
+
85
+ context.save()
86
+
87
+ context.clearRect(0, 0, this._overlay.width, this._overlay.height)
88
+
89
+ context.lineWidth = 5
90
+ context.strokeStyle = 'red'
91
+ context.fillStyle = 'red'
92
+ context.lineJoin = 'round'
93
+ context.lineCap = 'round'
94
+
95
+ this._image &&
96
+ boundaries
97
+ .map((bounds): Array<{ x: number; y: number }> => {
98
+ return bounds.map(bound => {
99
+ return {
100
+ x: bound.x, //* this._ratio.x,
101
+ y: bound.y // * this._ratio.y
102
+ }
103
+ })
104
+ })
105
+ .forEach((bounds, idx) => {
106
+ context.beginPath()
107
+ context.moveTo(bounds[0].x, bounds[0].y)
108
+ context.lineTo(bounds[1].x, bounds[1].y)
109
+ context.lineTo(bounds[2].x, bounds[2].y)
110
+ context.lineTo(bounds[3].x, bounds[3].y)
111
+ context.closePath()
112
+
113
+ if (this._selections.includes(idx)) {
114
+ context.fill()
115
+ }
116
+ context.stroke()
117
+ })
118
+
119
+ /* draw trails */
120
+ if (this._trails && this._trails.length > 0) {
121
+ context.lineWidth = 10
122
+ context.strokeStyle = 'blue'
123
+
124
+ context.beginPath()
125
+
126
+ this._trails.forEach(trail => {
127
+ if (trail && trail.length > 0) {
128
+ const { x, y } = trail[0]
129
+ context.moveTo(x, y)
130
+
131
+ trail.slice(1).forEach(point => {
132
+ const { x, y } = point
133
+ context.lineTo(x, y)
134
+ })
135
+ }
136
+ })
137
+
138
+ context.stroke()
139
+ }
140
+
141
+ context.restore()
142
+ }
143
+
144
+ async calculateRatio() {
145
+ const { naturalWidth, naturalHeight, offsetWidth, offsetHeight } = this._img
146
+ const { offsetWidth: overlayWidth, offsetHeight: overlayHeight } = this._overlay
147
+
148
+ if (!naturalWidth || !naturalHeight) {
149
+ return
150
+ }
151
+
152
+ this._ratio = {
153
+ x: offsetWidth / naturalWidth,
154
+ y: offsetHeight / naturalHeight
155
+ }
156
+
157
+ this._overlay.setAttribute('width', String(overlayWidth / this._ratio.x))
158
+ this._overlay.setAttribute('height', String(overlayHeight / this._ratio.y))
159
+ }
160
+
161
+ async connectedCallback() {
162
+ await super.connectedCallback()
163
+
164
+ this._resizeObserver = new ResizeObserver(entries => {
165
+ this.calculateRatio()
166
+ this.renderOverlay()
167
+ })
168
+
169
+ await this.updateComplete
170
+ this._resizeObserver.observe(this._overlay)
171
+
172
+ this.calculateRatio()
173
+
174
+ this.addEventListener('mousedown', this.onTrailStart.bind(this) as EventListener)
175
+ this.addEventListener('mouseup', this.onTrailEnd.bind(this) as EventListener)
176
+ this.addEventListener('mousemove', this.onTrail.bind(this) as EventListener)
177
+ this.addEventListener('touchstart', touch2mouse as EventListener)
178
+ this.addEventListener('touchend', touch2mouse as EventListener)
179
+ this.addEventListener('touchmove', touch2mouse as EventListener)
180
+ }
181
+
182
+ disconnectedCallback() {
183
+ super.disconnectedCallback()
184
+
185
+ this._resizeObserver.disconnect()
186
+ }
187
+
188
+ reset() {
189
+ this._selections = []
190
+ this._trails = []
191
+ this._text = ''
192
+ }
193
+
194
+ async updated(changes: PropertyValues<this>) {
195
+ if (changes.has('file') || changes.has('result')) {
196
+ this.reset()
197
+ }
198
+
199
+ if (changes.has('file')) {
200
+ this._image = this.file && URL.createObjectURL(this.file)
201
+ if (this._image) {
202
+ requestAnimationFrame(() => {
203
+ URL.revokeObjectURL(this._image)
204
+ })
205
+
206
+ await this.updateComplete
207
+ this.calculateRatio()
208
+ }
209
+ }
210
+
211
+ this.renderOverlay()
212
+ }
213
+
214
+ findIndex(x: number, y: number): number {
215
+ const { boundaries } = this.result
216
+
217
+ return boundaries.findIndex(path => {
218
+ var result = false
219
+
220
+ path.forEach((p, idx) => {
221
+ let j = (idx + path.length + 1) % path.length
222
+
223
+ let x1 = p.x
224
+ let y1 = p.y
225
+ let x2 = path[j].x
226
+ let y2 = path[j].y
227
+
228
+ if (y1 > y != y2 > y && x < ((x2 - x1) * (y - y1)) / (y2 - y1) + x1) {
229
+ result = !result
230
+ }
231
+ })
232
+
233
+ return result
234
+ })
235
+ }
236
+
237
+ updateTrails(point: { x: number; y: number }, started: boolean, attached?: boolean) {
238
+ if (started && !attached) {
239
+ this.reset()
240
+ }
241
+
242
+ if (started) {
243
+ this._trails.push([])
244
+ }
245
+
246
+ var trail = this._trails[this._trails.length - 1]
247
+ if (!trail) {
248
+ return
249
+ }
250
+
251
+ trail.push(point)
252
+
253
+ this._trails.flat().forEach(({ x, y }) => {
254
+ const idx = this.findIndex(x, y)
255
+ if (idx === -1) {
256
+ return
257
+ }
258
+
259
+ if (!this._selections.includes(idx)) {
260
+ this._selections.push(idx)
261
+ }
262
+ })
263
+
264
+ this.requestUpdate()
265
+ }
266
+
267
+ onTrailStart(e: MouseEvent) {
268
+ const { offsetX: x, offsetY: y, button, shiftKey } = e
269
+
270
+ if (button !== 0) {
271
+ return
272
+ }
273
+
274
+ this._tracking = true
275
+ this.updateTrails({ x: x / this._ratio.x, y: y / this._ratio.y }, true, shiftKey)
276
+ }
277
+
278
+ onTrailEnd(e: MouseEvent) {
279
+ if (!this._tracking) {
280
+ return
281
+ }
282
+
283
+ this._text = this._selections.map(idx => this.result.texts[idx]).join('')
284
+
285
+ this.dispatchEvent(
286
+ new CustomEvent('selected', {
287
+ detail: this._text
288
+ })
289
+ )
290
+
291
+ this._tracking = false
292
+ }
293
+
294
+ onTrail(e: MouseEvent) {
295
+ const { offsetX: x, offsetY: y } = e
296
+
297
+ if (!this._tracking) {
298
+ return
299
+ }
300
+
301
+ this.updateTrails({ x: x / this._ratio.x, y: y / this._ratio.y }, false)
302
+ }
303
+ }
package/src/type.ts ADDED
@@ -0,0 +1,13 @@
1
+ export type ScanResult = {
2
+ key_values: {
3
+ [key: string]: Array<string>
4
+ }
5
+ boundaries: Array<Array<{ x: number; y: number }>>
6
+ texts: Array<string>
7
+ }
8
+
9
+ export const NOTHING_RESULT = {
10
+ boundaries: [],
11
+ key_values: {},
12
+ texts: []
13
+ }
@@ -0,0 +1,39 @@
1
+ export function touch2mouse(e: TouchEvent) {
2
+ e.preventDefault()
3
+
4
+ if (e.touches.length > 1 || (e.type == 'touchend' && e.touches.length > 0)) {
5
+ return
6
+ }
7
+
8
+ var type = ''
9
+ const touch = e.changedTouches[0]
10
+
11
+ switch (e.type) {
12
+ case 'touchstart':
13
+ type = 'mousedown'
14
+ break
15
+ case 'touchmove':
16
+ type = 'mousemove'
17
+ break
18
+ case 'touchend':
19
+ type = 'mouseup'
20
+ break
21
+ }
22
+
23
+ const { screenX, screenY, clientX, clientY } = touch
24
+ const { ctrlKey, altKey, shiftKey, metaKey } = e
25
+
26
+ e.target?.dispatchEvent(
27
+ new MouseEvent(type, {
28
+ screenX,
29
+ screenY,
30
+ clientX,
31
+ clientY,
32
+ ctrlKey,
33
+ altKey,
34
+ shiftKey,
35
+ metaKey,
36
+ button: 0
37
+ })
38
+ )
39
+ }
@@ -1,60 +1,52 @@
1
- import { html, TemplateResult } from 'lit';
2
- import '../src/ocr-helper.js';
1
+ import '../src/ox-ocr-helper.js'
2
+
3
+ import { html, TemplateResult } from 'lit'
3
4
 
4
5
  export default {
5
6
  title: 'OcrHelper',
6
- component: 'ocr-helper',
7
+ component: 'ox-ocr-helper',
7
8
  argTypes: {
8
9
  title: { control: 'text' },
9
10
  counter: { control: 'number' },
10
- textColor: { control: 'color' },
11
- },
12
- };
11
+ textColor: { control: 'color' }
12
+ }
13
+ }
13
14
 
14
15
  interface Story<T> {
15
- (args: T): TemplateResult;
16
- args?: Partial<T>;
17
- argTypes?: Record<string, unknown>;
16
+ (args: T): TemplateResult
17
+ args?: Partial<T>
18
+ argTypes?: Record<string, unknown>
18
19
  }
19
20
 
20
21
  interface ArgTypes {
21
- title?: string;
22
- counter?: number;
23
- textColor?: string;
24
- slot?: TemplateResult;
22
+ title?: string
23
+ counter?: number
24
+ textColor?: string
25
+ slot?: TemplateResult
25
26
  }
26
27
 
27
- const Template: Story<ArgTypes> = ({
28
- title = 'Hello world',
29
- counter = 5,
30
- textColor,
31
- slot,
32
- }: ArgTypes) => html`
33
- <ocr-helper
34
- style="--ocr-helper-text-color: ${textColor || 'black'}"
35
- .title=${title}
36
- .counter=${counter}
37
- >
28
+ const Template: Story<ArgTypes> = ({ title = 'Hello world', counter = 5, textColor, slot }: ArgTypes) => html`
29
+ <ocr-helper style="--ocr-helper-text-color: ${textColor || 'black'}" .title=${title} .counter=${counter}>
38
30
  ${slot}
39
31
  </ocr-helper>
40
- `;
32
+ `
41
33
 
42
- export const Regular = Template.bind({});
34
+ export const Regular = Template.bind({})
43
35
 
44
- export const CustomTitle = Template.bind({});
36
+ export const CustomTitle = Template.bind({})
45
37
  CustomTitle.args = {
46
- title: 'My title',
47
- };
38
+ title: 'My title'
39
+ }
48
40
 
49
- export const CustomCounter = Template.bind({});
41
+ export const CustomCounter = Template.bind({})
50
42
  CustomCounter.args = {
51
- counter: 123456,
52
- };
43
+ counter: 123456
44
+ }
53
45
 
54
- export const SlottedContent = Template.bind({});
46
+ export const SlottedContent = Template.bind({})
55
47
  SlottedContent.args = {
56
- slot: html`<p>Slotted content</p>`,
57
- };
48
+ slot: html`<p>Slotted content</p>`
49
+ }
58
50
  SlottedContent.argTypes = {
59
- slot: { table: { disable: true } },
60
- };
51
+ slot: { table: { disable: true } }
52
+ }
@@ -1,33 +1,34 @@
1
- import '../src/ocr-helper.js'
1
+ import '../src/ox-ocr-helper.js'
2
+
3
+ import { html } from 'lit'
2
4
 
3
5
  import { expect, fixture } from '@open-wc/testing'
4
6
 
5
- import { OcrHelper } from '../src/ocr-helper.js'
6
- import { html } from 'lit'
7
+ import { OcrHelper } from '../src/ox-ocr-helper.js'
7
8
 
8
9
  describe('OcrHelper', () => {
9
10
  it('has a default title "Hey there" and counter 5', async () => {
10
- const el = await fixture<OcrHelper>(html`<ocr-helper></ocr-helper>`)
11
+ const el = await fixture<OcrHelper>(html`<ox-ocr-helper></ox-ocr-helper>`)
11
12
 
12
13
  expect(el.title).to.equal('Hey there')
13
14
  // expect(el.counter).to.equal(5)
14
15
  })
15
16
 
16
17
  it('increases the counter on button click', async () => {
17
- const el = await fixture<OcrHelper>(html`<ocr-helper></ocr-helper>`)
18
+ const el = await fixture<OcrHelper>(html`<ox-ocr-helper></ox-ocr-helper>`)
18
19
  el.shadowRoot!.querySelector('button')!.click()
19
20
 
20
21
  // expect(el.counter).to.equal(6)
21
22
  })
22
23
 
23
24
  it('can override the title via attribute', async () => {
24
- const el = await fixture<OcrHelper>(html`<ocr-helper title="attribute title"></ocr-helper>`)
25
+ const el = await fixture<OcrHelper>(html`<ox-ocr-helper title="attribute title"></ox-ocr-helper>`)
25
26
 
26
27
  expect(el.title).to.equal('attribute title')
27
28
  })
28
29
 
29
30
  it('passes the a11y audit', async () => {
30
- const el = await fixture<OcrHelper>(html`<ocr-helper></ocr-helper>`)
31
+ const el = await fixture<OcrHelper>(html`<ox-ocr-helper></ox-ocr-helper>`)
31
32
 
32
33
  await expect(el).shadowDom.to.be.accessible()
33
34
  })
@@ -1 +0,0 @@
1
- {"version":3,"file":"camera-capturer.js","sourceRoot":"","sources":["../../src/camera-capturer.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/mwc-icon'\n\nimport { LitElement, css, html } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\n\nimport { FileDropHelper } from './file-drop-helper'\n\n@customElement('camera-capturer')\nexport class CameraCapturer extends LitElement {\n static styles = [\n css`\n :host {\n display: flex;\n flex-direction: column;\n border-radius: var(--border-radius);\n text-align: center;\n padding-bottom: 5px !important;\n text-transform: capitalize;\n\n border: var(--file-uploader-border);\n background-color: var(--main-section-background-color);\n font: var(--file-uploader-font) !important;\n color: var(--file-uploader-color);\n }\n :host > mwc-icon {\n color: var(--file-uploader-icon-color);\n }\n\n :host(.candrop) {\n background-color: var(--file-uploader-candrop-background-color);\n }\n\n #input-file {\n display: none;\n }\n\n label {\n position: relative;\n width: auto;\n border: none;\n text-transform: capitalize;\n\n padding: var(--file-uploader-label-padding);\n border-radius: var(--file-uploader-label-border-radius);\n background-color: var(--file-uploader-label-background-color);\n color: var(--file-uploader-label-color);\n font: var(--file-uploader-label-font) !important;\n }\n\n ul {\n max-width: 500px;\n list-style: none;\n padding: 0;\n }\n li {\n text-align: left;\n\n padding: var(--file-uploader-li-padding);\n border-bottom: var(--file-uploader-li-border-bottom);\n }\n li mwc-icon {\n float: right;\n cursor: pointer;\n font: var(--file-uploader-li-icon-font);\n margin: var(--file-uploader-li-icon-margin);\n }\n li mwc-icon:hover,\n li mwc-icon:active {\n color: var(--file-uploader-li-icon-focus-color);\n }\n `\n ]\n\n @property({ type: Boolean }) multiple?: boolean\n @property({ type: String }) accept?: string\n @property({ type: String }) label?: string\n @property({ type: Array }) _files?: File[]\n\n render() {\n var files = this._files || []\n\n return html`\n <mwc-icon>camera</mwc-icon>\n <span>Capture image<br />or drop files here!</span>\n <input\n id=\"input-file\"\n type=\"file\"\n accept=${this.accept}\n ?multiple=${this.multiple}\n hidden\n capture=\"environment\"\n @change=${(e: Event) => {\n const fileInput = e.currentTarget as HTMLInputElement\n\n this._files = [...files, ...Array.from(fileInput.files as FileList)]\n\n this.dispatchEvent(\n new CustomEvent('files-change', {\n bubbles: true,\n composed: true,\n detail: {\n files: files\n }\n })\n )\n\n // fileInput.value = null\n fileInput.files = null\n }}\n />\n <label for=\"input-file\">${this.label || 'capture image'}</label>\n\n ${files?.length\n ? html` <ul>\n ${files.map(\n file => html`\n <li>\n - ${file.name}\n <mwc-icon\n @click=${(e: Event) => {\n this._files = [...files.splice(files.indexOf(file), 1)]\n this.dispatchEvent(\n new CustomEvent('files-change', {\n bubbles: true,\n composed: true,\n detail: {\n files: this._files\n }\n })\n )\n }}\n >delete_outline</mwc-icon\n >\n </li>\n `\n )}\n </ul>`\n : ''}\n `\n }\n\n firstUpdated() {\n FileDropHelper.set(this)\n\n this.addEventListener('file-drop', (e: Event) => {\n const detail = (e as CustomEvent).detail\n this._files = this.multiple ? detail : detail[0] ? [detail[0]] : []\n\n this.dispatchEvent(\n new CustomEvent('files-change', {\n bubbles: true,\n composed: true,\n detail: {\n files: this._files\n }\n })\n )\n })\n }\n\n @query('#input-file') fileInput!: HTMLInputElement\n\n get files() {\n return this._files\n }\n\n reset() {\n this.fileInput.value = ''\n this._files = []\n\n this.dispatchEvent(\n new CustomEvent('files-change', {\n bubbles: true,\n composed: true,\n detail: {\n files: this._files\n }\n })\n )\n }\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"file-drop-helper.js","sourceRoot":"","sources":["../../src/file-drop-helper.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,MAAM,OAAO,cAAc;IACzB;;;;OAIG;IACH,MAAM,CAAC,GAAG,CAAC,QAAqB,EAAE,KAAqB;QACrD,IAAI,eAAe,GAAG,CAAC,CAAQ,EAAE,EAAE;YACjC,IAAI,CAAC,KAAK,IAAI,KAAK,EAAE,EAAE;gBACrB,CAAC,CAAC,cAAc,EAAE,CAAA;gBAClB,CAAC,CAAC,eAAe,EAAE,CAAA;aACpB;QACH,CAAC,CAAA;QAED,IAAI,SAAS,GAAG,CAAC,CAAQ,EAAE,EAAE;YAC3B,IAAI,CAAC,KAAK,IAAI,KAAK,EAAE,EAAE;gBACrB,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;aAClC;QACH,CAAC,CAAA;QAED,IAAI,WAAW,GAAG,CAAC,CAAQ,EAAE,EAAE;YAC7B,IAAI,CAAC,KAAK,IAAI,KAAK,EAAE,EAAE;gBACrB,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;aACrC;QACH,CAAC,CAEA;QAAA,CAAC,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YAC9D,QAAQ,CAAC,gBAAgB,CAAC,KAAK,EAAE,eAAe,EAAE,KAAK,CAAC,CAAA;QAC1D,CAAC,CAAC,CACD;QAAA,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YACzC,QAAQ,CAAC,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,CAAA;QACpD,CAAC,CAAC,CACD;QAAA,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YACrC,QAAQ,CAAC,gBAAgB,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,CAAC,CAAA;QACtD,CAAC,CAAC,CAAA;QAEF,QAAQ,CAAC,gBAAgB,CACvB,MAAM,EACN,CAAC,CAAC,EAAE;YACF,IAAI,CAAC,KAAK,IAAI,KAAK,EAAE,EAAE;gBACrB,IAAI,EAAE,GAAG,CAAC,CAAC,YAAa,CAAA;gBACxB,IAAI,KAAK,GAAG,EAAE,CAAC,KAAK,CAAA;gBAEpB,QAAQ,CAAC,aAAa,CACpB,IAAI,WAAW,CAAC,WAAW,EAAE;oBAC3B,MAAM,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;iBAC/B,CAAC,CACH,CAAA;aACF;QACH,CAAC,EACD,KAAK,CACN,CAAA;IACH,CAAC;CACF","sourcesContent":["/**\n * judge callback function for FileDropHelper.set\n */\ntype JudgeCallback = () => boolean\n\n/**\n * file drop assist class\n */\nexport class FileDropHelper {\n /**\n * 파일 드롭 영역에서의 file drag&drop과 관련된 이벤트에 대한 처리를 설정한다.\n * @param dropArea file drag&drop target area\n * @param [judge] file drag&drop과 관련된 이벤트에 대한 judge callback function\n */\n static set(dropArea: HTMLElement, judge?: JudgeCallback) {\n var preventDefaults = (e: Event) => {\n if (!judge || judge()) {\n e.preventDefault()\n e.stopPropagation()\n }\n }\n\n var highlight = (e: Event) => {\n if (!judge || judge()) {\n dropArea.classList.add('candrop')\n }\n }\n\n var unhighlight = (e: Event) => {\n if (!judge || judge()) {\n dropArea.classList.remove('candrop')\n }\n }\n\n ;['dragenter', 'dragover', 'dragleave', 'drop'].forEach(event => {\n dropArea.addEventListener(event, preventDefaults, false)\n })\n ;['dragenter', 'dragover'].forEach(event => {\n dropArea.addEventListener(event, highlight, false)\n })\n ;['dragleave', 'drop'].forEach(event => {\n dropArea.addEventListener(event, unhighlight, false)\n })\n\n dropArea.addEventListener(\n 'drop',\n e => {\n if (!judge || judge()) {\n let dt = e.dataTransfer!\n let files = dt.files\n\n dropArea.dispatchEvent(\n new CustomEvent('file-drop', {\n detail: [...Array.from(files)]\n })\n )\n }\n },\n false\n )\n }\n}\n"]}