@knowark/componarkjs 1.13.4 → 1.14.1

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 (118) hide show
  1. package/README.md +57 -45
  2. package/lib/base/component/component.js +142 -20
  3. package/lib/base/component/component.test.js +753 -374
  4. package/lib/base/component/index.js +3 -0
  5. package/lib/base/styles/index.js +4 -1
  6. package/lib/base/utils/define.js +30 -7
  7. package/lib/base/utils/define.test.js +129 -42
  8. package/lib/base/utils/format.js +12 -6
  9. package/lib/base/utils/format.test.js +16 -16
  10. package/lib/base/utils/helpers.js +42 -9
  11. package/lib/base/utils/helpers.test.js +134 -115
  12. package/lib/base/utils/index.js +1 -0
  13. package/lib/base/utils/slots.js +3 -2
  14. package/lib/base/utils/slots.test.js +38 -38
  15. package/lib/base/utils/uuid.js +1 -1
  16. package/lib/base/utils/uuid.test.js +13 -13
  17. package/lib/components/audio/components/audio.js +36 -3
  18. package/lib/components/audio/components/audio.test.js +120 -90
  19. package/lib/components/audio/index.js +1 -0
  20. package/lib/components/audio/styles/index.js +5 -1
  21. package/lib/components/camera/components/camera.js +15 -0
  22. package/lib/components/camera/components/camera.test.js +96 -91
  23. package/lib/components/camera/index.js +1 -0
  24. package/lib/components/camera/styles/index.js +5 -1
  25. package/lib/components/capture/components/capture.js +48 -4
  26. package/lib/components/capture/components/capture.test.js +165 -97
  27. package/lib/components/capture/index.js +1 -0
  28. package/lib/components/droparea/components/droparea-preview.js +114 -19
  29. package/lib/components/droparea/components/droparea-preview.test.js +344 -80
  30. package/lib/components/droparea/components/droparea.js +82 -6
  31. package/lib/components/droparea/components/droparea.test.js +309 -299
  32. package/lib/components/droparea/index.js +1 -0
  33. package/lib/components/droparea/styles/index.js +5 -1
  34. package/lib/components/emit/components/emit.js +34 -4
  35. package/lib/components/emit/components/emit.test.js +192 -134
  36. package/lib/components/emit/index.js +1 -0
  37. package/lib/components/index.js +2 -1
  38. package/lib/components/list/components/item.js +6 -0
  39. package/lib/components/list/components/item.test.js +69 -68
  40. package/lib/components/list/components/list.js +51 -7
  41. package/lib/components/list/components/list.test.js +358 -227
  42. package/lib/components/list/index.js +1 -0
  43. package/lib/components/paginator/components/paginator.js +34 -8
  44. package/lib/components/paginator/components/paginator.test.js +146 -143
  45. package/lib/components/paginator/index.js +1 -0
  46. package/lib/components/paginator/styles/index.js +5 -1
  47. package/lib/components/spinner/components/spinner.js +10 -0
  48. package/lib/components/spinner/components/spinner.test.js +36 -41
  49. package/lib/components/spinner/index.js +1 -0
  50. package/lib/components/spinner/styles/index.js +5 -1
  51. package/lib/components/splitview/components/splitview.detail.js +10 -1
  52. package/lib/components/splitview/components/splitview.detail.test.js +75 -73
  53. package/lib/components/splitview/components/splitview.js +54 -11
  54. package/lib/components/splitview/components/splitview.master.js +37 -2
  55. package/lib/components/splitview/components/splitview.master.test.js +52 -52
  56. package/lib/components/splitview/components/splitview.test.js +135 -31
  57. package/lib/components/splitview/index.js +1 -0
  58. package/lib/components/translate/components/translate.js +65 -14
  59. package/lib/components/translate/components/translate.test.js +658 -131
  60. package/lib/components/translate/index.js +1 -0
  61. package/lib/index.js +3 -0
  62. package/package.json +4 -27
  63. package/scripts/node-test-setup.js +94 -0
  64. package/tsconfig.json +1 -1
  65. package/types/base/component/component.d.ts +43 -8
  66. package/types/base/component/component.d.ts.map +1 -1
  67. package/types/base/component/index.d.ts +4 -6
  68. package/types/base/component/index.d.ts.map +1 -1
  69. package/types/base/styles/index.d.ts +3 -2
  70. package/types/base/styles/index.d.ts.map +1 -1
  71. package/types/base/utils/define.d.ts +3 -2
  72. package/types/base/utils/define.d.ts.map +1 -1
  73. package/types/base/utils/format.d.ts +12 -6
  74. package/types/base/utils/format.d.ts.map +1 -1
  75. package/types/base/utils/helpers.d.ts +27 -7
  76. package/types/base/utils/helpers.d.ts.map +1 -1
  77. package/types/base/utils/slots.d.ts +8 -10
  78. package/types/base/utils/slots.d.ts.map +1 -1
  79. package/types/base/utils/uuid.d.ts +1 -1
  80. package/types/base/utils/uuid.d.ts.map +1 -1
  81. package/types/components/audio/components/audio.d.ts +23 -9
  82. package/types/components/audio/components/audio.d.ts.map +1 -1
  83. package/types/components/audio/styles/index.d.ts +3 -2
  84. package/types/components/audio/styles/index.d.ts.map +1 -1
  85. package/types/components/camera/components/camera.d.ts +11 -3
  86. package/types/components/camera/components/camera.d.ts.map +1 -1
  87. package/types/components/camera/styles/index.d.ts +3 -2
  88. package/types/components/camera/styles/index.d.ts.map +1 -1
  89. package/types/components/capture/components/capture.d.ts +23 -3
  90. package/types/components/capture/components/capture.d.ts.map +1 -1
  91. package/types/components/droparea/components/droparea-preview.d.ts +64 -11
  92. package/types/components/droparea/components/droparea-preview.d.ts.map +1 -1
  93. package/types/components/droparea/components/droparea.d.ts +58 -13
  94. package/types/components/droparea/components/droparea.d.ts.map +1 -1
  95. package/types/components/droparea/styles/index.d.ts +3 -2
  96. package/types/components/droparea/styles/index.d.ts.map +1 -1
  97. package/types/components/emit/components/emit.d.ts +15 -3
  98. package/types/components/emit/components/emit.d.ts.map +1 -1
  99. package/types/components/list/components/item.d.ts +8 -1
  100. package/types/components/list/components/item.d.ts.map +1 -1
  101. package/types/components/list/components/list.d.ts +23 -5
  102. package/types/components/list/components/list.d.ts.map +1 -1
  103. package/types/components/paginator/components/paginator.d.ts +32 -8
  104. package/types/components/paginator/components/paginator.d.ts.map +1 -1
  105. package/types/components/paginator/styles/index.d.ts +3 -2
  106. package/types/components/paginator/styles/index.d.ts.map +1 -1
  107. package/types/components/spinner/components/spinner.d.ts +14 -3
  108. package/types/components/spinner/components/spinner.d.ts.map +1 -1
  109. package/types/components/spinner/styles/index.d.ts +3 -2
  110. package/types/components/spinner/styles/index.d.ts.map +1 -1
  111. package/types/components/splitview/components/splitview.d.ts +22 -4
  112. package/types/components/splitview/components/splitview.d.ts.map +1 -1
  113. package/types/components/splitview/components/splitview.detail.d.ts +12 -2
  114. package/types/components/splitview/components/splitview.detail.d.ts.map +1 -1
  115. package/types/components/splitview/components/splitview.master.d.ts +12 -1
  116. package/types/components/splitview/components/splitview.master.d.ts.map +1 -1
  117. package/types/components/translate/components/translate.d.ts +44 -10
  118. package/types/components/translate/components/translate.d.ts.map +1 -1
