@kitconcept/core 1.0.0-alpha.9 → 1.0.0-beta.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/.changelog.draft +3 -3
- package/CHANGELOG.md +142 -0
- package/package.json +14 -6
- package/src/config/slots.ts +19 -0
- package/src/helpers/BlocksConfigMerger.test.ts +98 -0
- package/src/helpers/BlocksConfigMerger.ts +42 -0
- package/src/index.ts +15 -1
- package/src/slots/ConfigInjector/ConfigInjector.tsx +32 -0
- package/src/slots/TTWCustomCSS/TTWCustomCSS.tsx +28 -0
- package/src/types.d.ts +22 -0
package/.changelog.draft
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,148 @@
|
|
|
8
8
|
|
|
9
9
|
<!-- towncrier release notes start -->
|
|
10
10
|
|
|
11
|
+
## 1.0.0-beta.1 (2025-09-26)
|
|
12
|
+
|
|
13
|
+
### Bugfix
|
|
14
|
+
|
|
15
|
+
- Update volto-authomatic to 3.0.0-alpha.6. @iFlameing
|
|
16
|
+
|
|
17
|
+
## 1.0.0-beta.0 (2025-09-25)
|
|
18
|
+
|
|
19
|
+
### Internal
|
|
20
|
+
|
|
21
|
+
- Use VLT 7.0.0 final. @sneridagh
|
|
22
|
+
|
|
23
|
+
## 1.0.0-alpha.31 (2025-09-24)
|
|
24
|
+
|
|
25
|
+
### Bugfix
|
|
26
|
+
|
|
27
|
+
- Update to @kitconcept/volto-light-theme 7.0.0-beta.7. @davisagli
|
|
28
|
+
|
|
29
|
+
## 1.0.0-alpha.30 (2025-09-18)
|
|
30
|
+
|
|
31
|
+
### Feature
|
|
32
|
+
|
|
33
|
+
- Transfer core features from intranet distribution to here: TTWCustomCSS and TTWBlocksConfig. @sneridagh [#53](https://github.com/kitconcept/kitconcept-core/issue/53)
|
|
34
|
+
|
|
35
|
+
### Bugfix
|
|
36
|
+
|
|
37
|
+
- Better buttons in slider add item. Refresh content button in slider. @sneridagh
|
|
38
|
+
|
|
39
|
+
## 1.0.0-alpha.29 (2025-09-17)
|
|
40
|
+
|
|
41
|
+
## 1.0.0-alpha.28 (2025-09-16)
|
|
42
|
+
|
|
43
|
+
### Bugfix
|
|
44
|
+
|
|
45
|
+
- Fixed theme CSS properties injection in add/edit view. Several CSS fixes. Use VLT 7b4 and plonegovbr/social-media 2.0.0a8. @sneridagh
|
|
46
|
+
|
|
47
|
+
## 1.0.0-alpha.27 (2025-09-15)
|
|
48
|
+
|
|
49
|
+
## 1.0.0-alpha.26 (2025-09-15)
|
|
50
|
+
|
|
51
|
+
## 1.0.0-alpha.25 (2025-09-12)
|
|
52
|
+
|
|
53
|
+
### Bugfix
|
|
54
|
+
|
|
55
|
+
- Update to @kitconcept/volto-light-theme 7.0.0-beta.2. @davisagli
|
|
56
|
+
- Update to Volto 18.26.0. @davisagli
|
|
57
|
+
|
|
58
|
+
## 1.0.0-alpha.24 (2025-09-12)
|
|
59
|
+
|
|
60
|
+
## 1.0.0-alpha.23 (2025-09-08)
|
|
61
|
+
|
|
62
|
+
### Bugfix
|
|
63
|
+
|
|
64
|
+
- Fixed slider flag position button in simple variant. Changed svg events calendar variant. Update VLT 7a28. @sneridagh
|
|
65
|
+
|
|
66
|
+
## 1.0.0-alpha.22 (2025-09-04)
|
|
67
|
+
|
|
68
|
+
### Bugfix
|
|
69
|
+
|
|
70
|
+
- Fix person grid teasers in edit mode. Update VLT 7a27. @sneridagh
|
|
71
|
+
|
|
72
|
+
## 1.0.0-alpha.21 (2025-09-03)
|
|
73
|
+
|
|
74
|
+
### Bugfix
|
|
75
|
+
|
|
76
|
+
- Fix image widget and new slider variant. Update to VLT 7a26. @sneridagh
|
|
77
|
+
|
|
78
|
+
## 1.0.0-alpha.20 (2025-09-03)
|
|
79
|
+
|
|
80
|
+
### Internal
|
|
81
|
+
|
|
82
|
+
- Due to a problem with the last release, re-releasing. @sneridagh
|
|
83
|
+
|
|
84
|
+
## 1.0.0-alpha.19 (2025-09-03)
|
|
85
|
+
|
|
86
|
+
### Feature
|
|
87
|
+
|
|
88
|
+
- Update to Volto 18.25.0 @sneridagh
|
|
89
|
+
|
|
90
|
+
## 1.0.0-alpha.18 (2025-09-01)
|
|
91
|
+
|
|
92
|
+
### Bugfix
|
|
93
|
+
|
|
94
|
+
- Several VLT bugfixes. Update to VLT 7a25. @sneridagh
|
|
95
|
+
|
|
96
|
+
## 1.0.0-alpha.17 (2025-08-26)
|
|
97
|
+
|
|
98
|
+
### Bugfix
|
|
99
|
+
|
|
100
|
+
- Fixed person images for search block. Update to VLT 7a24. @sneridagh
|
|
101
|
+
|
|
102
|
+
## 1.0.0-alpha.16 (2025-08-25)
|
|
103
|
+
|
|
104
|
+
### Feature
|
|
105
|
+
|
|
106
|
+
- Update to Volto 18.24.0 and VLT 7a23. @sneridagh [#36](https://github.com/kitconcept/kitconcept-core/issue/36)
|
|
107
|
+
|
|
108
|
+
## 1.0.0-alpha.15 (2025-07-25)
|
|
109
|
+
|
|
110
|
+
### Internal
|
|
111
|
+
|
|
112
|
+
- Update to VLT 7a19 @sneridagh
|
|
113
|
+
|
|
114
|
+
## 1.0.0-alpha.14 (2025-07-23)
|
|
115
|
+
|
|
116
|
+
### Internal
|
|
117
|
+
|
|
118
|
+
- Revert #31 @sneridagh [#32](https://github.com/kitconcept/kitconcept-core/issue/32)
|
|
119
|
+
- Update to VLT 7a18. @sneridagh
|
|
120
|
+
|
|
121
|
+
## 1.0.0-alpha.13 (2025-07-17)
|
|
122
|
+
|
|
123
|
+
### Internal
|
|
124
|
+
|
|
125
|
+
- Update VLT 7a15. @sneridagh
|
|
126
|
+
|
|
127
|
+
## 1.0.0-alpha.12 (2025-07-10)
|
|
128
|
+
|
|
129
|
+
### Internal
|
|
130
|
+
|
|
131
|
+
- Added new event calendar block.
|
|
132
|
+
Added `footer_main_logo_inversed` image field to kitconcept.footer behavior, and related frontend code.
|
|
133
|
+
Several fixes.
|
|
134
|
+
Update to VLT 7a14. @sneridagh
|
|
135
|
+
|
|
136
|
+
## 1.0.0-alpha.11 (2025-06-18)
|
|
137
|
+
|
|
138
|
+
### Bugfix
|
|
139
|
+
|
|
140
|
+
- Fixed default `selectedItemAttrs` for Teaser to include Person specific attributes. @sneridagh
|
|
141
|
+
Update to use VLT 7a13.
|
|
142
|
+
|
|
143
|
+
## 1.0.0-alpha.10 (2025-06-18)
|
|
144
|
+
|
|
145
|
+
### Feature
|
|
146
|
+
|
|
147
|
+
- Add `volto-carousel-block` and `volto-logos-block` as addons. @jnptk
|
|
148
|
+
|
|
149
|
+
### Internal
|
|
150
|
+
|
|
151
|
+
- Update to VLT 7a12. Fixes several CSS issues with persons variants. @sneridagh
|
|
152
|
+
|
|
11
153
|
## 1.0.0-alpha.9 (2025-06-13)
|
|
12
154
|
|
|
13
155
|
### Internal
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kitconcept/core",
|
|
3
|
-
"version": "1.0.0-
|
|
3
|
+
"version": "1.0.0-beta.1",
|
|
4
4
|
"description": "Core setup for kitconcept GmbH distributions built on top of Plone",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,9 +23,11 @@
|
|
|
23
23
|
"@eeacms/volto-accordion-block",
|
|
24
24
|
"@kitconcept/volto-banner-block",
|
|
25
25
|
"@kitconcept/volto-button-block",
|
|
26
|
+
"@kitconcept/volto-carousel-block",
|
|
26
27
|
"@kitconcept/volto-heading-block",
|
|
27
28
|
"@kitconcept/volto-highlight-block",
|
|
28
29
|
"@kitconcept/volto-introduction-block",
|
|
30
|
+
"@kitconcept/volto-logos-block",
|
|
29
31
|
"@kitconcept/volto-separator-block",
|
|
30
32
|
"@kitconcept/volto-slider-block",
|
|
31
33
|
"@mbarde/volto-image-crop-widget",
|
|
@@ -34,21 +36,27 @@
|
|
|
34
36
|
"@kitconcept/volto-light-theme"
|
|
35
37
|
],
|
|
36
38
|
"dependencies": {
|
|
37
|
-
"@plone-collective/volto-authomatic": "3.0.0-alpha.
|
|
38
|
-
"@kitconcept/volto-light-theme": "7.0.0
|
|
39
|
+
"@plone-collective/volto-authomatic": "3.0.0-alpha.6",
|
|
40
|
+
"@kitconcept/volto-light-theme": "7.0.0",
|
|
39
41
|
"@mbarde/volto-image-crop-widget": "^0.5.1",
|
|
40
|
-
"@kitconcept/volto-banner-block": "^1.0.1",
|
|
41
42
|
"@plone/components": "3.0.2"
|
|
42
43
|
},
|
|
43
44
|
"peerDependencies": {
|
|
45
|
+
"@plonegovbr/volto-social-media": "^2.0.0-alpha.8",
|
|
44
46
|
"react": "18.2.0",
|
|
45
|
-
"react-dom": "18.2.0"
|
|
47
|
+
"react-dom": "18.2.0",
|
|
48
|
+
"react-intl": "^3.12.1",
|
|
49
|
+
"react-redux": "^8.1.2"
|
|
46
50
|
},
|
|
47
51
|
"devDependencies": {
|
|
48
52
|
"@plone/scripts": "^3.6.1",
|
|
53
|
+
"@types/lodash": "^4.14.201",
|
|
49
54
|
"@types/react": "^18.3.12",
|
|
50
55
|
"@types/react-dom": "^18.3.1",
|
|
51
|
-
"
|
|
56
|
+
"lodash": "4.17.21",
|
|
57
|
+
"release-it": "^19.0.4",
|
|
58
|
+
"typescript": "^5.7.3",
|
|
59
|
+
"vitest": "^3.1.2",
|
|
52
60
|
"@plone/types": "1.4.5"
|
|
53
61
|
},
|
|
54
62
|
"scripts": {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ConfigType } from '@plone/registry';
|
|
2
|
+
import TTWCustomCSS from '../slots/TTWCustomCSS/TTWCustomCSS';
|
|
3
|
+
import ConfigInjector from '../slots/ConfigInjector/ConfigInjector';
|
|
4
|
+
|
|
5
|
+
export default function install(config: ConfigType) {
|
|
6
|
+
config.registerSlotComponent({
|
|
7
|
+
slot: 'aboveHeader',
|
|
8
|
+
name: 'ConfigInjector',
|
|
9
|
+
component: ConfigInjector,
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
config.registerSlotComponent({
|
|
13
|
+
slot: 'aboveHeader',
|
|
14
|
+
name: 'TTWCustomCSS',
|
|
15
|
+
component: TTWCustomCSS,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
return config;
|
|
19
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { BlocksConfigMerger } from './BlocksConfigMerger';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
|
|
4
|
+
const baseBlocksConfig = {
|
|
5
|
+
teaser: {
|
|
6
|
+
restricted: false,
|
|
7
|
+
variations: [
|
|
8
|
+
{ id: 'variation1', label: 'Variation 1' },
|
|
9
|
+
{ id: 'variation2', label: 'Variation 2' },
|
|
10
|
+
{ id: 'variation3', label: 'Variation 3' },
|
|
11
|
+
],
|
|
12
|
+
themes: [],
|
|
13
|
+
},
|
|
14
|
+
gridBlock: {
|
|
15
|
+
restricted: false,
|
|
16
|
+
variations: [
|
|
17
|
+
{ id: 'variationA', label: 'Variation A' },
|
|
18
|
+
{ id: 'variationB', label: 'Variation B' },
|
|
19
|
+
],
|
|
20
|
+
themes: [],
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const mutator = {
|
|
25
|
+
teaser: {
|
|
26
|
+
disable: true,
|
|
27
|
+
variations: ['variation1', 'variation2'],
|
|
28
|
+
themes: [
|
|
29
|
+
{
|
|
30
|
+
style: {
|
|
31
|
+
'--theme-color': '#fff',
|
|
32
|
+
'--theme-high-contrast-color': '#ecebeb',
|
|
33
|
+
'--theme-foreground-color': '#000',
|
|
34
|
+
'--theme-low-contrast-foreground-color': '#555555',
|
|
35
|
+
},
|
|
36
|
+
name: 'default',
|
|
37
|
+
label: 'Default',
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
gridBlock: {
|
|
42
|
+
variations: ['variationB'],
|
|
43
|
+
},
|
|
44
|
+
description: {
|
|
45
|
+
disable: true,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
describe('BlocksConfigMerger', () => {
|
|
50
|
+
it('disables the block if disable is true', () => {
|
|
51
|
+
const result = BlocksConfigMerger(baseBlocksConfig, mutator);
|
|
52
|
+
expect(result.teaser.restricted).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('filters variations according to mutator', () => {
|
|
56
|
+
const result = BlocksConfigMerger(baseBlocksConfig, mutator);
|
|
57
|
+
expect(result.teaser.variations.map((v) => v.id)).toEqual([
|
|
58
|
+
'variation1',
|
|
59
|
+
'variation2',
|
|
60
|
+
]);
|
|
61
|
+
expect(result.gridBlock.variations.map((v) => v.id)).toEqual([
|
|
62
|
+
'variationB',
|
|
63
|
+
]);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('assigns themes from mutator', () => {
|
|
67
|
+
const result = BlocksConfigMerger(baseBlocksConfig, mutator);
|
|
68
|
+
expect(result.teaser.themes).toEqual([
|
|
69
|
+
{
|
|
70
|
+
style: {
|
|
71
|
+
'--theme-color': '#fff',
|
|
72
|
+
'--theme-high-contrast-color': '#ecebeb',
|
|
73
|
+
'--theme-foreground-color': '#000',
|
|
74
|
+
'--theme-low-contrast-foreground-color': '#555555',
|
|
75
|
+
},
|
|
76
|
+
name: 'default',
|
|
77
|
+
label: 'Default',
|
|
78
|
+
},
|
|
79
|
+
]);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('does not modify blocks not present in mutator', () => {
|
|
83
|
+
const result = BlocksConfigMerger(baseBlocksConfig, mutator);
|
|
84
|
+
expect(result.teaser.variations.length).toBe(2);
|
|
85
|
+
expect(result.gridBlock.restricted).toBe(false);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('ignores blocks in mutator that do not exist in blocksConfig', () => {
|
|
89
|
+
const result = BlocksConfigMerger(baseBlocksConfig, mutator);
|
|
90
|
+
expect(result.description).toBeUndefined();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('does not mutate the original blocksConfig', () => {
|
|
94
|
+
const original = JSON.parse(JSON.stringify(baseBlocksConfig));
|
|
95
|
+
BlocksConfigMerger(baseBlocksConfig, mutator);
|
|
96
|
+
expect(baseBlocksConfig).toEqual(original);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { BlocksConfig } from '@plone/types';
|
|
2
|
+
import cloneDeep from 'lodash/cloneDeep';
|
|
3
|
+
import type { MutatorDSL } from '../types';
|
|
4
|
+
|
|
5
|
+
// Utility type for deep recursive Partial
|
|
6
|
+
type DeepPartial<T> = {
|
|
7
|
+
[P in keyof T]?: T[P] extends object
|
|
8
|
+
? T[P] extends Array<infer U>
|
|
9
|
+
? Array<DeepPartial<U>>
|
|
10
|
+
: DeepPartial<T[P]>
|
|
11
|
+
: T[P];
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export function BlocksConfigMerger(
|
|
15
|
+
blocksConfig: DeepPartial<BlocksConfig['blocksConfig']>,
|
|
16
|
+
merger: MutatorDSL,
|
|
17
|
+
): BlocksConfig['blocksConfig'] {
|
|
18
|
+
const mergedConfig = cloneDeep(blocksConfig);
|
|
19
|
+
|
|
20
|
+
Object.entries(merger).forEach(([blockId, dsl]) => {
|
|
21
|
+
if (!mergedConfig[blockId]) return;
|
|
22
|
+
|
|
23
|
+
// 1. Disable block
|
|
24
|
+
if (dsl.disable) {
|
|
25
|
+
mergedConfig[blockId]!.restricted = true;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 2. Filter variations
|
|
29
|
+
if (Array.isArray(dsl.variations) && mergedConfig[blockId]!.variations) {
|
|
30
|
+
mergedConfig[blockId]!.variations = mergedConfig[
|
|
31
|
+
blockId
|
|
32
|
+
]!.variations!.filter((v) => dsl.variations!.includes(v.id));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 3. Assign themes
|
|
36
|
+
if (Array.isArray(dsl.themes)) {
|
|
37
|
+
mergedConfig[blockId]!.themes = dsl.themes;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return mergedConfig as BlocksConfig['blocksConfig'];
|
|
42
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
import type { ConfigType } from '@plone/registry';
|
|
2
|
-
|
|
2
|
+
import type { CustomInheritBehavior, BlocksConfigSettings } from './types';
|
|
3
3
|
import installSettings from './config/settings';
|
|
4
|
+
import installSlots from './config/slots';
|
|
5
|
+
|
|
6
|
+
declare module '@plone/types' {
|
|
7
|
+
export interface GetSiteResponse {
|
|
8
|
+
'kitconcept.intranet.custom_css': string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface Expanders {
|
|
12
|
+
inherit: {
|
|
13
|
+
'kitconcept.blocks.config': CustomInheritBehavior<BlocksConfigSettings>;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
4
17
|
|
|
5
18
|
const applyConfig = (config: ConfigType) => {
|
|
6
19
|
installSettings(config);
|
|
20
|
+
installSlots(config);
|
|
7
21
|
return config;
|
|
8
22
|
};
|
|
9
23
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import config from '@plone/volto/registry';
|
|
2
|
+
import { useSelector } from 'react-redux';
|
|
3
|
+
import { BlocksConfigMerger } from '../../helpers/BlocksConfigMerger';
|
|
4
|
+
import type { Content } from '@plone/types';
|
|
5
|
+
import type { MutatorDSL } from '../../types';
|
|
6
|
+
|
|
7
|
+
type FormState = {
|
|
8
|
+
content: {
|
|
9
|
+
data: Content;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const ConfigInjector = () => {
|
|
14
|
+
const blockConfigData = useSelector<FormState, MutatorDSL>(
|
|
15
|
+
(state) =>
|
|
16
|
+
state.content.data?.['@components']?.inherit?.['kitconcept.blocks.config']
|
|
17
|
+
?.data?.blocks_config_mutator,
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
if (blockConfigData) {
|
|
21
|
+
config.blocks.blocksConfig = BlocksConfigMerger(
|
|
22
|
+
config.blocks.blocksConfig,
|
|
23
|
+
blockConfigData,
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// This component does not render anything, it just injects config from the Redux
|
|
28
|
+
// store in the global config
|
|
29
|
+
return null;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export default ConfigInjector;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import Helmet from '@plone/volto/helpers/Helmet/Helmet';
|
|
2
|
+
import { useSelector } from 'react-redux';
|
|
3
|
+
import type { GetSiteResponse } from '@plone/types';
|
|
4
|
+
|
|
5
|
+
type FormState = {
|
|
6
|
+
site: { data: GetSiteResponse };
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const TTWCustomCSS = () => {
|
|
10
|
+
const site = useSelector<FormState, GetSiteResponse>(
|
|
11
|
+
(state) => state.site.data,
|
|
12
|
+
);
|
|
13
|
+
const customCSS = site['kitconcept.custom_css'];
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<>
|
|
17
|
+
{customCSS ? (
|
|
18
|
+
<>
|
|
19
|
+
<Helmet>
|
|
20
|
+
<style>{customCSS}</style>
|
|
21
|
+
</Helmet>
|
|
22
|
+
</>
|
|
23
|
+
) : null}
|
|
24
|
+
</>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default TTWCustomCSS;
|
package/src/types.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { StyleDefinition } from '@plone/types';
|
|
2
|
+
|
|
3
|
+
export type MutatorDSL = Record<
|
|
4
|
+
string,
|
|
5
|
+
{
|
|
6
|
+
disable?: boolean;
|
|
7
|
+
variations?: string[];
|
|
8
|
+
themes?: StyleDefinition[];
|
|
9
|
+
}
|
|
10
|
+
>;
|
|
11
|
+
|
|
12
|
+
export type BlocksConfigSettings = {
|
|
13
|
+
blocks_config_mutator: MutatorDSL;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type CustomInheritBehavior<T> = {
|
|
17
|
+
data: T;
|
|
18
|
+
from: {
|
|
19
|
+
'@id': string;
|
|
20
|
+
title: string;
|
|
21
|
+
};
|
|
22
|
+
};
|