docusaurus-plugin-generate-schema-docs 1.6.0 → 1.7.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 +17 -0
- package/__tests__/__fixtures__/static/schemas/battle-test-event.json +771 -0
- package/__tests__/__fixtures__/static/schemas/conditional-event.json +52 -0
- package/__tests__/__fixtures__/static/schemas/nested-conditional-event.json +50 -0
- package/__tests__/components/ConditionalRows.test.js +150 -0
- package/__tests__/components/ConnectorLines.visualRegression.test.js +93 -0
- package/__tests__/components/FoldableRows.test.js +7 -4
- package/__tests__/components/SchemaRows.test.js +31 -0
- package/__tests__/components/__snapshots__/ConnectorLines.visualRegression.test.js.snap +7 -0
- package/__tests__/generateEventDocs.partials.test.js +134 -0
- package/__tests__/helpers/buildExampleFromSchema.test.js +49 -0
- package/__tests__/helpers/schemaToExamples.test.js +75 -0
- package/__tests__/helpers/schemaToTableData.battleTest.test.js +704 -0
- package/__tests__/helpers/schemaToTableData.hierarchicalLines.test.js +190 -7
- package/__tests__/helpers/schemaToTableData.test.js +263 -2
- package/__tests__/helpers/validator.test.js +6 -6
- package/__tests__/syncGtm.test.js +346 -0
- package/components/ConditionalRows.js +156 -0
- package/components/FoldableRows.js +88 -61
- package/components/PropertiesTable.js +1 -1
- package/components/PropertyRow.js +24 -8
- package/components/SchemaRows.css +115 -0
- package/components/SchemaRows.js +31 -4
- package/generateEventDocs.js +41 -34
- package/helpers/buildExampleFromSchema.js +11 -0
- package/helpers/continuingLinesStyle.js +169 -0
- package/helpers/schema-doc-template.js +2 -5
- package/helpers/schemaToExamples.js +75 -2
- package/helpers/schemaToTableData.js +252 -26
- package/helpers/update-schema-ids.js +3 -3
- package/helpers/validator.js +7 -19
- package/index.js +34 -0
- package/package.json +1 -1
- package/scripts/sync-gtm.js +397 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import clsx from 'clsx';
|
|
3
3
|
import CodeBlock from '@theme/CodeBlock';
|
|
4
|
+
import { getBracketLinesStyle } from '../helpers/continuingLinesStyle';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Formats a single example value into a string for display in a CodeBlock.
|
|
@@ -30,7 +31,7 @@ const getContainerSymbol = (containerType) => {
|
|
|
30
31
|
* All data is passed in via the `row` prop, which comes from `tableData`.
|
|
31
32
|
* This component handles multi-row constraints using `rowSpan`.
|
|
32
33
|
*/
|
|
33
|
-
export default function PropertyRow({ row, isLastInGroup }) {
|
|
34
|
+
export default function PropertyRow({ row, isLastInGroup, bracketEnds }) {
|
|
34
35
|
const {
|
|
35
36
|
name,
|
|
36
37
|
level,
|
|
@@ -42,6 +43,7 @@ export default function PropertyRow({ row, isLastInGroup }) {
|
|
|
42
43
|
hasChildren,
|
|
43
44
|
containerType,
|
|
44
45
|
continuingLevels = [],
|
|
46
|
+
groupBrackets = [],
|
|
45
47
|
} = row;
|
|
46
48
|
|
|
47
49
|
const indentStyle = {
|
|
@@ -56,7 +58,7 @@ export default function PropertyRow({ row, isLastInGroup }) {
|
|
|
56
58
|
? constraints
|
|
57
59
|
: [null];
|
|
58
60
|
|
|
59
|
-
// Generate background gradients for:
|
|
61
|
+
// Generate background gradients for tree connector lines (left side):
|
|
60
62
|
// 1. Parent-to-child line (from 50% down) - for elements with children
|
|
61
63
|
// 2. Continuing ancestor lines (full height) - for ancestors that have more siblings below
|
|
62
64
|
//
|
|
@@ -69,7 +71,6 @@ export default function PropertyRow({ row, isLastInGroup }) {
|
|
|
69
71
|
const allPositions = [];
|
|
70
72
|
|
|
71
73
|
// Parent-to-child line: draws from 50% (below symbol) to bottom of cell
|
|
72
|
-
// Position is at the child's level, which is (level * 20 + 8)px
|
|
73
74
|
if (hasChildren) {
|
|
74
75
|
const childLevelPos = level * 1.25 + 0.5;
|
|
75
76
|
allGradients.push(
|
|
@@ -79,10 +80,14 @@ export default function PropertyRow({ row, isLastInGroup }) {
|
|
|
79
80
|
allPositions.push(`${childLevelPos}rem top`);
|
|
80
81
|
}
|
|
81
82
|
|
|
82
|
-
// Continuing ancestor lines: full-height vertical lines for ancestors with more siblings
|
|
83
|
-
//
|
|
83
|
+
// Continuing ancestor lines: full-height vertical lines for ancestors with more siblings.
|
|
84
|
+
// Only levels strictly below the immediate parent (< level - 1) are drawn here.
|
|
85
|
+
// The ::before pseudo-element handles the immediate parent connector at level - 1.
|
|
86
|
+
// We also require lvl+1 to be in continuingLevels: if the next level up is not continuing
|
|
87
|
+
// (i.e. the parent was the last sibling), drawing lvl's line would create a stray line at
|
|
88
|
+
// the same x-position as that parent's elbow.
|
|
84
89
|
continuingLevels
|
|
85
|
-
.filter((lvl) => lvl < level - 1)
|
|
90
|
+
.filter((lvl) => lvl < level - 1 && continuingLevels.includes(lvl + 1))
|
|
86
91
|
.forEach((lvl) => {
|
|
87
92
|
const pos = getLevelPosition(lvl);
|
|
88
93
|
allGradients.push(
|
|
@@ -102,11 +107,20 @@ export default function PropertyRow({ row, isLastInGroup }) {
|
|
|
102
107
|
}
|
|
103
108
|
: {};
|
|
104
109
|
|
|
110
|
+
// Bracket lines on the right side (description column)
|
|
111
|
+
const bracketCaps = bracketEnds ? { ending: bracketEnds } : undefined;
|
|
112
|
+
const bracketStyle = getBracketLinesStyle(groupBrackets, bracketCaps);
|
|
113
|
+
|
|
105
114
|
const containerSymbol = getContainerSymbol(containerType);
|
|
106
115
|
|
|
107
116
|
return (
|
|
108
117
|
<>
|
|
109
|
-
<tr
|
|
118
|
+
<tr
|
|
119
|
+
className={clsx(
|
|
120
|
+
required && 'required-row',
|
|
121
|
+
row.isCondition && 'conditional-condition-row',
|
|
122
|
+
)}
|
|
123
|
+
>
|
|
110
124
|
<td
|
|
111
125
|
rowSpan={rowSpan}
|
|
112
126
|
style={{ ...indentStyle, ...continuingLinesStyle }}
|
|
@@ -159,7 +173,9 @@ export default function PropertyRow({ row, isLastInGroup }) {
|
|
|
159
173
|
);
|
|
160
174
|
})}
|
|
161
175
|
</td>
|
|
162
|
-
<td rowSpan={rowSpan}
|
|
176
|
+
<td rowSpan={rowSpan} style={bracketStyle}>
|
|
177
|
+
{description || ''}
|
|
178
|
+
</td>
|
|
163
179
|
</tr>
|
|
164
180
|
|
|
165
181
|
{/* Render subsequent constraints in their own rows */}
|
|
@@ -42,6 +42,40 @@
|
|
|
42
42
|
margin-left: -0.55em;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
/* --- Schema Table Border Model --- */
|
|
46
|
+
|
|
47
|
+
/*
|
|
48
|
+
* Use border-collapse: separate with 0 spacing so that backgrounds are
|
|
49
|
+
* painted directly adjacent between rows — no collapsed border line is
|
|
50
|
+
* rendered on top of the background gradients. Horizontal separators are
|
|
51
|
+
* recreated via box-shadow so they don't interrupt vertical lines.
|
|
52
|
+
*/
|
|
53
|
+
.schema-table {
|
|
54
|
+
border-collapse: separate;
|
|
55
|
+
border-spacing: 0;
|
|
56
|
+
border: 1px solid var(--ifm-table-border-color);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.schema-table th,
|
|
60
|
+
.schema-table td {
|
|
61
|
+
border: none;
|
|
62
|
+
border-left: 1px solid var(--ifm-table-border-color);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.schema-table th:first-child,
|
|
66
|
+
.schema-table td:first-child {
|
|
67
|
+
border-left: none;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.schema-table thead th {
|
|
71
|
+
border-bottom: 2px solid var(--ifm-table-border-color);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* Row separators via box-shadow (doesn't mask background gradients) */
|
|
75
|
+
.schema-table tbody tr + tr td {
|
|
76
|
+
box-shadow: inset 0 1px 0 var(--ifm-table-border-color);
|
|
77
|
+
}
|
|
78
|
+
|
|
45
79
|
/* --- Organigram Connector Line Styles --- */
|
|
46
80
|
|
|
47
81
|
/*
|
|
@@ -225,6 +259,87 @@ td.level-6::after {
|
|
|
225
259
|
transform: rotate(45deg);
|
|
226
260
|
}
|
|
227
261
|
|
|
262
|
+
/* --- Conditional Row Styles --- */
|
|
263
|
+
|
|
264
|
+
.conditional-condition-header {
|
|
265
|
+
background-color: rgba(var(--ifm-color-info-rgb), 0.08);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.conditional-condition-header:hover {
|
|
269
|
+
background-color: rgba(var(--ifm-color-info-rgb), 0.12);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.conditional-condition-label {
|
|
273
|
+
display: flex;
|
|
274
|
+
align-items: center;
|
|
275
|
+
gap: 0.5rem;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.conditional-info-icon-wrapper {
|
|
279
|
+
position: relative;
|
|
280
|
+
display: inline-flex;
|
|
281
|
+
cursor: help;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.conditional-info-icon {
|
|
285
|
+
display: inline-flex;
|
|
286
|
+
align-items: center;
|
|
287
|
+
justify-content: center;
|
|
288
|
+
width: 1.25rem;
|
|
289
|
+
height: 1.25rem;
|
|
290
|
+
border-radius: 50%;
|
|
291
|
+
background-color: var(--ifm-color-info);
|
|
292
|
+
color: white;
|
|
293
|
+
font-size: 0.75rem;
|
|
294
|
+
font-weight: bold;
|
|
295
|
+
font-style: italic;
|
|
296
|
+
flex-shrink: 0;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.conditional-info-tooltip {
|
|
300
|
+
display: none;
|
|
301
|
+
position: absolute;
|
|
302
|
+
bottom: calc(100% + 0.5rem);
|
|
303
|
+
left: 0;
|
|
304
|
+
background-color: var(--ifm-color-emphasis-800);
|
|
305
|
+
color: var(--ifm-color-emphasis-0);
|
|
306
|
+
padding: 0.5rem 0.75rem;
|
|
307
|
+
border-radius: 0.375rem;
|
|
308
|
+
font-size: 0.8rem;
|
|
309
|
+
font-style: normal;
|
|
310
|
+
font-weight: normal;
|
|
311
|
+
line-height: 1.4;
|
|
312
|
+
white-space: normal;
|
|
313
|
+
width: max-content;
|
|
314
|
+
max-width: 280px;
|
|
315
|
+
z-index: 10;
|
|
316
|
+
pointer-events: none;
|
|
317
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.conditional-info-tooltip::after {
|
|
321
|
+
content: '';
|
|
322
|
+
position: absolute;
|
|
323
|
+
top: 100%;
|
|
324
|
+
left: 0.625rem;
|
|
325
|
+
border: 0.375rem solid transparent;
|
|
326
|
+
border-top-color: var(--ifm-color-emphasis-800);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.conditional-info-icon-wrapper:hover .conditional-info-tooltip {
|
|
330
|
+
display: block;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.conditional-condition-description {
|
|
334
|
+
margin-left: 1.75rem;
|
|
335
|
+
font-size: 0.9em;
|
|
336
|
+
color: var(--ifm-color-secondary-darkest);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.conditional-condition-row {
|
|
340
|
+
background-color: rgba(var(--ifm-color-info-rgb), 0.04);
|
|
341
|
+
}
|
|
342
|
+
|
|
228
343
|
/* --- Example CodeBlock Styles --- */
|
|
229
344
|
|
|
230
345
|
.schema-examples {
|
package/components/SchemaRows.js
CHANGED
|
@@ -2,26 +2,53 @@ import React from 'react';
|
|
|
2
2
|
import './SchemaRows.css';
|
|
3
3
|
import PropertyRow from './PropertyRow';
|
|
4
4
|
import FoldableRows from './FoldableRows';
|
|
5
|
+
import ConditionalRows from './ConditionalRows';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Renders the rows of the schema table from a flat `tableData` array.
|
|
8
9
|
* It maps over the array and renders the appropriate component for each row.
|
|
10
|
+
*
|
|
11
|
+
* @param {object} props
|
|
12
|
+
* @param {Array} props.tableData - Flat array of row objects
|
|
13
|
+
* @param {Array} [props.bracketEnds] - Bracket descriptors that end on the last row
|
|
9
14
|
*/
|
|
10
|
-
export default function SchemaRows({ tableData }) {
|
|
15
|
+
export default function SchemaRows({ tableData, bracketEnds }) {
|
|
11
16
|
if (!tableData) {
|
|
12
17
|
return null;
|
|
13
18
|
}
|
|
14
19
|
|
|
15
|
-
return tableData.map((row) => {
|
|
20
|
+
return tableData.map((row, index) => {
|
|
16
21
|
const key = row.path.join('.');
|
|
22
|
+
const isLast = index === tableData.length - 1;
|
|
17
23
|
|
|
18
24
|
if (row.type === 'choice') {
|
|
19
|
-
return
|
|
25
|
+
return (
|
|
26
|
+
<FoldableRows
|
|
27
|
+
key={key}
|
|
28
|
+
row={row}
|
|
29
|
+
bracketEnds={isLast ? bracketEnds : undefined}
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (row.type === 'conditional') {
|
|
35
|
+
return (
|
|
36
|
+
<ConditionalRows
|
|
37
|
+
key={key}
|
|
38
|
+
row={row}
|
|
39
|
+
bracketEnds={isLast ? bracketEnds : undefined}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
20
42
|
}
|
|
21
43
|
|
|
22
44
|
if (row.type === 'property') {
|
|
23
45
|
return (
|
|
24
|
-
<PropertyRow
|
|
46
|
+
<PropertyRow
|
|
47
|
+
key={key}
|
|
48
|
+
row={row}
|
|
49
|
+
isLastInGroup={row.isLastInGroup}
|
|
50
|
+
bracketEnds={isLast ? bracketEnds : undefined}
|
|
51
|
+
/>
|
|
25
52
|
);
|
|
26
53
|
}
|
|
27
54
|
|
package/generateEventDocs.js
CHANGED
|
@@ -7,6 +7,20 @@ import SchemaDocTemplate from './helpers/schema-doc-template.js';
|
|
|
7
7
|
import ChoiceIndexTemplate from './helpers/choice-index-template.js';
|
|
8
8
|
import processSchema from './helpers/processSchema.js';
|
|
9
9
|
|
|
10
|
+
function buildEditUrl(organizationName, projectName, siteDir, filePath) {
|
|
11
|
+
const baseEditUrl = `https://github.com/${organizationName}/${projectName}/edit/main`;
|
|
12
|
+
return `${baseEditUrl}/${path.relative(path.join(siteDir, '..'), filePath)}`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function resolvePartial(partialPath, relativePartialsDir, componentPrefix) {
|
|
16
|
+
if (!fs.existsSync(partialPath)) return { import: '', component: '' };
|
|
17
|
+
const fileName = path.basename(partialPath);
|
|
18
|
+
return {
|
|
19
|
+
import: `import ${componentPrefix} from '@site/${relativePartialsDir}/${fileName}';`,
|
|
20
|
+
component: `<${componentPrefix} />`,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
10
24
|
async function generateAndWriteDoc(
|
|
11
25
|
filePath,
|
|
12
26
|
schema,
|
|
@@ -18,7 +32,6 @@ async function generateAndWriteDoc(
|
|
|
18
32
|
) {
|
|
19
33
|
const { organizationName, projectName, siteDir, dataLayerName, version } =
|
|
20
34
|
options;
|
|
21
|
-
const baseEditUrl = `https://github.com/${organizationName}/${projectName}/edit/main`;
|
|
22
35
|
|
|
23
36
|
const { outputDir: versionOutputDir } = getPathsForVersion(version, siteDir);
|
|
24
37
|
const PARTIALS_DIR = path.join(versionOutputDir, 'partials');
|
|
@@ -27,37 +40,33 @@ async function generateAndWriteDoc(
|
|
|
27
40
|
const mergedSchema = alreadyMergedSchema || (await processSchema(filePath));
|
|
28
41
|
|
|
29
42
|
// Check for partials
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const editUrl = `${baseEditUrl}/${path.relative(
|
|
48
|
-
path.join(siteDir, '..'),
|
|
43
|
+
const top = resolvePartial(
|
|
44
|
+
path.join(PARTIALS_DIR, `_${eventName}.mdx`),
|
|
45
|
+
relativePartialsDir,
|
|
46
|
+
'TopPartial',
|
|
47
|
+
);
|
|
48
|
+
const bottom = resolvePartial(
|
|
49
|
+
path.join(PARTIALS_DIR, `_${eventName}_bottom.mdx`),
|
|
50
|
+
relativePartialsDir,
|
|
51
|
+
'BottomPartial',
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const editUrl = buildEditUrl(
|
|
55
|
+
organizationName,
|
|
56
|
+
projectName,
|
|
57
|
+
siteDir,
|
|
49
58
|
editFilePath || filePath,
|
|
50
|
-
)
|
|
59
|
+
);
|
|
51
60
|
|
|
52
61
|
const mdxContent = SchemaDocTemplate({
|
|
53
62
|
schema,
|
|
54
63
|
mergedSchema,
|
|
55
64
|
editUrl,
|
|
56
65
|
file: path.basename(filePath),
|
|
57
|
-
topPartialImport,
|
|
58
|
-
bottomPartialImport,
|
|
59
|
-
topPartialComponent,
|
|
60
|
-
bottomPartialComponent,
|
|
66
|
+
topPartialImport: top.import,
|
|
67
|
+
bottomPartialImport: bottom.import,
|
|
68
|
+
topPartialComponent: top.component,
|
|
69
|
+
bottomPartialComponent: bottom.component,
|
|
61
70
|
dataLayerName,
|
|
62
71
|
});
|
|
63
72
|
|
|
@@ -73,8 +82,12 @@ async function generateOneOfDocs(
|
|
|
73
82
|
options,
|
|
74
83
|
) {
|
|
75
84
|
const { organizationName, projectName, siteDir } = options;
|
|
76
|
-
const
|
|
77
|
-
|
|
85
|
+
const editUrl = buildEditUrl(
|
|
86
|
+
organizationName,
|
|
87
|
+
projectName,
|
|
88
|
+
siteDir,
|
|
89
|
+
filePath,
|
|
90
|
+
);
|
|
78
91
|
|
|
79
92
|
const eventOutputDir = path.join(outputDir, eventName);
|
|
80
93
|
createDir(eventOutputDir);
|
|
@@ -96,8 +109,6 @@ async function generateOneOfDocs(
|
|
|
96
109
|
const prefixedSlug = `${(index + 1).toString().padStart(2, '0')}-${slug}`;
|
|
97
110
|
|
|
98
111
|
if (subChoiceType) {
|
|
99
|
-
const tempFilePath = path.join(eventOutputDir, `${slug}.json`);
|
|
100
|
-
fs.writeFileSync(tempFilePath, JSON.stringify(processedSchema, null, 2));
|
|
101
112
|
await generateOneOfDocs(
|
|
102
113
|
prefixedSlug,
|
|
103
114
|
processedSchema,
|
|
@@ -105,12 +116,9 @@ async function generateOneOfDocs(
|
|
|
105
116
|
eventOutputDir,
|
|
106
117
|
options,
|
|
107
118
|
);
|
|
108
|
-
fs.unlinkSync(tempFilePath);
|
|
109
119
|
} else {
|
|
110
|
-
const tempFilePath = path.join(eventOutputDir, `${prefixedSlug}.json`);
|
|
111
|
-
fs.writeFileSync(tempFilePath, JSON.stringify(processedSchema, null, 2));
|
|
112
120
|
await generateAndWriteDoc(
|
|
113
|
-
|
|
121
|
+
`${prefixedSlug}.json`,
|
|
114
122
|
processedSchema,
|
|
115
123
|
slug,
|
|
116
124
|
eventOutputDir,
|
|
@@ -118,7 +126,6 @@ async function generateOneOfDocs(
|
|
|
118
126
|
processedSchema,
|
|
119
127
|
sourceFilePath || filePath,
|
|
120
128
|
);
|
|
121
|
-
fs.unlinkSync(tempFilePath);
|
|
122
129
|
}
|
|
123
130
|
}
|
|
124
131
|
}
|
|
@@ -30,6 +30,17 @@ const buildExampleFromSchema = (schema) => {
|
|
|
30
30
|
return buildExampleFromSchema(merged);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
// For conditionals, default to the 'then' branch and recurse.
|
|
34
|
+
if (schema.if && schema.then) {
|
|
35
|
+
const newSchema = { ...schema };
|
|
36
|
+
const thenBranch = newSchema.then;
|
|
37
|
+
delete newSchema.if;
|
|
38
|
+
delete newSchema.then;
|
|
39
|
+
delete newSchema.else;
|
|
40
|
+
const merged = mergeJsonSchema({ allOf: [newSchema, thenBranch] });
|
|
41
|
+
return buildExampleFromSchema(merged);
|
|
42
|
+
}
|
|
43
|
+
|
|
33
44
|
// If there's an explicit example, use it.
|
|
34
45
|
const exampleValue = getSingleExampleValue(schema);
|
|
35
46
|
if (typeof exampleValue !== 'undefined') {
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Colors for group bracket lines, indexed by bracketIndex.
|
|
3
|
+
* Uses Docusaurus CSS custom properties so they adapt to light/dark themes.
|
|
4
|
+
*/
|
|
5
|
+
const BRACKET_COLORS = [
|
|
6
|
+
'var(--ifm-color-info)',
|
|
7
|
+
'var(--ifm-color-warning)',
|
|
8
|
+
'var(--ifm-color-success)',
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Returns the right-offset (in rem) for a bracket line.
|
|
13
|
+
* Brackets are positioned from the right edge of the cell so they appear
|
|
14
|
+
* on the right side of the table, away from the tree connector lines.
|
|
15
|
+
*
|
|
16
|
+
* B=0 → 0.50 rem from right
|
|
17
|
+
* B=1 → 0.75 rem from right
|
|
18
|
+
* B=2 → 1.00 rem from right
|
|
19
|
+
*/
|
|
20
|
+
export const getBracketPosition = (bracketIndex) => 0.5 + bracketIndex * 0.25;
|
|
21
|
+
|
|
22
|
+
export const getBracketColor = (bracketIndex) =>
|
|
23
|
+
BRACKET_COLORS[bracketIndex % BRACKET_COLORS.length];
|
|
24
|
+
|
|
25
|
+
/** Width of horizontal cap lines in pixels */
|
|
26
|
+
const CAP_WIDTH = 10;
|
|
27
|
+
|
|
28
|
+
/** Inset from cell edge for cap lines (so they aren't hidden by table borders) */
|
|
29
|
+
const CAP_INSET = 6;
|
|
30
|
+
|
|
31
|
+
/** Helper to create a bracket key for Set lookups */
|
|
32
|
+
const bracketKey = (b) => `${b.level}:${b.bracketIndex}`;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Generates inline styles for bracket lines positioned on the right side.
|
|
36
|
+
* Supports optional horizontal "cap" lines at the top and/or bottom of
|
|
37
|
+
* brackets to visually delineate where a bracket group starts and ends.
|
|
38
|
+
*
|
|
39
|
+
* @param {Array<{level: number, bracketIndex: number}>} groupBrackets - Active bracket groups
|
|
40
|
+
* @param {object} [caps] - Optional cap configuration
|
|
41
|
+
* @param {Array<{level: number, bracketIndex: number}>} [caps.starting] - Brackets needing a top cap
|
|
42
|
+
* @param {Array<{level: number, bracketIndex: number}>} [caps.ending] - Brackets needing a bottom cap
|
|
43
|
+
* @returns {object} Style object with background gradients
|
|
44
|
+
*/
|
|
45
|
+
export const getBracketLinesStyle = (groupBrackets = [], caps = {}) => {
|
|
46
|
+
if (groupBrackets.length === 0) return {};
|
|
47
|
+
|
|
48
|
+
const startingKeys = new Set((caps.starting || []).map(bracketKey));
|
|
49
|
+
const endingKeys = new Set((caps.ending || []).map(bracketKey));
|
|
50
|
+
|
|
51
|
+
const gradients = [];
|
|
52
|
+
const sizes = [];
|
|
53
|
+
const positions = [];
|
|
54
|
+
|
|
55
|
+
groupBrackets.forEach((bracket) => {
|
|
56
|
+
const { bracketIndex } = bracket;
|
|
57
|
+
const pos = getBracketPosition(bracketIndex);
|
|
58
|
+
const color = getBracketColor(bracketIndex);
|
|
59
|
+
const key = bracketKey(bracket);
|
|
60
|
+
const isStarting = startingKeys.has(key);
|
|
61
|
+
const isEnding = endingKeys.has(key);
|
|
62
|
+
|
|
63
|
+
// Vertical line — shortened when caps are present so it doesn't bleed past them
|
|
64
|
+
const topInset = isStarting ? CAP_INSET : 0;
|
|
65
|
+
const bottomInset = isEnding ? CAP_INSET : 0;
|
|
66
|
+
gradients.push(`linear-gradient(${color}, ${color})`);
|
|
67
|
+
sizes.push(`1px calc(100% - ${topInset + bottomInset}px)`);
|
|
68
|
+
positions.push(`right ${pos}rem top ${topInset}px`);
|
|
69
|
+
|
|
70
|
+
// Horizontal cap at the top (bracket start) — inset from cell edge
|
|
71
|
+
if (isStarting) {
|
|
72
|
+
const capOffset = (CAP_WIDTH - 1) / 2; // center cap on the vertical line
|
|
73
|
+
gradients.push(`linear-gradient(${color}, ${color})`);
|
|
74
|
+
sizes.push(`${CAP_WIDTH}px 1px`);
|
|
75
|
+
positions.push(
|
|
76
|
+
`right calc(${pos}rem - ${capOffset}px) top ${CAP_INSET}px`,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Horizontal cap at the bottom (bracket end) — inset from cell edge
|
|
81
|
+
if (isEnding) {
|
|
82
|
+
const capOffset = (CAP_WIDTH - 1) / 2;
|
|
83
|
+
gradients.push(`linear-gradient(${color}, ${color})`);
|
|
84
|
+
sizes.push(`${CAP_WIDTH}px 1px`);
|
|
85
|
+
positions.push(
|
|
86
|
+
`right calc(${pos}rem - ${capOffset}px) bottom ${CAP_INSET}px`,
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
backgroundImage: gradients.join(', '),
|
|
93
|
+
backgroundSize: sizes.join(', '),
|
|
94
|
+
backgroundPosition: positions.join(', '),
|
|
95
|
+
backgroundRepeat: 'no-repeat',
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Merges two background-gradient style objects into one.
|
|
101
|
+
* @param {object} style1 - First style object
|
|
102
|
+
* @param {object} style2 - Second style object
|
|
103
|
+
* @returns {object} Merged style object
|
|
104
|
+
*/
|
|
105
|
+
export const mergeBackgroundStyles = (style1, style2) => {
|
|
106
|
+
if (!style2.backgroundImage) return style1;
|
|
107
|
+
if (!style1.backgroundImage) return { ...style1, ...style2 };
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
...style1,
|
|
111
|
+
backgroundImage: `${style1.backgroundImage}, ${style2.backgroundImage}`,
|
|
112
|
+
backgroundSize: `${style1.backgroundSize}, ${style2.backgroundSize}`,
|
|
113
|
+
backgroundPosition: `${style1.backgroundPosition}, ${style2.backgroundPosition}`,
|
|
114
|
+
backgroundRepeat: 'no-repeat',
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Generates inline styles for continuing hierarchical lines through a row.
|
|
120
|
+
* Only handles tree connector lines (left side). Bracket lines are separate.
|
|
121
|
+
* @param {number[]} continuingLevels - Array of ancestor levels that need lines
|
|
122
|
+
* @param {number} level - Current level of the row
|
|
123
|
+
* @returns {object} Style object with background gradients
|
|
124
|
+
*/
|
|
125
|
+
export const getContinuingLinesStyle = (continuingLevels = [], level = 0) => {
|
|
126
|
+
const getLevelPosition = (lvl) => lvl * 1.25 + 0.5;
|
|
127
|
+
|
|
128
|
+
const allGradients = [];
|
|
129
|
+
const allSizes = [];
|
|
130
|
+
const allPositions = [];
|
|
131
|
+
|
|
132
|
+
// Draw continuing lines for all ancestor levels
|
|
133
|
+
continuingLevels.forEach((lvl) => {
|
|
134
|
+
const pos = getLevelPosition(lvl);
|
|
135
|
+
allGradients.push(
|
|
136
|
+
'linear-gradient(var(--ifm-table-border-color), var(--ifm-table-border-color))',
|
|
137
|
+
);
|
|
138
|
+
allSizes.push('1px 100%');
|
|
139
|
+
allPositions.push(`${pos}rem top`);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Also draw the line for the immediate parent level (level - 1) if level > 0
|
|
143
|
+
// This connects the rows to their parent property
|
|
144
|
+
if (level > 0) {
|
|
145
|
+
const parentPos = getLevelPosition(level - 1);
|
|
146
|
+
if (!continuingLevels.includes(level - 1)) {
|
|
147
|
+
allGradients.push(
|
|
148
|
+
'linear-gradient(var(--ifm-table-border-color), var(--ifm-table-border-color))',
|
|
149
|
+
);
|
|
150
|
+
allSizes.push('1px 100%');
|
|
151
|
+
allPositions.push(`${parentPos}rem top`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Calculate indentation based on level
|
|
156
|
+
const paddingLeft = `${level * 1.25 + 0.5}rem`;
|
|
157
|
+
|
|
158
|
+
if (allGradients.length === 0) {
|
|
159
|
+
return { paddingLeft };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
paddingLeft,
|
|
164
|
+
backgroundImage: allGradients.join(', '),
|
|
165
|
+
backgroundSize: allSizes.join(', '),
|
|
166
|
+
backgroundPosition: allPositions.join(', '),
|
|
167
|
+
backgroundRepeat: 'no-repeat',
|
|
168
|
+
};
|
|
169
|
+
};
|
|
@@ -8,6 +8,7 @@ export default function MdxTemplate(data) {
|
|
|
8
8
|
bottomPartialImport,
|
|
9
9
|
topPartialComponent,
|
|
10
10
|
bottomPartialComponent,
|
|
11
|
+
dataLayerName,
|
|
11
12
|
} = data;
|
|
12
13
|
|
|
13
14
|
return `---
|
|
@@ -30,11 +31,7 @@ ${topPartialComponent}
|
|
|
30
31
|
|
|
31
32
|
<SchemaViewer
|
|
32
33
|
schema={${JSON.stringify(mergedSchema)}}
|
|
33
|
-
${
|
|
34
|
-
data.dataLayerName && data.dataLayerName !== 'undefined'
|
|
35
|
-
? ` dataLayerName={'${data.dataLayerName}'}`
|
|
36
|
-
: ''
|
|
37
|
-
}
|
|
34
|
+
${dataLayerName ? ` dataLayerName={'${dataLayerName}'}` : ''}
|
|
38
35
|
/>
|
|
39
36
|
<SchemaJsonViewer schema={${JSON.stringify(schema)}} />
|
|
40
37
|
|