@knowark/componarkjs 1.14.0 → 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.
- package/README.md +57 -45
- package/lib/base/component/component.js +127 -21
- package/lib/base/component/component.test.js +296 -3
- package/lib/base/component/index.js +3 -0
- package/lib/base/styles/index.js +4 -1
- package/lib/base/utils/define.js +2 -1
- package/lib/base/utils/format.js +12 -6
- package/lib/base/utils/helpers.js +31 -5
- package/lib/base/utils/index.js +1 -0
- package/lib/base/utils/slots.js +3 -2
- package/lib/base/utils/uuid.js +1 -1
- package/lib/components/audio/components/audio.js +17 -2
- package/lib/components/audio/index.js +1 -0
- package/lib/components/audio/styles/index.js +5 -1
- package/lib/components/camera/components/camera.js +10 -0
- package/lib/components/camera/index.js +1 -0
- package/lib/components/camera/styles/index.js +5 -1
- package/lib/components/capture/components/capture.js +18 -2
- package/lib/components/capture/index.js +1 -0
- package/lib/components/droparea/components/droparea-preview.js +58 -13
- package/lib/components/droparea/components/droparea-preview.test.js +82 -0
- package/lib/components/droparea/components/droparea.js +41 -2
- package/lib/components/droparea/index.js +1 -0
- package/lib/components/droparea/styles/index.js +5 -1
- package/lib/components/emit/components/emit.js +11 -1
- package/lib/components/emit/index.js +1 -0
- package/lib/components/index.js +2 -1
- package/lib/components/list/components/item.js +6 -0
- package/lib/components/list/components/list.js +18 -4
- package/lib/components/list/index.js +1 -0
- package/lib/components/paginator/components/paginator.js +34 -8
- package/lib/components/paginator/index.js +1 -0
- package/lib/components/paginator/styles/index.js +5 -1
- package/lib/components/spinner/components/spinner.js +10 -0
- package/lib/components/spinner/index.js +1 -0
- package/lib/components/spinner/styles/index.js +5 -1
- package/lib/components/splitview/components/splitview.detail.js +10 -1
- package/lib/components/splitview/components/splitview.js +18 -3
- package/lib/components/splitview/components/splitview.master.js +10 -0
- package/lib/components/splitview/index.js +1 -0
- package/lib/components/translate/components/translate.js +42 -11
- package/lib/components/translate/components/translate.test.js +169 -1
- package/lib/components/translate/index.js +1 -0
- package/lib/index.js +3 -0
- package/package.json +2 -1
- package/tsconfig.json +1 -1
- package/types/base/component/component.d.ts +43 -8
- package/types/base/component/component.d.ts.map +1 -1
- package/types/base/component/index.d.ts +4 -6
- package/types/base/component/index.d.ts.map +1 -1
- package/types/base/styles/index.d.ts +3 -2
- package/types/base/styles/index.d.ts.map +1 -1
- package/types/base/utils/define.d.ts +3 -2
- package/types/base/utils/define.d.ts.map +1 -1
- package/types/base/utils/format.d.ts +12 -6
- package/types/base/utils/format.d.ts.map +1 -1
- package/types/base/utils/helpers.d.ts +27 -7
- package/types/base/utils/helpers.d.ts.map +1 -1
- package/types/base/utils/slots.d.ts +8 -10
- package/types/base/utils/slots.d.ts.map +1 -1
- package/types/base/utils/uuid.d.ts +1 -1
- package/types/base/utils/uuid.d.ts.map +1 -1
- package/types/components/audio/components/audio.d.ts +23 -9
- package/types/components/audio/components/audio.d.ts.map +1 -1
- package/types/components/audio/styles/index.d.ts +3 -2
- package/types/components/audio/styles/index.d.ts.map +1 -1
- package/types/components/camera/components/camera.d.ts +11 -3
- package/types/components/camera/components/camera.d.ts.map +1 -1
- package/types/components/camera/styles/index.d.ts +3 -2
- package/types/components/camera/styles/index.d.ts.map +1 -1
- package/types/components/capture/components/capture.d.ts +23 -3
- package/types/components/capture/components/capture.d.ts.map +1 -1
- package/types/components/droparea/components/droparea-preview.d.ts +64 -11
- package/types/components/droparea/components/droparea-preview.d.ts.map +1 -1
- package/types/components/droparea/components/droparea.d.ts +58 -13
- package/types/components/droparea/components/droparea.d.ts.map +1 -1
- package/types/components/droparea/styles/index.d.ts +3 -2
- package/types/components/droparea/styles/index.d.ts.map +1 -1
- package/types/components/emit/components/emit.d.ts +15 -3
- package/types/components/emit/components/emit.d.ts.map +1 -1
- package/types/components/list/components/item.d.ts +8 -1
- package/types/components/list/components/item.d.ts.map +1 -1
- package/types/components/list/components/list.d.ts +23 -5
- package/types/components/list/components/list.d.ts.map +1 -1
- package/types/components/paginator/components/paginator.d.ts +32 -8
- package/types/components/paginator/components/paginator.d.ts.map +1 -1
- package/types/components/paginator/styles/index.d.ts +3 -2
- package/types/components/paginator/styles/index.d.ts.map +1 -1
- package/types/components/spinner/components/spinner.d.ts +14 -3
- package/types/components/spinner/components/spinner.d.ts.map +1 -1
- package/types/components/spinner/styles/index.d.ts +3 -2
- package/types/components/spinner/styles/index.d.ts.map +1 -1
- package/types/components/splitview/components/splitview.d.ts +22 -4
- package/types/components/splitview/components/splitview.d.ts.map +1 -1
- package/types/components/splitview/components/splitview.detail.d.ts +12 -2
- package/types/components/splitview/components/splitview.detail.d.ts.map +1 -1
- package/types/components/splitview/components/splitview.master.d.ts +12 -1
- package/types/components/splitview/components/splitview.master.d.ts.map +1 -1
- package/types/components/translate/components/translate.d.ts +44 -10
- package/types/components/translate/components/translate.d.ts.map +1 -1
package/lib/base/styles/index.js
CHANGED
package/lib/base/utils/define.js
CHANGED
|
@@ -5,7 +5,8 @@ const fallbackRegistry = new Map()
|
|
|
5
5
|
|
|
6
6
|
/** @param {string} tag
|
|
7
7
|
* @param {CustomElementConstructor} element
|
|
8
|
-
* @param {string} styles
|
|
8
|
+
* @param {string} [styles]
|
|
9
|
+
* @returns {CSSStyleSheet|HTMLStyleElement|undefined} */
|
|
9
10
|
export function define (tag, element, styles = '') {
|
|
10
11
|
const definedElement = globalThis.customElements.get(tag)
|
|
11
12
|
if (!definedElement) {
|
package/lib/base/utils/format.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Convert Strings from camelCase to kebab-case
|
|
3
|
-
* @param {string} input
|
|
2
|
+
* Convert Strings from camelCase to kebab-case.
|
|
3
|
+
* @param {string} input
|
|
4
|
+
* @returns {string}
|
|
5
|
+
*/
|
|
4
6
|
export function camelToKebab (input) {
|
|
5
7
|
return input.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()
|
|
6
8
|
}
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
|
-
* Convert Strings from kebab-case to camelCase
|
|
10
|
-
* @param {string} input
|
|
11
|
+
* Convert Strings from kebab-case to camelCase.
|
|
12
|
+
* @param {string} input
|
|
13
|
+
* @returns {string}
|
|
14
|
+
*/
|
|
11
15
|
export function kebabToCamel (input) {
|
|
12
16
|
return input.replace(/-([a-z])/g, function (g) {
|
|
13
17
|
return g[1].toUpperCase()
|
|
@@ -15,8 +19,10 @@ export function kebabToCamel (input) {
|
|
|
15
19
|
}
|
|
16
20
|
|
|
17
21
|
/**
|
|
18
|
-
* Convert Strings from snake to camelCase
|
|
19
|
-
* @param {string} input
|
|
22
|
+
* Convert Strings from snake to camelCase.
|
|
23
|
+
* @param {string} input
|
|
24
|
+
* @returns {string}
|
|
25
|
+
*/
|
|
20
26
|
export function snakeToCamel (input) {
|
|
21
27
|
return input.replace(/_([a-z])/g, function (g) {
|
|
22
28
|
return g[1].toUpperCase()
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @import { Component } from '../component/component.js'
|
|
3
|
+
*/
|
|
1
4
|
import { camelToKebab } from './format.js'
|
|
2
5
|
|
|
3
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Binds declarative event handlers in descendant nodes for a component.
|
|
8
|
+
* @param {Component|HTMLElement} self
|
|
9
|
+
* @returns {void}
|
|
10
|
+
*/
|
|
4
11
|
export function listen (self) {
|
|
5
12
|
/** @ts-ignore */
|
|
6
13
|
const binding = self.binding
|
|
@@ -62,7 +69,11 @@ export function listen (self) {
|
|
|
62
69
|
}
|
|
63
70
|
}
|
|
64
71
|
|
|
65
|
-
/**
|
|
72
|
+
/**
|
|
73
|
+
* Resolve dependencies from descendants using `resolve` events.
|
|
74
|
+
* @param {Component|HTMLElement} self
|
|
75
|
+
* @returns {void}
|
|
76
|
+
*/
|
|
66
77
|
function provide (self) {
|
|
67
78
|
/** @ts-ignore */
|
|
68
79
|
if (!self.provide) return
|
|
@@ -102,7 +113,13 @@ function transform (pipe, value) {
|
|
|
102
113
|
}[pipe?.toLowerCase() || 'string'](value)
|
|
103
114
|
}
|
|
104
115
|
|
|
105
|
-
/**
|
|
116
|
+
/**
|
|
117
|
+
* Sets a nested property value by object path.
|
|
118
|
+
* @param {unknown} object
|
|
119
|
+
* @param {string} path
|
|
120
|
+
* @param {any} value
|
|
121
|
+
* @returns {void}
|
|
122
|
+
*/
|
|
106
123
|
export function set (object, path, value) {
|
|
107
124
|
const pathArray = path.match(/([^[.\]])+/g)
|
|
108
125
|
if (!pathArray?.length) return
|
|
@@ -114,7 +131,13 @@ export function set (object, path, value) {
|
|
|
114
131
|
}, object)
|
|
115
132
|
}
|
|
116
133
|
|
|
117
|
-
/**
|
|
134
|
+
/**
|
|
135
|
+
* Reads a nested property value by path.
|
|
136
|
+
* @param {unknown} object
|
|
137
|
+
* @param {string} path
|
|
138
|
+
* @param {any} fallback
|
|
139
|
+
* @returns {any}
|
|
140
|
+
*/
|
|
118
141
|
export function get (object, path, fallback) {
|
|
119
142
|
const pathArray = path.match(/([^[.\]])+/g)
|
|
120
143
|
if (!pathArray?.length) return fallback
|
|
@@ -125,7 +148,10 @@ export function get (object, path, fallback) {
|
|
|
125
148
|
return value === undefined ? fallback : value
|
|
126
149
|
}
|
|
127
150
|
|
|
128
|
-
/** @param {object} object
|
|
151
|
+
/** @param {object} object
|
|
152
|
+
* @return {string}
|
|
153
|
+
* @description Returns truthy CSS class names from object values.
|
|
154
|
+
*/
|
|
129
155
|
export function keys (object) {
|
|
130
156
|
return Object.keys(object).filter(
|
|
131
157
|
key => Boolean(object[key])).join(' ')
|
package/lib/base/utils/index.js
CHANGED
package/lib/base/utils/slots.js
CHANGED
package/lib/base/utils/uuid.js
CHANGED
|
@@ -2,8 +2,16 @@ 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
|
|
@@ -18,6 +26,7 @@ export class Audio extends Component {
|
|
|
18
26
|
return ['status']
|
|
19
27
|
}
|
|
20
28
|
|
|
29
|
+
/** @returns {this} */
|
|
21
30
|
render () {
|
|
22
31
|
if (this.status === 'done') {
|
|
23
32
|
this.content = `
|
|
@@ -45,7 +54,8 @@ export class Audio extends Component {
|
|
|
45
54
|
return super.render()
|
|
46
55
|
}
|
|
47
56
|
|
|
48
|
-
/** @param {Event} event
|
|
57
|
+
/** @param {Event} event
|
|
58
|
+
* @returns {Promise<void>} */
|
|
49
59
|
async start (event) {
|
|
50
60
|
event.stopPropagation()
|
|
51
61
|
this.status = 'recording'
|
|
@@ -60,7 +70,8 @@ export class Audio extends Component {
|
|
|
60
70
|
this.recorder.start()
|
|
61
71
|
}
|
|
62
72
|
|
|
63
|
-
/** @param {Event} event
|
|
73
|
+
/** @param {Event} event
|
|
74
|
+
* @returns {void} */
|
|
64
75
|
stop (event) {
|
|
65
76
|
event.stopPropagation()
|
|
66
77
|
this.status = 'done'
|
|
@@ -70,6 +81,7 @@ export class Audio extends Component {
|
|
|
70
81
|
this.render()
|
|
71
82
|
}
|
|
72
83
|
|
|
84
|
+
/** @returns {void} */
|
|
73
85
|
reset () {
|
|
74
86
|
clearInterval(this.timerId)
|
|
75
87
|
this._revokeObjectURL()
|
|
@@ -80,6 +92,7 @@ export class Audio extends Component {
|
|
|
80
92
|
this.recorder = null
|
|
81
93
|
}
|
|
82
94
|
|
|
95
|
+
/** @returns {void} */
|
|
83
96
|
disconnectedCallback () {
|
|
84
97
|
clearInterval(this.timerId)
|
|
85
98
|
this.recorder?.stream?.getTracks?.().forEach(track => track.stop())
|
|
@@ -87,6 +100,7 @@ export class Audio extends Component {
|
|
|
87
100
|
super.disconnectedCallback()
|
|
88
101
|
}
|
|
89
102
|
|
|
103
|
+
/** @returns {ReturnType<typeof setInterval>} Interval handle. */
|
|
90
104
|
_time () {
|
|
91
105
|
let count = 0
|
|
92
106
|
return setInterval(() => {
|
|
@@ -113,6 +127,7 @@ export class Audio extends Component {
|
|
|
113
127
|
reader.onloadend = () => { this.dataURL = reader.result }
|
|
114
128
|
}
|
|
115
129
|
|
|
130
|
+
/** @returns {void} */
|
|
116
131
|
_revokeObjectURL () {
|
|
117
132
|
if (!this.objectURL) return
|
|
118
133
|
this.global.URL.revokeObjectURL?.(this.objectURL)
|
|
@@ -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,22 @@ 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} */
|
|
75
85
|
disconnectedCallback () {
|
|
76
86
|
this.stop()
|
|
77
87
|
super.disconnectedCallback()
|
|
@@ -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,7 +13,8 @@ export class Capture extends Component {
|
|
|
12
13
|
return ['receive']
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
/** @param {
|
|
16
|
+
/** @param {object} context
|
|
17
|
+
* @returns {this} */
|
|
16
18
|
init (context = {}) {
|
|
17
19
|
const data = this._parseJSON(this._pop(':scope > data')?.textContent)
|
|
18
20
|
this.source = /** @type {object} */ (
|
|
@@ -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,11 +39,16 @@ 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
53
|
let render = null
|
|
46
54
|
|
|
@@ -62,12 +70,20 @@ export class Capture extends Component {
|
|
|
62
70
|
}
|
|
63
71
|
}
|
|
64
72
|
|
|
73
|
+
/**
|
|
74
|
+
* @param {string} selector
|
|
75
|
+
* @returns {HTMLElement|null}
|
|
76
|
+
*/
|
|
65
77
|
_pop (selector) {
|
|
66
78
|
const element = this.querySelector(selector)
|
|
67
79
|
element?.remove()
|
|
68
|
-
return element
|
|
80
|
+
return /** @type {HTMLElement|null} */ (element)
|
|
69
81
|
}
|
|
70
82
|
|
|
83
|
+
/**
|
|
84
|
+
* @param {string|null} source
|
|
85
|
+
* @returns {object|null}
|
|
86
|
+
*/
|
|
71
87
|
_parseJSON (source) {
|
|
72
88
|
if (!source) return null
|
|
73
89
|
|
|
@@ -4,6 +4,9 @@ import './droparea.js'
|
|
|
4
4
|
/** @import {Droparea} from './droparea.js' */
|
|
5
5
|
|
|
6
6
|
const tag = 'ark-droparea-preview'
|
|
7
|
+
/**
|
|
8
|
+
* Renders file previews and drag-sort ordering.
|
|
9
|
+
*/
|
|
7
10
|
|
|
8
11
|
export class DropareaPreview extends Component {
|
|
9
12
|
constructor () {
|
|
@@ -12,15 +15,19 @@ export class DropareaPreview extends Component {
|
|
|
12
15
|
this._onDragEnd = this.handleDrop.bind(this)
|
|
13
16
|
}
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
/** @param {object} context
|
|
19
|
+
* @returns {this} */
|
|
20
|
+
init (context = {}) {
|
|
16
21
|
return super.init()
|
|
17
22
|
}
|
|
18
23
|
|
|
24
|
+
/** @returns {void} */
|
|
19
25
|
disconnectedCallback () {
|
|
20
26
|
this.revokeAllFiles()
|
|
21
27
|
super.disconnectedCallback()
|
|
22
28
|
}
|
|
23
29
|
|
|
30
|
+
/** @returns {this} */
|
|
24
31
|
render () {
|
|
25
32
|
this.content = /* html */ `
|
|
26
33
|
<ul data-preview-list class="ark-droparea-preview__list drag-sort-enable"></ul>
|
|
@@ -28,6 +35,10 @@ export class DropareaPreview extends Component {
|
|
|
28
35
|
return super.render()
|
|
29
36
|
}
|
|
30
37
|
|
|
38
|
+
/**
|
|
39
|
+
* @param {File} file
|
|
40
|
+
* @returns {void}
|
|
41
|
+
*/
|
|
31
42
|
previewFile (file) {
|
|
32
43
|
const blobUrl = this.getObjectURL(file)
|
|
33
44
|
const fileType = file.type.split('/')[0]
|
|
@@ -58,6 +69,7 @@ export class DropareaPreview extends Component {
|
|
|
58
69
|
}
|
|
59
70
|
}
|
|
60
71
|
|
|
72
|
+
/** @returns {void} */
|
|
61
73
|
toggleVisibility () {
|
|
62
74
|
const previewZone = this.select('[data-preview-list]')
|
|
63
75
|
this.files.length !== 0
|
|
@@ -67,6 +79,8 @@ export class DropareaPreview extends Component {
|
|
|
67
79
|
|
|
68
80
|
/* DragSort Functionality */
|
|
69
81
|
|
|
82
|
+
/** @param {string} listClass
|
|
83
|
+
* @returns {void} */
|
|
70
84
|
enableDragSort (listClass) {
|
|
71
85
|
const sortableLists = this.getElementsByClassName(listClass)
|
|
72
86
|
Array.prototype.map.call(sortableLists, (list) => {
|
|
@@ -74,56 +88,69 @@ export class DropareaPreview extends Component {
|
|
|
74
88
|
})
|
|
75
89
|
}
|
|
76
90
|
|
|
91
|
+
/** @param {HTMLUListElement} list
|
|
92
|
+
* @returns {void} */
|
|
77
93
|
enableDragList (list) {
|
|
78
94
|
Array.prototype.map.call(list.children, (item) => {
|
|
79
95
|
this.enableDragItem(item)
|
|
80
96
|
})
|
|
81
97
|
}
|
|
82
98
|
|
|
99
|
+
/** @param {HTMLElement} item
|
|
100
|
+
* @returns {void} */
|
|
83
101
|
enableDragItem (item) {
|
|
84
102
|
if (item.hasAttribute('data-drag-enabled')) return
|
|
85
103
|
|
|
86
104
|
item.setAttribute('data-drag-enabled', '')
|
|
87
|
-
item.setAttribute('draggable', true)
|
|
105
|
+
item.setAttribute('draggable', 'true')
|
|
88
106
|
item.addEventListener('drag', this.handleDrag.bind(this, item))
|
|
89
107
|
item.addEventListener('dragend', this._onDragEnd, false)
|
|
90
108
|
}
|
|
91
109
|
|
|
92
110
|
/* istanbul ignore next */
|
|
111
|
+
/** @param {HTMLLIElement} item
|
|
112
|
+
* @param {DragEvent} event
|
|
113
|
+
* @returns {void} */
|
|
93
114
|
handleDrag (item, event) {
|
|
94
115
|
const selectedItem = item
|
|
95
|
-
const list = selectedItem.
|
|
116
|
+
const list = /** @type {HTMLElement} */ (selectedItem.parentElement)
|
|
96
117
|
const x = event.clientX
|
|
97
118
|
const y = event.clientY
|
|
98
119
|
|
|
99
120
|
selectedItem.classList.add('drag-sort-active')
|
|
100
|
-
let swapItem =
|
|
101
|
-
document.elementFromPoint(x, y)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (list === swapItem.parentNode) {
|
|
121
|
+
let swapItem = /** @type {ChildNode|null} */ (
|
|
122
|
+
document.elementFromPoint(x, y))
|
|
123
|
+
if (!swapItem) swapItem = selectedItem
|
|
124
|
+
|
|
125
|
+
if (list && swapItem && list === swapItem.parentNode) {
|
|
105
126
|
swapItem = (
|
|
106
127
|
swapItem !== selectedItem.nextSibling
|
|
107
128
|
? swapItem
|
|
108
129
|
: swapItem.nextSibling)
|
|
109
|
-
list.insertBefore(selectedItem, swapItem)
|
|
130
|
+
list.insertBefore(selectedItem, /** @type {ChildNode|null} */ (swapItem))
|
|
110
131
|
}
|
|
111
132
|
}
|
|
112
133
|
|
|
134
|
+
/** @param {DragEvent} event
|
|
135
|
+
* @returns {void} */
|
|
113
136
|
handleDrop (event) {
|
|
114
|
-
const
|
|
137
|
+
const target = /** @type {HTMLElement|null} */ (event.target)
|
|
138
|
+
if (!target) return
|
|
139
|
+
const droparea = /** @type {Droparea|null} */ (target.closest('ark-droparea'))
|
|
115
140
|
if (!droparea) return
|
|
116
141
|
|
|
117
142
|
droparea.preview.createNewFileList()
|
|
118
|
-
|
|
143
|
+
target.classList.remove('drag-sort-active')
|
|
119
144
|
droparea.preview.dispatchAlterEvent()
|
|
120
145
|
}
|
|
121
146
|
/* ---------------------------------------------------- */
|
|
122
147
|
|
|
148
|
+
/** @returns {void} */
|
|
123
149
|
dispatchAlterEvent () {
|
|
124
150
|
this.emit('alter', this.mediaList)
|
|
125
151
|
}
|
|
126
152
|
|
|
153
|
+
/** @returns {void} */
|
|
127
154
|
createNewFileList () {
|
|
128
155
|
const nodeList = this.querySelectorAll('li')
|
|
129
156
|
const newList = []
|
|
@@ -134,10 +161,16 @@ export class DropareaPreview extends Component {
|
|
|
134
161
|
this.droparea.fileList = newList
|
|
135
162
|
}
|
|
136
163
|
|
|
164
|
+
/**
|
|
165
|
+
* @param {File} file
|
|
166
|
+
* @returns {boolean}
|
|
167
|
+
*/
|
|
137
168
|
fileExists (file) {
|
|
138
169
|
return this.files.some((item) => item.name === file.name)
|
|
139
170
|
}
|
|
140
171
|
|
|
172
|
+
/** @param {File} file
|
|
173
|
+
* @returns {string} */
|
|
141
174
|
getObjectURL (file) {
|
|
142
175
|
if (this._objectUrls.has(file)) return this._objectUrls.get(file)
|
|
143
176
|
|
|
@@ -146,6 +179,8 @@ export class DropareaPreview extends Component {
|
|
|
146
179
|
return url
|
|
147
180
|
}
|
|
148
181
|
|
|
182
|
+
/** @param {File} file
|
|
183
|
+
* @returns {void} */
|
|
149
184
|
revokeFile (file) {
|
|
150
185
|
const url = this._objectUrls.get(file)
|
|
151
186
|
if (!url) return
|
|
@@ -154,6 +189,7 @@ export class DropareaPreview extends Component {
|
|
|
154
189
|
URL.revokeObjectURL?.(url)
|
|
155
190
|
}
|
|
156
191
|
|
|
192
|
+
/** @returns {void} */
|
|
157
193
|
revokeAllFiles () {
|
|
158
194
|
for (const url of this._objectUrls.values()) {
|
|
159
195
|
URL.revokeObjectURL?.(url)
|
|
@@ -161,20 +197,25 @@ export class DropareaPreview extends Component {
|
|
|
161
197
|
this._objectUrls.clear()
|
|
162
198
|
}
|
|
163
199
|
|
|
200
|
+
/** @returns {void} */
|
|
164
201
|
clearPreview () {
|
|
165
202
|
const previewZone = this.select('[data-preview-list]')
|
|
166
203
|
previewZone && (previewZone.textContent = '')
|
|
167
204
|
this.toggleVisibility()
|
|
168
205
|
}
|
|
169
206
|
|
|
207
|
+
/** @param {File} file
|
|
208
|
+
* @param {MouseEvent} event
|
|
209
|
+
* @returns {void} */
|
|
170
210
|
removeFile (file, event) {
|
|
171
|
-
const element = event.target
|
|
211
|
+
const element = /** @type {HTMLElement|null} */ (event.target)
|
|
212
|
+
if (!element) return
|
|
172
213
|
const fileIndex = this.droparea.fileList.indexOf(file)
|
|
173
214
|
if (fileIndex < 0) return
|
|
174
215
|
|
|
175
216
|
this.revokeFile(file)
|
|
176
217
|
this.droparea.fileList.splice(fileIndex, 1)
|
|
177
|
-
element.
|
|
218
|
+
element.parentElement?.remove()
|
|
178
219
|
this.selectAll('li').forEach((item, index) =>
|
|
179
220
|
item.setAttribute('index', String(index))
|
|
180
221
|
)
|
|
@@ -182,14 +223,18 @@ export class DropareaPreview extends Component {
|
|
|
182
223
|
this.dispatchAlterEvent()
|
|
183
224
|
}
|
|
184
225
|
|
|
226
|
+
/** @param {File} file
|
|
227
|
+
* @returns {number} */
|
|
185
228
|
fileIndex (file) {
|
|
186
229
|
return this.droparea.fileList.indexOf(file)
|
|
187
230
|
}
|
|
188
231
|
|
|
232
|
+
/** @returns {Droparea} */
|
|
189
233
|
get droparea () {
|
|
190
234
|
return /** @type {Droparea} */ (this.closest('ark-droparea'))
|
|
191
235
|
}
|
|
192
236
|
|
|
237
|
+
/** @returns {Array<{name:string,type:string,size:number,url:string}>} */
|
|
193
238
|
get mediaList () {
|
|
194
239
|
const mediaList = []
|
|
195
240
|
this.droparea.fileList.map((file) => {
|
|
@@ -287,3 +287,85 @@ it('does nothing when revoking a file without an object URL', () => {
|
|
|
287
287
|
preview.revokeFile(file)
|
|
288
288
|
})
|
|
289
289
|
})
|
|
290
|
+
|
|
291
|
+
it('renders a text preview in single mode and clears previous preview items', () => {
|
|
292
|
+
setup()
|
|
293
|
+
container.innerHTML = /* html */ `
|
|
294
|
+
<ark-droparea single></ark-droparea>
|
|
295
|
+
`
|
|
296
|
+
const droparea = container.querySelector('ark-droparea')
|
|
297
|
+
const dropZone = droparea.querySelector('.ark-droparea__form')
|
|
298
|
+
const firstFile = new File(['first'], 'first.txt', { type: 'text/plain' })
|
|
299
|
+
const secondFile = new File(['second'], 'second.txt', { type: 'text/plain' })
|
|
300
|
+
|
|
301
|
+
dropZone.dispatchEvent(createBubbledEvent('drop', {
|
|
302
|
+
dataTransfer: { files: [firstFile] }
|
|
303
|
+
}))
|
|
304
|
+
|
|
305
|
+
const firstPreviewItem = droparea.preview.querySelector('li')
|
|
306
|
+
assert.deepStrictEqual(firstPreviewItem.querySelector('p').textContent, 'first.txt')
|
|
307
|
+
assert.ok(firstPreviewItem.getAttribute('data').includes('mock://data/url/'))
|
|
308
|
+
assert.strictEqual(firstPreviewItem.getAttribute('index'), null)
|
|
309
|
+
|
|
310
|
+
dropZone.dispatchEvent(createBubbledEvent('drop', {
|
|
311
|
+
dataTransfer: { files: [secondFile] }
|
|
312
|
+
}))
|
|
313
|
+
|
|
314
|
+
const frames = droparea.preview.querySelectorAll('li')
|
|
315
|
+
assert.deepStrictEqual(frames.length, 1)
|
|
316
|
+
assert.deepStrictEqual(frames[0].querySelector('p').textContent, 'second.txt')
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
it('clearPreview tolerates missing preview list nodes', () => {
|
|
320
|
+
setup()
|
|
321
|
+
const preview = document.createElement('ark-droparea-preview')
|
|
322
|
+
const originalSelect = preview.select
|
|
323
|
+
preview.select = () => null
|
|
324
|
+
preview.toggleVisibility = () => {}
|
|
325
|
+
|
|
326
|
+
assert.doesNotThrow(() => {
|
|
327
|
+
preview.clearPreview()
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
preview.select = originalSelect
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
it('returns early when handleDrop receives a null target', () => {
|
|
334
|
+
setup()
|
|
335
|
+
const preview = document.createElement('ark-droparea-preview')
|
|
336
|
+
|
|
337
|
+
assert.doesNotThrow(() => {
|
|
338
|
+
preview.handleDrop({ target: null })
|
|
339
|
+
})
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
it('returns early when removeFile receives a null target', () => {
|
|
343
|
+
setup()
|
|
344
|
+
const preview = document.createElement('ark-droparea-preview')
|
|
345
|
+
const file = new File(['image'], 'Nully.png', { type: 'image/png' })
|
|
346
|
+
|
|
347
|
+
assert.doesNotThrow(() => {
|
|
348
|
+
preview.removeFile(file, { target: null })
|
|
349
|
+
})
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
it('revokeFile and revokeAllFiles tolerate missing revokeObjectURL', () => {
|
|
353
|
+
setup()
|
|
354
|
+
const preview = document.createElement('ark-droparea-preview')
|
|
355
|
+
const file = new File(['one'], 'one.txt', { type: 'text/plain' })
|
|
356
|
+
const secondFile = new File(['two'], 'two.txt', { type: 'text/plain' })
|
|
357
|
+
preview._objectUrls.set(file, 'mock://data/url/a')
|
|
358
|
+
preview._objectUrls.set(secondFile, 'mock://data/url/b')
|
|
359
|
+
|
|
360
|
+
const originalRevoke = global.URL.revokeObjectURL
|
|
361
|
+
global.URL.revokeObjectURL = undefined
|
|
362
|
+
|
|
363
|
+
try {
|
|
364
|
+
assert.doesNotThrow(() => {
|
|
365
|
+
preview.revokeFile(file)
|
|
366
|
+
preview.revokeAllFiles()
|
|
367
|
+
})
|
|
368
|
+
} finally {
|
|
369
|
+
global.URL.revokeObjectURL = originalRevoke
|
|
370
|
+
}
|
|
371
|
+
})
|