@knowark/componarkjs 1.7.3 → 1.7.5

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 (77) hide show
  1. package/Makefile +6 -3
  2. package/jsconfig.json +23 -0
  3. package/lib/base/component/component.js +27 -26
  4. package/lib/base/component/component.test.js +76 -32
  5. package/lib/base/styles/styles.js +34 -5
  6. package/lib/base/utils/define.js +6 -7
  7. package/lib/base/utils/define.test.js +5 -5
  8. package/lib/base/utils/helpers.js +14 -10
  9. package/lib/base/utils/helpers.test.js +13 -13
  10. package/lib/base/utils/uuid.js +4 -4
  11. package/lib/components/audio/components/audio.js +6 -6
  12. package/lib/components/audio/components/audio.test.js +11 -10
  13. package/lib/components/audio/styles/ark.css.js +1 -1
  14. package/lib/components/camera/components/camera.test.js +6 -6
  15. package/lib/components/camera/styles/ark.css.js +1 -1
  16. package/lib/components/camera/styles/index.js +1 -1
  17. package/lib/components/capture/components/capture.js +2 -2
  18. package/lib/components/capture/components/capture.test.js +1 -1
  19. package/lib/components/droparea/components/droparea-preview.js +27 -26
  20. package/lib/components/droparea/components/droparea-preview.test.js +9 -9
  21. package/lib/components/droparea/components/droparea.js +19 -19
  22. package/lib/components/droparea/components/droparea.test.js +42 -42
  23. package/lib/components/droparea/styles/ark.css.js +1 -1
  24. package/lib/components/emit/components/emit.js +4 -4
  25. package/lib/components/emit/components/emit.test.js +5 -5
  26. package/lib/components/list/components/item.test.js +12 -14
  27. package/lib/components/list/components/list.js +25 -25
  28. package/lib/components/list/components/list.test.js +27 -29
  29. package/lib/components/paginator/components/paginator.js +2 -2
  30. package/lib/components/paginator/components/paginator.test.js +15 -18
  31. package/lib/components/paginator/styles/ark.css.js +1 -1
  32. package/lib/components/spinner/components/spinner.js +17 -17
  33. package/lib/components/spinner/styles/index.js +1 -1
  34. package/lib/components/splitview/components/splitview.detail.js +3 -3
  35. package/lib/components/splitview/components/splitview.detail.test.js +23 -23
  36. package/lib/components/splitview/components/splitview.js +3 -3
  37. package/lib/components/splitview/components/splitview.master.js +3 -3
  38. package/lib/components/splitview/components/splitview.master.test.js +2 -2
  39. package/lib/components/splitview/components/splitview.test.js +5 -7
  40. package/lib/components/translate/components/translate.js +17 -19
  41. package/lib/components/translate/components/translate.test.js +13 -14
  42. package/package.json +1 -1
  43. package/showcase/assets/knowark.svg +1 -0
  44. package/showcase/{design/screens/base/audio/audioDemo.js → components/demos/audio.js} +6 -10
  45. package/showcase/{design/screens/base/camera/cameraDemo.js → components/demos/camera.js} +6 -7
  46. package/showcase/{design/screens/base/droparea/dropareaDemo.js → components/demos/droparea.js} +7 -7
  47. package/showcase/{design/screens/base/list/listDemo.js → components/demos/list.js} +2 -3
  48. package/showcase/{design/screens/base/paginator/paginatorDemo.js → components/demos/paginator.js} +9 -9
  49. package/showcase/{design/screens/base/splitview/splitViewDemo.js → components/demos/splitview.js} +42 -9
  50. package/showcase/{design/screens/base/translate/translateDemo.js → components/demos/translate.js} +4 -5
  51. package/showcase/components/index.html +81 -0
  52. package/showcase/index.html +40 -82
  53. package/showcase/index.js +0 -1
  54. package/webpack.config.cjs +50 -50
  55. package/showcase/design/core/factories/development/development.factory.js +0 -5
  56. package/showcase/design/core/factories/development/index.js +0 -1
  57. package/showcase/design/core/factories/index.js +0 -11
  58. package/showcase/design/core/factories/standard.factory.js +0 -19
  59. package/showcase/design/index.html +0 -22
  60. package/showcase/design/index.js +0 -7
  61. package/showcase/design/screens/base/audio/index.js +0 -25
  62. package/showcase/design/screens/base/camera/index.js +0 -25
  63. package/showcase/design/screens/base/droparea/index.js +0 -25
  64. package/showcase/design/screens/base/index.js +0 -42
  65. package/showcase/design/screens/base/list/index.js +0 -25
  66. package/showcase/design/screens/base/paginator/index.js +0 -25
  67. package/showcase/design/screens/base/root.component.js +0 -294
  68. package/showcase/design/screens/base/root.routes.js +0 -28
  69. package/showcase/design/screens/base/spinner/index.js +0 -25
  70. package/showcase/design/screens/base/spinner/spinnerDemo.js +0 -55
  71. package/showcase/design/screens/base/splitview/detailDemo.js +0 -40
  72. package/showcase/design/screens/base/splitview/index.js +0 -25
  73. package/showcase/design/screens/base/translate/index.js +0 -20
  74. package/showcase/design/screens/main.js +0 -12
  75. package/showcase/design/screens/screens.routes.js +0 -23
  76. package/tsconfig.json +0 -23
  77. /package/showcase/{design/.htaccess → .htaccess} +0 -0
