Skip to content

Commit b2313e9

Browse files
marinaaisahqhhuang
andauthored
[rdar://30234820] fix: AX in tables (#674)
Co-authored-by: Hanqing Huang <[email protected]>
1 parent 8696137 commit b2313e9

File tree

5 files changed

+95
-94
lines changed

5 files changed

+95
-94
lines changed

src/components/ContentNode.vue

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import CodeVoice from './ContentNode/CodeVoice.vue';
1717
import DictionaryExample from './ContentNode/DictionaryExample.vue';
1818
import EndpointExample from './ContentNode/EndpointExample.vue';
1919
import Figure from './ContentNode/Figure.vue';
20-
import FigureCaption from './ContentNode/FigureCaption.vue';
20+
import Caption from './ContentNode/Caption.vue';
2121
import InlineImage from './ContentNode/InlineImage.vue';
2222
import Reference from './ContentNode/Reference.vue';
2323
import Table from './ContentNode/Table.vue';
@@ -230,8 +230,8 @@ function renderNode(createElement, references) {
230230
if ((title && abstract.length) || abstract.length) {
231231
// if there is a `title`, it should be above, otherwise below
232232
figureContent.splice(title ? 0 : 1, 0,
233-
createElement(FigureCaption, {
234-
props: { title, centered: !title },
233+
createElement(Caption, {
234+
props: { title, tag: 'figcaption', centered: !title },
235235
}, renderChildren(abstract)));
236236
}
237237
return createElement(Figure, { props: { anchor } }, figureContent);
@@ -297,18 +297,27 @@ function renderNode(createElement, references) {
297297
renderChildren(node.inlineContent)
298298
));
299299
}
300-
case BlockType.table:
301-
if (node.metadata && node.metadata.anchor) {
302-
return renderFigure(node);
300+
case BlockType.table: {
301+
const tableChildren = [];
302+
if (node.metadata && node.metadata.anchor && node.metadata.title) {
303+
tableChildren.push(
304+
createElement(Caption,
305+
{ props: { title: node.metadata.title } },
306+
renderChildren(node.metadata.abstract)),
307+
);
303308
}
304-
305-
return createElement(Table, {
306-
props: {
307-
spanned: !!node.extendedData,
308-
},
309-
}, (
310-
renderTableChildren(node.rows, node.header, node.extendedData, node.alignments)
309+
tableChildren.push(renderTableChildren(
310+
node.rows, node.header, node.extendedData, node.alignments,
311311
));
312+
return createElement(
313+
Table,
314+
{
315+
attrs: { id: node.metadata && node.metadata.anchor },
316+
props: { spanned: !!node.extendedData },
317+
},
318+
tableChildren,
319+
);
320+
}
312321
case BlockType.termList:
313322
return createElement('dl', {}, node.items.map(({ term, definition }) => [
314323
createElement('dt', {}, (

src/components/ContentNode/FigureCaption.vue renamed to src/components/ContentNode/Caption.vue

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@
99
-->
1010

1111
<template>
12-
<figcaption class="caption" :class="{ centered }">
12+
<component :is="tag" class="caption" :class="{ centered }">
1313
<template v-if="title">
1414
<strong>{{ title }}</strong>&nbsp;<slot />
1515
</template>
1616
<template v-else>
1717
<slot />
1818
</template>
19-
</figcaption>
19+
</component>
2020
</template>
2121

2222
<script>
2323
export default {
24-
name: 'FigureCaption',
24+
name: 'Caption',
2525
props: {
2626
title: {
2727
type: String,
@@ -31,6 +31,11 @@ export default {
3131
type: Boolean,
3232
default: false,
3333
},
34+
tag: {
35+
type: String,
36+
required: false,
37+
default: () => 'caption',
38+
},
3439
},
3540
};
3641
</script>
@@ -53,4 +58,8 @@ export default {
5358
/deep/ p {
5459
display: inline-block;
5560
}
61+
62+
caption {
63+
margin: 1rem 0;
64+
}
5665
</style>

src/styles/core/typography/_font-styles.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ $font-styles: (
153153
documentation-code-listing-number: (
154154
large: 12_18_normal_compact_mono,
155155
),
156-
documentation-figcaption: (
156+
documentation-caption: (
157157
large: 14_21,
158158
),
159159
documentation-declaration-link: (

tests/unit/components/ContentNode.spec.js

Lines changed: 44 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import ContentNode from 'docc-render/components/ContentNode.vue';
1616
import DictionaryExample from 'docc-render/components/ContentNode/DictionaryExample.vue';
1717
import EndpointExample from 'docc-render/components/ContentNode/EndpointExample.vue';
1818
import Figure from 'docc-render/components/ContentNode/Figure.vue';
19-
import FigureCaption from 'docc-render/components/ContentNode/FigureCaption.vue';
19+
import Caption from 'docc-render/components/ContentNode/Caption.vue';
2020
import InlineImage from 'docc-render/components/ContentNode/InlineImage.vue';
2121
import Reference from 'docc-render/components/ContentNode/Reference.vue';
2222
import Table from 'docc-render/components/ContentNode/Table.vue';
@@ -112,29 +112,6 @@ describe('ContentNode', () => {
112112
expect(codeListing.props('content')).toEqual(listing.code);
113113
expect(codeListing.isEmpty()).toBe(true);
114114
});
115-
116-
it('renders a `Figure`/`Figcaption` with metadata', () => {
117-
const metadata = {
118-
anchor: '42',
119-
title: 'Listing 42',
120-
abstract: [{
121-
type: 'paragraph',
122-
inlineContent: [{ type: 'text', text: 'blah' }],
123-
}],
124-
};
125-
const wrapper = mountWithItem({ ...listing, metadata });
126-
127-
const figure = wrapper.find(Figure);
128-
expect(figure.exists()).toBe(true);
129-
expect(figure.props('anchor')).toBe(metadata.anchor);
130-
expect(figure.contains(CodeListing)).toBe(true);
131-
132-
const caption = figure.find(FigureCaption);
133-
expect(caption.exists()).toBe(true);
134-
expect(caption.props('title')).toBe(metadata.title);
135-
expect(caption.contains('p')).toBe(true);
136-
expect(caption.text()).toContain('blah');
137-
});
138115
});
139116

140117
describe('with type="endpointExample"', () => {
@@ -714,7 +691,7 @@ describe('ContentNode', () => {
714691
}, {})).not.toThrow();
715692
});
716693

717-
it('renders a `Figure`/`FigureCaption` with metadata', () => {
694+
it('renders a `Figure`/`Caption` with metadata', () => {
718695
const metadata = {
719696
anchor: '42',
720697
title: 'Figure 42',
@@ -734,14 +711,14 @@ describe('ContentNode', () => {
734711
expect(figure.props('anchor')).toBe(metadata.anchor);
735712
expect(figure.contains(InlineImage)).toBe(true);
736713

737-
const caption = wrapper.find(FigureCaption);
714+
const caption = wrapper.find(Caption);
738715
expect(caption.exists()).toBe(true);
739716
expect(caption.contains('p')).toBe(true);
740717
expect(caption.props('title')).toBe(metadata.title);
741718
expect(caption.text()).toContain('blah');
742719
});
743720

744-
it('renders a `Figure`/`FigureCaption` without an anchor, with text under the image', () => {
721+
it('renders a `Figure`/`Caption` without an anchor, with text under the image', () => {
745722
const metadata = {
746723
abstract: [{
747724
type: 'paragraph',
@@ -759,7 +736,7 @@ describe('ContentNode', () => {
759736
expect(figure.props('anchor')).toBeFalsy();
760737
expect(figure.contains(InlineImage)).toBe(true);
761738

762-
const caption = wrapper.find(FigureCaption);
739+
const caption = wrapper.find(Caption);
763740
expect(caption.exists()).toBe(true);
764741
expect(caption.contains('p')).toBe(true);
765742
expect(caption.props('title')).toBeFalsy();
@@ -769,9 +746,9 @@ describe('ContentNode', () => {
769746
expect(figure.html()).toMatchInlineSnapshot(`
770747
<figure-stub>
771748
<inlineimage-stub alt="" variants="[object Object],[object Object]"></inlineimage-stub>
772-
<figurecaption-stub centered="true">
749+
<caption-stub centered="true" tag="figcaption">
773750
<p>blah</p>
774-
</figurecaption-stub>
751+
</caption-stub>
775752
</figure-stub>
776753
`);
777754
});
@@ -791,9 +768,9 @@ describe('ContentNode', () => {
791768
}, references);
792769
expect(wrapper.find(Figure).html()).toMatchInlineSnapshot(`
793770
<figure-stub>
794-
<figurecaption-stub title="foo">
771+
<caption-stub title="foo" tag="figcaption">
795772
<p>blah</p>
796-
</figurecaption-stub>
773+
</caption-stub>
797774
<inlineimage-stub alt="" variants="[object Object],[object Object]"></inlineimage-stub>
798775
</figure-stub>
799776
`);
@@ -816,7 +793,7 @@ describe('ContentNode', () => {
816793
expect(figure.props('anchor')).toBe('foo-figure');
817794
expect(figure.contains(InlineImage)).toBe(true);
818795

819-
expect(wrapper.find(FigureCaption).exists()).toBe(false);
796+
expect(wrapper.find(Caption).exists()).toBe(false);
820797
});
821798

822799
it('renders within a `DeviceFrame`', () => {
@@ -892,7 +869,7 @@ describe('ContentNode', () => {
892869
}, {})).not.toThrow();
893870
});
894871

895-
it('renders a `Figure`/`FigureCaption` with metadata', () => {
872+
it('renders a `Figure`/`Caption` with metadata', () => {
896873
const metadata = {
897874
anchor: 'foo',
898875
abstract: [{
@@ -911,15 +888,16 @@ describe('ContentNode', () => {
911888
expect(figure.props('anchor')).toBe('foo');
912889
expect(figure.contains(BlockVideo)).toBe(true);
913890

914-
const caption = wrapper.find(FigureCaption);
891+
const caption = wrapper.find(Caption);
915892
expect(caption.exists()).toBe(true);
893+
expect(caption.props('tag')).toBe('figcaption');
916894
expect(caption.contains('p')).toBe(true);
917895
expect(caption.props('title')).toBe(metadata.title);
918896
expect(caption.props('centered')).toBe(true);
919897
expect(caption.text()).toContain('blah');
920898
});
921899

922-
it('renders a `Figure`/`FigureCaption` without an anchor, with text under the video', () => {
900+
it('renders a `Figure`/`Caption` without an anchor, with text under the video', () => {
923901
const metadata = {
924902
abstract: [{
925903
type: 'paragraph',
@@ -937,7 +915,7 @@ describe('ContentNode', () => {
937915
expect(figure.props('anchor')).toBeFalsy();
938916
expect(figure.contains(BlockVideo)).toBe(true);
939917

940-
const caption = wrapper.find(FigureCaption);
918+
const caption = wrapper.find(Caption);
941919
expect(caption.exists()).toBe(true);
942920
expect(caption.contains('p')).toBe(true);
943921
expect(caption.props('title')).toBeFalsy();
@@ -947,9 +925,9 @@ describe('ContentNode', () => {
947925
expect(figure.html()).toMatchInlineSnapshot(`
948926
<figure-stub>
949927
<blockvideo-stub identifier="video.mp4"></blockvideo-stub>
950-
<figurecaption-stub centered="true">
928+
<caption-stub centered="true" tag="figcaption">
951929
<p>blah</p>
952-
</figurecaption-stub>
930+
</caption-stub>
953931
</figure-stub>
954932
`);
955933
});
@@ -1372,6 +1350,33 @@ describe('ContentNode', () => {
13721350
expect(table.findAll('tbody tr td').length).toBe(4);
13731351
});
13741352

1353+
it('renders a `Table` with metadata', () => {
1354+
const metadata = {
1355+
anchor: '42',
1356+
title: 'Listing 42',
1357+
abstract: [{
1358+
type: 'paragraph',
1359+
inlineContent: [{ type: 'text', text: 'blah' }],
1360+
}],
1361+
};
1362+
1363+
const wrapper = mountWithItem({
1364+
type: 'table',
1365+
header: TableHeaderStyle.none,
1366+
rows,
1367+
metadata,
1368+
});
1369+
1370+
const table = wrapper.find('.content').find(Table);
1371+
expect(table.exists()).toBe(true);
1372+
expect(table.attributes('id')).toBe(metadata.anchor);
1373+
1374+
const caption = wrapper.find(Caption);
1375+
expect(caption.exists()).toBe(true);
1376+
expect(caption.props('title')).toBe(metadata.title);
1377+
expect(caption.text()).toContain('blah');
1378+
});
1379+
13751380
it('renders header="both" style tables', () => {
13761381
const wrapper = mountWithItem({
13771382
type: 'table',
@@ -1410,35 +1415,6 @@ describe('ContentNode', () => {
14101415
expect(table.findAll('tbody tr td').length).toBe(2);
14111416
});
14121417

1413-
it('renders a `Figure`/`FigureCaption` with metadata', () => {
1414-
const metadata = {
1415-
anchor: '42',
1416-
title: 'Table 42',
1417-
abstract: [{
1418-
type: 'paragraph',
1419-
inlineContent: [{ type: 'text', text: 'blah' }],
1420-
}],
1421-
};
1422-
const wrapper = mountWithItem({
1423-
type: 'table',
1424-
header: TableHeaderStyle.none,
1425-
rows,
1426-
metadata,
1427-
});
1428-
1429-
const figure = wrapper.find(Figure);
1430-
expect(figure.exists()).toBe(true);
1431-
expect(figure.props('anchor')).toBe(metadata.anchor);
1432-
expect(figure.contains(Table)).toBe(true);
1433-
1434-
const caption = figure.find(FigureCaption);
1435-
expect(caption.exists()).toBe(true);
1436-
expect(caption.props('title')).toBe(metadata.title);
1437-
expect(caption.props('centered')).toBe(false);
1438-
expect(caption.contains('p')).toBe(true);
1439-
expect(caption.text()).toContain('blah');
1440-
});
1441-
14421418
describe('and column/row spanning', () => {
14431419
// <table>
14441420
// <tr>

tests/unit/components/ContentNode/FigureCaption.spec.js renamed to tests/unit/components/ContentNode/Caption.spec.js

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,37 @@
99
*/
1010

1111
import { shallowMount } from '@vue/test-utils';
12-
import FigureCaption from 'docc-render/components/ContentNode/FigureCaption.vue';
12+
import Caption from '@/components/ContentNode/Caption.vue';
1313

14-
describe('FigureCaption', () => {
15-
it('renders a <figcaption> with the title and slot content', () => {
14+
describe('Caption', () => {
15+
it('renders a <caption> with the title and slot content', () => {
1616
const propsData = { title: 'Figure 1' };
1717
const slots = { default: '<p>Blah</p>' };
18-
const wrapper = shallowMount(FigureCaption, { propsData, slots });
18+
const wrapper = shallowMount(Caption, { propsData, slots });
1919

20-
expect(wrapper.is('figcaption')).toBe(true);
21-
expect(wrapper.text()).toBe('Figure 1\u00a0Blah');
20+
expect(wrapper.is('caption')).toBe(true);
21+
expect(wrapper.text()).toMatch(/Figure 1\sBlah/);
2222
});
2323

2424
it('renders a <figcaption> with slot content only', () => {
2525
const slots = { default: '<p>Blah</p>' };
26-
const wrapper = shallowMount(FigureCaption, { slots });
26+
const wrapper = shallowMount(Caption, { slots });
2727

28-
expect(wrapper.is('figcaption')).toBe(true);
28+
expect(wrapper.is('caption')).toBe(true);
2929
expect(wrapper.text()).toBe('Blah');
3030
expect(wrapper.text()).not.toBe('\u00a0Blah');
3131
});
3232

3333
it('renders a <figcaption> centered', () => {
3434
const slots = { default: '<p>Blah</p>' };
35-
const wrapper = shallowMount(FigureCaption, { slots, propsData: { centered: true } });
35+
const wrapper = shallowMount(Caption, { slots, propsData: { centered: true } });
3636
expect(wrapper.classes()).toContain('centered');
3737
});
38+
39+
it('renders a <figcaption> if tag is `figcaption`', () => {
40+
const propsData = { title: 'Figure 1', tag: 'figcaption' };
41+
const wrapper = shallowMount(Caption, { propsData });
42+
43+
expect(wrapper.is('figcaption')).toBe(true);
44+
});
3845
});

0 commit comments

Comments
 (0)