@teambit/api-reference 1.0.1079 → 1.0.1081
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/api-compare.module.scss +2 -244
- package/api-compare.section.tsx +12 -5
- package/api-compare.tsx +67 -185
- package/api-reference.ui.runtime.tsx +3 -2
- package/dist/api-compare.d.ts +12 -3
- package/dist/api-compare.js +63 -186
- package/dist/api-compare.js.map +1 -1
- package/dist/api-compare.module.scss +2 -244
- package/dist/api-compare.section.d.ts +6 -4
- package/dist/api-compare.section.js +10 -5
- package/dist/api-compare.section.js.map +1 -1
- package/dist/api-reference.ui.runtime.js +3 -2
- package/dist/api-reference.ui.runtime.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +14 -13
- package/dist/api-compare.types.d.ts +0 -33
- package/dist/api-compare.types.js +0 -3
- package/dist/api-compare.types.js.map +0 -1
- /package/dist/{preview-1785260578779.js → preview-1785278532531.js} +0 -0
package/api-compare.module.scss
CHANGED
|
@@ -3,248 +3,6 @@
|
|
|
3
3
|
flex-direction: column;
|
|
4
4
|
height: 100%;
|
|
5
5
|
overflow: auto;
|
|
6
|
-
padding: 24px;
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
.summary {
|
|
11
|
-
display: flex;
|
|
12
|
-
gap: 12px;
|
|
13
|
-
align-items: center;
|
|
14
|
-
padding: 12px 16px;
|
|
15
|
-
background: var(--bit-bg-dent, #f6f6f6);
|
|
16
|
-
border-radius: 8px;
|
|
17
|
-
font-size: 13px;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
.summaryDivider {
|
|
21
|
-
opacity: 0.3;
|
|
22
|
-
color: var(--bit-text-color-light, #6c707c);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
.summaryBadge {
|
|
26
|
-
display: inline-flex;
|
|
27
|
-
align-items: center;
|
|
28
|
-
gap: 4px;
|
|
29
|
-
padding: 3px 10px;
|
|
30
|
-
border-radius: 12px;
|
|
31
|
-
font-weight: 500;
|
|
32
|
-
font-size: 12px;
|
|
33
|
-
white-space: nowrap;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
.addedBadge {
|
|
37
|
-
composes: summaryBadge;
|
|
38
|
-
background: color-mix(in srgb, var(--bit-color-added, #2ea043) 15%, transparent);
|
|
39
|
-
color: var(--bit-color-added, #2ea043);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
.removedBadge {
|
|
43
|
-
composes: summaryBadge;
|
|
44
|
-
background: color-mix(in srgb, var(--bit-color-removed, #f85149) 15%, transparent);
|
|
45
|
-
color: var(--bit-color-removed, #f85149);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
.modifiedBadge {
|
|
49
|
-
composes: summaryBadge;
|
|
50
|
-
background: color-mix(in srgb, var(--bit-color-modified, #d29922) 15%, transparent);
|
|
51
|
-
color: var(--bit-color-modified, #d29922);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
.changeList {
|
|
55
|
-
display: flex;
|
|
56
|
-
flex-direction: column;
|
|
57
|
-
gap: 8px;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.sectionTitle {
|
|
61
|
-
margin: 16px 0 8px;
|
|
62
|
-
font-size: 12px;
|
|
63
|
-
font-weight: 600;
|
|
64
|
-
text-transform: uppercase;
|
|
65
|
-
letter-spacing: 0.5px;
|
|
66
|
-
color: var(--bit-text-color-light, #6c707c);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.diffEntry {
|
|
70
|
-
border: 1px solid var(--bit-border-color-lightest, #ededed);
|
|
71
|
-
border-radius: 8px;
|
|
72
|
-
overflow: hidden;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
.diffEntryHeader {
|
|
76
|
-
display: flex;
|
|
77
|
-
align-items: center;
|
|
78
|
-
gap: 10px;
|
|
79
|
-
padding: 10px 16px;
|
|
80
|
-
cursor: pointer;
|
|
81
|
-
user-select: none;
|
|
82
|
-
|
|
83
|
-
&:hover {
|
|
84
|
-
background: var(--bit-bg-dent, #f6f6f6);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
.statusBadge {
|
|
89
|
-
display: inline-flex;
|
|
90
|
-
align-items: center;
|
|
91
|
-
padding: 2px 8px;
|
|
92
|
-
border-radius: 4px;
|
|
93
|
-
font-weight: 600;
|
|
94
|
-
font-size: 11px;
|
|
95
|
-
text-transform: uppercase;
|
|
96
|
-
letter-spacing: 0.3px;
|
|
97
|
-
flex-shrink: 0;
|
|
98
|
-
white-space: nowrap;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
.statusAdded {
|
|
102
|
-
composes: statusBadge;
|
|
103
|
-
background: color-mix(in srgb, var(--bit-color-added, #2ea043) 15%, transparent);
|
|
104
|
-
color: var(--bit-color-added, #2ea043);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
.statusRemoved {
|
|
108
|
-
composes: statusBadge;
|
|
109
|
-
background: color-mix(in srgb, var(--bit-color-removed, #f85149) 15%, transparent);
|
|
110
|
-
color: var(--bit-color-removed, #f85149);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
.statusModified {
|
|
114
|
-
composes: statusBadge;
|
|
115
|
-
background: color-mix(in srgb, var(--bit-color-modified, #d29922) 15%, transparent);
|
|
116
|
-
color: var(--bit-color-modified, #d29922);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
.exportName {
|
|
120
|
-
font-weight: 600;
|
|
121
|
-
font-size: 14px;
|
|
122
|
-
font-family: var(--bit-font-mono, monospace);
|
|
123
|
-
color: var(--bit-text-color-heavy, #2b2b2b);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
.schemaType {
|
|
127
|
-
color: var(--bit-text-color-light, #6c707c);
|
|
128
|
-
font-size: 12px;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
.impactBadge {
|
|
132
|
-
composes: summaryBadge;
|
|
133
|
-
margin-left: auto;
|
|
134
|
-
font-size: 11px;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
.expandIcon {
|
|
138
|
-
color: var(--bit-text-color-light, #6c707c);
|
|
139
|
-
font-size: 10px;
|
|
140
|
-
transition: transform 0.2s;
|
|
141
|
-
flex-shrink: 0;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
.expandIconOpen {
|
|
145
|
-
composes: expandIcon;
|
|
146
|
-
transform: rotate(90deg);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
.diffEntryBody {
|
|
150
|
-
padding: 0 16px 16px;
|
|
151
|
-
border-top: 1px solid var(--bit-border-color-lightest, #ededed);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
.detailsList {
|
|
155
|
-
list-style: none;
|
|
156
|
-
padding: 12px 0 0;
|
|
157
|
-
margin: 0;
|
|
158
|
-
display: flex;
|
|
159
|
-
flex-direction: column;
|
|
160
|
-
gap: 8px;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
.detailItem {
|
|
164
|
-
display: flex;
|
|
165
|
-
align-items: flex-start;
|
|
166
|
-
gap: 8px;
|
|
167
|
-
font-size: 13px;
|
|
168
|
-
line-height: 1.5;
|
|
169
|
-
color: var(--bit-text-color-heavy, #2b2b2b);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
.detailDot {
|
|
173
|
-
width: 7px;
|
|
174
|
-
height: 7px;
|
|
175
|
-
min-width: 7px;
|
|
176
|
-
border-radius: 50%;
|
|
177
|
-
margin-top: 6px;
|
|
178
|
-
flex-shrink: 0;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
.dotBreaking {
|
|
182
|
-
composes: detailDot;
|
|
183
|
-
background: var(--bit-color-removed, #f85149);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
.dotNonBreaking {
|
|
187
|
-
composes: detailDot;
|
|
188
|
-
background: var(--bit-color-added, #2ea043);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
.dotPatch {
|
|
192
|
-
composes: detailDot;
|
|
193
|
-
background: var(--bit-color-modified, #d29922);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
.detailDescription {
|
|
197
|
-
color: var(--bit-text-color-heavy, #2b2b2b);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
.signatureBlock {
|
|
201
|
-
margin-top: 12px;
|
|
202
|
-
padding: 12px;
|
|
203
|
-
background: var(--bit-bg-dent, #f6f6f6);
|
|
204
|
-
border-radius: 6px;
|
|
205
|
-
font-family: var(--bit-font-mono, monospace);
|
|
206
|
-
font-size: 12px;
|
|
207
|
-
white-space: pre-wrap;
|
|
208
|
-
word-break: break-word;
|
|
209
|
-
line-height: 1.6;
|
|
210
|
-
color: var(--bit-text-color-heavy, #2b2b2b);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
.signatureLabel {
|
|
214
|
-
font-weight: 600;
|
|
215
|
-
color: var(--bit-text-color-light, #6c707c);
|
|
216
|
-
margin-top: 12px;
|
|
217
|
-
margin-bottom: 4px;
|
|
218
|
-
font-size: 11px;
|
|
219
|
-
text-transform: uppercase;
|
|
220
|
-
letter-spacing: 0.5px;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
.signatureRemoved {
|
|
224
|
-
composes: signatureBlock;
|
|
225
|
-
text-decoration: line-through;
|
|
226
|
-
opacity: 0.6;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
.emptyState {
|
|
230
|
-
display: flex;
|
|
231
|
-
align-items: center;
|
|
232
|
-
justify-content: center;
|
|
233
|
-
height: 100%;
|
|
234
|
-
color: var(--bit-text-color-light, #6c707c);
|
|
235
|
-
font-size: 14px;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
.toggleSignatures {
|
|
239
|
-
background: none;
|
|
240
|
-
border: none;
|
|
241
|
-
color: var(--bit-accent-color, #0366d6);
|
|
242
|
-
font-size: 12px;
|
|
243
|
-
cursor: pointer;
|
|
244
|
-
padding: 4px 0;
|
|
245
|
-
margin-top: 12px;
|
|
246
|
-
|
|
247
|
-
&:hover {
|
|
248
|
-
text-decoration: underline;
|
|
249
|
-
}
|
|
6
|
+
padding: 16px 24px;
|
|
7
|
+
max-width: 980px;
|
|
250
8
|
}
|
package/api-compare.section.tsx
CHANGED
|
@@ -2,12 +2,24 @@ import React from 'react';
|
|
|
2
2
|
import type { Section } from '@teambit/component';
|
|
3
3
|
import type { TabItem } from '@teambit/component.ui.component-compare.models.component-compare-props';
|
|
4
4
|
import type { ChangeType } from '@teambit/component.ui.component-compare.models.component-compare-change-type';
|
|
5
|
+
import type { ApiDiffInsight } from '@teambit/semantics.ui.api-diff-view';
|
|
5
6
|
import { APICompare } from './api-compare';
|
|
6
7
|
|
|
7
8
|
// Use string cast since the external ChangeType enum doesn't have API yet
|
|
8
9
|
const ChangeTypeAPI = 'API' as unknown as ChangeType;
|
|
9
10
|
|
|
10
11
|
export class APICompareSection implements TabItem, Section {
|
|
12
|
+
route: { path: string; element: React.ReactNode };
|
|
13
|
+
|
|
14
|
+
constructor(getInsights?: () => ApiDiffInsight[]) {
|
|
15
|
+
// built in the constructor (not a field initializer) so the element captures the
|
|
16
|
+
// getter regardless of class-field initialization order.
|
|
17
|
+
this.route = {
|
|
18
|
+
path: 'api/*',
|
|
19
|
+
element: <APICompare getInsights={getInsights} />,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
11
23
|
navigationLink = {
|
|
12
24
|
href: 'api',
|
|
13
25
|
children: 'API',
|
|
@@ -15,11 +27,6 @@ export class APICompareSection implements TabItem, Section {
|
|
|
15
27
|
|
|
16
28
|
props = this.navigationLink;
|
|
17
29
|
|
|
18
|
-
route = {
|
|
19
|
-
path: 'api/*',
|
|
20
|
-
element: <APICompare />,
|
|
21
|
-
};
|
|
22
|
-
|
|
23
30
|
order = 15;
|
|
24
31
|
changeType = ChangeTypeAPI;
|
|
25
32
|
id = 'api';
|
package/api-compare.tsx
CHANGED
|
@@ -1,202 +1,84 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { useComponentCompare } from '@teambit/component.ui.component-compare.context';
|
|
3
|
-
import
|
|
3
|
+
import {
|
|
4
|
+
ComponentApiDiffSection,
|
|
5
|
+
ApiDiffSlimRow,
|
|
6
|
+
ApiDiffInsightProvider,
|
|
7
|
+
useApiDiff,
|
|
8
|
+
} from '@teambit/semantics.ui.api-diff-view';
|
|
9
|
+
import type { ApiDiffInsight } from '@teambit/semantics.ui.api-diff-view';
|
|
4
10
|
import styles from './api-compare.module.scss';
|
|
5
11
|
|
|
6
|
-
|
|
12
|
+
// single source of truth for the API diff model lives in api-diff-view.
|
|
13
|
+
export type { APIDiffResult, APIDiffChange, APIDiffDetail } from '@teambit/semantics.ui.api-diff-view';
|
|
7
14
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
case 'NON_BREAKING':
|
|
13
|
-
return styles.addedBadge;
|
|
14
|
-
case 'PATCH':
|
|
15
|
-
return styles.modifiedBadge;
|
|
16
|
-
default:
|
|
17
|
-
return styles.summaryBadge;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function impactLabel(impact: string): string {
|
|
22
|
-
switch (impact) {
|
|
23
|
-
case 'BREAKING':
|
|
24
|
-
return 'Breaking';
|
|
25
|
-
case 'NON_BREAKING':
|
|
26
|
-
return 'Non-breaking';
|
|
27
|
-
case 'PATCH':
|
|
28
|
-
return 'Patch';
|
|
29
|
-
default:
|
|
30
|
-
return impact;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function getStatusClass(status: string): string {
|
|
35
|
-
switch (status) {
|
|
36
|
-
case 'ADDED':
|
|
37
|
-
return styles.statusAdded;
|
|
38
|
-
case 'REMOVED':
|
|
39
|
-
return styles.statusRemoved;
|
|
40
|
-
case 'MODIFIED':
|
|
41
|
-
return styles.statusModified;
|
|
42
|
-
default:
|
|
43
|
-
return styles.statusBadge;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function getStatusLabel(status: string): string {
|
|
48
|
-
switch (status) {
|
|
49
|
-
case 'ADDED':
|
|
50
|
-
return '+ Added';
|
|
51
|
-
case 'REMOVED':
|
|
52
|
-
return '- Removed';
|
|
53
|
-
case 'MODIFIED':
|
|
54
|
-
return '~ Modified';
|
|
55
|
-
default:
|
|
56
|
-
return status;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function dotClass(impact: string): string {
|
|
61
|
-
switch (impact) {
|
|
62
|
-
case 'BREAKING':
|
|
63
|
-
return styles.dotBreaking;
|
|
64
|
-
case 'NON_BREAKING':
|
|
65
|
-
return styles.dotNonBreaking;
|
|
66
|
-
default:
|
|
67
|
-
return styles.dotPatch;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function DetailItem({ detail }: { detail: APIDiffDetail }) {
|
|
72
|
-
return (
|
|
73
|
-
<li className={styles.detailItem}>
|
|
74
|
-
<span className={dotClass(detail.impact)} />
|
|
75
|
-
<span className={styles.detailDescription}>{detail.description}</span>
|
|
76
|
-
</li>
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function APIDiffEntry({ change }: { change: APIDiffChange }) {
|
|
81
|
-
const [expanded, setExpanded] = React.useState(change.status === 'MODIFIED');
|
|
82
|
-
const [showSignatures, setShowSignatures] = React.useState(false);
|
|
15
|
+
export type APICompareProps = {
|
|
16
|
+
/** resolved lazily at render time — slot registrations can land after the section is constructed */
|
|
17
|
+
getInsights?: () => ApiDiffInsight[];
|
|
18
|
+
};
|
|
83
19
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
>
|
|
104
|
-
<span className={getStatusClass(change.status)}>{getStatusLabel(change.status)}</span>
|
|
105
|
-
<span className={styles.exportName}>{change.exportName}</span>
|
|
106
|
-
<span className={styles.schemaType}>{change.schemaType}</span>
|
|
107
|
-
<span className={`${impactClass(change.impact)} ${styles.impactBadge}`}>{impactLabel(change.impact)}</span>
|
|
108
|
-
{hasBody && <span className={expanded ? styles.expandIconOpen : styles.expandIcon}>▶</span>}
|
|
109
|
-
</div>
|
|
110
|
-
{expanded && hasBody && (
|
|
111
|
-
<div className={styles.diffEntryBody}>
|
|
112
|
-
{change.status === 'MODIFIED' && change.changes && change.changes.length > 0 && (
|
|
113
|
-
<ul className={styles.detailsList}>
|
|
114
|
-
{change.changes.map((detail, i) => (
|
|
115
|
-
<DetailItem key={`${detail.changeKind}-${i}`} detail={detail} />
|
|
116
|
-
))}
|
|
117
|
-
</ul>
|
|
118
|
-
)}
|
|
119
|
-
{change.status === 'MODIFIED' && (change.baseSignature || change.compareSignature) && (
|
|
120
|
-
<>
|
|
121
|
-
<button className={styles.toggleSignatures} onClick={() => setShowSignatures(!showSignatures)}>
|
|
122
|
-
{showSignatures ? '▼ Hide signatures' : '▶ Show signatures'}
|
|
123
|
-
</button>
|
|
124
|
-
{showSignatures && (
|
|
125
|
-
<>
|
|
126
|
-
{change.baseSignature && (
|
|
127
|
-
<div>
|
|
128
|
-
<div className={styles.signatureLabel}>Base</div>
|
|
129
|
-
<div className={styles.signatureRemoved}>{change.baseSignature}</div>
|
|
130
|
-
</div>
|
|
131
|
-
)}
|
|
132
|
-
{change.compareSignature && (
|
|
133
|
-
<div>
|
|
134
|
-
<div className={styles.signatureLabel}>Compare</div>
|
|
135
|
-
<div className={styles.signatureBlock}>{change.compareSignature}</div>
|
|
136
|
-
</div>
|
|
137
|
-
)}
|
|
138
|
-
</>
|
|
139
|
-
)}
|
|
140
|
-
</>
|
|
141
|
-
)}
|
|
142
|
-
{change.status === 'ADDED' && change.compareSignature && (
|
|
143
|
-
<div className={styles.signatureBlock}>{change.compareSignature}</div>
|
|
144
|
-
)}
|
|
145
|
-
{change.status === 'REMOVED' && change.baseSignature && (
|
|
146
|
-
<div className={styles.signatureRemoved}>{change.baseSignature}</div>
|
|
147
|
-
)}
|
|
148
|
-
</div>
|
|
149
|
-
)}
|
|
150
|
-
</div>
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function ChangeSection({ title, changes }: { title: string; changes: APIDiffChange[] }) {
|
|
155
|
-
if (changes.length === 0) return null;
|
|
156
|
-
|
|
157
|
-
const sorted = [...changes].sort((a, b) => {
|
|
158
|
-
const order: Record<string, number> = { REMOVED: 0, MODIFIED: 1, ADDED: 2 };
|
|
159
|
-
return (order[a.status] ?? 3) - (order[b.status] ?? 3);
|
|
20
|
+
/**
|
|
21
|
+
* the API tab of the single-component compare page. thin host around the same
|
|
22
|
+
* `ComponentApiDiffSection` the lane-compare API view uses — one implementation, two hosts.
|
|
23
|
+
* data comes from the compare context (fetched once by ComponentCompare).
|
|
24
|
+
*/
|
|
25
|
+
export function APICompare({ getInsights }: APICompareProps) {
|
|
26
|
+
const compareContext = useComponentCompare();
|
|
27
|
+
const baseModel = compareContext?.base?.model;
|
|
28
|
+
const compareModel = compareContext?.compare?.model;
|
|
29
|
+
|
|
30
|
+
// Prefer a diff already on the context — the legacy `ComponentCompare` fetches it once and sets
|
|
31
|
+
// it there. The redesign single-component page does NOT put it on its inline context, so we fetch
|
|
32
|
+
// on our own. This hook is only mounted when the API view is the active tab (the page renders the
|
|
33
|
+
// element on-demand), so lane-compare — which renders one panel per component and never mounts
|
|
34
|
+
// this tab — pays nothing.
|
|
35
|
+
const contextApiDiff = compareContext?.apiDiffResult;
|
|
36
|
+
const shouldSelfFetch = contextApiDiff === undefined;
|
|
37
|
+
const { result: fetchedApiDiff } = useApiDiff(baseModel?.id.toString(), compareModel?.id.toString(), {
|
|
38
|
+
skip: !shouldSelfFetch,
|
|
160
39
|
});
|
|
40
|
+
const apiDiffResult = shouldSelfFetch ? fetchedApiDiff : contextApiDiff;
|
|
161
41
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
<div className={styles.changeList}>
|
|
166
|
-
{sorted.map((change) => (
|
|
167
|
-
<APIDiffEntry key={`${change.visibility}-${change.status}-${change.exportName}`} change={change} />
|
|
168
|
-
))}
|
|
169
|
-
</div>
|
|
170
|
-
</>
|
|
171
|
-
);
|
|
172
|
-
}
|
|
42
|
+
// memoized so the insights context value keeps a stable identity — otherwise a fresh array every
|
|
43
|
+
// render would re-render every `useApiDiffInsights` consumer (incl. the React.memo'd ApiChangeBlock).
|
|
44
|
+
const insights = React.useMemo(() => getInsights?.(), [getInsights]);
|
|
173
45
|
|
|
174
|
-
|
|
175
|
-
const compareContext = useComponentCompare();
|
|
176
|
-
const apiDiffResult: APIDiffResult | null | undefined = (compareContext as any)?.apiDiffResult;
|
|
46
|
+
if (!compareContext) return null;
|
|
177
47
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
48
|
+
const id = (compareModel || baseModel)?.id;
|
|
49
|
+
if (!id) return null;
|
|
181
50
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
51
|
+
const componentIdStr = id.toStringWithoutVersion();
|
|
52
|
+
const baseVersion = baseModel?.id.version;
|
|
53
|
+
const compareVersion = compareModel?.id.version;
|
|
185
54
|
|
|
186
|
-
|
|
55
|
+
// no base (first version) or identical versions — nothing to diff, not a failure.
|
|
56
|
+
const nothingToCompare = apiDiffResult === null && (!baseVersion || baseVersion === compareVersion);
|
|
187
57
|
|
|
188
58
|
return (
|
|
189
|
-
<
|
|
190
|
-
<div className={styles.
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
59
|
+
<ApiDiffInsightProvider insights={insights}>
|
|
60
|
+
<div className={styles.apiCompareContainer}>
|
|
61
|
+
{nothingToCompare ? (
|
|
62
|
+
<ApiDiffSlimRow
|
|
63
|
+
componentIdStr={componentIdStr}
|
|
64
|
+
displayName={id.fullName}
|
|
65
|
+
chip="nothing to compare"
|
|
66
|
+
detail={baseVersion ? 'both sides are the same version' : 'no base version to compare against'}
|
|
67
|
+
tone="ok"
|
|
68
|
+
/>
|
|
69
|
+
) : (
|
|
70
|
+
<ComponentApiDiffSection
|
|
71
|
+
componentIdStr={componentIdStr}
|
|
72
|
+
displayName={id.fullName}
|
|
73
|
+
baseId={baseModel?.id.toString()}
|
|
74
|
+
compareId={compareModel?.id.toString()}
|
|
75
|
+
baseVersion={baseVersion}
|
|
76
|
+
compareVersion={compareVersion}
|
|
77
|
+
result={apiDiffResult}
|
|
78
|
+
loading={apiDiffResult === undefined}
|
|
79
|
+
/>
|
|
80
|
+
)}
|
|
197
81
|
</div>
|
|
198
|
-
|
|
199
|
-
<ChangeSection title="Internal (non-exported)" changes={internalChanges} />
|
|
200
|
-
</div>
|
|
82
|
+
</ApiDiffInsightProvider>
|
|
201
83
|
);
|
|
202
84
|
}
|
|
@@ -87,8 +87,9 @@ export class APIReferenceUI {
|
|
|
87
87
|
// register all default schema classes
|
|
88
88
|
apiReferenceUI.registerSchemaClasses(() => Object.values(Schemas));
|
|
89
89
|
|
|
90
|
-
// register API compare tab in component compare
|
|
91
|
-
|
|
90
|
+
// register API compare tab in component compare. insights are resolved lazily —
|
|
91
|
+
// aspects can register them on componentCompareUI after this provider runs.
|
|
92
|
+
const apiCompareSection = new APICompareSection(() => componentCompareUI.getApiDiffInsights());
|
|
92
93
|
componentCompareUI.registerNavigation(apiCompareSection);
|
|
93
94
|
componentCompareUI.registerRoutes([apiCompareSection.route]);
|
|
94
95
|
|
package/dist/api-compare.d.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type {
|
|
3
|
-
export type { APIDiffResult, APIDiffChange, APIDiffDetail };
|
|
4
|
-
export
|
|
2
|
+
import type { ApiDiffInsight } from '@teambit/semantics.ui.api-diff-view';
|
|
3
|
+
export type { APIDiffResult, APIDiffChange, APIDiffDetail } from '@teambit/semantics.ui.api-diff-view';
|
|
4
|
+
export type APICompareProps = {
|
|
5
|
+
/** resolved lazily at render time — slot registrations can land after the section is constructed */
|
|
6
|
+
getInsights?: () => ApiDiffInsight[];
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* the API tab of the single-component compare page. thin host around the same
|
|
10
|
+
* `ComponentApiDiffSection` the lane-compare API view uses — one implementation, two hosts.
|
|
11
|
+
* data comes from the compare context (fetched once by ComponentCompare).
|
|
12
|
+
*/
|
|
13
|
+
export declare function APICompare({ getInsights }: APICompareProps): React.JSX.Element | null;
|