package/Makefile CHANGED
@@ -1,4 +1,4 @@
1
- .PHONY: all tests coverage
1
+ .PHONY: all tests coverage showcase
2
2
 
3
3
  setup:
4
4
  npm install -g browser-sync && \
@@ -15,8 +15,11 @@ test:
15
15
  clean:
16
16
  rm -rf ./dist
17
17
 
18
+ standard:
19
+ npx standard --fix
20
+
18
21
  showcase:
19
- npx live-server ./showcase/
22
+ npx live-server ./showcase
20
23
 
21
24
  dev:
22
25
  npm run dev
@@ -28,7 +31,7 @@ push:
28
31
  git push && git push --tags
29
32
 
30
33
  deploy:
31
- sshpass -e rsync -av --delete ./dist/ \
34
+ sshpass -e rsync -av --delete ./showcase/ \
32
35
  ${RSYNC_USER}@${RSYNC_HOST}:${RSYNC_DIR}
33
36
 
34
37
  reset:
package/jsconfig.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "esnext",
4
+ "module": "esnext",
5
+ "moduleResolution": "nodenext",
6
+ "allowJs": true,
7
+ "checkJs": true,
8
+ "baseUrl": "lib",
9
+ "paths": {
10
+ "@base*": [
11
+ "base",
12
+ "base*"
13
+ ],
14
+ "*": [
15
+ "*"
16
+ ]
17
+ }
18
+ },
19
+ "exclude": [
20
+ "node_modules",
21
+ "*/node_modules/"
22
+ ]
23
+ }
@@ -1,11 +1,11 @@
1
- import { define, listen, reflect, slot, keys } from "../utils/index.js"
1
+ import { define, listen, reflect, slot, keys } from '../utils/index.js'
2
2
  import styles from '../styles/index.js'
3
3
 
4
4
  const tag = 'ark-component'
