@knowark/componarkjs 1.8.1 → 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.
- package/.github/workflows/node.js.yml +35 -0
- package/README.md +11 -0
- package/lib/base/component/component.js +2 -1
- package/lib/base/component/component.test.js +39 -1
- package/lib/base/styles/styles.js +4 -4
- package/lib/base/utils/helpers.js +15 -5
- package/lib/components/emit/components/emit.js +16 -5
- package/lib/components/emit/components/emit.test.js +31 -0
- package/package.json +14 -15
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
|
|
2
|
+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
|
|
3
|
+
|
|
4
|
+
name: Node.js CI
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches: [ "master" ]
|
|
9
|
+
paths-ignore:
|
|
10
|
+
- '**/README.md'
|
|
11
|
+
pull_request:
|
|
12
|
+
branches: [ "master" ]
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
build:
|
|
16
|
+
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
|
|
19
|
+
strategy:
|
|
20
|
+
matrix:
|
|
21
|
+
node-version: [16.x, 18.x]
|
|
22
|
+
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v3
|
|
25
|
+
- name: Use Node.js ${{ matrix.node-version }}
|
|
26
|
+
uses: actions/setup-node@v3
|
|
27
|
+
with:
|
|
28
|
+
node-version: ${{ matrix.node-version }}
|
|
29
|
+
cache: 'npm'
|
|
30
|
+
- run: npm ci
|
|
31
|
+
- run: npm test
|
|
32
|
+
- name: Upload coverage reports to Codecov
|
|
33
|
+
uses: codecov/codecov-action@v3
|
|
34
|
+
env:
|
|
35
|
+
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
package/README.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://codecov.io/gh/librark/componark">
|
|
3
|
+
<img src="https://codecov.io/gh/librark/componark/graph/badge.svg?token=IWNapsPUch"/>
|
|
4
|
+
</a>
|
|
5
|
+
</p>
|
|
6
|
+
<p align="center">
|
|
7
|
+
<a href="https://codecov.io/gh/librark/componark">
|
|
8
|
+
<img src="https://codecov.io/gh/librark/componark/graphs/sunburst.svg?token=IWNapsPUch"/>
|
|
9
|
+
</a>
|
|
10
|
+
</p>
|
|
11
|
+
|
|
1
12
|
# ComponArk
|
|
2
13
|
|
|
3
14
|
Pragmatic Web Components Library
|
|
@@ -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">
|
|
@@ -267,21 +267,21 @@ ${effects.map(effect => actions.map(action => css`
|
|
|
267
267
|
/* COMBINATORS */
|
|
268
268
|
|
|
269
269
|
${[...mutableProperties, ...effects].map(
|
|
270
|
-
effect =>
|
|
270
|
+
effect => actions.map(action => css`
|
|
271
271
|
*${action.replace('-', ':')} > [style*='--${effect}-parent${action}:'] {
|
|
272
272
|
${effect}: var(--${effect}-parent${action});
|
|
273
273
|
}
|
|
274
274
|
`.trim())).flat().join('\n')}
|
|
275
275
|
|
|
276
276
|
${[...mutableProperties, ...effects].map(
|
|
277
|
-
effect =>
|
|
277
|
+
effect => actions.map(action => css`
|
|
278
278
|
*${action.replace('-', ':')} + [style*='--${effect}-sibling${action}:'] {
|
|
279
279
|
${effect}: var(--${effect}-sibling${action});
|
|
280
280
|
}
|
|
281
281
|
`.trim())).flat().join('\n')}
|
|
282
282
|
|
|
283
283
|
${[...mutableProperties, ...effects].map(
|
|
284
|
-
effect =>
|
|
284
|
+
effect => actions.map(action => css`
|
|
285
285
|
*${action.replace('-', ':')} ~ [style*='--${effect}-antecessor${action}:'] {
|
|
286
286
|
${effect}: var(--${effect}-antecessor${action});
|
|
287
287
|
}
|
|
@@ -289,7 +289,7 @@ ${[...mutableProperties, ...effects].map(
|
|
|
289
289
|
|
|
290
290
|
/* MEDIA QUERIES */
|
|
291
291
|
|
|
292
|
-
@media (min-width: 960px) {
|
|
292
|
+
@media (min-width: 960px) {
|
|
293
293
|
[style*='--grid-large:'] {
|
|
294
294
|
display: grid;
|
|
295
295
|
grid: var(--grid-large);
|
|
@@ -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
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knowark/componarkjs",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.3",
|
|
4
4
|
"author": "Knowark",
|
|
5
5
|
"description": "Knowark's Web Components Library",
|
|
6
6
|
"license": "ISC",
|
|
@@ -20,21 +20,21 @@
|
|
|
20
20
|
"components"
|
|
21
21
|
],
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@knowark/injectarkjs": "^0.
|
|
24
|
-
"@knowark/routarkjs": "^0.6.
|
|
25
|
-
"@types/jest": "^29.5.
|
|
23
|
+
"@knowark/injectarkjs": "^0.10.6",
|
|
24
|
+
"@knowark/routarkjs": "^0.6.6",
|
|
25
|
+
"@types/jest": "^29.5.11",
|
|
26
26
|
"clean-webpack-plugin": "^4.0.0",
|
|
27
|
-
"copy-webpack-plugin": "^
|
|
27
|
+
"copy-webpack-plugin": "^12.0.2",
|
|
28
28
|
"file-loader": "^6.2.0",
|
|
29
|
-
"html-webpack-plugin": "^5.
|
|
30
|
-
"jest": "^29.
|
|
31
|
-
"jest-canvas-mock": "^2.5.
|
|
32
|
-
"jest-environment-jsdom": "^29.
|
|
33
|
-
"jsdom": "^
|
|
34
|
-
"npm-check-updates": "^16.
|
|
35
|
-
"webpack": "^5.
|
|
36
|
-
"webpack-cli": "^5.1.
|
|
37
|
-
"webpack-dev-server": "^4.15.
|
|
29
|
+
"html-webpack-plugin": "^5.6.0",
|
|
30
|
+
"jest": "^29.7.0",
|
|
31
|
+
"jest-canvas-mock": "^2.5.2",
|
|
32
|
+
"jest-environment-jsdom": "^29.7.0",
|
|
33
|
+
"jsdom": "^24.0.0",
|
|
34
|
+
"npm-check-updates": "^16.14.12",
|
|
35
|
+
"webpack": "^5.90.0",
|
|
36
|
+
"webpack-cli": "^5.1.4",
|
|
37
|
+
"webpack-dev-server": "^4.15.1"
|
|
38
38
|
},
|
|
39
39
|
"directories": {
|
|
40
40
|
"test": "tests"
|
|
@@ -48,7 +48,6 @@
|
|
|
48
48
|
"verbose": true,
|
|
49
49
|
"clearMocks": true,
|
|
50
50
|
"testEnvironment": "jsdom",
|
|
51
|
-
"coverageDirectory": "/tmp/componark/coverage",
|
|
52
51
|
"transform": {},
|
|
53
52
|
"setupFiles": [
|
|
54
53
|
"jest-canvas-mock"
|