@pyreon/attrs 0.11.4 → 0.11.6
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 +18 -13
- package/package.json +22 -22
- package/src/__tests__/attrs.test.ts +177 -177
- package/src/__tests__/attrsHoc.test.ts +39 -39
- package/src/__tests__/utils.test.ts +69 -69
- package/src/attrs.ts +13 -13
- package/src/hoc/attrsHoc.ts +4 -4
- package/src/hoc/index.ts +1 -1
- package/src/index.ts +9 -9
- package/src/init.ts +7 -7
- package/src/isAttrsComponent.ts +2 -2
- package/src/types/AttrsComponent.ts +6 -6
- package/src/types/InitAttrsComponent.ts +3 -3
- package/src/types/config.ts +1 -1
- package/src/types/configuration.ts +1 -1
- package/src/types/hoc.ts +1 -1
- package/src/types/utils.ts +1 -1
- package/src/utils/attrs.ts +1 -1
- package/src/utils/chaining.ts +2 -2
- package/src/utils/compose.ts +1 -1
- package/src/utils/statics.ts +1 -1
|
@@ -1,98 +1,98 @@
|
|
|
1
|
-
import createAttrsHOC from
|
|
1
|
+
import createAttrsHOC from '../hoc/attrsHoc'
|
|
2
2
|
|
|
3
3
|
const Receiver = (props: any) => ({
|
|
4
|
-
type:
|
|
5
|
-
props: { ...props,
|
|
6
|
-
children: props.label ??
|
|
4
|
+
type: 'div',
|
|
5
|
+
props: { ...props, 'data-testid': 'receiver' },
|
|
6
|
+
children: props.label ?? '',
|
|
7
7
|
key: null,
|
|
8
8
|
})
|
|
9
9
|
|
|
10
10
|
// --------------------------------------------------------
|
|
11
11
|
// attrsHoc - props merging
|
|
12
12
|
// --------------------------------------------------------
|
|
13
|
-
describe(
|
|
14
|
-
it(
|
|
13
|
+
describe('attrsHoc - props merging', () => {
|
|
14
|
+
it('should pass through props unchanged when no attrs defined', () => {
|
|
15
15
|
const hoc = createAttrsHOC({ attrs: [], priorityAttrs: [] })
|
|
16
16
|
const Enhanced = hoc(Receiver)
|
|
17
17
|
|
|
18
|
-
const result = Enhanced({ label:
|
|
19
|
-
expect(result.children).toBe(
|
|
20
|
-
expect(result.props[
|
|
18
|
+
const result = Enhanced({ label: 'hello', 'data-custom': 'yes' }) as any
|
|
19
|
+
expect(result.children).toBe('hello')
|
|
20
|
+
expect(result.props['data-custom']).toBe('yes')
|
|
21
21
|
})
|
|
22
22
|
|
|
23
|
-
it(
|
|
23
|
+
it('should apply attrs as default props', () => {
|
|
24
24
|
const hoc = createAttrsHOC({
|
|
25
|
-
attrs: [(_props: any) => ({ label:
|
|
25
|
+
attrs: [(_props: any) => ({ label: 'default' })],
|
|
26
26
|
priorityAttrs: [],
|
|
27
27
|
})
|
|
28
28
|
const Enhanced = hoc(Receiver)
|
|
29
29
|
|
|
30
30
|
const result = Enhanced({}) as any
|
|
31
|
-
expect(result.children).toBe(
|
|
31
|
+
expect(result.children).toBe('default')
|
|
32
32
|
})
|
|
33
33
|
|
|
34
|
-
it(
|
|
34
|
+
it('should let explicit props override attrs', () => {
|
|
35
35
|
const hoc = createAttrsHOC({
|
|
36
|
-
attrs: [() => ({ label:
|
|
36
|
+
attrs: [() => ({ label: 'from-attrs' })],
|
|
37
37
|
priorityAttrs: [],
|
|
38
38
|
})
|
|
39
39
|
const Enhanced = hoc(Receiver)
|
|
40
40
|
|
|
41
|
-
const result = Enhanced({ label:
|
|
42
|
-
expect(result.children).toBe(
|
|
41
|
+
const result = Enhanced({ label: 'explicit' }) as any
|
|
42
|
+
expect(result.children).toBe('explicit')
|
|
43
43
|
})
|
|
44
44
|
|
|
45
|
-
it(
|
|
45
|
+
it('should apply priorityAttrs with lowest precedence', () => {
|
|
46
46
|
const hoc = createAttrsHOC({
|
|
47
|
-
attrs: [(_props: any) => ({ label:
|
|
48
|
-
priorityAttrs: [(_props: any) => ({ label:
|
|
47
|
+
attrs: [(_props: any) => ({ label: 'from-attrs' })],
|
|
48
|
+
priorityAttrs: [(_props: any) => ({ label: 'from-priority' })],
|
|
49
49
|
})
|
|
50
50
|
const Enhanced = hoc(Receiver)
|
|
51
51
|
|
|
52
52
|
const result = Enhanced({}) as any
|
|
53
|
-
expect(result.children).toBe(
|
|
53
|
+
expect(result.children).toBe('from-attrs')
|
|
54
54
|
})
|
|
55
55
|
|
|
56
|
-
it(
|
|
56
|
+
it('should merge results from multiple attrs functions', () => {
|
|
57
57
|
const hoc = createAttrsHOC({
|
|
58
|
-
attrs: [() => ({
|
|
58
|
+
attrs: [() => ({ 'data-first': 'a' }), () => ({ 'data-second': 'b' })],
|
|
59
59
|
priorityAttrs: [],
|
|
60
60
|
})
|
|
61
61
|
const Enhanced = hoc(Receiver)
|
|
62
62
|
|
|
63
63
|
const result = Enhanced({}) as any
|
|
64
|
-
expect(result.props[
|
|
65
|
-
expect(result.props[
|
|
64
|
+
expect(result.props['data-first']).toBe('a')
|
|
65
|
+
expect(result.props['data-second']).toBe('b')
|
|
66
66
|
})
|
|
67
67
|
|
|
68
|
-
it(
|
|
68
|
+
it('should remove undefined props so they dont override defaults', () => {
|
|
69
69
|
const hoc = createAttrsHOC({
|
|
70
|
-
attrs: [() => ({ label:
|
|
70
|
+
attrs: [() => ({ label: 'default-label' })],
|
|
71
71
|
priorityAttrs: [],
|
|
72
72
|
})
|
|
73
73
|
const Enhanced = hoc(Receiver)
|
|
74
74
|
|
|
75
75
|
const result = Enhanced({ label: undefined }) as any
|
|
76
|
-
expect(result.children).toBe(
|
|
76
|
+
expect(result.children).toBe('default-label')
|
|
77
77
|
})
|
|
78
78
|
|
|
79
|
-
it(
|
|
79
|
+
it('should allow null to override defaults', () => {
|
|
80
80
|
const hoc = createAttrsHOC({
|
|
81
|
-
attrs: [() => ({ label:
|
|
81
|
+
attrs: [() => ({ label: 'default-label' })],
|
|
82
82
|
priorityAttrs: [],
|
|
83
83
|
})
|
|
84
84
|
const Enhanced = hoc(Receiver)
|
|
85
85
|
|
|
86
86
|
const result = Enhanced({ label: null }) as any
|
|
87
|
-
expect(result.children).toBe(
|
|
87
|
+
expect(result.children).toBe('')
|
|
88
88
|
})
|
|
89
89
|
})
|
|
90
90
|
|
|
91
91
|
// --------------------------------------------------------
|
|
92
92
|
// attrsHoc - attrs callback receives props
|
|
93
93
|
// --------------------------------------------------------
|
|
94
|
-
describe(
|
|
95
|
-
it(
|
|
94
|
+
describe('attrsHoc - attrs callback receives props', () => {
|
|
95
|
+
it('should pass filtered props to attrs callback', () => {
|
|
96
96
|
const attrsFn = vi.fn(() => ({}))
|
|
97
97
|
const hoc = createAttrsHOC({
|
|
98
98
|
attrs: [attrsFn],
|
|
@@ -100,13 +100,13 @@ describe("attrsHoc - attrs callback receives props", () => {
|
|
|
100
100
|
})
|
|
101
101
|
const Enhanced = hoc(Receiver)
|
|
102
102
|
|
|
103
|
-
Enhanced({ variant:
|
|
103
|
+
Enhanced({ variant: 'primary', size: 'lg' })
|
|
104
104
|
expect(attrsFn).toHaveBeenCalledWith(
|
|
105
|
-
expect.objectContaining({ variant:
|
|
105
|
+
expect.objectContaining({ variant: 'primary', size: 'lg' }),
|
|
106
106
|
)
|
|
107
107
|
})
|
|
108
108
|
|
|
109
|
-
it(
|
|
109
|
+
it('should pass priority attrs merged with props to attrs callback', () => {
|
|
110
110
|
const attrsFn = vi.fn(() => ({}))
|
|
111
111
|
const hoc = createAttrsHOC({
|
|
112
112
|
attrs: [attrsFn],
|
|
@@ -114,9 +114,9 @@ describe("attrsHoc - attrs callback receives props", () => {
|
|
|
114
114
|
})
|
|
115
115
|
const Enhanced = hoc(Receiver)
|
|
116
116
|
|
|
117
|
-
Enhanced({ variant:
|
|
117
|
+
Enhanced({ variant: 'primary' })
|
|
118
118
|
expect(attrsFn).toHaveBeenCalledWith(
|
|
119
|
-
expect.objectContaining({ variant:
|
|
119
|
+
expect.objectContaining({ variant: 'primary', fromPriority: true }),
|
|
120
120
|
)
|
|
121
121
|
})
|
|
122
122
|
})
|
|
@@ -124,8 +124,8 @@ describe("attrsHoc - attrs callback receives props", () => {
|
|
|
124
124
|
// --------------------------------------------------------
|
|
125
125
|
// attrsHoc - ref passthrough
|
|
126
126
|
// --------------------------------------------------------
|
|
127
|
-
describe(
|
|
128
|
-
it(
|
|
127
|
+
describe('attrsHoc - ref passthrough', () => {
|
|
128
|
+
it('should pass ref as a normal prop to wrapped component', () => {
|
|
129
129
|
const hoc = createAttrsHOC({ attrs: [], priorityAttrs: [] })
|
|
130
130
|
const Enhanced = hoc(Receiver)
|
|
131
131
|
|
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
import { calculateChainOptions, removeUndefinedProps } from
|
|
2
|
-
import { chainOptions } from
|
|
3
|
-
import { removeNullableValues } from
|
|
4
|
-
import { calculateHocsFuncs } from
|
|
5
|
-
import { createStaticsEnhancers } from
|
|
1
|
+
import { calculateChainOptions, removeUndefinedProps } from '../utils/attrs'
|
|
2
|
+
import { chainOptions } from '../utils/chaining'
|
|
3
|
+
import { removeNullableValues } from '../utils/collection'
|
|
4
|
+
import { calculateHocsFuncs } from '../utils/compose'
|
|
5
|
+
import { createStaticsEnhancers } from '../utils/statics'
|
|
6
6
|
|
|
7
7
|
// --------------------------------------------------------
|
|
8
8
|
// removeUndefinedProps
|
|
9
9
|
// --------------------------------------------------------
|
|
10
|
-
describe(
|
|
11
|
-
it(
|
|
10
|
+
describe('removeUndefinedProps', () => {
|
|
11
|
+
it('should remove properties with undefined values', () => {
|
|
12
12
|
const result = removeUndefinedProps({
|
|
13
13
|
a: 1,
|
|
14
14
|
b: undefined,
|
|
15
|
-
c:
|
|
15
|
+
c: 'hello',
|
|
16
16
|
})
|
|
17
|
-
expect(result).toEqual({ a: 1, c:
|
|
17
|
+
expect(result).toEqual({ a: 1, c: 'hello' })
|
|
18
18
|
})
|
|
19
19
|
|
|
20
|
-
it(
|
|
20
|
+
it('should keep null values', () => {
|
|
21
21
|
const result = removeUndefinedProps({ a: null, b: undefined })
|
|
22
22
|
expect(result).toEqual({ a: null })
|
|
23
23
|
})
|
|
24
24
|
|
|
25
|
-
it(
|
|
25
|
+
it('should keep false values', () => {
|
|
26
26
|
const result = removeUndefinedProps({ a: false, b: undefined })
|
|
27
27
|
expect(result).toEqual({ a: false })
|
|
28
28
|
})
|
|
29
29
|
|
|
30
|
-
it(
|
|
30
|
+
it('should keep zero values', () => {
|
|
31
31
|
const result = removeUndefinedProps({ a: 0, b: undefined })
|
|
32
32
|
expect(result).toEqual({ a: 0 })
|
|
33
33
|
})
|
|
34
34
|
|
|
35
|
-
it(
|
|
36
|
-
const result = removeUndefinedProps({ a:
|
|
37
|
-
expect(result).toEqual({ a:
|
|
35
|
+
it('should keep empty string values', () => {
|
|
36
|
+
const result = removeUndefinedProps({ a: '', b: undefined })
|
|
37
|
+
expect(result).toEqual({ a: '' })
|
|
38
38
|
})
|
|
39
39
|
|
|
40
|
-
it(
|
|
40
|
+
it('should return empty object when all values are undefined', () => {
|
|
41
41
|
const result = removeUndefinedProps({ a: undefined, b: undefined })
|
|
42
42
|
expect(result).toEqual({})
|
|
43
43
|
})
|
|
44
44
|
|
|
45
|
-
it(
|
|
46
|
-
const input = { a: 1, b:
|
|
45
|
+
it('should return all props when none are undefined', () => {
|
|
46
|
+
const input = { a: 1, b: 'test', c: true }
|
|
47
47
|
const result = removeUndefinedProps(input)
|
|
48
48
|
expect(result).toEqual(input)
|
|
49
49
|
})
|
|
50
50
|
|
|
51
|
-
it(
|
|
51
|
+
it('should handle empty object', () => {
|
|
52
52
|
const result = removeUndefinedProps({})
|
|
53
53
|
expect(result).toEqual({})
|
|
54
54
|
})
|
|
@@ -57,38 +57,38 @@ describe("removeUndefinedProps", () => {
|
|
|
57
57
|
// --------------------------------------------------------
|
|
58
58
|
// removeNullableValues
|
|
59
59
|
// --------------------------------------------------------
|
|
60
|
-
describe(
|
|
61
|
-
it(
|
|
60
|
+
describe('removeNullableValues', () => {
|
|
61
|
+
it('should remove null values', () => {
|
|
62
62
|
const result = removeNullableValues({ a: 1, b: null })
|
|
63
63
|
expect(result).toEqual({ a: 1 })
|
|
64
64
|
})
|
|
65
65
|
|
|
66
|
-
it(
|
|
66
|
+
it('should remove undefined values', () => {
|
|
67
67
|
const result = removeNullableValues({ a: 1, b: undefined })
|
|
68
68
|
expect(result).toEqual({ a: 1 })
|
|
69
69
|
})
|
|
70
70
|
|
|
71
|
-
it(
|
|
71
|
+
it('should remove false values', () => {
|
|
72
72
|
const result = removeNullableValues({ a: 1, b: false })
|
|
73
73
|
expect(result).toEqual({ a: 1 })
|
|
74
74
|
})
|
|
75
75
|
|
|
76
|
-
it(
|
|
76
|
+
it('should keep zero values', () => {
|
|
77
77
|
const result = removeNullableValues({ a: 0, b: null })
|
|
78
78
|
expect(result).toEqual({ a: 0 })
|
|
79
79
|
})
|
|
80
80
|
|
|
81
|
-
it(
|
|
82
|
-
const result = removeNullableValues({ a:
|
|
83
|
-
expect(result).toEqual({ a:
|
|
81
|
+
it('should keep empty string values', () => {
|
|
82
|
+
const result = removeNullableValues({ a: '', b: null })
|
|
83
|
+
expect(result).toEqual({ a: '' })
|
|
84
84
|
})
|
|
85
85
|
|
|
86
|
-
it(
|
|
87
|
-
const result = removeNullableValues({ a: 1, b:
|
|
88
|
-
expect(result).toEqual({ a: 1, b:
|
|
86
|
+
it('should keep truthy values', () => {
|
|
87
|
+
const result = removeNullableValues({ a: 1, b: 'test', c: true })
|
|
88
|
+
expect(result).toEqual({ a: 1, b: 'test', c: true })
|
|
89
89
|
})
|
|
90
90
|
|
|
91
|
-
it(
|
|
91
|
+
it('should handle empty object', () => {
|
|
92
92
|
const result = removeNullableValues({})
|
|
93
93
|
expect(result).toEqual({})
|
|
94
94
|
})
|
|
@@ -97,48 +97,48 @@ describe("removeNullableValues", () => {
|
|
|
97
97
|
// --------------------------------------------------------
|
|
98
98
|
// calculateChainOptions
|
|
99
99
|
// --------------------------------------------------------
|
|
100
|
-
describe(
|
|
101
|
-
it(
|
|
100
|
+
describe('calculateChainOptions', () => {
|
|
101
|
+
it('should return empty object when no options provided', () => {
|
|
102
102
|
const calculate = calculateChainOptions(undefined)
|
|
103
103
|
const result = calculate([{}])
|
|
104
104
|
expect(result).toEqual({})
|
|
105
105
|
})
|
|
106
106
|
|
|
107
|
-
it(
|
|
107
|
+
it('should return empty object for empty options array', () => {
|
|
108
108
|
const calculate = calculateChainOptions([])
|
|
109
109
|
const result = calculate([{}])
|
|
110
110
|
expect(result).toEqual({})
|
|
111
111
|
})
|
|
112
112
|
|
|
113
|
-
it(
|
|
113
|
+
it('should execute a single option function', () => {
|
|
114
114
|
const fn = (props: any) => ({
|
|
115
|
-
color: props.variant ===
|
|
115
|
+
color: props.variant === 'primary' ? 'blue' : 'gray',
|
|
116
116
|
})
|
|
117
117
|
const calculate = calculateChainOptions([fn])
|
|
118
|
-
const result = calculate([{ variant:
|
|
119
|
-
expect(result).toEqual({ color:
|
|
118
|
+
const result = calculate([{ variant: 'primary' }])
|
|
119
|
+
expect(result).toEqual({ color: 'blue' })
|
|
120
120
|
})
|
|
121
121
|
|
|
122
|
-
it(
|
|
123
|
-
const fn1 = (_: any) => ({ color:
|
|
124
|
-
const fn2 = (_: any) => ({ size:
|
|
122
|
+
it('should merge results from multiple option functions', () => {
|
|
123
|
+
const fn1 = (_: any) => ({ color: 'blue' })
|
|
124
|
+
const fn2 = (_: any) => ({ size: 'large' })
|
|
125
125
|
const calculate = calculateChainOptions([fn1, fn2])
|
|
126
126
|
const result = calculate([{}])
|
|
127
|
-
expect(result).toEqual({ color:
|
|
127
|
+
expect(result).toEqual({ color: 'blue', size: 'large' })
|
|
128
128
|
})
|
|
129
129
|
|
|
130
|
-
it(
|
|
131
|
-
const fn1 = (_: any) => ({ color:
|
|
132
|
-
const fn2 = (_: any) => ({ color:
|
|
130
|
+
it('should let later functions override earlier ones', () => {
|
|
131
|
+
const fn1 = (_: any) => ({ color: 'blue' })
|
|
132
|
+
const fn2 = (_: any) => ({ color: 'red' })
|
|
133
133
|
const calculate = calculateChainOptions([fn1, fn2])
|
|
134
134
|
const result = calculate([{}])
|
|
135
|
-
expect(result).toEqual({ color:
|
|
135
|
+
expect(result).toEqual({ color: 'red' })
|
|
136
136
|
})
|
|
137
137
|
|
|
138
|
-
it(
|
|
138
|
+
it('should pass arguments to each option function', () => {
|
|
139
139
|
const fn = vi.fn((_: any) => ({}))
|
|
140
140
|
const calculate = calculateChainOptions([fn])
|
|
141
|
-
const props = { variant:
|
|
141
|
+
const props = { variant: 'primary' }
|
|
142
142
|
calculate([props])
|
|
143
143
|
expect(fn).toHaveBeenCalledWith(props)
|
|
144
144
|
})
|
|
@@ -147,14 +147,14 @@ describe("calculateChainOptions", () => {
|
|
|
147
147
|
// --------------------------------------------------------
|
|
148
148
|
// chainOptions
|
|
149
149
|
// --------------------------------------------------------
|
|
150
|
-
describe(
|
|
151
|
-
it(
|
|
150
|
+
describe('chainOptions', () => {
|
|
151
|
+
it('should return default options when opts is undefined', () => {
|
|
152
152
|
const defaults = [() => ({})]
|
|
153
153
|
const result = chainOptions(undefined, defaults)
|
|
154
154
|
expect(result).toEqual(defaults)
|
|
155
155
|
})
|
|
156
156
|
|
|
157
|
-
it(
|
|
157
|
+
it('should append function to defaults', () => {
|
|
158
158
|
const fn1 = () => ({ a: 1 })
|
|
159
159
|
const fn2 = () => ({ b: 2 })
|
|
160
160
|
const result = chainOptions(fn2, [fn1])
|
|
@@ -163,19 +163,19 @@ describe("chainOptions", () => {
|
|
|
163
163
|
expect(result[1]).toBe(fn2)
|
|
164
164
|
})
|
|
165
165
|
|
|
166
|
-
it(
|
|
167
|
-
const obj = { color:
|
|
166
|
+
it('should wrap object in a function and append', () => {
|
|
167
|
+
const obj = { color: 'blue' }
|
|
168
168
|
const result = chainOptions(obj, [])
|
|
169
169
|
expect(result).toHaveLength(1)
|
|
170
170
|
expect(result[0]?.()).toEqual(obj)
|
|
171
171
|
})
|
|
172
172
|
|
|
173
|
-
it(
|
|
173
|
+
it('should return empty array when no defaults and undefined opts', () => {
|
|
174
174
|
const result = chainOptions(undefined, [])
|
|
175
175
|
expect(result).toEqual([])
|
|
176
176
|
})
|
|
177
177
|
|
|
178
|
-
it(
|
|
178
|
+
it('should not mutate the defaults array', () => {
|
|
179
179
|
const defaults = [() => ({})]
|
|
180
180
|
const fn = () => ({ a: 1 })
|
|
181
181
|
const result = chainOptions(fn, defaults)
|
|
@@ -187,46 +187,46 @@ describe("chainOptions", () => {
|
|
|
187
187
|
// --------------------------------------------------------
|
|
188
188
|
// createStaticsEnhancers
|
|
189
189
|
// --------------------------------------------------------
|
|
190
|
-
describe(
|
|
191
|
-
it(
|
|
190
|
+
describe('createStaticsEnhancers', () => {
|
|
191
|
+
it('should assign options to context', () => {
|
|
192
192
|
const context: Record<string, any> = {}
|
|
193
193
|
createStaticsEnhancers({
|
|
194
194
|
context,
|
|
195
|
-
options: { theme:
|
|
195
|
+
options: { theme: 'dark', variant: 'primary' },
|
|
196
196
|
})
|
|
197
|
-
expect(context).toEqual({ theme:
|
|
197
|
+
expect(context).toEqual({ theme: 'dark', variant: 'primary' })
|
|
198
198
|
})
|
|
199
199
|
|
|
200
|
-
it(
|
|
200
|
+
it('should not modify context when options is empty', () => {
|
|
201
201
|
const context: Record<string, any> = { existing: true }
|
|
202
202
|
createStaticsEnhancers({ context, options: {} })
|
|
203
203
|
expect(context).toEqual({ existing: true })
|
|
204
204
|
})
|
|
205
205
|
|
|
206
|
-
it(
|
|
206
|
+
it('should merge with existing context properties', () => {
|
|
207
207
|
const context: Record<string, any> = { existing: true }
|
|
208
|
-
createStaticsEnhancers({ context, options: { newProp:
|
|
209
|
-
expect(context).toEqual({ existing: true, newProp:
|
|
208
|
+
createStaticsEnhancers({ context, options: { newProp: 'value' } })
|
|
209
|
+
expect(context).toEqual({ existing: true, newProp: 'value' })
|
|
210
210
|
})
|
|
211
211
|
})
|
|
212
212
|
|
|
213
213
|
// --------------------------------------------------------
|
|
214
214
|
// calculateHocsFuncs
|
|
215
215
|
// --------------------------------------------------------
|
|
216
|
-
describe(
|
|
217
|
-
it(
|
|
216
|
+
describe('calculateHocsFuncs', () => {
|
|
217
|
+
it('should return empty array for empty options', () => {
|
|
218
218
|
const result = calculateHocsFuncs({})
|
|
219
219
|
expect(result).toEqual([])
|
|
220
220
|
})
|
|
221
221
|
|
|
222
|
-
it(
|
|
222
|
+
it('should filter out non-function values', () => {
|
|
223
223
|
const fn = (x: any) => x
|
|
224
|
-
const result = calculateHocsFuncs({ a: fn, b:
|
|
224
|
+
const result = calculateHocsFuncs({ a: fn, b: 'string', c: 123 })
|
|
225
225
|
expect(result).toHaveLength(1)
|
|
226
226
|
expect(result[0]).toBe(fn)
|
|
227
227
|
})
|
|
228
228
|
|
|
229
|
-
it(
|
|
229
|
+
it('should reverse the order of functions', () => {
|
|
230
230
|
const fn1 = (x: any) => x
|
|
231
231
|
const fn2 = (x: any) => x
|
|
232
232
|
const result = calculateHocsFuncs({ a: fn1, b: fn2 })
|
|
@@ -234,7 +234,7 @@ describe("calculateHocsFuncs", () => {
|
|
|
234
234
|
expect(result[1]).toBe(fn1)
|
|
235
235
|
})
|
|
236
236
|
|
|
237
|
-
it(
|
|
237
|
+
it('should return empty array for undefined input', () => {
|
|
238
238
|
const result = calculateHocsFuncs(undefined as any)
|
|
239
239
|
expect(result).toEqual([])
|
|
240
240
|
})
|
package/src/attrs.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { compose, hoistNonReactStatics, omit, pick } from
|
|
2
|
-
import { attrsHoc } from
|
|
3
|
-
import type { AttrsComponent as AttrsComponentType } from
|
|
4
|
-
import type { Configuration, ExtendedConfiguration } from
|
|
5
|
-
import type { InitAttrsComponent } from
|
|
6
|
-
import { calculateChainOptions } from
|
|
7
|
-
import { chainOptions } from
|
|
8
|
-
import { calculateHocsFuncs } from
|
|
9
|
-
import { createStaticsEnhancers } from
|
|
1
|
+
import { compose, hoistNonReactStatics, omit, pick } from '@pyreon/ui-core'
|
|
2
|
+
import { attrsHoc } from './hoc'
|
|
3
|
+
import type { AttrsComponent as AttrsComponentType } from './types/AttrsComponent'
|
|
4
|
+
import type { Configuration, ExtendedConfiguration } from './types/configuration'
|
|
5
|
+
import type { InitAttrsComponent } from './types/InitAttrsComponent'
|
|
6
|
+
import { calculateChainOptions } from './utils/attrs'
|
|
7
|
+
import { chainOptions } from './utils/chaining'
|
|
8
|
+
import { calculateHocsFuncs } from './utils/compose'
|
|
9
|
+
import { createStaticsEnhancers } from './utils/statics'
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Clones the current configuration and merges new options, then creates a
|
|
@@ -62,8 +62,8 @@ const attrsComponent: InitAttrsComponent = (options) => {
|
|
|
62
62
|
const filteredProps = needsFiltering ? omit(props, options.filterAttrs) : props
|
|
63
63
|
|
|
64
64
|
const finalProps =
|
|
65
|
-
process.env.NODE_ENV !==
|
|
66
|
-
? { ...filteredProps,
|
|
65
|
+
process.env.NODE_ENV !== 'production'
|
|
66
|
+
? { ...filteredProps, 'data-attrs': componentName }
|
|
67
67
|
: filteredProps
|
|
68
68
|
|
|
69
69
|
return RenderComponent(finalProps)
|
|
@@ -97,12 +97,12 @@ const attrsComponent: InitAttrsComponent = (options) => {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
if (priority) {
|
|
100
|
-
result.priorityAttrs = attrs as ExtendedConfiguration[
|
|
100
|
+
result.priorityAttrs = attrs as ExtendedConfiguration['priorityAttrs']
|
|
101
101
|
|
|
102
102
|
return cloneAndEnhance(options, result)
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
result.attrs = attrs as ExtendedConfiguration[
|
|
105
|
+
result.attrs = attrs as ExtendedConfiguration['attrs']
|
|
106
106
|
|
|
107
107
|
return cloneAndEnhance(options, result)
|
|
108
108
|
},
|
package/src/hoc/attrsHoc.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { Configuration } from
|
|
2
|
-
import type { ComponentFn } from
|
|
3
|
-
import { calculateChainOptions, removeUndefinedProps } from
|
|
1
|
+
import type { Configuration } from '../types/configuration'
|
|
2
|
+
import type { ComponentFn } from '../types/utils'
|
|
3
|
+
import { calculateChainOptions, removeUndefinedProps } from '../utils/attrs'
|
|
4
4
|
|
|
5
5
|
export type AttrsStyleHOC = ({
|
|
6
6
|
attrs,
|
|
7
7
|
priorityAttrs,
|
|
8
|
-
}: Pick<Configuration,
|
|
8
|
+
}: Pick<Configuration, 'attrs' | 'priorityAttrs'>) => (
|
|
9
9
|
WrappedComponent: ComponentFn<any>,
|
|
10
10
|
) => ComponentFn<any>
|
|
11
11
|
|
package/src/hoc/index.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import type { Attrs } from
|
|
2
|
-
import attrs from
|
|
3
|
-
import type { IsAttrsComponent } from
|
|
4
|
-
import isAttrsComponent from
|
|
5
|
-
import type { AttrsComponent } from
|
|
6
|
-
import type { AttrsCb } from
|
|
7
|
-
import type { AttrsComponentType, ConfigAttrs } from
|
|
8
|
-
import type { ComposeParam, GenericHoc } from
|
|
9
|
-
import type { ComponentFn, ElementType, TObj } from
|
|
1
|
+
import type { Attrs } from './init'
|
|
2
|
+
import attrs from './init'
|
|
3
|
+
import type { IsAttrsComponent } from './isAttrsComponent'
|
|
4
|
+
import isAttrsComponent from './isAttrsComponent'
|
|
5
|
+
import type { AttrsComponent } from './types/AttrsComponent'
|
|
6
|
+
import type { AttrsCb } from './types/attrs'
|
|
7
|
+
import type { AttrsComponentType, ConfigAttrs } from './types/config'
|
|
8
|
+
import type { ComposeParam, GenericHoc } from './types/hoc'
|
|
9
|
+
import type { ComponentFn, ElementType, TObj } from './types/utils'
|
|
10
10
|
|
|
11
11
|
export type {
|
|
12
12
|
Attrs,
|
package/src/init.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { isEmpty } from
|
|
2
|
-
import attrsComponent from
|
|
3
|
-
import type { InitAttrsComponent } from
|
|
4
|
-
import type { ElementType } from
|
|
1
|
+
import { isEmpty } from '@pyreon/ui-core'
|
|
2
|
+
import attrsComponent from './attrs'
|
|
3
|
+
import type { InitAttrsComponent } from './types/InitAttrsComponent'
|
|
4
|
+
import type { ElementType } from './types/utils'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Public entry point for creating an attrs-enhanced component.
|
|
@@ -24,7 +24,7 @@ export type Attrs = <C extends ElementType>({
|
|
|
24
24
|
|
|
25
25
|
const attrs: Attrs = ({ name, component }) => {
|
|
26
26
|
// Validate required params in development — fail fast with clear errors.
|
|
27
|
-
if (process.env.NODE_ENV !==
|
|
27
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
28
28
|
type Errors = Partial<{
|
|
29
29
|
component: string
|
|
30
30
|
name: string
|
|
@@ -32,11 +32,11 @@ const attrs: Attrs = ({ name, component }) => {
|
|
|
32
32
|
|
|
33
33
|
const errors: Errors = {}
|
|
34
34
|
if (!component) {
|
|
35
|
-
errors.component =
|
|
35
|
+
errors.component = 'Parameter `component` is missing in params!'
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
if (!name) {
|
|
39
|
-
errors.name =
|
|
39
|
+
errors.name = 'Parameter `name` is missing in params!'
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
if (!isEmpty(errors)) {
|
package/src/isAttrsComponent.ts
CHANGED
|
@@ -4,8 +4,8 @@ export type IsAttrsComponent = <T>(component: T) => boolean
|
|
|
4
4
|
const isAttrsComponent: IsAttrsComponent = (component) => {
|
|
5
5
|
if (
|
|
6
6
|
component &&
|
|
7
|
-
(typeof component ===
|
|
8
|
-
Object.hasOwn(component as object,
|
|
7
|
+
(typeof component === 'object' || typeof component === 'function') &&
|
|
8
|
+
Object.hasOwn(component as object, 'IS_ATTRS')
|
|
9
9
|
) {
|
|
10
10
|
return true
|
|
11
11
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import type { VNode } from
|
|
2
|
-
import type { AttrsCb } from
|
|
3
|
-
import type { ConfigAttrs } from
|
|
4
|
-
import type { ComposeParam } from
|
|
5
|
-
import type { ElementType, ExtractProps, MergeTypes, TObj } from
|
|
1
|
+
import type { VNode } from '@pyreon/core'
|
|
2
|
+
import type { AttrsCb } from './attrs'
|
|
3
|
+
import type { ConfigAttrs } from './config'
|
|
4
|
+
import type { ComposeParam } from './hoc'
|
|
5
|
+
import type { ElementType, ExtractProps, MergeTypes, TObj } from './utils'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Props passed to the inner enhanced component.
|
|
9
9
|
* In Pyreon there's no forwardRef — ref flows as a normal prop.
|
|
10
10
|
*/
|
|
11
11
|
export type InnerComponentProps = {
|
|
12
|
-
|
|
12
|
+
'data-attrs'?: string | undefined
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
/**
|