@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|detail.name@#child">
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, pipe] = reference.split('|').map(
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
- let [objectPath, eventPath] = assignment.split('=')
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
- set(this, objectPath.trim(), get(
24
- event, eventPath, get(event, 'detail', '')))
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 = pipe ? get(event, pipe) : event
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
- const type = this.receive || 'click'
8
- this.source = JSON.parse(this._pop(':scope > data')?.textContent || null)
9
- this.addEventListener(type, this.handle.bind(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
- if (this.source) Object.assign(detail, this.source)
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
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knowark/componarkjs",
3
- "version": "1.8.2",
3
+ "version": "1.8.3",
4
4
  "author": "Knowark",
5
5
  "description": "Knowark's Web Components Library",
6
6
  "license": "ISC",