5
- export class Component extends HTMLElement {
6
- constructor() {
5
+ export class Component extends globalThis.HTMLElement {
6
+ constructor () {
7
7
  super()
8
- this.binding = "listen"
8
+ this.binding = 'listen'
9
9
  reflect(this, this.reflectedProperties())
10
10
  }
11
11
 
@@ -13,74 +13,75 @@ export class Component extends HTMLElement {
13
13
  * @param {string} tag
14
14
  * @param {CustomElementConstructor} element
15
15
  * @param {string} styles **/
16
- static define(tag, element, styles = null) {
16
+ static define (tag, element, styles = null) {
17
17
  define(tag, element, styles)
18
18
  }
19
19
 
20
20
  /**
21
21
  * @param {object} styleMap
22
22
  * @return {string} **/
23
- styleNames(styleMap) {
23
+ styleNames (styleMap) {
24
24
  return keys(styleMap)
25
25
  }
26
26
 
27
27
  /**
28
- * @param {Object<string, any>} _context
28
+ * @param {object} context
29
29
  * @return {Component} */
30
- init(_context = {}) {
30
+ init (context = {}) {
31
31
  return this
32
32
  }
33
33
 
34
34
  /** @return {string[]} */
35
- reflectedProperties() {
35
+ reflectedProperties () {
36
36
  return []
37
37
  }
38
38
 
39
- get slots() {
39
+ get slots () {
40
40
  return slot(this)
41
41
  }
42
42
 
43
43
  /** @param {string} content */
44
- set content(content) {
44
+ set content (content) {
45
45
  this.innerHTML = content
46
46
  }
47
47
 
48
48
  /** @return {string} */
49
- get content() {
49
+ get content () {
50
50
  return this.innerHTML
51
51
  }
52
52
 
53
- connectedCallback() {
53
+ connectedCallback () {
54
54
  try {
55
- !this['state'] && this.init({})
55
+ !this.state && this.init({})
56
56
  this.render()
57
57
  } catch (error) {
58
- this.emit("error", error)
58
+ this.emit('error', error)
59
59
  throw error
60
60
  }
61
- this.load()
61
+ this.load({})
62
62
  }
63
63
 
64
64
  /** @return {Component} */
65
- render() {
65
+ render () {
66
66
  this.classList.add(this.tagName.toLowerCase())
67
67
  listen(this)
68
68
  return this
69
69
  }
70
70
 
71
- async load() {}
71
+ /** @param {object} context */
72
+ async load (context = {}) {}
72
73
 
73
74
  /**
74
75
  * @param {string} selectors
75
76
  * @return {Component} */
76
- select(selectors) {
77
+ select (selectors) {
77
78
  return /** @type {Component} */ (this.querySelector(selectors))
78
79
  }
79
80
 
80
81
  /**
81
82
  * @param {string} selectors
82
83
  * @return {NodeListOf<Component>} */
83
- selectAll(selectors) {
84
+ selectAll (selectors) {
84
85
  return /** @type {NodeListOf<Component>} */ (this.querySelectorAll(
85
86
  selectors
86
87
  ))
@@ -89,12 +90,12 @@ export class Component extends HTMLElement {
89
90
  /**
90
91
  * @param {string} type
91
92
  * @param {any} detail */
92
- emit(type, detail) {
93
+ emit (type, detail) {
93
94
  this.dispatchEvent(
94
- new CustomEvent(type, {
95
+ new globalThis.CustomEvent(type, {
95
96
  detail,
96
97
  bubbles: true,
97
- cancelable: true,
98
+ cancelable: true
98
99
  })
99
100
  )
100
101
  }
@@ -102,11 +103,11 @@ export class Component extends HTMLElement {
102
103
  /**
103
104
  * @param {string} resource
104
105
  * @return {any} */
105
- resolve(resource) {
106
- const event = new CustomEvent("resolve", {
106
+ resolve (resource) {
107
+ const event = new globalThis.CustomEvent('resolve', {
107
108
  detail: { resource },
108
109
  bubbles: true,
109
- cancelable: true,
110
+ cancelable: true
110
111
  })
111
112
  this.dispatchEvent(event)
112
113
  return event.detail[resource]
@@ -2,39 +2,44 @@ import { jest } from '@jest/globals'
2
2
  import { Component } from './component.js'
3
3
 
4
4
  class MockComponent extends Component {
5
- init(context = {}) {
5
+ init (context = {}) {
6
6
  this.context = context
7
7
  this.data = {}
8
8
  this.dependency = undefined
9
+ this.code = this.code || null
9
10
  return super.init()
10
11
  }
11
12
 
12
- reflectedProperties() { return ['code'] }
13
+ reflectedProperties () { return ['code'] }
14
+
15
+ customHandler (/** @type {CustomEvent} */ event) {
16
+ event.detail.code = this.code
17
+ }
13
18
 
14
19
  erroringHandler (_event) {
15
20
  throw new Error('Something went wrong!')
16
21
  }
17
22
 
18
23
  async asyncErroringHandler (_event) {
19
- const callback = async () => {
20
- throw new Error('Something went async wrong!') }
24
+ const callback = async () => {
25
+ throw new Error('Something went async wrong!')
26
+ }
21
27
  await callback()
22
28
  }
23
29
 
24
- render() {
30
+ render () {
25
31
  this.dependency = this.resolve('Dependency')
26
32
  return super.render()
27
33
  }
28
34
  }
29
35
  Component.define('mock-component', MockComponent)
30
36
 
31
-
32
37
  describe('Component', () => {
33
38
  let container = null
34
39
  let component = null
35
40
  beforeEach(() => {
36
41
  container = document.createElement('div')
37
- container.innerHTML = `<mock-component code="XYZ123"></mock-component>`
42
+ container.innerHTML = '<mock-component code="XYZ123"></mock-component>'
38
43
  component = container.querySelector('mock-component')
39
44
  document.body.append(container)
40
45
  })
@@ -63,15 +68,15 @@ describe('Component', () => {
63
68
  })
64
69
 
65
70
  it('has an init method through which state is set', () => {
66
- const response = component.init({attribute: 'value'})
71
+ const response = component.init({ attribute: 'value' })
67
72
  expect(response).toBe(component)
68
73
  })
69
74
 
70
75
  it('can set its content via a property', () => {
71
- component.content = `<p>Hello World</p>`
76
+ component.content = '<p>Hello World</p>'
72
77
  const paragraph = component.querySelector('p')
73
- expect(component.content).toBe(`<p>Hello World</p>`)
74
- expect(paragraph.outerHTML).toBe(`<p>Hello World</p>`)
78
+ expect(component.content).toBe('<p>Hello World</p>')
79
+ expect(paragraph.outerHTML).toBe('<p>Hello World</p>')
75
80
  })
76
81
 
77
82
  it('can have some of its attributes reflected as properties', () => {
@@ -94,16 +99,16 @@ describe('Component', () => {
94
99
 
95
100
  it('emits custom events', () => {
96
101
  let detail = null
97
- const handler = (event) => {detail = event.detail}
102
+ const handler = (event) => { detail = event.detail }
98
103
  component.addEventListener('fire', handler)
99
104
 
100
- component.emit('fire', {location: 'indoors'})
105
+ component.emit('fire', { location: 'indoors' })
101
106
 
102
- expect(detail).toEqual({location: 'indoors'})
107
+ expect(detail).toEqual({ location: 'indoors' })
103
108
  })
104
109
 
105
110
  it('calls the load method on connectedCallback', async () => {
106
- const component = document.createElement('mock-component')
111
+ const component = document.createElement('mock-component')
107
112
  const initSpy = jest.spyOn(component, 'init')
108
113
  const renderSpy = jest.spyOn(component, 'render')
109
114
  const loadSpy = jest.spyOn(component, 'load')
@@ -117,10 +122,10 @@ describe('Component', () => {
117
122
 
118
123
  it('catches and re-raises connectedCallback errors', async () => {
119
124
  expect.assertions(1)
120
- const component = document.createElement('mock-component')
125
+ const component = document.createElement('mock-component')
121
126
  const consoleError = console.error
122
127
  console.error = jest.fn()
123
- component.render = () => {
128
+ component.render = () => {
124
129
  throw new Error('Render Error!')
125
130
  }
126
131
 
@@ -133,7 +138,6 @@ describe('Component', () => {
133
138
  console.error = consoleError
134
139
  })
135
140
 
136
-
137
141
  it('selects the children matching a selector', () => {
138
142
  container.innerHTML = `
139
143
  <mock-component>
@@ -168,7 +172,7 @@ describe('Component', () => {
168
172
  footer: [component.select('.footer')]
169
173
  })
170
174
  })
171
-
175
+
172
176
  it('binds its properties to children events', async () => {
173
177
  container.innerHTML = `
174
178
  <mock-component>
@@ -179,8 +183,9 @@ describe('Component', () => {
179
183
  const component = container.querySelector('mock-component')
180
184
  const input = component.select('input')
181
185
 
182
-
183
- input.dispatchEvent(new InputEvent('input', {bubbles: true, data: 'E'}))
186
+ input.dispatchEvent(
187
+ new globalThis.InputEvent('input', { bubbles: true, data: 'E' })
188
+ )
184
189
 
185
190
  expect(component.data.value).toEqual('E')
186
191
  })
@@ -193,10 +198,10 @@ describe('Component', () => {
193
198
  `
194
199
  const component = container.querySelector('mock-component')
195
200
  const input = component.select('input')
196
- const inputEvent = new InputEvent('input')
201
+ const inputEvent = new globalThis.InputEvent('input')
197
202
  const target = { name: 'input', value: 'X' }
198
203
  Object.defineProperty(
199
- inputEvent, 'target', { writable: false, value: target });
204
+ inputEvent, 'target', { writable: false, value: target })
200
205
 
201
206
  input.dispatchEvent(inputEvent)
202
207
 
@@ -214,11 +219,46 @@ describe('Component', () => {
214
219
  const input = component.select('input')
215
220
 
216
221
  input.dispatchEvent(
217
- new CustomEvent('alter', { bubbles: true, detail: 'A' }))
222
+ new globalThis.CustomEvent('alter', { bubbles: true, detail: 'A' }))
218
223
 
219
224
  expect(component.data.value).toEqual('A')
220
225
  })
221
226
 
227
+ it('listens to events and handles them with its own methods', async () => {
228
+ container.innerHTML = `
229
+ <mock-component code="ABC123">
230
+ <input type="text" listen on-alter="customHandler"></input>
231
+ </mock-component>
232
+ `
233
+
234
+ const component = container.querySelector('mock-component')
235
+ const input = component.select('input')
236
+
237
+ const event = new globalThis.CustomEvent(
238
+ 'alter', { bubbles: true, detail: { code: '' } })
239
+ input.dispatchEvent(event)
240
+
241
+ expect(event.detail.code).toEqual('ABC123')
242
+ })
243
+
244
+ it('listens to events and redirects them to target components', async () => {
245
+ container.innerHTML = `
246
+ <mock-component code="ABC123">
247
+ <input type="text" listen on-alter="customHandler" at="#child"></input>
248
+ <mock-component id="child" code="XYZ890"></mock-component>
249
+ </mock-component>
250
+ `
251
+
252
+ const component = container.querySelector('mock-component')
253
+ const input = component.select('input')
254
+
255
+ const event = new globalThis.CustomEvent(
256
+ 'alter', { bubbles: true, detail: { code: '' } })
257
+ input.dispatchEvent(event)
258
+
259
+ expect(event.detail.code).toEqual('XYZ890')
260
+ })
261
+
222
262
  it('emits an error event on declared listeners', async () => {
223
263
  container.innerHTML = `
224
264
  <mock-component>
@@ -229,12 +269,14 @@ describe('Component', () => {
229
269
  const component = container.querySelector('mock-component')
230
270
 
231
271
  let errorEvent = {}
232
- component.addEventListener('error', (event) => errorEvent = event)
272
+ component.addEventListener('error', (event) => { errorEvent = event })
233
273
 
234
274
  const input = component.select('input')
235
275
 
236
276
  input.dispatchEvent(
237
- new CustomEvent('alter', { bubbles: true, detail: 'I will error!' }))
277
+ new globalThis.CustomEvent(
278
+ 'alter', { bubbles: true, detail: 'I will error!' }
279
+ ))
238
280
 
239
281
  expect(errorEvent.detail.message).toEqual('Something went wrong!')
240
282
  })
@@ -249,12 +291,14 @@ describe('Component', () => {
249
291
  const component = container.querySelector('mock-component')
250
292
 
251
293
  let errorEvent = {}
252
- component.addEventListener('error', (event) => errorEvent = event)
294
+ component.addEventListener('error', (event) => { errorEvent = event })
253
295
 
254
296
  const input = component.select('input')
255
297
 
256
298
  input.dispatchEvent(
257
- new CustomEvent('alter', { bubbles: true, detail: 'I will error!' }))
299
+ new globalThis.CustomEvent(
300
+ 'alter', { bubbles: true, detail: 'I will error!' }
301
+ ))
258
302
 
259
303
  // Sleep
260
304
  await new Promise(resolve => setTimeout(resolve, 0))
@@ -279,7 +323,7 @@ describe('Component', () => {
279
323
 
280
324
  it('provides the dependencies requested to it by child components', () => {
281
325
  class ParentComponent extends MockComponent {
282
- provide(resource) {
326
+ provide (resource) {
283
327
  if (resource === 'Dependency') {
284
328
  return `RESOURCE: ${resource} PROVIDED BY: ${this.id}`
285
329
  }
@@ -293,11 +337,11 @@ describe('Component', () => {
293
337
  <mock-component id="child"></mock-component>
294
338
  </parent-component>
295
339
  `
296
- const parent = container.querySelector('#parent')
340
+
297
341
  const child = container.querySelector('#child')
298
342
 
299
343
  expect(child.dependency).toEqual(
300
- "RESOURCE: Dependency PROVIDED BY: parent")
344
+ 'RESOURCE: Dependency PROVIDED BY: parent')
301
345
 
302
346
  const state = child.resolve('state')
303
347
  expect(state).toEqual({ key: 'value' })
@@ -317,7 +361,7 @@ describe('Component', () => {
317
361
  const styleMap = {
318
362
  [`background-${background}`]: background,
319
363
  [`color-${color}`]: color,
320
- [`shadow-${shadow}`]: shadow,
364
+ [`shadow-${shadow}`]: shadow
321
365
  }
322
366
 
323
367
  const result = component.styleNames(styleMap)
@@ -1,4 +1,4 @@
1
- const userActions = ['-hover', '-active' ]
1
+ const userActions = ['-hover', '-active']
2
2
 
3
3
  const formActions = ['-focus-within', '-valid', '-invalid', '-checked']
4
4
 
@@ -46,7 +46,8 @@ html {
46
46
 
47
47
  /* TYPOGRAPHY */
48
48
 
49
- --font-size-step: 0.25rem;
49
+ --font-size-base: 0.5rem;
50
+ --font-size-step: 0.125rem;
50
51
  --line-height-step: 0.5;
51
52
  --word-spacing-step: 0.1rem;
52
53
  --letter-spacing-step: 0.05rem;
@@ -102,7 +103,8 @@ ${actions.map(action => css`
102
103
  /* TYPOGRAPHY */
103
104
 
104
105
  [style*='--font-size:'] {
105
- font-size: calc(var(--font-size-step) * var(--font-size));
106
+ font-size: calc(var(--font-size-base) + (
107
+ var(--font-size-step) * var(--font-size)));
106
108
  }
107
109
  [style*='--line-height:'] {
108
110
  line-height: calc(var(--line-height-step) * var(--line-height));
@@ -114,6 +116,18 @@ ${actions.map(action => css`
114
116
  letter-spacing: calc(var(--letter-spacing-step) * var(--letter-spacing));
115
117
  }
116
118
 
119
+ [style*='--text-overflow:'] {
120
+ overflow: hidden;
121
+ white-space: nowrap;
122
+ text-overflow: var(--text-overflow);
123
+ }
124
+ [style*='--overflow:'] {
125
+ overflow: var(--overflow);
126
+ }
127
+ [style*='--white-space:'] {
128
+ white-space: var(--white-space);
129
+ }
130
+
117
131
  /* SPACING */
118
132
 
119
133
  ${sides.map(side => css`
@@ -252,7 +266,7 @@ ${effects.map(effect => actions.map(action => css`
252
266
 
253
267
  /* COMBINATORS */
254
268
 
255
- ${[...mutableProperties, ...effects].map(
269
+ ${[...mutableProperties, ...effects].map(
256
270
  effect => userActions.map(action => css`
257
271
  *${action.replace('-', ':')} > [style*='--${effect}-parent${action}:'] {
258
272
  ${effect}: var(--${effect}-parent${action});
@@ -277,7 +291,22 @@ ${[...mutableProperties, ...effects].map(
277
291
  [style*='--display-large:'] {
278
292
  display: var(--display-large);
279
293
  }
280
- }
294
+ }
295
+
296
+ /* PSEUDO-ELEMENTS */
297
+
298
+ ${actions.map(action => css`
299
+ [style*='--content-before${action}:']${action.replace('-', ':')}::before {
300
+ content: var(--content-before${action});
301
+ }
302
+ [style*='--content-after${action}:']${action.replace('-', ':')}::after {
303
+ content: var(--content-after${action});
304
+ }
305
+ [style*='--background-backdrop${action}:']${action.replace(
306
+ '-', ':')}::backdrop {
307
+ background: var(--background-backdrop${action});
308
+ }
309
+ `.trim()).join('\n')}
281
310
 
282
311
  /* ANIMATIONS */
283
312
 
@@ -3,19 +3,18 @@
3
3
  /** @param {string} tag
4
4
  * @param {CustomElementConstructor} element
5
5
  * @param {string} styles **/
6
- export function define(tag, element, styles='') {
7
- customElements.define(tag, element)
6
+ export function define (tag, element, styles = '') {
7
+ globalThis.customElements.define(tag, element)
8
8
  if (!styles?.trim()) return
9
9
 
10
10
  try {
11
- const sheet = new CSSStyleSheet()
11
+ const sheet = new globalThis.CSSStyleSheet()
12
12
  sheet.replaceSync(styles)
13
- return document.adoptedStyleSheets = [
14
- ...document.adoptedStyleSheets, sheet]
13
+ return (document.adoptedStyleSheets = [
14
+ ...document.adoptedStyleSheets, sheet])
15
15
  } catch (error) {
16
16
  const style = document.createElement('style')
17
17
  style.textContent = styles
18
- document.head.appendChild(style);
18
+ document.head.appendChild(style)
19
19
  }
20
-
21
20
  }
@@ -3,7 +3,7 @@ import { define } from './define.js'
3
3
 
4
4
  describe('Define', () => {
5
5
  it('can define a custome element', () => {
6
- class NewElement extends HTMLElement {}
6
+ class NewElement extends globalThis.HTMLElement {}
7
7
  define('new-element', NewElement)
8
8
 
9
9
  const newElement = document.createElement('new-element')
@@ -12,16 +12,16 @@ describe('Define', () => {
12
12
 
13
13
  it('can define a custom element using constructable CSSStyleSheet', () => {
14
14
  let definedStyles = null
15
- class MockCSSStyleSheet extends CSSStyleSheet {
15
+ class MockCSSStyleSheet extends globalThis.CSSStyleSheet {
16
16
  replaceSync (styles) {
17
17
  definedStyles = styles
18
18
  }
19
19
  }
20
20
 
21
- jest.spyOn(window, "CSSStyleSheet").mockReturnValue(
21
+ jest.spyOn(window, 'CSSStyleSheet').mockReturnValue(
22
22
  new MockCSSStyleSheet())
23
23
 
24
- class CSSStyledElement extends HTMLElement {}
24
+ class CSSStyledElement extends globalThis.HTMLElement {}
25
25
  const styles = `
26
26
  body {
27
27
  color: red;
@@ -41,7 +41,7 @@ describe('Define', () => {
41
41
  })
42
42
 
43
43
  it('can define a custom element using an style fallback element', () => {
44
- class StyledElement extends HTMLElement {}
44
+ class StyledElement extends globalThis.HTMLElement {}
45
45
  const styles = `
46
46
  body {
47
47
  color: red;
@@ -2,36 +2,41 @@ import { camelToKebab } from './format.js'
2
2
 
3
3
  /** @param {HTMLElement} self */
4
4
  export function listen (self) {
5
- const binding = self['binding']
5
+ const binding = self.binding
6
6
  const elements = self.querySelectorAll(`[${binding}]`)
7
7
  for (const element of elements) {
8
8
  for (const attribute of Array.from(element.attributes)) {
9
9
  if (attribute.name.startsWith('on-')) {
10
- const eventName = attribute.name.replace('on-', '').trim()
11
10
  let handler = self[attribute.value]
12
11
 
13
12
  const [assignment] = attribute.value.match(/[^{{]+(?=\}})/g) || []
14
13
 
15
14
  if (assignment) {
16
15
  let [objectPath, eventPath] = assignment.split('=')
17
- eventPath = eventPath || 'target.value'
16
+ eventPath = eventPath?.trim() || 'target.value'
18
17
  handler = function (event) {
19
18
  set(this, objectPath.trim(), get(
20
19
  event, eventPath, get(event, 'detail', '')))
21
- }
22
- }
20
+ }
21
+ }
23
22
 
24
23
  if (!handler) continue
25
24
 
25
+ const at = element.getAttribute('at')
26
26
  const catchingHandler = async function (event) {
27
27
  try {
28
- return await Promise.resolve(handler.bind(this)(event))
28
+ let receiver = this
29
+ if (at) receiver = this.select(at)
30
+ return await Promise.resolve(handler.bind(receiver)(event))
29
31
  } catch (error) {
30
- this.dispatchEvent(new CustomEvent('error', {
31
- detail: error, bubbles: true, cancelable: true }))
32
+ this.dispatchEvent(
33
+ new globalThis.CustomEvent(
34
+ 'error', { detail: error, bubbles: true, cancelable: true }
35
+ ))
32
36
  }
33
37
  }
34
38
 
39
+ const eventName = attribute.name.replace('on-', '').trim()
35
40
  element.addEventListener(eventName, catchingHandler.bind(self))
36
41
  element.removeAttribute(binding)
37
42
  }
@@ -42,13 +47,12 @@ export function listen (self) {
42
47
  /** @param {HTMLElement} self */
43
48
  function provide (self) {
44
49
  if (!self.provide) return
45
- self.addEventListener('resolve', (event) => {
50
+ self.addEventListener('resolve', (/** @type {CustomEvent} */ event) => {
46
51
  const resource = event.detail.resource
47
52
  const dependency = self.provide(resource)
48
53
  if (dependency === undefined) return
49
54
  event.detail[resource] = dependency
50
55
  })
51
-
52
56
  }
53
57
 
54
58
  /** @param {HTMLElement} self @param {string[]} properties */