@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,154 +1,173 @@
1
+ import { it } from 'node:test';
2
+ import assert from 'node:assert/strict';
1
3
  import { listen, reflect, set, get, keys } from './helpers.js'
2
4
 
3
- describe('Helpers', () => {
4
- it('does not allow invalid attribute', () => {
5
- const element = document.createElement('div')
6
- element.innerHTML = /* html */`
7
- <button on-open="click" listen on-click="click" on-click="myMethod"
8
- on-close="click"></button>
9
- `
10
-
11
- listen(element)
12
-
13
- element.querySelector('button').click()
14
- expect(!element.hasAttribute('clicked-element')).toBeTruthy()
15
- })
16
-
17
- it('does not allow invalid attribute', () => {
18
- const element = document.createElement('div')
19
- element.innerHTML = /* html */`
20
- <button listen ark-on-click="myMethod"></button>
21
- `
5
+ it('does not allow invalid attribute', () => {
6
+ const element = document.createElement('div')
7
+ element.innerHTML = /* html */`
8
+ <button on-open="click" listen on-click="click" on-click="myMethod"
9
+ on-close="click"></button>
10
+ `
22
11
 
23
- listen(element)
12
+ listen(element)
24
13
 
25
- element.querySelector('button').click()
26
- expect(!element.hasAttribute('clicked-element')).toBeTruthy()
27
- })
14
+ element.querySelector('button').click()
15
+ assert.ok(!element.hasAttribute('clicked-element'))
16
+ })
17
+
18
+ it('does not allow invalid attribute', () => {
19
+ const element = document.createElement('div')
20
+ element.innerHTML = /* html */`
21
+ <button listen ark-on-click="myMethod"></button>
22
+ `
23
+
24
+ listen(element)
25
+
26
+ element.querySelector('button').click()
27
+ assert.ok(!element.hasAttribute('clicked-element'))
28
+ })
28
29
 
29
- it('attribute ', () => {
30
- const button = document.createElement('button')
31
- button.setAttribute('listen', '')
32
- button.setAttribute('on-abc', 'method')
33
- button.setAttribute('on-xyz', 'method')
30
+ it('attribute ', () => {
31
+ const button = document.createElement('button')
32
+ button.setAttribute('listen', '')
33
+ button.setAttribute('on-abc', 'method')
34
+ button.setAttribute('on-xyz', 'method')
34
35
 
35
- const content = document.createElement('div')
36
- content.appendChild(button)
36
+ const content = document.createElement('div')
37
+ content.appendChild(button)
37
38
 
38
- listen(content)
39
- })
39
+ listen(content)
40
+ })
40
41
 
41
- it('It does not allow to execute undeclared methods.', () => {
42
- const element = document.createElement('div')
43
- element.innerHTML = /* html */`
44
- <button listen on-click="myMethod"></button>
45
- `
42
+ it('It does not allow to execute undeclared methods.', () => {
43
+ const element = document.createElement('div')
44
+ element.innerHTML = /* html */`
45
+ <button listen on-click="myMethod"></button>
46
+ `
46
47
 
47
- listen(element)
48
+ listen(element)
48
49
 
49
- element.querySelector('button').click()
50
- expect(!element.hasAttribute('clicked-element')).toBeTruthy()
51
- })
50
+ element.querySelector('button').click()
51
+ assert.ok(!element.hasAttribute('clicked-element'))
52
+ })
52
53
 
53
- it('can listen events', () => {
54
- const element = document.createElement('div')
55
- Object.defineProperty(element, 'binding', {value: 'listen'})
56
- element.innerHTML = /* html */`
57
- <button listen on-click="myMethod"></button>
58
- `
59
- // @ts-ignore
60
- element.myMethod = function () {
61
- element.setAttribute('clicked-element', '')
62
- }
54
+ it('can listen events', () => {
55
+ const element = document.createElement('div')
56
+ Object.defineProperty(element, 'binding', {value: 'listen'})
57
+ element.innerHTML = /* html */`
58
+ <button listen on-click="myMethod"></button>
59
+ `
60
+ // @ts-ignore
61
+ element.myMethod = function () {
62
+ element.setAttribute('clicked-element', '')
63
+ }
64
+
65
+ listen(element)
66
+
67
+ element.querySelector('button').click()
68
+ assert.ok(element.hasAttribute('clicked-element'))
69
+ })
63
70
 
64
- listen(element)
71
+ it('ignores missing methods when listening', () => {
72
+ const element = document.createElement('div')
73
+ Object.defineProperty(element, 'binding', {value: 'listen'})
74
+ element.innerHTML = /* html */`
75
+ <button listen on-click="missing"></button>
76
+ `
77
+ // @ts-ignore
78
+ element.myMethod = function () {
79
+ element.setAttribute('clicked-element', '')
80
+ }
81
+
82
+ listen(element)
83
+
84
+ element.querySelector('button').click()
85
+ assert.ok(!element.hasAttribute('clicked-element'))
86
+ })
65
87
 
66
- element.querySelector('button').click()
67
- expect(element.hasAttribute('clicked-element')).toBeTruthy()
68
- })
88
+ it('can create attribute', () => {
89
+ const element = document.createElement('div')
90
+ const properties = ['myProperty']
69
91
 
70
- it('ignores missing methods when listening', () => {
71
- const element = document.createElement('div')
72
- Object.defineProperty(element, 'binding', {value: 'listen'})
73
- element.innerHTML = /* html */`
74
- <button listen on-click="missing"></button>
75
- `
76
- // @ts-ignore
77
- element.myMethod = function () {
78
- element.setAttribute('clicked-element', '')
79
- }
92
+ reflect(element, properties)
80
93
 
81
- listen(element)
94
+ // @ts-ignore
95
+ element.myProperty = 'value'
82
96
 
83
- element.querySelector('button').click()
84
- expect(element.hasAttribute('clicked-element')).toBeFalsy()
85
- })
97
+ // @ts-ignore
98
+ assert.strictEqual(element.myProperty, 'value')
99
+ assert.ok(element.hasAttribute('my-property'))
100
+ })
86
101
 
87
- it('can create attribute', () => {
88
- const element = document.createElement('div')
89
- const properties = ['myProperty']
102
+ it('cannot create attribute with property undefined', () => {
103
+ const element = document.createElement('div')
104
+ const properties = ['myProperty']
90
105
 
91
- reflect(element, properties)
106
+ reflect(element, properties)
92
107
 
93
- // @ts-ignore
94
- element.myProperty = 'value'
108
+ // @ts-ignore
109
+ element.myProperty = undefined
95
110
 
96
- // @ts-ignore
97
- expect(element.myProperty).toBe('value')
98
- expect(element.hasAttribute('my-property')).toBeTruthy()
99
- })
111
+ // @ts-ignore
112
+ assert.strictEqual(element.myProperty, '')
113
+ assert.ok(!element.hasAttribute('my-property'))
114
+ })
100
115
 
101
- it('cannot create attribute with property undefined', () => {
102
- const element = document.createElement('div')
103
- const properties = ['myProperty']
116
+ it('sets an object properties by a given path', () => {
117
+ const object = {}
104
118
 
105
- reflect(element, properties)
119
+ set(object, 'value.data', 'Hello')
106
120
 
107
- // @ts-ignore
108
- element.myProperty = undefined
121
+ assert.deepStrictEqual(object.value.data, 'Hello')
122
+ })
109
123
 
110
- // @ts-ignore
111
- expect(element.myProperty).toBe('')
112
- expect(!element.hasAttribute('my-property')).toBeTruthy()
113
- })
124
+ it('ignores set paths that cannot be parsed', () => {
125
+ const object = { value: 7 }
126
+ set(object, '', 'Hello')
127
+ assert.deepStrictEqual(object, { value: 7 })
128
+ })
114
129
 
115
- it('sets an object properties by a given path', () => {
116
- const object = {}
130
+ it('gets an object properties by a given path', () => {
131
+ const object = { state: { data: { value: 25 } }, data: 13 }
117
132
 
118
- set(object, 'value.data', 'Hello')
133
+ let value = get(object, 'data')
119
134
 
120
- expect(object.value.data).toEqual('Hello')
121
- })
135
+ assert.deepStrictEqual(value, 13)
122
136
 
123
- it('gets an object properties by a given path', () => {
124
- const object = { state: { data: { value: 25 } }, data: 13 }
137
+ value = get(object, 'state.data.value')
125
138
 
126
- let value = get(object, 'data')
139
+ assert.deepStrictEqual(value, 25)
127
140
 
128
- expect(value).toEqual(13)
141
+ const fallback = get(object, 'state.missing.value', 7)
129
142
 
130
- value = get(object, 'state.data.value')
143
+ assert.deepStrictEqual(fallback, 7)
144
+ })
131
145
 
132
- expect(value).toEqual(25)
146
+ it('gets falsy values by a given path without replacing them', () => {
147
+ const object = { state: { count: 0, enabled: false, empty: '' } }
133
148
 
134
- const fallback = get(object, 'state.missing.value', 7)
149
+ assert.deepStrictEqual(get(object, 'state.count', 7), 0)
150
+ assert.deepStrictEqual(get(object, 'state.enabled', true), false)
151
+ assert.deepStrictEqual(get(object, 'state.empty', 'fallback'), '')
152
+ })
135
153
 
136
- expect(fallback).toEqual(7)
137
- })
154
+ it('returns fallback when get path cannot be parsed', () => {
155
+ const object = { value: 7 }
156
+ assert.deepStrictEqual(get(object, '', 'fallback'), 'fallback')
157
+ })
138
158
 
139
- it('retrieves the object keys of truthy values', () => {
140
- const background = 'primary'
141
- const shadow = 'small'
142
- const color = ''
159
+ it('retrieves the object keys of truthy values', () => {
160
+ const background = 'primary'
161
+ const shadow = 'small'
162
+ const color = ''
143
163
 
144
- const classes = {
145
- [`background-${background}`]: background,
146
- [`color-${color}`]: color,
147
- [`shadow-${shadow}`]: shadow
148
- }
164
+ const classes = {
165
+ [`background-${background}`]: background,
166
+ [`color-${color}`]: color,
167
+ [`shadow-${shadow}`]: shadow
168
+ }
149
169
 
150
- const result = keys(classes)
170
+ const result = keys(classes)
151
171
 
152
- expect(result).toEqual('background-primary shadow-small')
153
- })
172
+ assert.deepStrictEqual(result, 'background-primary shadow-small')
154
173
  })
@@ -1,3 +1,4 @@
1
+ /** Utility helpers for component internals and runtime bindings. */
1
2
  export * from './define.js'
2
3
  export * from './format.js'
3
4
  export * from './helpers.js'
@@ -1,7 +1,8 @@
1
1
  /**
2
+ * Groups child nodes by slot name.
2
3
  * @param {HTMLElement} container
3
- * @return {Object<string, Array<HTMLElement>>}
4
- * */
4
+ * @returns {Record<string, HTMLElement[]>}
5
+ */
5
6
  export function getSlots (container) {
6
7
  const slots = { general: [] }
7
8
 
@@ -1,52 +1,52 @@
1
+ import { it } from 'node:test';
2
+ import assert from 'node:assert/strict';
1
3
  import { getSlots } from './slots.js'
2
4
 
3
- describe('Slots', () => {
4
- it('can be rendered without content', () => {
5
- const item = document.createElement('div')
6
- const slots = getSlots(item)
7
- expect(!slots.general.length).toBeTruthy()
8
- })
5
+ it('can be rendered without content', () => {
6
+ const item = document.createElement('div')
7
+ const slots = getSlots(item)
8
+ assert.ok(!slots.general.length)
9
+ })
9
10
 
10
- it('can be rendered with content', () => {
11
- const item = document.createElement('div')
11
+ it('can be rendered with content', () => {
12
+ const item = document.createElement('div')
12
13
 
13
- const obj = document.createElement('div')
14
+ const obj = document.createElement('div')
14
15
 
15
- item.appendChild(obj)
16
- const slots = getSlots(item)
17
- expect(slots.general.length).toBeTruthy()
18
- })
16
+ item.appendChild(obj)
17
+ const slots = getSlots(item)
18
+ assert.ok(slots.general.length)
19
+ })
19
20
 
20
- it('can be rendered with value slot', () => {
21
- const item = document.createElement('div')
21
+ it('can be rendered with value slot', () => {
22
+ const item = document.createElement('div')
22
23
 
23
- const obj = document.createElement('div')
24
- const att = document.createAttribute('slot')
25
- att.value = 'mySlot'
26
- obj.setAttributeNode(att)
24
+ const obj = document.createElement('div')
25
+ const att = document.createAttribute('slot')
26
+ att.value = 'mySlot'
27
+ obj.setAttributeNode(att)
27
28
 
28
- item.appendChild(obj)
29
- const slots = getSlots(item)
30
- expect(slots.mySlot.length).toBeTruthy()
31
- })
29
+ item.appendChild(obj)
30
+ const slots = getSlots(item)
31
+ assert.ok(slots.mySlot.length)
32
+ })
32
33
 
33
- it('can be rendered with multiple values slot', () => {
34
- const item = document.createElement('div')
34
+ it('can be rendered with multiple values slot', () => {
35
+ const item = document.createElement('div')
35
36
 
36
- const obj = document.createElement('div')
37
- const att = document.createAttribute('slot')
38
- att.value = 'mySlot'
39
- obj.setAttributeNode(att)
37
+ const obj = document.createElement('div')
38
+ const att = document.createAttribute('slot')
39
+ att.value = 'mySlot'
40
+ obj.setAttributeNode(att)
40
41
 
41
- item.appendChild(obj)
42
+ item.appendChild(obj)
42
43
 
43
- const obj2 = document.createElement('div')
44
- const att2 = document.createAttribute('slot')
45
- att2.value = 'mySlot'
46
- obj2.setAttributeNode(att2)
44
+ const obj2 = document.createElement('div')
45
+ const att2 = document.createAttribute('slot')
46
+ att2.value = 'mySlot'
47
+ obj2.setAttributeNode(att2)
47
48
 
48
- item.appendChild(obj2)
49
- const slots = getSlots(item)
50
- expect(slots.mySlot.length).toBeTruthy()
51
- })
49
+ item.appendChild(obj2)
50
+ const slots = getSlots(item)
51
+ assert.ok(slots.mySlot.length)
52
52
  })
@@ -1,4 +1,4 @@
1
- /** @returns {string} */
1
+ /** @returns {string} Generated RFC-4122-like identifier. */
2
2
  export function uuid () {
3
3
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
4
4
  /[xy]/g, function (c) {
@@ -1,19 +1,19 @@
1
+ import { it } from 'node:test';
2
+ import assert from 'node:assert/strict';
1
3
  import { uuid } from './uuid.js'
2
4
 
3
- describe('Slots', () => {
4
- it('groups separated by dashes', () => {
5
- const id = uuid()
6
- expect(id.split('-').length === 5).toBeTruthy()
7
- })
8
-
9
- it('total digits == 32', () => {
10
- const id = uuid()
5
+ it('groups separated by dashes', () => {
6
+ const id = uuid()
7
+ assert.ok(id.split('-').length === 5)
8
+ })
11
9
 
12
- let digits = ''
13
- id.split('-').forEach(element => {
14
- digits += element
15
- })
10
+ it('total digits == 32', () => {
11
+ const id = uuid()
16
12
 
17
- expect(digits.length === 32).toBeTruthy()
13
+ let digits = ''
14
+ id.split('-').forEach(element => {
15
+ digits += element
18
16
  })
17
+
18
+ assert.ok(digits.length === 32)
19
19
  })
@@ -2,12 +2,21 @@ import { Component } from '#base/index.js'
2
2
  import styles from '../styles/index.js'
3
3
 
4
4
  const tag = 'ark-audio'
5
+ /**
6
+ * Audio recorder component.
7
+ * Emits:
8
+ * - `error` with `Error` detail on capture/rendering issues.
9
+ */
5
10
  export class Audio extends Component {
11
+ /** @param {object} context
12
+ * @returns {this} */
6
13
  init (context = {}) {
14
+ /** @type {'idle'|'recording'|'done'} */
7
15
  this.status = 'idle'
8
16
  this.dataURL = null
9
17
  this.timerId = null
10
18
  this.recorder = null
19
+ this.objectURL = null
11
20
  this.global = context.global || window
12
21
 
13
22
  return super.init()
@@ -17,6 +26,7 @@ export class Audio extends Component {
17
26
  return ['status']
18
27
  }
19
28
 
29
+ /** @returns {this} */
20
30
  render () {
21
31
  if (this.status === 'done') {
22
32
  this.content = `
@@ -44,7 +54,8 @@ export class Audio extends Component {
44
54
  return super.render()
45
55
  }
46
56
 
47
- /** @param {Event} event */
57
+ /** @param {Event} event
58
+ * @returns {Promise<void>} */
48
59
  async start (event) {
49
60
  event.stopPropagation()
50
61
  this.status = 'recording'
@@ -59,7 +70,8 @@ export class Audio extends Component {
59
70
  this.recorder.start()
60
71
  }
61
72
 
62
- /** @param {Event} event */
73
+ /** @param {Event} event
74
+ * @returns {void} */
63
75
  stop (event) {
64
76
  event.stopPropagation()
65
77
  this.status = 'done'
@@ -69,7 +81,10 @@ export class Audio extends Component {
69
81
  this.render()
70
82
  }
71
83
 
84
+ /** @returns {void} */
72
85
  reset () {
86
+ clearInterval(this.timerId)
87
+ this._revokeObjectURL()
73
88
  this.status = 'idle'
74
89
  this.render()
75
90
  this.dataURL = null
@@ -77,6 +92,15 @@ export class Audio extends Component {
77
92
  this.recorder = null
78
93
  }
79
94
 
95
+ /** @returns {void} */
96
+ disconnectedCallback () {
97
+ clearInterval(this.timerId)
98
+ this.recorder?.stream?.getTracks?.().forEach(track => track.stop())
99
+ this._revokeObjectURL()
100
+ super.disconnectedCallback()
101
+ }
102
+
103
+ /** @returns {ReturnType<typeof setInterval>} Interval handle. */
80
104
  _time () {
81
105
  let count = 0
82
106
  return setInterval(() => {
@@ -95,10 +119,19 @@ export class Audio extends Component {
95
119
  _onData (event) {
96
120
  const audio = /** @type {HTMLAudioElement} */ (
97
121
  this.querySelector('.ark-audio__audio'))
98
- audio.src = this.global.URL.createObjectURL(event.data)
122
+ this._revokeObjectURL()
123
+ this.objectURL = this.global.URL.createObjectURL(event.data)
124
+ audio.src = this.objectURL
99
125
  const reader = new this.global.FileReader()
100
126
  reader.readAsDataURL(event.data)
101
127
  reader.onloadend = () => { this.dataURL = reader.result }
102
128
  }
129
+
130
+ /** @returns {void} */
131
+ _revokeObjectURL () {
132
+ if (!this.objectURL) return
133
+ this.global.URL.revokeObjectURL?.(this.objectURL)
134
+ this.objectURL = null
135
+ }
103
136
  }
104
137
  Component.define(tag, Audio, styles)