@@ -1,8 +1,7 @@
1
- import { jest } from '@jest/globals'
1
+ import { it, mock } from 'node:test'
2
+ import assert from 'node:assert/strict'
2
3
  import './audio.js'
3
4
 
4
- jest.useFakeTimers()
5
-
6
5
  const mockGlobal = {
7
6
  navigator: {
8
7
  mediaDevices: {
@@ -25,104 +24,135 @@ const mockGlobal = {
25
24
  URL: { createObjectURL: (data) => 'mock://data/url' }
26
25
  }
27
26
 
28
- describe('Audio', () => {
29
- let container = null
30
- beforeEach(() => {
31
- container = document.createElement('div')
32
- document.body.appendChild(container)
33
- })
27
+ const mockGlobalWithRevoke = {
28
+ ...mockGlobal,
29
+ URL: {
30
+ createObjectURL: (data) => 'mock://data/url',
31
+ revokeObjectURL: mock.fn()
32
+ }
33
+ }
34
34
 
35
- afterEach(() => {
36
- container.remove()
37
- container = null
38
- })
35
+ let container = null
39
36
 
40
- it('can be instantiated', () => {
41
- container.innerHTML = `
42
- <ark-audio></ark-audio>
43
- `
44
- const audio = container.querySelector('ark-audio')
45
- audio.init()
46
- expect(audio).toBeTruthy()
37
+ const setup = () => {
38
+ document.body.innerHTML = ''
39
+ mock.timers.reset()
40
+ mock.timers.enable({
41
+ apis: ['setInterval', 'setTimeout']
47
42
  })
43
+ container = document.createElement('div')
44
+ document.body.appendChild(container)
45
+ }
48
46
 
49
- it('can start recording', async () => {
50
- container.innerHTML = `
51
- <ark-audio></ark-audio>
52
- `
53
- const audio = container.querySelector('ark-audio')
54
- audio.init({ global: mockGlobal })
55
-
56
- expect(audio.status).toEqual('idle')
57
- await audio.start(new Event('click'))
58
- expect(audio.status).toEqual('recording')
59
- expect(audio.recorder).toBeTruthy()
60
- })
47
+ it('can be instantiated', () => {
48
+ setup()
49
+ container.innerHTML = `
50
+ <ark-audio></ark-audio>
51
+ `
52
+ const audio = container.querySelector('ark-audio')
53
+ audio.init()
54
+ assert.ok(audio)
55
+ })
61
56
 
62
- it('can stop recording', async () => {
63
- container.innerHTML = `
64
- <ark-audio></ark-audio>
65
- `
66
- const audio = container.querySelector('ark-audio')
67
- audio.init({ global: mockGlobal })
68
-
69
- expect(audio.status).toEqual('idle')
70
- await audio.start(new Event('click'))
71
- expect(audio.status).toEqual('recording')
72
- audio.stop(new Event('click'))
73
- expect(audio.status).toEqual('done')
74
- })
57
+ it('can start recording', async () => {
58
+ setup()
59
+ container.innerHTML = `
60
+ <ark-audio></ark-audio>
61
+ `
62
+ const audio = container.querySelector('ark-audio')
63
+ audio.init({ global: mockGlobal })
64
+
65
+ assert.deepStrictEqual(audio.status, 'idle')
66
+ await audio.start(new Event('click'))
67
+ assert.deepStrictEqual(audio.status, 'recording')
68
+ assert.ok(audio.recorder)
69
+ })
75
70
 
76
- it('can reset recording', async () => {
77
- container.innerHTML = `
78
- <ark-audio></ark-audio>
79
- `
80
- const audio = container.querySelector('ark-audio')
81
- audio.init({ global: mockGlobal })
82
-
83
- expect(audio.status).toEqual('idle')
84
- await audio.start(new Event('click'))
85
- expect(audio.status).toEqual('recording')
86
- audio.stop(new Event('click'))
87
- expect(audio.status).toEqual('done')
88
- audio.reset(new Event('click'))
89
- expect(audio.status).toEqual('idle')
90
- expect(audio.recorder).toBeNull()
91
- })
71
+ it('can stop recording', async () => {
72
+ setup()
73
+ container.innerHTML = `
74
+ <ark-audio></ark-audio>
75
+ `
76
+ const audio = container.querySelector('ark-audio')
77
+ audio.init({ global: mockGlobal })
78
+
79
+ assert.deepStrictEqual(audio.status, 'idle')
80
+ await audio.start(new Event('click'))
81
+ assert.deepStrictEqual(audio.status, 'recording')
82
+ audio.stop(new Event('click'))
83
+ assert.deepStrictEqual(audio.status, 'done')
84
+ })
92
85
 
93
- it('counts the ellapsed time of the recording', async () => {
94
- container.innerHTML = `
95
- <ark-audio></ark-audio>
96
- `
97
- const audio = container.querySelector('ark-audio')
98
- audio.init({ global: mockGlobal })
86
+ it('can reset recording', async () => {
87
+ setup()
88
+ container.innerHTML = `
89
+ <ark-audio></ark-audio>
90
+ `
91
+ const audio = container.querySelector('ark-audio')
92
+ audio.init({ global: mockGlobal })
93
+
94
+ assert.deepStrictEqual(audio.status, 'idle')
95
+ await audio.start(new Event('click'))
96
+ assert.deepStrictEqual(audio.status, 'recording')
97
+ audio.stop(new Event('click'))
98
+ assert.deepStrictEqual(audio.status, 'done')
99
+ audio.reset(new Event('click'))
100
+ assert.deepStrictEqual(audio.status, 'idle')
101
+ assert.strictEqual(audio.recorder, null)
102
+ })
99
103
 
100
- await audio.start(new Event('click'))
101
- jest.runOnlyPendingTimers()
104
+ it('counts the ellapsed time of the recording', async () => {
105
+ setup()
106
+ container.innerHTML = `
107
+ <ark-audio></ark-audio>
108
+ `
109
+ const audio = container.querySelector('ark-audio')
110
+ audio.init({ global: mockGlobal })
111
+
112
+ await audio.start(new Event('click'))
113
+ mock.timers.tick(1000)
114
+
115
+ const timer = audio.select('.ark-audio__timer')
116
+ assert.deepStrictEqual(timer.textContent, '00:01')
117
+ mock.timers.tick(623000)
118
+ assert.deepStrictEqual(timer.textContent, '10:24')
119
+ })
102
120
 
103
- const timer = audio.select('.ark-audio__timer')
104
- expect(timer.textContent).toEqual('00:01')
105
- jest.advanceTimersByTime(623000)
106
- expect(timer.textContent).toEqual('10:24')
107
- })
121
+ it('sets the dataURL (base64) property when stopped', async () => {
122
+ setup()
123
+ container.innerHTML = `
124
+ <ark-audio></ark-audio>
125
+ `
126
+ const audio = container.querySelector('ark-audio')
127
+ audio.init({ global: mockGlobal })
108
128
 
109
- it('sets the dataURL (base64) property when stopped', async () => {
110
- container.innerHTML = `
111
- <ark-audio></ark-audio>
112
- `
113
- const audio = container.querySelector('ark-audio')
114
- audio.init({ global: mockGlobal })
129
+ await audio.start(new Event('click'))
130
+ audio.stop(new Event('click'))
115
131
 
116
- await audio.start(new Event('click'))
117
- audio.stop(new Event('click'))
132
+ audio._onData({
133
+ data: new globalThis.Blob(['Hello'], { type: 'text/plain' })
134
+ })
135
+ mock.timers.tick(1000)
118
136
 
119
- audio._onData({
120
- data: new globalThis.Blob(['Hello'], { type: 'text/plain' })
121
- })
122
- jest.runOnlyPendingTimers()
137
+ assert.deepStrictEqual(audio.dataURL, 'base64::data::result')
138
+ assert.deepStrictEqual(audio.querySelector('.ark-audio__audio').src, 'mock://data/url')
139
+ })
123
140
 
124
- expect(audio.dataURL).toEqual('base64::data::result')
125
- expect(audio.querySelector('.ark-audio__audio').src).toEqual(
126
- 'mock://data/url')
127
- })
141
+ it('revokes the previously created object URL', () => {
142
+ setup()
143
+ container.innerHTML = `
144
+ <ark-audio></ark-audio>
145
+ `
146
+ const audio = container.querySelector('ark-audio')
147
+ mockGlobalWithRevoke.URL.revokeObjectURL.mock.resetCalls()
148
+ audio.init({ global: mockGlobalWithRevoke })
149
+ audio.objectURL = 'mock://data/url'
150
+
151
+ audio._revokeObjectURL()
152
+
153
+ assert.deepStrictEqual(
154
+ mockGlobalWithRevoke.URL.revokeObjectURL.mock.calls[0].arguments[0],
155
+ 'mock://data/url'
156
+ )
157
+ assert.strictEqual(audio.objectURL, null)
128
158
  })
@@ -1 +1,2 @@
1
+ /** Audio recording component. */
1
2
  export { Audio } from './components/audio.js'
@@ -1,2 +1,6 @@
1
1
  import styles from './ark.css.js'
2
- export default styles
2
+
3
+ /** @type {string} */
4
+ const stylesText = styles
5
+
6
+ export default stylesText
@@ -2,7 +2,12 @@ import { Component } from '#base/index.js'
2
2
  import styles from '../styles/index.js'
3
3
 
4
4
  const tag = 'ark-camera'
5
+ /**
6
+ * Camera capture component.
7
+ */
5
8
  export class Camera extends Component {
9
+ /** @param {object} context
10
+ * @returns {this} */
6
11
  init (context = {}) {
7
12
  this.width = this.width || context.width || 320
8
13
  this.height = this.height || context.height || 320
@@ -47,6 +52,7 @@ export class Camera extends Component {
47
52
  return canvas.toDataURL('image/jpg')
48
53
  }
49
54
 
55
+ /** @returns {Promise<void>} */
50
56
  async start () {
51
57
  const stream = await this.global.navigator.mediaDevices.getUserMedia({
52
58
  video: {
@@ -60,18 +66,27 @@ export class Camera extends Component {
60
66
  this.video.srcObject = stream
61
67
  }
62
68
 
69
+ /** @returns {void} */
63
70
  stop () {
64
71
  // @ts-ignore
65
72
  const tracks = this.video.srcObject ? this.video.srcObject.getTracks() : []
66
73
  tracks.forEach(track => track.stop())
67
74
  }
68
75
 
76
+ /** @param {string} facingMode
77
+ * @returns {Promise<void>} */
69
78
  async setCameraOrientation (facingMode) {
70
79
  this.stop()
71
80
  this.facingMode = facingMode
72
81
  await this.start()
73
82
  }
74
83
 
84
+ /** @returns {void} */
85
+ disconnectedCallback () {
86
+ this.stop()
87
+ super.disconnectedCallback()
88
+ }
89
+
75
90
  /** @returns {HTMLVideoElement} */
76
91
  get video () {
77
92
  return this.querySelector('.ark-camera__video')
@@ -1,3 +1,5 @@
1
+ import { it } from 'node:test'
2
+ import assert from 'node:assert/strict'
1
3
  import './camera.js'
2
4
 
3
5
  const mockGlobal = () => ({
@@ -5,100 +7,103 @@ const mockGlobal = () => ({
5
7
  mediaDevices: {
6
8
  __stops: 0,
7
9
  async getUserMedia (_options) {
8
- return { getTracks: () => [{ stop: () => { this.__stops += 1 } }] }
10
+ const stream = {}
11
+ stream.getTracks = () => [{ stop: () => { this.__stops += 1 } }]
12
+ return stream
9
13
  }
10
14
  }
11
15
  }
12
16
  })
13
17
 
14
- describe('Camera', () => {
15
- let container = null
16
- beforeEach(() => {
17
- container = document.createElement('div')
18
- document.body.appendChild(container)
19
- })
20
-
21
- afterEach(() => {
22
- container.remove()
23
- container = null
24
- })
25
-
26
- it('can be instantiated', () => {
27
- container.innerHTML = `
28
- <ark-camera></ark-camera>
29
- `
30
- const camera = container.querySelector('ark-camera')
31
- expect(camera).toBeTruthy()
32
-
33
- expect(camera).toBe(camera.init())
34
- })
35
-
36
- it('sets its dimensions on canplay event', async () => {
37
- container.innerHTML = `
38
- <ark-camera width="50" height="80"></ark-camera>
39
- `
40
- const camera = container.querySelector('ark-camera')
41
- const video = camera.select('video')
42
- const canvas = camera.select('canvas')
43
-
44
- video.dispatchEvent(new Event('canplay'))
45
-
46
- expect(video.width).toEqual(50)
47
- expect(video.height).toEqual(80)
48
-
49
- expect(canvas.width).toEqual(50)
50
- expect(canvas.height).toEqual(80)
51
- })
52
-
53
- it('can start video recording', async () => {
54
- container.innerHTML = `
55
- <ark-camera></ark-camera>
56
- `
57
- const camera = container.querySelector('ark-camera')
58
- camera.init({ global: mockGlobal() })
59
-
60
- await camera.start()
61
-
62
- expect(camera.video.srcObject.getTracks()).toBeTruthy()
63
- })
64
-
65
- it('can stop video recording', async () => {
66
- container.innerHTML = `
67
- <ark-camera></ark-camera>
68
- `
69
- const camera = container.querySelector('ark-camera')
70
- const global = mockGlobal()
71
- camera.init({ global })
72
-
73
- await camera.start()
74
-
75
- camera.stop()
76
-
77
- expect(global.navigator.mediaDevices.__stops).toEqual(1)
78
- })
79
-
80
- it('can set the camera orientation', async () => {
81
- container.innerHTML = `
82
- <ark-camera></ark-camera>
83
- `
84
- const camera = container.querySelector('ark-camera')
85
- const global = mockGlobal()
86
- camera.init({ global })
87
-
88
- await camera.setCameraOrientation('environment')
89
-
90
- expect(camera.facingMode).toEqual('environment')
91
- })
92
-
93
- it('gets the dataURL (base64) of its containing canvas', async () => {
94
- container.innerHTML = `
95
- <ark-camera></ark-camera>
96
- `
97
- const camera = container.querySelector('ark-camera')
98
- camera.init({ global: mockGlobal() })
99
-
100
- const data = camera.dataURL()
101
-
102
- expect(data).toBeTruthy()
103
- })
18
+ let container = null
19
+
20
+ const setup = () => {
21
+ document.body.innerHTML = ''
22
+ container = document.createElement('div')
23
+ document.body.appendChild(container)
24
+ }
25
+
26
+ it('can be instantiated', () => {
27
+ setup()
28
+ container.innerHTML = `
29
+ <ark-camera></ark-camera>
30
+ `
31
+ const camera = container.querySelector('ark-camera')
32
+ assert.ok(camera)
33
+
34
+ assert.strictEqual(camera, camera.init())
35
+ })
36
+
37
+ it('sets its dimensions on canplay event', async () => {
38
+ setup()
39
+ container.innerHTML = `
40
+ <ark-camera width="50" height="80"></ark-camera>
41
+ `
42
+ const camera = container.querySelector('ark-camera')
43
+ const video = camera.select('video')
44
+ const canvas = camera.select('canvas')
45
+
46
+ video.dispatchEvent(new Event('canplay'))
47
+
48
+ assert.deepStrictEqual(video.getAttribute('width'), '50px')
49
+ assert.deepStrictEqual(video.getAttribute('height'), '80px')
50
+
51
+ assert.deepStrictEqual(canvas.getAttribute('width'), '50px')
52
+ assert.deepStrictEqual(canvas.getAttribute('height'), '80px')
53
+ })
54
+
55
+ it('can start video recording', async () => {
56
+ setup()
57
+ container.innerHTML = `
58
+ <ark-camera></ark-camera>
59
+ `
60
+ const camera = container.querySelector('ark-camera')
61
+ camera.init({ global: mockGlobal() })
62
+
63
+ await camera.start()
64
+
65
+ assert.ok(camera.video.srcObject.getTracks())
66
+ })
67
+
68
+ it('can stop video recording', async () => {
69
+ setup()
70
+ container.innerHTML = `
71
+ <ark-camera></ark-camera>
72
+ `
73
+ const camera = container.querySelector('ark-camera')
74
+ const global = mockGlobal()
75
+ camera.init({ global })
76
+
77
+ await camera.start()
78
+
79
+ camera.stop()
80
+
81
+ assert.deepStrictEqual(global.navigator.mediaDevices.__stops, 1)
82
+ })
83
+
84
+ it('can set the camera orientation', async () => {
85
+ setup()
86
+ container.innerHTML = `
87
+ <ark-camera></ark-camera>
88
+ `
89
+ const camera = container.querySelector('ark-camera')
90
+ const global = mockGlobal()
91
+ camera.init({ global })
92
+
93
+ await camera.setCameraOrientation('environment')
94
+
95
+ assert.deepStrictEqual(camera.facingMode, 'environment')
96
+ })
97
+
98
+ it('gets the dataURL (base64) of its containing canvas', async () => {
99
+ setup()
100
+ container.innerHTML = `
101
+ <ark-camera></ark-camera>
102
+ `
103
+ const camera = container.querySelector('ark-camera')
104
+ camera.init({ global: mockGlobal() })
105
+
106
+ const data = camera.dataURL()
107
+
108
+ assert.ok(data)
104
109
  })
@@ -1 +1,2 @@
1
+ /** Camera capture component. */
1
2
  export { Camera } from './components/camera.js'
@@ -1,2 +1,6 @@
1
1
  import styles from './ark.css.js'
2
- export default styles
2
+
3
+ /** @type {string} */
4
+ const stylesText = styles
5
+
6
+ export default stylesText
@@ -1,6 +1,7 @@
1
1
  import { Component } from "#base/index.js"
2
2
 
3
3
  const tag = 'ark-capture'
4
+ /** Template-driven renderer component. */
4
5
  export class Capture extends Component {
5
6
  constructor () {
6
7
  super()
@@ -12,9 +13,10 @@ export class Capture extends Component {
12
13
  return ['receive']
13
14
  }
14
15
 
15
- /** @param {Object} context */
16
+ /** @param {object} context
17
+ * @returns {this} */
16
18
  init (context = {}) {
17
- const data = JSON.parse(this._pop(':scope > data')?.textContent || null)
19
+ const data = this._parseJSON(this._pop(':scope > data')?.textContent)
18
20
  this.source = /** @type {object} */ (
19
21
  context.source) || data || this.source || {}
20
22
  this.template = context.template || this.template || (
@@ -23,6 +25,7 @@ export class Capture extends Component {
23
25
  return super.init()
24
26
  }
25
27
 
28
+ /** @returns {this} */
26
29
  render () {
27
30
  const outputTemplate = this._pop(':scope > template')?.innerHTML
28
31
  this.template = (
@@ -36,19 +39,60 @@ export class Capture extends Component {
36
39
  return super.render()
37
40
  }
38
41
 
42
+ /** @param {{detail:any}} event */
39
43
  handle (event) {
40
44
  const source = event.detail
41
45
  this.init({ source }).render()
42
46
  }
43
47
 
48
+ /**
49
+ * @param {string} template
50
+ * @returns {(data: any) => string}
51
+ */
44
52
  _format (template) {
45
- return (data) => Function(`return \`${template}\``).call(data)
53
+ let render = null
54
+
55
+ try {
56
+ render = Function(`return \`${template}\``)
57
+ } catch (error) {
58
+ this.emit('error', error)
59
+ }
60
+
61
+ return (data) => {
62
+ if (!render) return ''
63
+
64
+ try {
65
+ return render.call(data)
66
+ } catch (error) {
67
+ this.emit('error', error)
68
+ return ''
69
+ }
70
+ }
46
71
  }
47
72
 
73
+ /**
74
+ * @param {string} selector
75
+ * @returns {HTMLElement|null}
76
+ */
48
77
  _pop (selector) {
49
78
  const element = this.querySelector(selector)
50
79
  element?.remove()
51
- return element
80
+ return /** @type {HTMLElement|null} */ (element)
81
+ }
82
+
83
+ /**
84
+ * @param {string|null} source
85
+ * @returns {object|null}
86
+ */
87
+ _parseJSON (source) {
88
+ if (!source) return null
89
+
90
+ try {
91
+ return JSON.parse(source)
92
+ } catch (error) {
93
+ this.emit('error', error)
94
+ return null
95
+ }
52
96
  }
53
97
  }
54
98
  Component.define(tag, Capture)