Skip to content

Commit 2a106f3

Browse files
authored
fix: resolve [object Object] in ChangeHistory aria-label and dropdown scrolbar (#1034)
1 parent 15b3f3e commit 2a106f3

4 files changed

Lines changed: 111 additions & 4 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@doc-kit/generator-react': patch
3+
---
4+
5+
Fix `[object Object]` in ChangeHistory aria-label and dropdown horizontal scrollbar
6+
7+
- Change history labels were passing a JSX AST object instead of a plain text
8+
string to the `ChangeHistory` component, causing `aria-label` to render as
9+
`[object Object]`. Labels are now extracted as plain text via `remark-parse`.
10+
- The ChangeHistory dropdown could show a horizontal scrollbar when label text
11+
overflowed the fixed-width container. Added `overflow-wrap` and `word-break`
12+
rules to prevent this.

packages/react/src/html/ui/index.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,12 @@ main {
120120

121121
div[role='menu'] {
122122
left: 0;
123+
124+
/* Prevent long labels from overflowing dropdown width */
125+
a[role='menuitem'] div {
126+
overflow-wrap: anywhere;
127+
word-break: break-word;
128+
}
123129
}
124130
}
125131
}

packages/react/src/jsx-ast/utils/__tests__/buildContent.test.mjs

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { describe, it } from 'node:test';
33

44
import { setConfig } from '@doc-kit/core/utils/configuration/index.mjs';
55

6-
import { transformHeadingNode } from '../buildContent.mjs';
6+
import { transformHeadingNode, gatherChangeEntries } from '../buildContent.mjs';
77

88
const heading = {
99
type: 'heading',
@@ -67,3 +67,78 @@ describe('transformHeadingNode (deprecation Type -> AlertBox level)', () => {
6767
assert.equal(levelAttr.value, 'danger');
6868
});
6969
});
70+
71+
describe('gatherChangeEntries', () => {
72+
it('returns empty array when entry has no changes', () => {
73+
assert.deepEqual(gatherChangeEntries({}), []);
74+
});
75+
76+
it('collects lifecycle changes with formatted labels', () => {
77+
const result = gatherChangeEntries({
78+
added: ['v20.0.0', 'v18.0.0'],
79+
deprecated: 'v22.0.0',
80+
});
81+
82+
assert.equal(result.length, 2);
83+
assert.deepEqual(result[0], {
84+
versions: ['v20.0.0', 'v18.0.0'],
85+
label: 'Added in: v20.0.0, v18.0.0',
86+
});
87+
assert.deepEqual(result[1], {
88+
versions: ['v22.0.0'],
89+
label: 'Deprecated in: v22.0.0',
90+
});
91+
});
92+
93+
it('extracts plain text labels from markdown descriptions', () => {
94+
const result = gatherChangeEntries({
95+
changes: [
96+
{
97+
version: 'v25.0.0',
98+
description:
99+
'Add `modifyPrototype` option to conditionally modify the prototype.',
100+
'pr-url': 'https://github.com/nodejs/node/pull/123',
101+
},
102+
],
103+
});
104+
105+
assert.equal(result.length, 1);
106+
assert.equal(
107+
result[0].label,
108+
'Add `modifyPrototype` option to conditionally modify the prototype.'
109+
);
110+
assert.equal(result[0].url, 'https://github.com/nodejs/node/pull/123');
111+
assert.deepEqual(result[0].versions, ['v25.0.0']);
112+
});
113+
114+
it('produces a string label, not an object (regression for [object Object])', () => {
115+
const result = gatherChangeEntries({
116+
changes: [
117+
{
118+
version: 'v1.0.0',
119+
description: 'Some **bold** and _italic_ text.',
120+
},
121+
],
122+
});
123+
124+
assert.equal(typeof result[0].label, 'string');
125+
assert.equal(result[0].label, 'Some **bold** and _italic_ text.');
126+
});
127+
128+
it('combines lifecycle changes and explicit changes', () => {
129+
const result = gatherChangeEntries({
130+
added: 'v20.0.0',
131+
changes: [
132+
{
133+
version: 'v21.0.0',
134+
description: 'Added new feature.',
135+
'pr-url': 'https://example.com/pr/1',
136+
},
137+
],
138+
});
139+
140+
assert.equal(result.length, 2);
141+
assert.equal(result[0].label, 'Added in: v20.0.0');
142+
assert.equal(result[1].label, 'Added new feature.');
143+
});
144+
});

packages/react/src/jsx-ast/utils/buildContent.mjs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@ import {
88
} from '@doc-kit/core/utils/configuration/templates.mjs';
99
import { omitKeys } from '@doc-kit/core/utils/misc.mjs';
1010
import { UNIST } from '@doc-kit/core/utils/queries/index.mjs';
11+
import { transformNodesToString } from '@doc-kit/core/utils/unist.mjs';
1112
import { h as createElement } from 'hastscript';
1213
import { slice } from 'mdast-util-slice-markdown';
1314
import readingTime from 'reading-time';
15+
import remarkParse from 'remark-parse';
16+
import { unified } from 'unified';
1417
import { u as createTree } from 'unist-builder';
1518
import { SKIP, visit } from 'unist-util-visit';
1619

@@ -35,6 +38,18 @@ import {
3538
getFullName,
3639
} from './signature.mjs';
3740

41+
/**
42+
* Converts a markdown string to plain text by parsing it and extracting
43+
* text and inline code values.
44+
*
45+
* @param {string} markdown - The markdown string to convert.
46+
* @returns {string} The plain text representation.
47+
*/
48+
const toPlainText = markdown =>
49+
transformNodesToString(
50+
unified().use(remarkParse).parse(markdown).children
51+
).trim();
52+
3853
/**
3954
* Processes lifecycle and change history data into a sorted array of change entries.
4055
* @param {import('@doc-kit/core/generators/metadata/types').MetadataEntry} entry - The metadata entry
@@ -48,11 +63,10 @@ export const gatherChangeEntries = entry => {
4863
label: `${label}: ${enforceArray(entry[field]).join(', ')}`,
4964
}));
5065

51-
// Explicit changes with parsed JSX labels
66+
// Explicit changes with plain-text labels extracted from markdown
5267
const explicitChanges = (entry.changes || []).map(change => ({
5368
versions: enforceArray(change.version),
54-
label: remark().runSync(remark().parse(change.description)).body[0]
55-
.expression,
69+
label: toPlainText(change.description),
5670
url: change['pr-url'],
5771
}));
5872

0 commit comments

Comments
 (0)