diff --git a/types/pdfmake/index.d.ts b/types/pdfmake/index.d.ts index fdc0a9de05..a812611400 100644 --- a/types/pdfmake/index.d.ts +++ b/types/pdfmake/index.d.ts @@ -2,7 +2,9 @@ // Project: http://pdfmake.org // Definitions by: Milen Stefanov // Rajab Shakirov +// Enzo Volkmann // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.4 declare module 'pdfmake/build/vfs_fonts' { let pdfMake: { @@ -16,15 +18,61 @@ declare module 'pdfmake/build/pdfmake' { let fonts: { [name: string]: TFontFamilyTypes }; function createPdf(documentDefinitions: TDocumentDefinitions): TCreatedPdf; - type pageSizeType = - '4A0' | '2A0' | 'A0' | 'A1' | 'A2' | 'A3' | 'A4' | 'A5' | 'A6' | 'A7' | 'A8' | 'A9' | 'A10' | - 'B0' | 'B1' | 'B2' | 'B3' | 'B4' | 'B5' | 'B6' | 'B7' | 'B8' | 'B9' | 'B10' | - 'C0' | 'C1' | 'C2' | 'C3' | 'C4' | 'C5' | 'C6' | 'C7' | 'C8' | 'C9' | 'C10' | - 'RA0' | 'RA1' | 'RA2' | 'RA3' | 'RA4' | - 'SRA0' | 'SRA1' | 'SRA2' | 'SRA3' | 'SRA4' | - 'EXECUTIVE' | 'FOLIO' | 'LEGAL' | 'LETTER' | 'TABLOID'; + enum PageSize { + A0_x_4 = '4A0', + A0_x_2 = '2A0', + AO = 'A0', + A1 = 'A1', + A2 = 'A2', + A3 = 'A3', + A4 = 'A4', + A5 = 'A5', + A6 = 'A6', + A7 = 'A7', + A8 = 'A8', + A9 = 'A9', + A1O = 'A10', + BO = 'B0', + B1 = 'B1', + B2 = 'B2', + B3 = 'B3', + B4 = 'B4', + B5 = 'B5', + B6 = 'B6', + B7 = 'B7', + B8 = 'B8', + B9 = 'B9', + B1O = 'B10', + CO = 'C0', + C1 = 'C1', + C2 = 'C2', + C3 = 'C3', + C4 = 'C4', + C5 = 'C5', + C6 = 'C6', + C7 = 'C7', + C8 = 'C8', + C9 = 'C9', + C1O = 'C10', + RA1 = 'RA1', + RA2 = 'RA2', + RA3 = 'RA3', + RA4 = 'RA4', + SRA1 = 'SRA1', + SRA2 = 'SRA2', + SRA3 = 'SRA3', + SRA4 = 'SRA4', + EXECUTIVE = 'EXECUTIVE', + FOLIO = 'FOLIO', + LEGAL = 'LEGAL', + LETTER = 'LETTER', + TABLOID = 'TABLOID' + } - type pageOrientationType = "portrait" | "landscape"; + enum PageOrientation { + PORTRAIT = 'PORTRAIT', + LANDSCAPE = 'LANDSCAPE' + } let pdfMake: pdfMakeStatic; @@ -48,18 +96,90 @@ declare module 'pdfmake/build/pdfmake' { type TDocumentHeaderFooterFunction = (currentPage: number, pageCount: number) => any; + type Margins = number | [number, number] | [number, number, number, number]; + + type Alignment = 'left' | 'right' | 'justify' | 'center' | string; + + interface Style { + font?: any; + fontSize?: number; + fontFeatures?: any; + bold?: boolean; + italics?: boolean; + alignment?: Alignment; + color?: string; + columnGap?: any; + fillColor?: string; + decoration?: any; + decorationany?: any; + decorationColor?: string; + background?: any; + lineHeight?: number; + characterSpacing?: number; + noWrap?: boolean; + markerColor?: string; + leadingIndent?: any; + [additionalProperty: string]: any; + } + + type TableRowFunction = (row: number) => number; + + interface TableLayoutFunctions { + hLineWidth?: (i: number, node: any) => number; + vLineWidth?: (i: number, node: any) => number; + hLineColor?: (i: number, node: any) => string; + vLineColor?: (i: number, node: any) => string; + fillColor?: (i: number, node: any) => string; + paddingLeft?: (i: number, node: any) => number; + paddingRight?: (i: number, node: any) => number; + paddingTop?: (i: number, node: any) => number; + paddingBottom?: (i: number, node: any) => number; + } + + interface TableCell { + text: string; + rowSpan?: number; + colSpan?: number; + fillColor?: string; + border?: [boolean, boolean, boolean, boolean]; + } + + interface Table { + widths?: Array<(string | number)>; + heights?: Array<(string | number)> | TableRowFunction; + headerRows?: number; + body: Content[][] | TableCell[][]; + layout?: string | TableLayoutFunctions; + } + + interface Content { + style?: 'string'; + margin?: Margins; + text?: string | string[] | Content[]; + columns?: Content[]; + stack?: Content[]; + image?: string; + width?: string | number; + height?: string | number; + fit?: [number, number]; + pageBreak?: 'before' | 'after'; + alignment?: Alignment; + table?: Table; + ul?: Content[]; + ol?: Content[]; + [additionalProperty: string]: any; + } + interface TDocumentDefinitions { info?: TDocumentInformation; - header?: any; - footer?: any; - content: any; - styles?: any; - pageSize?: pageSizeType; - pageOrientation?: pageOrientationType; - pageMargins?: [number, number, number, number]; - defaultStyle?: { - font?: string; - }; + header?: TDocumentHeaderFooterFunction; + footer?: TDocumentHeaderFooterFunction; + content: string | Content; + styles?: Style; + pageSize?: PageSize; + pageOrientation?: PageOrientation; + pageMargins?: Margins; + defaultStyle?: Style; } type CreatedPdfParams = ( diff --git a/types/pdfmake/pdfmake-tests.ts b/types/pdfmake/pdfmake-tests.ts index 0f23e5c5d5..1913e3fe8a 100644 --- a/types/pdfmake/pdfmake-tests.ts +++ b/types/pdfmake/pdfmake-tests.ts @@ -1,10 +1,1330 @@ import * as pdfMake from 'pdfmake/build/pdfmake'; import * as pdfFonts from 'pdfmake/build/vfs_fonts'; -const docDefinition = { content: 'This is an sample PDF printed with pdfMake' }; +const definitions = [ + { + content: [ + 'First paragraph', + 'Another paragraph, this time a little bit longer to make sure, this line will be divided into at least two lines' + ] + }, + { + content: [ + { + text: 'This is a header, using header style', + style: 'header' + }, + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. \n\n', + { + text: 'Subheader 1 - using subheader style', + style: 'subheader' + }, + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. ', + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. ', + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. \n\n', + { + text: 'Subheader 2 - using subheader style', + style: 'subheader' + }, + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. ', + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. \n\n', + { + text: 'It is possible to apply multiple styles, ', + style: ['quote', 'small'] + } + ], + styles: { + header: { + fontSize: 18, + bold: true + }, + subheader: { + fontSize: 15, + bold: true + }, + quote: { + italics: true + }, + small: { + fontSize: 8 + } + } + }, + { + content: [ + { + text: 'This is a header (whole paragraph uses the same header style)\n\n', + style: 'header' + }, + { + text: [ + 'It is however possible to provide an array of texts ', + 'to the paragraph (instead of a single string) and have ', + { text: 'a better ', fontSize: 15, bold: true }, + 'control over it. \nEach inline can be ', + { text: 'styled ', fontSize: 20 }, + { text: 'independently ', italics: true, fontSize: 40 }, + 'then.\n\n' + ] + }, + { text: 'Mixing named styles and style-overrides', style: 'header' }, + { + style: 'bigger', + italics: false, + text: [ + 'We can also mix named-styles and style-overrides at both paragraph and inline level. ', + 'For example, this paragraph uses the "bigger" style, which changes fontSize to 15 and sets italics to true. ', + 'Texts are not italics though. It\'s because we\'ve overriden italics back to false at ', + 'the paragraph level. \n\n', + 'We can also change the style of a single inline. Let\'s use a named style called header: ', + { text: 'like here.\n', style: 'header' }, + 'It got bigger and bold.\n\n', + 'OK, now we\'re going to mix named styles and style-overrides at the inline level. ', + 'We\'ll use header style (it makes texts bigger and bold), but we\'ll override ', + 'bold back to false: ', + { text: 'wow! it works!', style: 'header', bold: false }, + '\n\nMake sure to take a look into the sources to understand what\'s going on here.' + ] + } + ], + styles: { + header: { + fontSize: 18, + bold: true + }, + bigger: { + fontSize: 15, + italics: true + } + } + }, + { + content: [ + { + text: 'This paragraph uses header style and extends the alignment property', + style: 'header', + alignment: 'center' + }, + { + text: [ + 'This paragraph uses header style and overrides bold value setting it back to false.\n', + 'Header style in this example sets alignment to justify, so this paragraph should be rendered \n', + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Malit profecta versatur nomine ocurreret ' + ], + style: 'header', + bold: false + } + ], + styles: { + header: { + fontSize: 18, + bold: true, + alignment: 'justify' + } + } + }, + { + content: [ + 'By default paragraphs are stacked one on top of (or actually - below) another. ', + 'It\'s possible however to split any paragraph (or even the whole document) into columns.\n\n', + 'Here we go with 2 star-sized columns, with justified text and gap set to 20:\n\n', + { + alignment: 'justify', + columns: [ + { + text: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' + }, + { + text: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' + } + ] + }, + '\nStar-sized columns have always equal widths, so if we define 3 of those, ', + 'it\'ll look like this (make sure to scroll to the next page, as we have a couple of more examples):\n\n', + { + columns: [ + { + text: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' + }, + { + text: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' + }, + { + text: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' + } + ] + }, + '\nYou can also specify accurate widths for some (or all columns)', + { + columns: [ + { + width: 90, + text: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' + }, + { + width: '*', + text: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' + }, + { + width: '*', + text: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' + }, + { + width: 90, + text: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' + } + ] + }, + '\nWe also support auto columns. They set their widths based on the content:\n\n', + { + columns: [ + { + width: 'auto', + text: 'auto column' + }, + { + width: '*', + text: 'This is a star-sized column. It should get the remaining' + + ' space divided by the number of all star-sized columns.' + }, + { + width: 50, + text: 'this one has specific width set to 50' + }, + { + width: 'auto', + text: 'another auto column' + }, + { + width: '*', + text: 'This is a star-sized column. It should get the remaining space ' + + 'divided by the number of all star-sized columns.' + }, + ] + }, + '\nIf all auto columns fit within available width, the table does not occupy whole space:\n\n', + { + columns: [ + { + width: 'auto', + text: 'val1' + }, + { + width: 'auto', + text: 'val2' + }, + { + width: 'auto', + text: 'value3' + }, + { + width: 'auto', + text: 'value 4' + }, + ] + }, + '\nAnother cool feature of pdfmake is the ability to have nested elements.', + { + columns: [ + { + width: 100, + fontSize: 9, + text: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. ' + }, + [ + 'As you can see in the document definition - this column is not defined with ', + 'an object, but an array, which means it\'s treated as an array of paragraphs rendered one below another.', + 'Just like on the top-level of the document. Let\'s try to divide the remaing space into 3 star-sized columns:\n\n', + { + columns: [ + { text: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' }, + { text: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' }, + { text: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' }, + ] + } + ] + ] + }, + '\n\nOh, don\'t forget, we can use everything from styling examples (named styles, custom overrides) here as well.\n\n', + 'For instance - our next paragraph will use the \'bigger\' style (with fontSize set to 15 and italics - true).', + ' We\'ll split it into three columns and make sure they inherit the style:\n\n', + { + style: 'bigger', + columns: [ + 'First column (BTW - it\'s defined as a single string value. pdfmake will turn it into appropriate structure ', + 'automatically and make sure it inherits the styles', + { + fontSize: 20, + text: 'In this column, we\'ve overriden fontSize to 20. It means the content should have italics=true' + + ' (inherited from the style) and be a little bit bigger' + }, + { + style: 'header', + text: 'Last column does not override any styling properties, but applies a new style (header) to itself.' + + ' Eventually - texts here have italics=true (from bigger) and derive fontSize from the style.' + + ' OK, but which one? Both styles define it. As we already know from our styling examples, multiple' + + ' styles can be applied to the element and their order is important. Because \'header\' style has been' + + ' set after \'bigger\' its fontSize takes precedence over the fontSize from \'bigger\'. This is how it works. ' + + 'You will find more examples in the unit tests.' + } + ] + }, + '\n\nWow, you\'ve read the whole document! Congratulations :D' + ], + styles: { + header: { + fontSize: 18, + bold: true + }, + bigger: { + fontSize: 15, + italics: true + } + }, + defaultStyle: { + columnGap: 20 + } + }, + { + content: [ + { text: 'Tables', style: 'header' }, + 'Official documentation is in progress, this document is just', + ' a glimpse of what is possible with pdfmake and its layout engine.', + { text: 'A simple table (no headers, no width specified, no spans, no styling)', + style: 'subheader' }, + 'The following table has nothing more than a body array', + { + style: 'tableExample', + table: { + body: [ + ['Column 1', 'Column 2', 'Column 3'], + ['One value goes here', 'Another one here', 'OK?'] + ] + } + }, + { text: 'A simple table with nested elements', style: 'subheader' }, + 'It is of course possible to nest any other type of nodes available in ', + 'pdfmake inside table cells', + { + style: 'tableExample', + table: { + body: [ + ['Column 1', 'Column 2', 'Column 3'], + [ + { + stack: [ + 'Let\'s try an unordered list', + { + ul: [ + 'item 1', + 'item 2' + ] + } + ] + }, + [ + 'or a nested table', + { + table: { + body: [ + ['Col1', 'Col2', 'Col3'], + ['1', '2', '3'], + ['1', '2', '3'] + ] + }, + } + ], + { + text: [ + 'Inlines can be ', + { text: 'styled\n', italics: true }, + { text: 'easily as everywhere else', fontSize: 10 }] + } + ] + ] + } + }, + { text: 'Defining column widths', style: 'subheader' }, + 'Tables support the same width definitions as standard columns:', + { + bold: true, + ul: [ + 'auto', + 'star', + 'fixed value' + ] + }, + { + style: 'tableExample', + table: { + widths: [100, '*', 200, '*'], + body: [ + ['width=100', 'star-sized', 'width=200', 'star-sized'], + ['fixed-width cells have exactly the specified width', + { text: 'nothing interesting here', italics: true, color: 'gray' }, + { text: 'nothing interesting here', italics: true, color: 'gray' }, + { text: 'nothing interesting here', italics: true, color: 'gray' }] + ] + } + }, + { + style: 'tableExample', + table: { + widths: ['*', 'auto'], + body: [ + ['This is a star-sized column. The next column over, an auto-sized column, will wrap to accomodate all the text in this cell.', 'I am auto sized.'], + ] + } + }, + { + style: 'tableExample', + table: { + widths: ['*', 'auto'], + body: [ + ['This is a star-sized column. The next column over, an auto-sized column', + { text: 'I am auto sized.', noWrap: true }], + ] + } + }, + { text: 'Defining row heights', style: 'subheader' }, + { + style: 'tableExample', + table: { + heights: [20, 50, 70], + body: [ + ['row 1 with height 20', 'column B'], + ['row 2 with height 50', 'column B'], + ['row 3 with height 70', 'column B'] + ] + } + }, + 'With same height:', + { + style: 'tableExample', + table: { + heights: 40, + body: [ + ['row 1', 'column B'], + ['row 2', 'column B'], + ['row 3', 'column B'] + ] + } + }, + 'With height from function:', + { + style: 'tableExample', + table: { + heights: (row: number) => { + return (row + 1) * 25; + }, + body: [ + ['row 1', 'column B'], + ['row 2', 'column B'], + ['row 3', 'column B'] + ] + } + }, + { text: 'Column/row spans', pageBreak: 'before', style: 'subheader' }, + 'Each cell-element can set a rowSpan or colSpan', + { + style: 'tableExample', + color: '#444', + table: { + widths: [200, 'auto', 'auto'], + headerRows: 2, + // keepWithHeaderRows: 1, + body: [ + [{ text: 'Header with Colspan = 2', style: 'tableHeader', colSpan: 2, alignment: 'center' }, + {}, { text: 'Header 3', style: 'tableHeader', alignment: 'center' }], + [{ text: 'Header 1', style: 'tableHeader', alignment: 'center' }, + { text: 'Header 2', style: 'tableHeader', alignment: 'center' }, + { text: 'Header 3', style: 'tableHeader', alignment: 'center' }], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + [{ rowSpan: 3, text: 'rowSpan set to 3\nLorem ipsum dolor sit amet' }, + 'Sample value 2', 'Sample value 3'], + ['', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', { colSpan: 2, rowSpan: 2, text: 'Both:\nrowSpan and colSpan\ncan be defined at the same time' }, ''], + ['Sample value 1', '', ''], + ] + } + }, + { text: 'Headers', pageBreak: 'before', style: 'subheader' }, + 'You can declare how many rows should be treated as a header. Headers are', + ' automatically repeated on the following pages', + { text: ['It is also possible to set keepWithHeaderRows to make sure there will be no page-break' + + 'between the header and these rows. Take a look at the document-definition and play with it. ' + + 'If you set it to one, the following table will automatically start on the next page, ' + + 'since there\'s not enough space for the first row to be rendered here'], color: 'gray', italics: true }, + { + style: 'tableExample', + table: { + headerRows: 1, + // dontBreakRows: true, + // keepWithHeaderRows: 1, + body: [ + [{ text: 'Header 1', style: 'tableHeader' }, { text: 'Header 2', style: 'tableHeader' }, + { text: 'Header 3', style: 'tableHeader' }], + [ + 'Lorem ipsum dolor sit amet, ', + 'Lorem ipsum dolor sit amet, ', + 'Lorem ipsum dolor sit amet, ', + ] + ] + } + }, + { text: 'Styling tables', style: 'subheader' }, + 'You can provide a custom styler for the table. Currently it supports:', + { + ul: [ + 'line widths', + 'line colors', + 'cell paddings', + ] + }, + 'with more options coming soon...\n\npdfmake currently has a few predefined styles (see them on the next page)', + { text: 'noBorders:', fontSize: 14, bold: true, pageBreak: 'before', margin: [0, 0, 0, 8] }, + { + style: 'tableExample', + table: { + headerRows: 1, + body: [ + [{ text: 'Header 1', style: 'tableHeader' }, { text: 'Header 2', style: 'tableHeader' }, + { text: 'Header 3', style: 'tableHeader' }], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ] + }, + layout: 'noBorders' + }, + { text: 'headerLineOnly:', fontSize: 14, bold: true, margin: [0, 20, 0, 8] }, + { + style: 'tableExample', + table: { + headerRows: 1, + body: [ + [{ text: 'Header 1', style: 'tableHeader' }, { text: 'Header 2', style: 'tableHeader' }, + { text: 'Header 3', style: 'tableHeader' }], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ] + }, + layout: 'headerLineOnly' + }, + { text: 'lightHorizontalLines:', fontSize: 14, bold: true, margin: [0, 20, 0, 8] }, + { + style: 'tableExample', + table: { + headerRows: 1, + body: [ + [{ text: 'Header 1', style: 'tableHeader' }, { text: 'Header 2', style: 'tableHeader' }, { text: 'Header 3', style: 'tableHeader' }], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ] + }, + layout: 'lightHorizontalLines' + }, + { text: 'but you can provide a custom styler as well', margin: [0, 20, 0, 8] }, + { + style: 'tableExample', + table: { + headerRows: 1, + body: [ + [{ text: 'Header 1', style: 'tableHeader' }, { text: 'Header 2', style: 'tableHeader' }, { text: 'Header 3', style: 'tableHeader' }], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ] + }, + layout: { + hLineWidth: (i: number, node: any) => { + return (i === 0 || i === node.table.body.length) ? 2 : 1; + }, + vLineWidth: (i: number, node: any) => { + return (i === 0 || i === node.table.widths.length) ? 2 : 1; + }, + hLineColor: (i: number, node: any) => { + return (i === 0 || i === node.table.body.length) ? 'black' : 'gray'; + }, + vLineColor: (i: number, node: any) => { + return (i === 0 || i === node.table.widths.length) ? 'black' : 'gray'; + }, + // paddingLeft: function(i, node) { return 4; }, + // paddingRight: function(i, node) { return 4; }, + // paddingTop: function(i, node) { return 2; }, + // paddingBottom: function(i, node) { return 2; }, + // fillColor: (i: number, node: any) => { return null; } + } + }, + { text: 'zebra style', margin: [0, 20, 0, 8] }, + { + style: 'tableExample', + table: { + body: [ + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ['Sample value 1', 'Sample value 2', 'Sample value 3'], + ] + }, + layout: { + fillColor: (i: number, node: any) => { + return (i % 2 === 0) ? '#CCCCCC' : null; + } + } + }, + { text: 'Optional border', fontSize: 14, bold: true, pageBreak: 'before', margin: [0, 0, 0, 8] }, + 'Each cell contains an optional border property: an array of 4 booleans for left border, top border, right border, bottom border.', + { + style: 'tableExample', + table: { + body: [ + [ + { + border: [false, true, false, false], + fillColor: '#eeeeee', + text: 'border:\n[false, true, false, false]' + }, + { + border: [false, false, false, false], + fillColor: '#dddddd', + text: 'border:\n[false, false, false, false]' + }, + { + border: [true, true, true, true], + fillColor: '#eeeeee', + text: 'border:\n[true, true, true, true]' + } + ], + [ + { + rowSpan: 3, + border: [true, true, true, true], + fillColor: '#eeeeff', + text: 'rowSpan: 3\n\nborder:\n[true, true, true, true]' + }, + { + border: undefined, + fillColor: '#eeeeee', + text: 'border:\nundefined' + }, + { + border: [true, false, false, false], + fillColor: '#dddddd', + text: 'border:\n[true, false, false, false]' + } + ], + [ + '', + { + colSpan: 2, + border: [true, true, true, true], + fillColor: '#eeffee', + text: 'colSpan: 2\n\nborder:\n[true, true, true, true]' + }, + '' + ], + [ + '', + { + border: undefined, + fillColor: '#eeeeee', + text: 'border:\nundefined' + }, + { + border: [false, false, true, true], + fillColor: '#dddddd', + text: 'border:\n[false, false, true, true]' + } + ] + ] + }, + layout: { + defaultBorder: false, + } + }, + 'For every cell without a border property, whether it has all borders or not is determined by ', + 'layout.defaultBorder, which is false in the table above and true (by default) in the table below.', + { + style: 'tableExample', + table: { + body: [ + [ + { + border: [false, false, false, false], + fillColor: '#eeeeee', + text: 'border:\n[false, false, false, false]' + }, + { + fillColor: '#dddddd', + text: 'border:\nundefined' + }, + { + fillColor: '#eeeeee', + text: 'border:\nundefined' + }, + ], + [ + { + fillColor: '#dddddd', + text: 'border:\nundefined' + }, + { + fillColor: '#eeeeee', + text: 'border:\nundefined' + }, + { + border: [true, true, false, false], + fillColor: '#dddddd', + text: 'border:\n[true, true, false, false]' + }, + ] + ] + } + }, + 'And some other examples with rowSpan/colSpan...', + { + style: 'tableExample', + table: { + body: [ + [ + '', + 'column 1', + 'column 2', + 'column 3' + ], + [ + 'row 1', + { + rowSpan: 3, + colSpan: 3, + border: [true, true, true, true], + fillColor: '#cccccc', + text: 'rowSpan: 3\ncolSpan: 3\n\nborder:\n[true, true, true, true]' + }, + '', + '' + ], + [ + 'row 2', + '', + '', + '' + ], + [ + 'row 3', + '', + '', + '' + ] + ] + }, + layout: { + defaultBorder: false, + } + }, + { + style: 'tableExample', + table: { + body: [ + [ + { + colSpan: 3, + text: 'colSpan: 3\n\nborder:\n[false, false, false, false]', + fillColor: '#eeeeee', + border: [false, false, false, false] + }, + '', + '' + ], + [ + 'border:\nundefined', + 'border:\nundefined', + 'border:\nundefined' + ] + ] + } + }, + { + style: 'tableExample', + table: { + body: [ + [ + { rowSpan: 3, text: 'rowSpan: 3\n\nborder:\n[false, false, false, false]', fillColor: '#eeeeee', border: [false, false, false, false] }, + 'border:\nundefined', + 'border:\nundefined' + ], + [ + '', + 'border:\nundefined', + 'border:\nundefined' + ], + [ + '', + 'border:\nundefined', + 'border:\nundefined' + ] + ] + } + } + ], + styles: { + header: { + fontSize: 18, + bold: true, + margin: [0, 0, 0, 10] + }, + subheader: { + fontSize: 16, + bold: true, + margin: [0, 10, 0, 5] + }, + tableExample: { + margin: [0, 5, 0, 15] + }, + tableHeader: { + bold: true, + fontSize: 13, + color: 'black' + } + }, + defaultStyle: { + // alignment: 'justify' + } + }, + { + content: [ + { text: 'Unordered list', style: 'header' }, + { + ul: [ + 'item 1', + 'item 2', + 'item 3' + ] + }, + { text: '\n\nUnordered list with longer lines', style: 'header' }, + { + ul: [ + 'item 1', + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.', + 'item 3' + ] + }, + { text: '\n\nOrdered list', style: 'header' }, + { + ol: [ + 'item 1', + 'item 2', + 'item 3' + ] + }, + { text: '\n\nOrdered list with longer lines', style: 'header' }, + { + ol: [ + 'item 1', + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.', + 'item 3' + ] + }, + { text: '\n\nOrdered list should be descending', style: 'header' }, + { + reversed: true, + ol: [ + 'item 1', + 'item 2', + 'item 3' + ] + }, + { text: '\n\nOrdered list with start value', style: 'header' }, + { + start: 50, + ol: [ + 'item 1', + 'item 2', + 'item 3' + ] + }, + { text: '\n\nOrdered list with own values', style: 'header' }, + { + ol: [ + { text: 'item 1', counter: 10 }, + { text: 'item 2', counter: 20 }, + { text: 'item 3', counter: 30 }, + { text: 'item 4 without own value' } + ] + }, + { text: '\n\nNested lists (ordered)', style: 'header' }, + { + ol: [ + 'item 1', + [ + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.', + { + ol: [ + 'subitem 1', + 'subitem 2', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + { + text: [ + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + ] + }, + + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 4', + 'subitem 5', + ] + } + ], + 'item 3\nsecond line of item3' + ] + }, + { text: '\n\nNested lists (unordered)', style: 'header' }, + { + ol: [ + 'item 1', + 'Lorem ipsum dolor sit amet', + { + ul: [ + 'subitem 1', + 'subitem 2', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + { + text: [ + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + ] + }, + + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 4', + 'subitem 5', + ] + }, + 'item 3\nsecond line of item3', + ] + }, + { text: '\n\nUnordered lists inside columns', style: 'header' }, + { + columns: [ + { + ul: [ + 'item 1', + 'Lorem ipsum dolor sit amet', + ] + }, + { + ul: [ + 'item 1', + 'Lorem ipsum dolor sit amet', + ] + } + ] + }, + { text: '\n\nOrdered lists inside columns', style: 'header' }, + { + columns: [ + { + ol: [ + 'item 1', + 'Lorem ipsum dolor sit amet', + ] + }, + { + ol: [ + 'item 1', + 'Lorem ipsum dolor sit amet', + ] + } + ] + }, + { text: '\n\nNested lists width columns', style: 'header' }, + { + ul: [ + 'item 1', + 'Lorem ipsum dolor sit amet', + { + ol: [ + [ + { + columns: [ + 'column 1', + { + stack: [ + 'column 2', + { + ul: [ + 'item 1', + 'item 2', + { + ul: [ + 'item', + 'item', + 'item', + ] + }, + 'item 4', + ] + } + ] + }, + 'column 3', + 'column 4', + ] + }, + 'subitem 1 in a vertical container', + 'subitem 2 in a vertical container', + ], + 'subitem 2', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + { + text: [ + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + ] + }, + + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 3 - Lorem ipsum dolor sit amet', + 'subitem 4', + 'subitem 5', + ] + }, + 'item 3\nsecond line of item3', + ] + }, + { text: '\n\nUnordered list with square marker type', style: 'header' }, + { + type: 'square', + ul: [ + 'item 1', + 'item 2', + 'item 3' + ] + }, + { text: '\n\nUnordered list with circle marker type', style: 'header' }, + { + type: 'circle', + ul: [ + 'item 1', + 'item 2', + 'item 3' + ] + }, + { text: '\n\nColored unordered list', style: 'header' }, + { + color: 'blue', + ul: [ + 'item 1', + 'item 2', + 'item 3' + ] + }, + { text: '\n\nColored unordered list with own marker color', style: 'header' }, + { + color: 'blue', + markerColor: 'red', + ul: [ + 'item 1', + 'item 2', + 'item 3' + ] + }, + { text: '\n\nColored ordered list', style: 'header' }, + { + color: 'blue', + ol: [ + 'item 1', + 'item 2', + 'item 3' + ] + }, + { text: '\n\nColored ordered list with own marker color', style: 'header' }, + { + color: 'blue', + markerColor: 'red', + ol: [ + 'item 1', + 'item 2', + 'item 3' + ] + }, + { text: '\n\nOrdered list - type: lower-alpha', style: 'header' }, + { + type: 'lower-alpha', + ol: [ + 'item 1', + 'item 2', + 'item 3' + ] + }, + { text: '\n\nOrdered list - type: upper-alpha', style: 'header' }, + { + type: 'upper-alpha', + ol: [ + 'item 1', + 'item 2', + 'item 3' + ] + }, + + { text: '\n\nOrdered list - type: upper-roman', style: 'header' }, + { + type: 'upper-roman', + ol: [ + 'item 1', + 'item 2', + 'item 3', + 'item 4', + 'item 5' + ] + }, + { text: '\n\nOrdered list - type: lower-roman', style: 'header' }, + { + type: 'lower-roman', + ol: [ + 'item 1', + 'item 2', + 'item 3', + 'item 4', + 'item 5' + ] + }, + { text: '\n\nOrdered list - type: none', style: 'header' }, + { + type: 'none', + ol: [ + 'item 1', + 'item 2', + 'item 3' + ] + }, + { text: '\n\nUnordered list - type: none', style: 'header' }, + { + type: 'none', + ul: [ + 'item 1', + 'item 2', + 'item 3' + ] + }, + { text: '\n\nOrdered list with own separator', style: 'header' }, + { + separator: ')', + ol: [ + 'item 1', + 'item 2', + 'item 3' + ] + }, + { text: '\n\nOrdered list with own complex separator', style: 'header' }, + { + separator: ['(', ')'], + ol: [ + 'item 1', + 'item 2', + 'item 3' + ] + }, + { text: '\n\nOrdered list with own items type', style: 'header' }, + { + ol: [ + 'item 1', + { text: 'item 2', listType: 'none' }, + { text: 'item 3', listType: 'upper-roman' } + ] + }, + { text: '\n\nUnordered list with own items type', style: 'header' }, + { + ul: [ + 'item 1', + { text: 'item 2', listType: 'none' }, + { text: 'item 3', listType: 'circle' } + ] + }, + ], + styles: { + header: { + bold: true, + fontSize: 15 + } + }, + defaultStyle: { + fontSize: 12 + } + }, + { + content: [ + { + stack: [ + 'This header has both top and bottom margins defined', + { text: 'This is a subheader', style: 'subheader' }, + ], + style: 'header' + }, + { + text: [ + 'Margins have slightly different behavior than other layout properties. ', + 'They are not inherited, unlike anything else. They\'re applied only to those nodes which explicitly ', + 'set margin or style property.\n', + ] + }, + { + text: 'This paragraph (consisting of a single line) directly sets top and bottom margin to 20', + margin: [0, 20], + }, + { + stack: [ + { + text: [ + 'This line begins a stack of paragraphs. The whole stack uses a ', + { text: 'superMargin', italics: true }, + ' style (with margin and fontSize properties).', + ] + }, + { text: ['When you look at the', { text: ' document definition', italics: true }, + ', you will notice that fontSize is inherited by all paragraphs inside the stack.'] }, + 'Margin however is only applied once (to the whole stack).' + ], + style: 'superMargin' + }, + { + stack: [ + 'I\'m not sure yet if this is the desired behavior. I find it a better approach however.', + ' One thing to be considered in the future is an explicit layout property called inheritMargin which could opt-in the inheritance.\n\n', + { + fontSize: 15, + text: [ + 'Currently margins for ', + /* the following margin definition doesn't change anything */ + { text: 'inlines', margin: 20 }, + ' are ignored\n\n' + ], + }, + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.\n', + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.\n', + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.\n', + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.\n', + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.\n', + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.\n', + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.\n', + ], + margin: [0, 20, 0, 0], + alignment: 'justify' + } + ], + styles: { + header: { + fontSize: 18, + bold: true, + alignment: 'right', + margin: [0, 190, 0, 80] + }, + subheader: { + fontSize: 14 + }, + superMargin: { + margin: [20, 0, 40, 0], + fontSize: 15 + } + } + }, + { + content: [ + 'pdfmake (since it\'s based on pdfkit) supports JPEG and PNG format', + 'If no width/height/fit is provided, image original size will be used', + { + image: 'sampleImage.jpg', + }, + 'If you specify width, image will scale proportionally', + { + image: 'sampleImage.jpg', + width: 150 + }, + 'If you specify both width and height - image will be stretched', + { + image: 'sampleImage.jpg', + width: 150, + height: 150, + }, + 'You can also fit the image inside a rectangle', + { + image: 'sampleImage.jpg', + fit: [100, 100], + pageBreak: 'after' + }, + // Warning! Make sure to copy this definition and paste it to an + // external text editor, as the online AceEditor has some troubles + // with long dataUrl lines and the following image values look like + // they're empty. + 'Images can be also provided in dataURL format...', + { + image: 'data:image/gif;base64,...', + width: 200 + }, + 'or be declared in an "images" dictionary and referenced by name', + { + image: 'building', + width: 200 + }, + ], + images: { + building: 'data:image/gif;base64,...' + } + } +]; const createPdf = () => { const pdf = pdfMake; pdf.vfs = pdfFonts.pdfMake.vfs; - pdfMake.createPdf(docDefinition).download(); + + for (const definition of definitions) { + const typedDefinition: pdfMake.TDocumentDefinitions = definition; + pdfMake.createPdf(typedDefinition).download(); + } };