@knowark/componarkjs 1.8.2 → 1.8.3
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.
|
@@ -6,6 +6,7 @@ export class Component extends globalThis.HTMLElement {
|
|
|
6
6
|
constructor () {
|
|
7
7
|
super()
|
|
8
8
|
this.binding = 'listen'
|
|
9
|
+
this.local = {}
|
|
9
10
|
reflect(this, this.reflectedProperties())
|
|
10
11
|
}
|
|
11
12
|
|
|
@@ -52,7 +53,7 @@ export class Component extends globalThis.HTMLElement {
|
|
|
52
53
|
|
|
53
54
|
connectedCallback () {
|
|
54
55
|
try {
|
|
55
|
-
!this.state && this.init({})
|
|
56
|
+
!(this.state || Object.keys(this.local).length) && this.init({})
|
|
56
57
|
this.render()
|
|
57
58
|
} catch (error) {
|
|
58
59
|
this.emit('error', error)
|
|
@@ -82,6 +82,9 @@ describe('Component', () => {
|
|
|
82
82
|
it('can have some of its attributes reflected as properties', () => {
|
|
83
83
|
expect(component.code).toBe('XYZ123')
|
|
84
84
|
})
|
|
85
|
+
it('has an asynchronous load method which is empty by default', async () => {
|
|
86
|
+
expect(await component.load()).toBeUndefined()
|
|
87
|
+
})
|
|
85
88
|
|
|
86
89
|
it('sets its tag name as class when rendered', () => {
|
|
87
90
|
component.render()
|
|
@@ -224,6 +227,22 @@ describe('Component', () => {
|
|
|
224
227
|
expect(component.data.value).toEqual('A')
|
|
225
228
|
})
|
|
226
229
|
|
|
230
|
+
it('performs basic transformations to event properties', async () => {
|
|
231
|
+
container.innerHTML = `
|
|
232
|
+
<mock-component>
|
|
233
|
+
<input type="text" listen on-alter="{{ data.value | number }}"></input>
|
|
234
|
+
</mock-component>
|
|
235
|
+
`
|
|
236
|
+
|
|
237
|
+
const component = container.querySelector('mock-component')
|
|
238
|
+
const input = component.select('input')
|
|
239
|
+
|
|
240
|
+
input.dispatchEvent(
|
|
241
|
+
new globalThis.CustomEvent('alter', { bubbles: true, detail: '777' }))
|
|
242
|
+
|
|
243
|
+
expect(component.data.value).toEqual(777)
|
|
244
|
+
})
|
|
245
|
+
|
|
227
246
|
it('listens to events and handles them with its own methods', async () => {
|
|
228
247
|
container.innerHTML = `
|
|
229
248
|
<mock-component code="ABC123">
|
|
@@ -259,6 +278,25 @@ describe('Component', () => {
|
|
|
259
278
|
expect(event.detail.code).toEqual(['XYZ890'])
|
|
260
279
|
})
|
|
261
280
|
|
|
281
|
+
it('does not launch and event if the target is not found', async () => {
|
|
282
|
+
container.innerHTML = `
|
|
283
|
+
<mock-component code="ABC123">
|
|
284
|
+
<input type="text" listen on-alter="customHandler@#missing"></input>
|
|
285
|
+
<mock-component id="child" code="XYZ890"></mock-component>
|
|
286
|
+
</mock-component>
|
|
287
|
+
`
|
|
288
|
+
|
|
289
|
+
const component = container.querySelector('mock-component')
|
|
290
|
+
const input = component.select('input')
|
|
291
|
+
|
|
292
|
+
const event = new globalThis.CustomEvent(
|
|
293
|
+
'alter', { bubbles: true, detail: { code: [] } })
|
|
294
|
+
input.dispatchEvent(event)
|
|
295
|
+
|
|
296
|
+
expect(event.detail.code).toEqual([])
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
|
|
262
300
|
it('listens to clicks and redirects them to target components', async () => {
|
|
263
301
|
container.innerHTML = `
|
|
264
302
|
<mock-component code="ABC123">
|
|
@@ -282,7 +320,7 @@ describe('Component', () => {
|
|
|
282
320
|
it('listens to events and pipes them to target components', async () => {
|
|
283
321
|
container.innerHTML = `
|
|
284
322
|
<mock-component code="ABC123">
|
|
285
|
-
<div type="text" listen on-change="replaceChildren
|
|
323
|
+
<div type="text" listen on-change="replaceChildren%detail.name@#child">
|
|
286
324
|
<button id="action">Action</button>
|
|
287
325
|
</div>
|
|
288
326
|
<div id="child">
|
|
@@ -10,18 +10,20 @@ export function listen (self) {
|
|
|
10
10
|
if (attribute.name.startsWith('on-')) {
|
|
11
11
|
const [reference, at] = attribute.value.split('@').map(
|
|
12
12
|
item => item.trim())
|
|
13
|
-
const [value,
|
|
13
|
+
const [value, field] = reference.split('%').map(
|
|
14
14
|
item => item.trim())
|
|
15
15
|
|
|
16
16
|
let handler = self[value]
|
|
17
17
|
const [assignment] = value.match(/[^{{]+(?=\}})/g) || []
|
|
18
18
|
|
|
19
19
|
if (assignment) {
|
|
20
|
-
|
|
20
|
+
const [content, pipe] = assignment.split('|').map(
|
|
21
|
+
item => item.trim())
|
|
22
|
+
let [objectPath, eventPath] = content.split('=')
|
|
21
23
|
eventPath = eventPath?.trim() || 'target.value'
|
|
22
24
|
handler = function (event) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
const variable = transform(pipe, get(event, 'detail', ''))
|
|
26
|
+
set(this, objectPath.trim(), get(event, eventPath, variable))
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
|
|
@@ -35,7 +37,7 @@ export function listen (self) {
|
|
|
35
37
|
if (!receiver) return
|
|
36
38
|
handler = receiver[value]
|
|
37
39
|
}
|
|
38
|
-
const data =
|
|
40
|
+
const data = field ? get(event, field) : event
|
|
39
41
|
return await Promise.resolve(handler.bind(receiver)(data))
|
|
40
42
|
} catch (error) {
|
|
41
43
|
this.dispatchEvent(
|
|
@@ -85,6 +87,14 @@ export function reflect (self, properties) {
|
|
|
85
87
|
provide(self)
|
|
86
88
|
}
|
|
87
89
|
|
|
90
|
+
function transform (pipe, value) {
|
|
91
|
+
return {
|
|
92
|
+
string: String,
|
|
93
|
+
boolean: Boolean,
|
|
94
|
+
number: Number
|
|
95
|
+
}[pipe?.toLowerCase() || 'string'](value)
|
|
96
|
+
}
|
|
97
|
+
|
|
88
98
|
/** @param {object} object @param {string} path @param {any} value */
|
|
89
99
|
export function set (object, path, value) {
|
|
90
100
|
const pathArray = path.match(/([^[.\]])+/g)
|
|
@@ -4,18 +4,29 @@ const tag = 'ark-emit'
|
|
|
4
4
|
export class Emit extends Component {
|
|
5
5
|
constructor () {
|
|
6
6
|
super()
|
|
7
|
-
|
|
8
|
-
this.
|
|
9
|
-
this.
|
|
7
|
+
this.bind = /** @type {string} */ (this.bind)
|
|
8
|
+
this.receive = /** @type {string} */ (this.receive)
|
|
9
|
+
this.dispatch = /** @type {string} */ (this.dispatch)
|
|
10
|
+
this.source = this._pop(':scope > data')?.textContent
|
|
11
|
+
this.addEventListener(this.receive || 'click', this.handle.bind(this))
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
reflectedProperties () {
|
|
13
|
-
return ['receive', 'dispatch']
|
|
15
|
+
return ['receive', 'dispatch', 'bind']
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
handle (event) {
|
|
17
19
|
const detail = Object.assign({}, event.detail)
|
|
18
|
-
|
|
20
|
+
|
|
21
|
+
let data = null
|
|
22
|
+
if (this.bind && this.source) {
|
|
23
|
+
const element = this.closest(this.bind)
|
|
24
|
+
data = Function(`return ${this.source.trim()}`).call(element)
|
|
25
|
+
} else if (this.source) {
|
|
26
|
+
data = JSON.parse(this.source)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
Object.assign(detail, data)
|
|
19
30
|
|
|
20
31
|
const value = event.target.value
|
|
21
32
|
if (value) Object.assign(detail, { value })
|
|
@@ -135,4 +135,35 @@ describe('Emit', () => {
|
|
|
135
135
|
|
|
136
136
|
input.dispatchEvent(inputEvent)
|
|
137
137
|
})
|
|
138
|
+
|
|
139
|
+
it('binds to the given ancestor referenced by a selector', async () => {
|
|
140
|
+
expect.assertions(1)
|
|
141
|
+
|
|
142
|
+
container.innerHTML = `
|
|
143
|
+
<div class="grandparent" data-name="John", data-surname="Doe">
|
|
144
|
+
<div class="parent">
|
|
145
|
+
<ark-emit bind=".grandparent">
|
|
146
|
+
<data>
|
|
147
|
+
{
|
|
148
|
+
name: this.dataset.name,
|
|
149
|
+
surname: this.dataset.surname
|
|
150
|
+
}
|
|
151
|
+
</data>
|
|
152
|
+
<button>Sending a click event when pressed!</button>
|
|
153
|
+
</ark-emit>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
`
|
|
157
|
+
|
|
158
|
+
const emit = container.querySelector('ark-emit')
|
|
159
|
+
emit.addEventListener('emit', (event) => {
|
|
160
|
+
const { detail } = event
|
|
161
|
+
expect(detail).toEqual({
|
|
162
|
+
name: 'John',
|
|
163
|
+
surname: 'Doe'
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
container.querySelector('button').click()
|
|
168
|
+
})
|
|
138
169
|
})
|