@knowark/componarkjs 1.13.4 → 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 +142 -20
- package/lib/base/component/component.test.js +753 -374
- package/lib/base/component/index.js +3 -0
- package/lib/base/styles/index.js +4 -1
- package/lib/base/utils/define.js +30 -7
- package/lib/base/utils/define.test.js +129 -42
- package/lib/base/utils/format.js +12 -6
- package/lib/base/utils/format.test.js +16 -16
- package/lib/base/utils/helpers.js +42 -9
- package/lib/base/utils/helpers.test.js +134 -115
- package/lib/base/utils/index.js +1 -0
- package/lib/base/utils/slots.js +3 -2
- package/lib/base/utils/slots.test.js +38 -38
- package/lib/base/utils/uuid.js +1 -1
- package/lib/base/utils/uuid.test.js +13 -13
- package/lib/components/audio/components/audio.js +36 -3
- package/lib/components/audio/components/audio.test.js +120 -90
- package/lib/components/audio/index.js +1 -0
- package/lib/components/audio/styles/index.js +5 -1
- package/lib/components/camera/components/camera.js +15 -0
- package/lib/components/camera/components/camera.test.js +96 -91
- package/lib/components/camera/index.js +1 -0
- package/lib/components/camera/styles/index.js +5 -1
- package/lib/components/capture/components/capture.js +48 -4
- package/lib/components/capture/components/capture.test.js +165 -97
- package/lib/components/capture/index.js +1 -0
- package/lib/components/droparea/components/droparea-preview.js +114 -19
- package/lib/components/droparea/components/droparea-preview.test.js +344 -80
- package/lib/components/droparea/components/droparea.js +82 -6
- package/lib/components/droparea/components/droparea.test.js +309 -299
- package/lib/components/droparea/index.js +1 -0
- package/lib/components/droparea/styles/index.js +5 -1
- package/lib/components/emit/components/emit.js +34 -4
- package/lib/components/emit/components/emit.test.js +192 -134
- 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/item.test.js +69 -68
- package/lib/components/list/components/list.js +51 -7
- package/lib/components/list/components/list.test.js +358 -227
- package/lib/components/list/index.js +1 -0
- package/lib/components/paginator/components/paginator.js +34 -8
- package/lib/components/paginator/components/paginator.test.js +146 -143
- 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/components/spinner.test.js +36 -41
- 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.detail.test.js +75 -73
- package/lib/components/splitview/components/splitview.js +54 -11
- package/lib/components/splitview/components/splitview.master.js +37 -2
- package/lib/components/splitview/components/splitview.master.test.js +52 -52
- package/lib/components/splitview/components/splitview.test.js +135 -31
- package/lib/components/splitview/index.js +1 -0
- package/lib/components/translate/components/translate.js +65 -14
- package/lib/components/translate/components/translate.test.js +658 -131
- package/lib/components/translate/index.js +1 -0
- package/lib/index.js +3 -0
- package/package.json +4 -27
- package/scripts/node-test-setup.js +94 -0
- 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
|
@@ -1,20 +1,43 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
|
|
3
|
+
const stylesheetRegistry = new Map()
|
|
4
|
+
const fallbackRegistry = new Map()
|
|
5
|
+
|
|
3
6
|
/** @param {string} tag
|
|
4
7
|
* @param {CustomElementConstructor} element
|
|
5
|
-
* @param {string} styles
|
|
8
|
+
* @param {string} [styles]
|
|
9
|
+
* @returns {CSSStyleSheet|HTMLStyleElement|undefined} */
|
|
6
10
|
export function define (tag, element, styles = '') {
|
|
7
|
-
globalThis.customElements.
|
|
11
|
+
const definedElement = globalThis.customElements.get(tag)
|
|
12
|
+
if (!definedElement) {
|
|
13
|
+
globalThis.customElements.define(tag, element)
|
|
14
|
+
}
|
|
8
15
|
if (!styles?.trim()) return
|
|
16
|
+
if (typeof document === 'undefined') return
|
|
9
17
|
|
|
10
18
|
try {
|
|
11
|
-
|
|
19
|
+
let sheet = stylesheetRegistry.get(tag)
|
|
20
|
+
if (!sheet) {
|
|
21
|
+
sheet = new globalThis.CSSStyleSheet()
|
|
22
|
+
stylesheetRegistry.set(tag, sheet)
|
|
23
|
+
}
|
|
12
24
|
sheet.replaceSync(styles)
|
|
13
|
-
|
|
14
|
-
|
|
25
|
+
|
|
26
|
+
const adopted = document.adoptedStyleSheets || []
|
|
27
|
+
if (!adopted.includes(sheet)) {
|
|
28
|
+
document.adoptedStyleSheets = [...adopted, sheet]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return sheet
|
|
15
32
|
} catch (error) {
|
|
16
|
-
|
|
33
|
+
let style = fallbackRegistry.get(tag)
|
|
34
|
+
if (!style) {
|
|
35
|
+
style = document.createElement('style')
|
|
36
|
+
style.setAttribute('data-componark-tag', tag)
|
|
37
|
+
fallbackRegistry.set(tag, style)
|
|
38
|
+
document.head.appendChild(style)
|
|
39
|
+
}
|
|
17
40
|
style.textContent = styles
|
|
18
|
-
|
|
41
|
+
return style
|
|
19
42
|
}
|
|
20
43
|
}
|
|
@@ -1,62 +1,149 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { it, mock } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
2
3
|
import { define } from './define.js'
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
define('new-element', NewElement)
|
|
5
|
+
it('can define a custome element', () => {
|
|
6
|
+
class NewElement extends globalThis.HTMLElement {}
|
|
7
|
+
define('new-element', NewElement)
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
const newElement = document.createElement('new-element')
|
|
10
|
+
assert.ok(newElement)
|
|
11
|
+
})
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
13
|
+
it('can define a custom element using constructable CSSStyleSheet', () => {
|
|
14
|
+
let definedStyles = null
|
|
15
|
+
class MockCSSStyleSheet extends globalThis.CSSStyleSheet {
|
|
16
|
+
replaceSync (styles) {
|
|
17
|
+
definedStyles = styles
|
|
19
18
|
}
|
|
19
|
+
}
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
body {
|
|
27
|
-
color: red;
|
|
21
|
+
const cssStyleSheetSpy = mock.method(
|
|
22
|
+
globalThis,
|
|
23
|
+
'CSSStyleSheet',
|
|
24
|
+
function () {
|
|
25
|
+
return new MockCSSStyleSheet()
|
|
28
26
|
}
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
class CSSStyledElement extends globalThis.HTMLElement {}
|
|
30
|
+
const styles = `
|
|
31
|
+
body {
|
|
32
|
+
color: red;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
div {
|
|
36
|
+
margin: 5px;
|
|
37
|
+
}
|
|
38
|
+
`
|
|
39
|
+
|
|
40
|
+
define('css-styled-element', CSSStyledElement, styles)
|
|
29
41
|
|
|
30
|
-
|
|
31
|
-
|
|
42
|
+
const styledElement = document.createElement('css-styled-element')
|
|
43
|
+
assert.ok(styledElement)
|
|
44
|
+
|
|
45
|
+
assert.deepStrictEqual(styles, definedStyles)
|
|
46
|
+
cssStyleSheetSpy.mock.restore()
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('can define a custom element using an style fallback element', () => {
|
|
50
|
+
const cssStyleSheetSpy = mock.method(
|
|
51
|
+
globalThis,
|
|
52
|
+
'CSSStyleSheet',
|
|
53
|
+
function () {
|
|
54
|
+
throw new Error('Constructable stylesheets are unavailable')
|
|
32
55
|
}
|
|
33
|
-
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
class StyledElement extends globalThis.HTMLElement {}
|
|
59
|
+
const styles = `
|
|
60
|
+
body {
|
|
61
|
+
color: red;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
div {
|
|
65
|
+
margin: 5px;
|
|
66
|
+
}
|
|
67
|
+
`
|
|
68
|
+
|
|
69
|
+
define('styled-element', StyledElement, styles)
|
|
70
|
+
cssStyleSheetSpy.mock.restore()
|
|
34
71
|
|
|
35
|
-
|
|
72
|
+
const styledElement = document.createElement('styled-element')
|
|
73
|
+
assert.ok(styledElement)
|
|
74
|
+
const style = Array.from(document.head.querySelectorAll('style')).find(
|
|
75
|
+
(item) => item.textContent.includes('color: red;')
|
|
76
|
+
)
|
|
77
|
+
assert.ok(style)
|
|
78
|
+
})
|
|
36
79
|
|
|
37
|
-
|
|
38
|
-
|
|
80
|
+
it('does not throw when defining an already defined custom element', () => {
|
|
81
|
+
class DuplicateElement extends globalThis.HTMLElement {}
|
|
82
|
+
define('duplicate-element', DuplicateElement)
|
|
39
83
|
|
|
40
|
-
|
|
84
|
+
assert.doesNotThrow(() => {
|
|
85
|
+
define('duplicate-element', DuplicateElement)
|
|
41
86
|
})
|
|
87
|
+
})
|
|
42
88
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
89
|
+
it('reuses fallback styles for repeated definitions of the same tag', () => {
|
|
90
|
+
const cssStyleSheetSpy = mock.method(
|
|
91
|
+
globalThis,
|
|
92
|
+
'CSSStyleSheet',
|
|
93
|
+
function () {
|
|
94
|
+
throw new Error('Constructable stylesheets are unavailable')
|
|
48
95
|
}
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
class ReusedStyledElement extends globalThis.HTMLElement {}
|
|
99
|
+
|
|
100
|
+
define('reused-styled-element', ReusedStyledElement, 'body { color: red; }')
|
|
101
|
+
define('reused-styled-element', ReusedStyledElement, 'body { color: blue; }')
|
|
102
|
+
|
|
103
|
+
cssStyleSheetSpy.mock.restore()
|
|
104
|
+
|
|
105
|
+
const styles = Array.from(
|
|
106
|
+
document.head.querySelectorAll('style[data-componark-tag="reused-styled-element"]')
|
|
107
|
+
)
|
|
108
|
+
assert.deepStrictEqual(styles.length, 1)
|
|
109
|
+
assert.ok(styles[0].textContent.includes('color: blue;'))
|
|
110
|
+
})
|
|
49
111
|
|
|
50
|
-
|
|
51
|
-
|
|
112
|
+
it('does not add a constructable stylesheet more than once for the same tag', () => {
|
|
113
|
+
class MockCSSStyleSheet extends globalThis.CSSStyleSheet {
|
|
114
|
+
replaceSync (_styles) {}
|
|
115
|
+
}
|
|
116
|
+
const cssStyleSheetSpy = mock.method(
|
|
117
|
+
globalThis,
|
|
118
|
+
'CSSStyleSheet',
|
|
119
|
+
function () {
|
|
120
|
+
return new MockCSSStyleSheet()
|
|
52
121
|
}
|
|
53
|
-
|
|
122
|
+
)
|
|
123
|
+
class OnceStyledElement extends globalThis.HTMLElement {}
|
|
54
124
|
|
|
55
|
-
|
|
125
|
+
const beforeCount = document.adoptedStyleSheets.length
|
|
126
|
+
define('once-styled-element', OnceStyledElement, 'body { color: orange; }')
|
|
127
|
+
const firstCount = document.adoptedStyleSheets.length
|
|
128
|
+
define('once-styled-element', OnceStyledElement, 'body { color: green; }')
|
|
129
|
+
const secondCount = document.adoptedStyleSheets.length
|
|
56
130
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
131
|
+
cssStyleSheetSpy.mock.restore()
|
|
132
|
+
assert.deepStrictEqual(firstCount, beforeCount + 1)
|
|
133
|
+
assert.deepStrictEqual(secondCount, firstCount)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it('returns early when styles are provided but document is unavailable', () => {
|
|
137
|
+
const previousDocument = globalThis.document
|
|
138
|
+
class NoDocumentElement extends globalThis.HTMLElement {}
|
|
139
|
+
|
|
140
|
+
delete globalThis.document
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
assert.doesNotThrow(() => {
|
|
144
|
+
define('no-document-element', NoDocumentElement, 'body { color: red; }')
|
|
145
|
+
})
|
|
146
|
+
} finally {
|
|
147
|
+
globalThis.document = previousDocument
|
|
148
|
+
}
|
|
62
149
|
})
|
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,19 +1,19 @@
|
|
|
1
|
+
import { it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
1
3
|
import { camelToKebab, kebabToCamel, snakeToCamel } from './format.js'
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
expect(camel).toBe('myVariable')
|
|
18
|
-
})
|
|
5
|
+
it('can convert camel to kebab', () => {
|
|
6
|
+
const camel = 'myVariable'
|
|
7
|
+
const kebab = camelToKebab(camel)
|
|
8
|
+
assert.strictEqual(kebab, 'my-variable')
|
|
9
|
+
})
|
|
10
|
+
it('can convert kebab to camel', () => {
|
|
11
|
+
const kebab = 'my-variable'
|
|
12
|
+
const camel = kebabToCamel(kebab)
|
|
13
|
+
assert.strictEqual(camel, 'myVariable')
|
|
14
|
+
})
|
|
15
|
+
it('can convert snake to camel', () => {
|
|
16
|
+
const kebab = 'my_variable'
|
|
17
|
+
const camel = snakeToCamel(kebab)
|
|
18
|
+
assert.strictEqual(camel, 'myVariable')
|
|
19
19
|
})
|
|
@@ -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
|
|
@@ -25,8 +32,11 @@ export function listen (self) {
|
|
|
25
32
|
if (pipe?.toLocaleLowerCase() === 'object') {
|
|
26
33
|
return set(this, objectPath.trim(), event.detail)
|
|
27
34
|
}
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
const inputValue = (
|
|
36
|
+
get(event, eventPath, undefined) ||
|
|
37
|
+
get(event, 'detail', '')
|
|
38
|
+
)
|
|
39
|
+
set(this, objectPath.trim(), transform(pipe, inputValue))
|
|
30
40
|
}
|
|
31
41
|
}
|
|
32
42
|
|
|
@@ -59,7 +69,11 @@ export function listen (self) {
|
|
|
59
69
|
}
|
|
60
70
|
}
|
|
61
71
|
|
|
62
|
-
/**
|
|
72
|
+
/**
|
|
73
|
+
* Resolve dependencies from descendants using `resolve` events.
|
|
74
|
+
* @param {Component|HTMLElement} self
|
|
75
|
+
* @returns {void}
|
|
76
|
+
*/
|
|
63
77
|
function provide (self) {
|
|
64
78
|
/** @ts-ignore */
|
|
65
79
|
if (!self.provide) return
|
|
@@ -99,9 +113,16 @@ function transform (pipe, value) {
|
|
|
99
113
|
}[pipe?.toLowerCase() || 'string'](value)
|
|
100
114
|
}
|
|
101
115
|
|
|
102
|
-
/**
|
|
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
|
+
*/
|
|
103
123
|
export function set (object, path, value) {
|
|
104
124
|
const pathArray = path.match(/([^[.\]])+/g)
|
|
125
|
+
if (!pathArray?.length) return
|
|
105
126
|
|
|
106
127
|
pathArray.reduce((accumulator, key, index) => {
|
|
107
128
|
if (accumulator[key.trim()] === undefined) accumulator[key.trim()] = {}
|
|
@@ -110,15 +131,27 @@ export function set (object, path, value) {
|
|
|
110
131
|
}, object)
|
|
111
132
|
}
|
|
112
133
|
|
|
113
|
-
/**
|
|
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
|
+
*/
|
|
114
141
|
export function get (object, path, fallback) {
|
|
115
142
|
const pathArray = path.match(/([^[.\]])+/g)
|
|
143
|
+
if (!pathArray?.length) return fallback
|
|
116
144
|
|
|
117
|
-
|
|
118
|
-
accumulator[key.trim()], object)
|
|
145
|
+
const value = pathArray.reduce((accumulator, key) => accumulator &&
|
|
146
|
+
accumulator[key.trim()], object)
|
|
147
|
+
|
|
148
|
+
return value === undefined ? fallback : value
|
|
119
149
|
}
|
|
120
150
|
|
|
121
|
-
/** @param {object} object
|
|
151
|
+
/** @param {object} object
|
|
152
|
+
* @return {string}
|
|
153
|
+
* @description Returns truthy CSS class names from object values.
|
|
154
|
+
*/
|
|
122
155
|
export function keys (object) {
|
|
123
156
|
return Object.keys(object).filter(
|
|
124
157
|
key => Boolean(object[key])).join(' ')
|