structured-render 0.0.0 → 0.0.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/LICENSE-CC0 +121 -0
- package/LICENSE-MIT +21 -0
- package/README.md +13 -0
- package/dist/augments/shadow-styles.d.ts +7 -0
- package/dist/augments/shadow-styles.js +17 -0
- package/dist/elements/vir-markdown.element.d.ts +16 -0
- package/dist/elements/vir-markdown.element.js +73 -0
- package/dist/elements/vir-source.element.d.ts +24 -0
- package/dist/elements/vir-source.element.js +158 -0
- package/dist/elements/vir-structured-render.element.d.ts +19 -0
- package/dist/elements/vir-structured-render.element.js +346 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +26 -0
- package/dist/render/browser-rendering.d.ts +90 -0
- package/dist/render/browser-rendering.js +233 -0
- package/dist/render/html-to-pdf.d.ts +50 -0
- package/dist/render/html-to-pdf.js +7 -0
- package/dist/render/render-html.d.ts +38 -0
- package/dist/render/render-html.js +504 -0
- package/dist/render/render-image.d.ts +24 -0
- package/dist/render/render-image.js +35 -0
- package/dist/render/render-markdown-styles.d.ts +62 -0
- package/dist/render/render-markdown-styles.js +242 -0
- package/dist/render/render-markdown.d.ts +8 -0
- package/dist/render/render-markdown.js +169 -0
- package/dist/render/render-pdf.d.ts +35 -0
- package/dist/render/render-pdf.js +65 -0
- package/dist/render/render-types.d.ts +134 -0
- package/dist/render/render-types.js +41 -0
- package/dist/structured-render-data/create-section.d.ts +23 -0
- package/dist/structured-render-data/create-section.js +16 -0
- package/dist/structured-render-data/sections/code-block.section.d.ts +30 -0
- package/dist/structured-render-data/sections/code-block.section.js +11 -0
- package/dist/structured-render-data/sections/empty.section.d.ts +14 -0
- package/dist/structured-render-data/sections/empty.section.js +9 -0
- package/dist/structured-render-data/sections/icon.section.d.ts +25 -0
- package/dist/structured-render-data/sections/icon.section.js +40 -0
- package/dist/structured-render-data/sections/inline-code.section.d.ts +29 -0
- package/dist/structured-render-data/sections/inline-code.section.js +9 -0
- package/dist/structured-render-data/sections/list.section.d.ts +169 -0
- package/dist/structured-render-data/sections/list.section.js +29 -0
- package/dist/structured-render-data/sections/markdown.section.d.ts +29 -0
- package/dist/structured-render-data/sections/markdown.section.js +9 -0
- package/dist/structured-render-data/sections/processing.section.d.ts +14 -0
- package/dist/structured-render-data/sections/processing.section.js +9 -0
- package/dist/structured-render-data/sections/source.section.d.ts +59 -0
- package/dist/structured-render-data/sections/source.section.js +47 -0
- package/dist/structured-render-data/sections/table.section.d.ts +939 -0
- package/dist/structured-render-data/sections/table.section.js +99 -0
- package/dist/structured-render-data/sections/tag.section.d.ts +39 -0
- package/dist/structured-render-data/sections/tag.section.js +20 -0
- package/dist/structured-render-data/sections/text.section.d.ts +48 -0
- package/dist/structured-render-data/sections/text.section.js +25 -0
- package/dist/structured-render-data/structured-render-card.d.ts +918 -0
- package/dist/structured-render-data/structured-render-card.js +11 -0
- package/dist/structured-render-data/structured-render-data.d.ts +919 -0
- package/dist/structured-render-data/structured-render-data.js +8 -0
- package/dist/structured-render-data/structured-render-section.d.ts +1857 -0
- package/dist/structured-render-data/structured-render-section.js +115 -0
- package/package.json +75 -11
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { check } from '@augment-vir/assert';
|
|
2
|
+
import { mapObjectValues, mergeDefinedProperties, } from '@augment-vir/common';
|
|
3
|
+
import { css, CSSResult, unsafeCSS } from 'element-vir';
|
|
4
|
+
import { noNativeSpacing, viraTheme } from 'vira';
|
|
5
|
+
/**
|
|
6
|
+
* The id attached to the content div which will be rendered to the PDF or image. Use this to create
|
|
7
|
+
* style selectors.
|
|
8
|
+
*
|
|
9
|
+
* @category Internal
|
|
10
|
+
*/
|
|
11
|
+
export const contentDivClass = 'structured-rendering-markdown-rendering-content-for-screenshot';
|
|
12
|
+
/**
|
|
13
|
+
* Base CSS reset styles that are always applied to the content div, regardless of custom style
|
|
14
|
+
* overrides. These ensure no unwanted whitespace from default browser margins on the first and last
|
|
15
|
+
* child elements.
|
|
16
|
+
*
|
|
17
|
+
* @category Internal
|
|
18
|
+
*/
|
|
19
|
+
export const baseContentResetStyles = `
|
|
20
|
+
.${contentDivClass} > *:first-child {
|
|
21
|
+
margin-top: 0;
|
|
22
|
+
}
|
|
23
|
+
.${contentDivClass} > *:last-child {
|
|
24
|
+
margin-bottom: 0;
|
|
25
|
+
}
|
|
26
|
+
`;
|
|
27
|
+
/**
|
|
28
|
+
* The standard rendering style configuration.
|
|
29
|
+
*
|
|
30
|
+
* @category Internal
|
|
31
|
+
*/
|
|
32
|
+
export const defaultMarkdownStyleConfiguration = {
|
|
33
|
+
accentColor: 'dodgerblue',
|
|
34
|
+
bodySize: '14px',
|
|
35
|
+
h1Size: '32px',
|
|
36
|
+
h2Size: '24px',
|
|
37
|
+
h3Size: '18px',
|
|
38
|
+
h4Size: '16px',
|
|
39
|
+
h5Size: '14px',
|
|
40
|
+
h6Size: '14px',
|
|
41
|
+
bodyGap: '24px',
|
|
42
|
+
smallTextSize: '10px',
|
|
43
|
+
liSpacing: '4px',
|
|
44
|
+
bodyFont: 'sans-serif',
|
|
45
|
+
codeFont: 'monospace',
|
|
46
|
+
codeSize: '1em',
|
|
47
|
+
codeBackgroundColor: viraTheme.colors['vira-grey-behind-fg-small-body'].background.value,
|
|
48
|
+
/** The selector used that all styles will be applied to. */
|
|
49
|
+
contentSelector: `.${contentDivClass}`,
|
|
50
|
+
tableBorderColor: viraTheme.colors['vira-grey-foreground-decoration'].foreground.value,
|
|
51
|
+
tableBorderWidth: '1px',
|
|
52
|
+
};
|
|
53
|
+
function resolveMarkdownStyleConfiguration(styleOptions) {
|
|
54
|
+
return mapObjectValues(mergeDefinedProperties(defaultMarkdownStyleConfiguration, styleOptions), (key, value) => {
|
|
55
|
+
return check.isString(value)
|
|
56
|
+
? unsafeCSS(value)
|
|
57
|
+
: value instanceof CSSResult
|
|
58
|
+
? value
|
|
59
|
+
: value.value;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Default plain styles for markdown converted to HTML.
|
|
64
|
+
*
|
|
65
|
+
* @category Internal
|
|
66
|
+
*/
|
|
67
|
+
export const defaultMarkdownRenderStyles = configureDefaultMarkdownRenderStyles();
|
|
68
|
+
/**
|
|
69
|
+
* Configure a stylesheet for rendering.
|
|
70
|
+
*
|
|
71
|
+
* @category Internal
|
|
72
|
+
*/
|
|
73
|
+
export function configureDefaultMarkdownRenderStyles(styleOptions) {
|
|
74
|
+
const styles = resolveMarkdownStyleConfiguration(styleOptions);
|
|
75
|
+
return css `
|
|
76
|
+
${unsafeCSS(styleOptions?.contentSelector || defaultMarkdownStyleConfiguration.contentSelector)} {
|
|
77
|
+
display: flex;
|
|
78
|
+
flex-direction: column;
|
|
79
|
+
gap: ${styles.bodyGap};
|
|
80
|
+
font-family: ${styles.bodyFont};
|
|
81
|
+
font-size: ${styles.bodySize};
|
|
82
|
+
align-items: flex-start;
|
|
83
|
+
|
|
84
|
+
& * {
|
|
85
|
+
font-family: inherit;
|
|
86
|
+
font-size: inherit;
|
|
87
|
+
${noNativeSpacing}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
& h1 {
|
|
91
|
+
font-size: ${styles.h1Size};
|
|
92
|
+
}
|
|
93
|
+
& h2 {
|
|
94
|
+
font-size: ${styles.h2Size};
|
|
95
|
+
}
|
|
96
|
+
& h3 {
|
|
97
|
+
font-size: ${styles.h3Size};
|
|
98
|
+
}
|
|
99
|
+
& h4 {
|
|
100
|
+
font-size: ${styles.h4Size};
|
|
101
|
+
}
|
|
102
|
+
& h5 {
|
|
103
|
+
font-size: ${styles.h5Size};
|
|
104
|
+
}
|
|
105
|
+
& h6 {
|
|
106
|
+
font-size: ${styles.h6Size};
|
|
107
|
+
}
|
|
108
|
+
& ul,
|
|
109
|
+
& ol {
|
|
110
|
+
padding-left: 1.1em;
|
|
111
|
+
& li {
|
|
112
|
+
margin-bottom: ${styles.liSpacing};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
& strong {
|
|
116
|
+
font-weight: bold;
|
|
117
|
+
}
|
|
118
|
+
& em {
|
|
119
|
+
font-style: italic;
|
|
120
|
+
}
|
|
121
|
+
& code {
|
|
122
|
+
background-color: ${styles.codeBackgroundColor};
|
|
123
|
+
padding: 2px 6px;
|
|
124
|
+
border-radius: 4px;
|
|
125
|
+
font-family: ${styles.codeFont};
|
|
126
|
+
font-size: ${styles.codeSize};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.inlineCode-section {
|
|
130
|
+
display: inline-flex;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
& pre {
|
|
134
|
+
background-color: ${styles.codeBackgroundColor};
|
|
135
|
+
padding: 2px 12px 6px;
|
|
136
|
+
border-radius: 6px;
|
|
137
|
+
white-space: pre-wrap;
|
|
138
|
+
overflow-x: auto;
|
|
139
|
+
|
|
140
|
+
& code {
|
|
141
|
+
background-color: transparent;
|
|
142
|
+
padding: 0;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
& blockquote {
|
|
147
|
+
border-left: 4px solid ${styles.accentColor};
|
|
148
|
+
padding-left: 16px;
|
|
149
|
+
margin-left: 0;
|
|
150
|
+
font-style: italic;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
& hr {
|
|
154
|
+
border: none;
|
|
155
|
+
border-top: 1px solid currentColor;
|
|
156
|
+
margin: 20px 0;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
& small {
|
|
160
|
+
font-size: ${styles.smallTextSize};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
& th,
|
|
164
|
+
& td {
|
|
165
|
+
border-top: ${styles.tableBorderWidth} solid ${styles.tableBorderColor};
|
|
166
|
+
border-left: ${styles.tableBorderWidth} solid ${styles.tableBorderColor};
|
|
167
|
+
padding: 8px 12px;
|
|
168
|
+
text-align: left;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
& thead tr:first-child th,
|
|
172
|
+
& thead tr:first-child td,
|
|
173
|
+
& tbody tr:first-child th,
|
|
174
|
+
& tbody tr:first-child td,
|
|
175
|
+
& tbody tr td.source-cell,
|
|
176
|
+
& thead tr th.source-cell {
|
|
177
|
+
border-top-color: transparent;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
& thead + tbody tr:first-child {
|
|
181
|
+
& td,
|
|
182
|
+
& th {
|
|
183
|
+
border-top-color: ${styles.tableBorderColor};
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
& table {
|
|
188
|
+
border-collapse: collapse;
|
|
189
|
+
max-width: 100%;
|
|
190
|
+
|
|
191
|
+
& th:first-child,
|
|
192
|
+
& td:first-child {
|
|
193
|
+
border-left: none;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
& th {
|
|
197
|
+
font-weight: bold;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
& a {
|
|
202
|
+
color: ${styles.accentColor};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
& img {
|
|
206
|
+
max-width: 100%;
|
|
207
|
+
height: auto;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
& h1,
|
|
211
|
+
& h2,
|
|
212
|
+
& h3,
|
|
213
|
+
& h4,
|
|
214
|
+
& h5,
|
|
215
|
+
& h6 {
|
|
216
|
+
break-after: avoid;
|
|
217
|
+
page-break-after: avoid;
|
|
218
|
+
break-inside: avoid;
|
|
219
|
+
page-break-inside: avoid;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
& h2:not(:first-child) {
|
|
223
|
+
margin-top: 16px;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
& table,
|
|
227
|
+
& pre,
|
|
228
|
+
& blockquote,
|
|
229
|
+
& ul,
|
|
230
|
+
& ol,
|
|
231
|
+
& img {
|
|
232
|
+
break-inside: avoid;
|
|
233
|
+
page-break-inside: avoid;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
& tr {
|
|
237
|
+
break-inside: avoid;
|
|
238
|
+
page-break-inside: avoid;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
`;
|
|
242
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type PartialWithUndefined } from '@augment-vir/common';
|
|
2
|
+
import { type RenderInput, type RenderMarkdownOptions } from './render-types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Convert any structured render data part to markdown.
|
|
5
|
+
*
|
|
6
|
+
* @category Render
|
|
7
|
+
*/
|
|
8
|
+
export declare function renderStructuredMarkdown(data: Readonly<RenderInput>, options?: Readonly<PartialWithUndefined<RenderMarkdownOptions>> | undefined): string;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { assert, assertWrap, check } from '@augment-vir/assert';
|
|
2
|
+
import { createArray, filterMap, mergeDefinedProperties, stringify, wrapString, } from '@augment-vir/common';
|
|
3
|
+
import { convertTemplateToString } from 'element-vir';
|
|
4
|
+
import { createStructuredRenderIcon, } from '../structured-render-data/sections/icon.section.js';
|
|
5
|
+
import { StructuredRenderCellDirection, } from '../structured-render-data/sections/table.section.js';
|
|
6
|
+
import { StructuredRenderTextStyle, } from '../structured-render-data/sections/text.section.js';
|
|
7
|
+
import { defaultRenderMarkdownOptions, } from './render-types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Convert any structured render data part to markdown.
|
|
10
|
+
*
|
|
11
|
+
* @category Render
|
|
12
|
+
*/
|
|
13
|
+
export function renderStructuredMarkdown(data, options) {
|
|
14
|
+
const finalOptions = mergeDefinedProperties(defaultRenderMarkdownOptions, options);
|
|
15
|
+
return structuredRenderToMarkdownArray(data, finalOptions).filter(check.isTruthy).join('\n\n');
|
|
16
|
+
}
|
|
17
|
+
const markdownStyleWrapper = {
|
|
18
|
+
[StructuredRenderTextStyle.Bold]: '**',
|
|
19
|
+
};
|
|
20
|
+
function buildVerticalTableRows(section, visibleHeaders, options) {
|
|
21
|
+
const columnCount = section.entries.length + 1;
|
|
22
|
+
const dataRows = visibleHeaders.map((header) => {
|
|
23
|
+
const headerText = header.text
|
|
24
|
+
? renderStructuredMarkdown(header.text, options)
|
|
25
|
+
: header.key;
|
|
26
|
+
const cells = section.entries.map((entry) => renderStructuredMarkdown(entry.data[header.key], options));
|
|
27
|
+
return [
|
|
28
|
+
headerText,
|
|
29
|
+
...cells,
|
|
30
|
+
];
|
|
31
|
+
});
|
|
32
|
+
return [
|
|
33
|
+
createArray(columnCount, () => ''),
|
|
34
|
+
...dataRows,
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
function buildHorizontalTableRows(section, visibleHeaders, options) {
|
|
38
|
+
const headerRow = visibleHeaders.map((header) => header.text ? renderStructuredMarkdown(header.text, options) : header.key);
|
|
39
|
+
const dataRows = section.entries.map((entry) => visibleHeaders.map((header) => renderStructuredMarkdown(entry.data[header.key], options)));
|
|
40
|
+
return [
|
|
41
|
+
headerRow,
|
|
42
|
+
...dataRows,
|
|
43
|
+
];
|
|
44
|
+
}
|
|
45
|
+
const tableRowBuilders = {
|
|
46
|
+
[StructuredRenderCellDirection.Vertical]: buildVerticalTableRows,
|
|
47
|
+
[StructuredRenderCellDirection.Horizontal]: buildHorizontalTableRows,
|
|
48
|
+
};
|
|
49
|
+
const markdownRenderers = {
|
|
50
|
+
icon(section, options) {
|
|
51
|
+
const coloredIcon = createStructuredRenderIcon(section, options);
|
|
52
|
+
if (!coloredIcon) {
|
|
53
|
+
return '';
|
|
54
|
+
}
|
|
55
|
+
return convertTemplateToString(coloredIcon.svgTemplate);
|
|
56
|
+
},
|
|
57
|
+
codeBlock(section) {
|
|
58
|
+
return `\`\`\`${section.syntax || ''}\n${section.code}\n\`\`\``;
|
|
59
|
+
},
|
|
60
|
+
inlineCode(section) {
|
|
61
|
+
return `\`${section.code}\``;
|
|
62
|
+
},
|
|
63
|
+
empty() {
|
|
64
|
+
return '';
|
|
65
|
+
},
|
|
66
|
+
list(section, options) {
|
|
67
|
+
return filterMap(section.items, (item) => {
|
|
68
|
+
const content = renderStructuredMarkdown(item.content, options);
|
|
69
|
+
const icon = renderStructuredMarkdown(item.icon, options);
|
|
70
|
+
if (content) {
|
|
71
|
+
return icon ? `- ${icon} ${content}` : `- ${content}`;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
return '';
|
|
75
|
+
}
|
|
76
|
+
}, check.isTruthy).join('\n');
|
|
77
|
+
},
|
|
78
|
+
markdown(section) {
|
|
79
|
+
return section.markdown;
|
|
80
|
+
},
|
|
81
|
+
tag(section) {
|
|
82
|
+
if (section.text == undefined) {
|
|
83
|
+
return '';
|
|
84
|
+
}
|
|
85
|
+
return String(section.text);
|
|
86
|
+
},
|
|
87
|
+
processing() {
|
|
88
|
+
return '';
|
|
89
|
+
},
|
|
90
|
+
source(section, options) {
|
|
91
|
+
const filteredPageNumbers = section.pageNumbers?.filter(check.isDefined);
|
|
92
|
+
const pageNumberLine = filteredPageNumbers?.length
|
|
93
|
+
? `p. ${filteredPageNumbers.join(', ')}`
|
|
94
|
+
: '';
|
|
95
|
+
const pageLine = [
|
|
96
|
+
section.fileName,
|
|
97
|
+
pageNumberLine,
|
|
98
|
+
]
|
|
99
|
+
.filter(check.isTruthy)
|
|
100
|
+
.join(', ');
|
|
101
|
+
return pageLine ? `<small>${options.sourceString}: ${pageLine}</small>` : '';
|
|
102
|
+
},
|
|
103
|
+
table(section, options) {
|
|
104
|
+
const visibleHeaders = section.headers.filter((header) => !header.hidden);
|
|
105
|
+
const rows = tableRowBuilders[section.direction](section, visibleHeaders, options);
|
|
106
|
+
const columnCount = rows[0].length || 0;
|
|
107
|
+
const colWidths = computeColumnWidths(rows, columnCount);
|
|
108
|
+
const [headerRow, ...dataRows] = rows;
|
|
109
|
+
return [
|
|
110
|
+
formatRow(headerRow, colWidths),
|
|
111
|
+
formatSeparatorRow(colWidths),
|
|
112
|
+
...dataRows.map((row) => formatRow(row, colWidths)),
|
|
113
|
+
].join('\n');
|
|
114
|
+
},
|
|
115
|
+
text(section, options) {
|
|
116
|
+
if (section.text == undefined) {
|
|
117
|
+
return '';
|
|
118
|
+
}
|
|
119
|
+
const styleWrapper = (section.style && markdownStyleWrapper[section.style]) || '';
|
|
120
|
+
const icon = renderStructuredMarkdown(section.icon, options);
|
|
121
|
+
const text = wrapString({
|
|
122
|
+
value: String(section.text),
|
|
123
|
+
wrapper: styleWrapper,
|
|
124
|
+
});
|
|
125
|
+
return icon ? `${icon} ${text}` : text;
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
function computeColumnWidths(rows, columnCount) {
|
|
129
|
+
return createArray(columnCount, (colIndex) => {
|
|
130
|
+
return rows.reduce((maxWidth, row, rowIndex) => {
|
|
131
|
+
return Math.max(maxWidth, assertWrap.isDefined(row[colIndex], `No cell at row index ${rowIndex}, column index ${colIndex}`).length);
|
|
132
|
+
}, 3);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
function formatRow(cells, widths) {
|
|
136
|
+
const paddedCells = cells.map((cell, i) => cell.padEnd(widths[i] ?? 3));
|
|
137
|
+
return `| ${paddedCells.join(' | ')} |`;
|
|
138
|
+
}
|
|
139
|
+
function formatSeparatorRow(widths) {
|
|
140
|
+
const dashes = widths.map((w) => '-'.repeat(w));
|
|
141
|
+
return `| ${dashes.join(' | ')} |`;
|
|
142
|
+
}
|
|
143
|
+
function structuredRenderToMarkdownArray(data, options) {
|
|
144
|
+
if (!data) {
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
else if (check.isArray(data)) {
|
|
148
|
+
return data.flatMap((entry) => renderStructuredMarkdown(entry, options));
|
|
149
|
+
}
|
|
150
|
+
else if ('type' in data) {
|
|
151
|
+
const sectionTitle = 'sectionTitle' in data ? data.sectionTitle : undefined;
|
|
152
|
+
const sources = ('sources' in data && data.sources) || [];
|
|
153
|
+
return [
|
|
154
|
+
sectionTitle ? `### ${sectionTitle}` : undefined,
|
|
155
|
+
markdownRenderers[data.type](data, options),
|
|
156
|
+
...sources.map((source) => renderStructuredMarkdown(source, options)),
|
|
157
|
+
];
|
|
158
|
+
}
|
|
159
|
+
else if ('sections' in data) {
|
|
160
|
+
return [
|
|
161
|
+
data.cardTitle && `## ${data.cardTitle}`,
|
|
162
|
+
...structuredRenderToMarkdownArray(data.sections, options),
|
|
163
|
+
].filter(check.isTruthy);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
assert.tsType(data).equals();
|
|
167
|
+
throw new Error(`Unexpected structured render type: ${stringify(data)}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type PartialWithUndefined } from '@augment-vir/common';
|
|
2
|
+
import { OutputPdfType } from './browser-rendering.js';
|
|
3
|
+
import { type RenderInput, type RenderOptions } from './render-types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Render to a PDF. Only works in Node.js, not a browser.
|
|
6
|
+
*
|
|
7
|
+
* @category Render
|
|
8
|
+
* @returns The output file path.
|
|
9
|
+
*/
|
|
10
|
+
export declare function renderToNodePdf(renderInput: Readonly<RenderInput>, params: Readonly<{
|
|
11
|
+
saveLocationPath: string;
|
|
12
|
+
options?: PartialWithUndefined<RenderOptions> | undefined;
|
|
13
|
+
}>): Promise<string>;
|
|
14
|
+
/**
|
|
15
|
+
* Render to a PDF. Only works in a browser, not Node.js.
|
|
16
|
+
*
|
|
17
|
+
* @category Render
|
|
18
|
+
*/
|
|
19
|
+
export declare function renderToBrowserPdf(renderInput: Readonly<RenderInput>, { pdfOutputType, ...params }: Readonly<{
|
|
20
|
+
fileName: string;
|
|
21
|
+
} & PartialWithUndefined<{
|
|
22
|
+
pdfOutputType: OutputPdfType;
|
|
23
|
+
options: RenderOptions;
|
|
24
|
+
}>>): Promise<unknown>;
|
|
25
|
+
/**
|
|
26
|
+
* Render to a PDF and trigger the browser's print feature to print that PDF. Only works in a
|
|
27
|
+
* browser, not Node.js.
|
|
28
|
+
*
|
|
29
|
+
* @category Render
|
|
30
|
+
*/
|
|
31
|
+
export declare function printPdf(renderInput: Readonly<RenderInput>, params: Readonly<{
|
|
32
|
+
fileName: string;
|
|
33
|
+
} & PartialWithUndefined<{
|
|
34
|
+
options: RenderOptions;
|
|
35
|
+
}>>): Promise<void>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { isRuntimeEnv, RuntimeEnv } from '@augment-vir/common';
|
|
2
|
+
import { OutputPdfType, renderInBrowser, renderInNode } from './browser-rendering.js';
|
|
3
|
+
/**
|
|
4
|
+
* Render to a PDF. Only works in Node.js, not a browser.
|
|
5
|
+
*
|
|
6
|
+
* @category Render
|
|
7
|
+
* @returns The output file path.
|
|
8
|
+
*/
|
|
9
|
+
export async function renderToNodePdf(renderInput, params) {
|
|
10
|
+
if (isRuntimeEnv(RuntimeEnv.Web)) {
|
|
11
|
+
throw new Error(`${renderToNodePdf.name} cannot run inside of a browser.`);
|
|
12
|
+
}
|
|
13
|
+
return await renderInNode(renderInput, {
|
|
14
|
+
outputType: {
|
|
15
|
+
pdf: true,
|
|
16
|
+
},
|
|
17
|
+
...params,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Render to a PDF. Only works in a browser, not Node.js.
|
|
22
|
+
*
|
|
23
|
+
* @category Render
|
|
24
|
+
*/
|
|
25
|
+
export async function renderToBrowserPdf(renderInput, { pdfOutputType, ...params }) {
|
|
26
|
+
if (!isRuntimeEnv(RuntimeEnv.Web)) {
|
|
27
|
+
throw new Error(`${renderToBrowserPdf.name} cannot run outside of a browser.`);
|
|
28
|
+
}
|
|
29
|
+
return renderInBrowser(renderInput, {
|
|
30
|
+
outputType: {
|
|
31
|
+
pdf: pdfOutputType || OutputPdfType.Download,
|
|
32
|
+
},
|
|
33
|
+
...params,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Render to a PDF and trigger the browser's print feature to print that PDF. Only works in a
|
|
38
|
+
* browser, not Node.js.
|
|
39
|
+
*
|
|
40
|
+
* @category Render
|
|
41
|
+
*/
|
|
42
|
+
export async function printPdf(renderInput, params) {
|
|
43
|
+
if (!isRuntimeEnv(RuntimeEnv.Web)) {
|
|
44
|
+
throw new Error(`${printPdf.name} cannot run outside of a browser.`);
|
|
45
|
+
}
|
|
46
|
+
const pdfBlob = (await renderInBrowser(renderInput, {
|
|
47
|
+
outputType: {
|
|
48
|
+
pdf: OutputPdfType.Blob,
|
|
49
|
+
},
|
|
50
|
+
...params,
|
|
51
|
+
}));
|
|
52
|
+
const blobUrl = URL.createObjectURL(pdfBlob);
|
|
53
|
+
const printFrame = globalThis.document.createElement('iframe');
|
|
54
|
+
printFrame.style.display = 'none';
|
|
55
|
+
printFrame.src = blobUrl;
|
|
56
|
+
globalThis.document.body.append(printFrame);
|
|
57
|
+
return new Promise((resolve) => {
|
|
58
|
+
printFrame.onload = () => {
|
|
59
|
+
printFrame.contentWindow?.print();
|
|
60
|
+
URL.revokeObjectURL(blobUrl);
|
|
61
|
+
resolve();
|
|
62
|
+
printFrame.remove();
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { type MaybeArray } from '@augment-vir/common';
|
|
2
|
+
import { type CSSResult } from 'element-vir';
|
|
3
|
+
import { type ViraIconSvg } from 'vira';
|
|
4
|
+
import { type StructuredRenderCard } from '../structured-render-data/structured-render-card.js';
|
|
5
|
+
import { type StructuredRenderData } from '../structured-render-data/structured-render-data.js';
|
|
6
|
+
import { type StructuredRenderSection } from '../structured-render-data/structured-render-section.js';
|
|
7
|
+
/**
|
|
8
|
+
* All acceptable inputs for Structured Render rendering.
|
|
9
|
+
*
|
|
10
|
+
* @category Internal
|
|
11
|
+
*/
|
|
12
|
+
export type RenderInput = MaybeArray<StructuredRenderData | StructuredRenderCard | StructuredRenderSection | null | undefined>;
|
|
13
|
+
/**
|
|
14
|
+
* Base options for Structured Render rendering.
|
|
15
|
+
*
|
|
16
|
+
* @category Internal
|
|
17
|
+
*/
|
|
18
|
+
export type RenderOptions = Readonly<{
|
|
19
|
+
/**
|
|
20
|
+
* Override the default icon set. The default icon set is provided by
|
|
21
|
+
* [Vira](https://www.npmjs.com/package/vira).
|
|
22
|
+
*/
|
|
23
|
+
icons: Readonly<{
|
|
24
|
+
[IconKey in string]: ViraIconSvg;
|
|
25
|
+
}>;
|
|
26
|
+
/**
|
|
27
|
+
* The prefix used when rendering a source.
|
|
28
|
+
*
|
|
29
|
+
* @default 'Source'
|
|
30
|
+
*/
|
|
31
|
+
sourceString: string;
|
|
32
|
+
/**
|
|
33
|
+
* The prefix used when rendering multiple sources.
|
|
34
|
+
*
|
|
35
|
+
* @default 'Sources'
|
|
36
|
+
*/
|
|
37
|
+
pluralSourcesString: string;
|
|
38
|
+
}>;
|
|
39
|
+
/**
|
|
40
|
+
* Default base option values for Structured Render rendering.
|
|
41
|
+
*
|
|
42
|
+
* @category Internal
|
|
43
|
+
*/
|
|
44
|
+
export declare const defaultRenderOptions: Readonly<RenderOptions>;
|
|
45
|
+
/**
|
|
46
|
+
* Option values for Structured Render rendering to Markdown.
|
|
47
|
+
*
|
|
48
|
+
* @category Internal
|
|
49
|
+
*/
|
|
50
|
+
export type RenderMarkdownOptions = RenderOptions & {
|
|
51
|
+
/**
|
|
52
|
+
* CSS styles for the rendering.
|
|
53
|
+
*
|
|
54
|
+
* @default
|
|
55
|
+
*/
|
|
56
|
+
styles: string | CSSResult;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Default option values for Structured Render rendering to Markdown.
|
|
60
|
+
*
|
|
61
|
+
* @category Internal
|
|
62
|
+
*/
|
|
63
|
+
export declare const defaultRenderMarkdownOptions: Readonly<RenderMarkdownOptions>;
|
|
64
|
+
/**
|
|
65
|
+
* Option values for Structured Render rendering to HTML.
|
|
66
|
+
*
|
|
67
|
+
* @category Internal
|
|
68
|
+
*/
|
|
69
|
+
export type RenderHtmlOptions = RenderOptions & {
|
|
70
|
+
/** Currently expanded sections and sources. */
|
|
71
|
+
currentlyExpanded: {
|
|
72
|
+
[SectionKey in string]: boolean;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* The string to use within the processing section.
|
|
76
|
+
*
|
|
77
|
+
* @default 'Processing'
|
|
78
|
+
*/
|
|
79
|
+
processingString: string;
|
|
80
|
+
/**
|
|
81
|
+
* The icon shown for source expansion.
|
|
82
|
+
*
|
|
83
|
+
* @default DocumentSearch24Icon
|
|
84
|
+
*/
|
|
85
|
+
sourceIcon: ViraIconSvg;
|
|
86
|
+
/**
|
|
87
|
+
* The icon shown next to processing text.
|
|
88
|
+
*
|
|
89
|
+
* @default LoaderAnimated24Icon
|
|
90
|
+
*/
|
|
91
|
+
processingIcon: ViraIconSvg;
|
|
92
|
+
/**
|
|
93
|
+
* The icon used for "view on page" buttons.
|
|
94
|
+
*
|
|
95
|
+
* @default EyeOpen24Icon
|
|
96
|
+
*/
|
|
97
|
+
viewOnPageIcon: ViraIconSvg;
|
|
98
|
+
/**
|
|
99
|
+
* If `true`, all sources will be expanded when printing.
|
|
100
|
+
*
|
|
101
|
+
* @default false
|
|
102
|
+
*/
|
|
103
|
+
expandSourcesOnPrint: boolean;
|
|
104
|
+
/**
|
|
105
|
+
* If `true`, phone-size compatible rendering will be used where supported.
|
|
106
|
+
*
|
|
107
|
+
* @default false
|
|
108
|
+
*/
|
|
109
|
+
isPhoneSize: boolean;
|
|
110
|
+
/**
|
|
111
|
+
* If `true`, the view-on-page eyeball buttons are not rendered.
|
|
112
|
+
*
|
|
113
|
+
* @default false
|
|
114
|
+
*/
|
|
115
|
+
hideViewOnPageButtons: boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Create a string for the source "view on page" buttons.
|
|
118
|
+
*
|
|
119
|
+
* This will only be used if `hideViewOnPageButtons` is not set to `true`.
|
|
120
|
+
*/
|
|
121
|
+
createViewOnPageString(pageNumber: number): string;
|
|
122
|
+
/**
|
|
123
|
+
* CSS styles for rendering internal Markdown.
|
|
124
|
+
*
|
|
125
|
+
* @default
|
|
126
|
+
*/
|
|
127
|
+
markdownStyles: string | CSSResult;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Default option values for Structured Render rendering to HTML.
|
|
131
|
+
*
|
|
132
|
+
* @category Internal
|
|
133
|
+
*/
|
|
134
|
+
export declare const defaultRenderHtmlOptions: Readonly<RenderHtmlOptions>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { allIconsByName, DocumentSearch24Icon, EyeOpen24Icon, LoaderAnimated24Icon, } from 'vira';
|
|
2
|
+
import { defaultMarkdownRenderStyles } from './render-markdown-styles.js';
|
|
3
|
+
/**
|
|
4
|
+
* Default base option values for Structured Render rendering.
|
|
5
|
+
*
|
|
6
|
+
* @category Internal
|
|
7
|
+
*/
|
|
8
|
+
export const defaultRenderOptions = {
|
|
9
|
+
icons: allIconsByName,
|
|
10
|
+
sourceString: 'Source',
|
|
11
|
+
pluralSourcesString: 'Sources',
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Default option values for Structured Render rendering to Markdown.
|
|
15
|
+
*
|
|
16
|
+
* @category Internal
|
|
17
|
+
*/
|
|
18
|
+
export const defaultRenderMarkdownOptions = {
|
|
19
|
+
...defaultRenderOptions,
|
|
20
|
+
styles: defaultMarkdownRenderStyles,
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Default option values for Structured Render rendering to HTML.
|
|
24
|
+
*
|
|
25
|
+
* @category Internal
|
|
26
|
+
*/
|
|
27
|
+
export const defaultRenderHtmlOptions = {
|
|
28
|
+
...defaultRenderOptions,
|
|
29
|
+
processingString: 'Processing',
|
|
30
|
+
currentlyExpanded: {},
|
|
31
|
+
sourceIcon: DocumentSearch24Icon,
|
|
32
|
+
viewOnPageIcon: EyeOpen24Icon,
|
|
33
|
+
processingIcon: LoaderAnimated24Icon,
|
|
34
|
+
expandSourcesOnPrint: false,
|
|
35
|
+
hideViewOnPageButtons: false,
|
|
36
|
+
isPhoneSize: false,
|
|
37
|
+
markdownStyles: defaultMarkdownRenderStyles,
|
|
38
|
+
createViewOnPageString(pageNumber) {
|
|
39
|
+
return `View on page ${pageNumber}`;
|
|
40
|
+
},
|
|
41
|
+
};
|