@nxgt/material-core 0.1.0 → 0.2.0
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 +70 -4
- package/dist/chunks/{index-8gf9e2d4.js → index-fp0822sa.js} +3 -3
- package/dist/chunks/{index-8gf9e2d4.js.map → index-fp0822sa.js.map} +3 -3
- package/dist/chunks/index-w3ajz57t.js.map +2 -2
- package/dist/index.js +1 -1
- package/dist/lib/format-file-size.d.ts +10 -0
- package/dist/lib/format-file-size.d.ts.map +1 -0
- package/dist/lib/format-file-size.js +17 -0
- package/dist/lib/format-file-size.js.map +10 -0
- package/dist/lib/print-format.utils.d.ts.map +1 -1
- package/dist/pdf/index.js +1 -1
- package/dist/pdf/model/index.js +1 -1
- package/dist/pdfkit-fonts/index.d.ts +61 -0
- package/dist/pdfkit-fonts/index.d.ts.map +1 -0
- package/dist/pdfkit-fonts/index.js +80 -0
- package/dist/pdfkit-fonts/index.js.map +10 -0
- package/docs/roadmap.md +15 -6
- package/docs/troubleshooting.md +65 -0
- package/package.json +15 -8
package/README.md
CHANGED
|
@@ -5,13 +5,16 @@ The framework-free core that [`@nxgt/material`](https://www.npmjs.com/package/@n
|
|
|
5
5
|
(Vue) share, as one copy: the PDF document model and its react-pdf renderer,
|
|
6
6
|
the print formatters, the PDF file helpers, the PDF viewer's framework-free
|
|
7
7
|
half (page geometry, scroll spy, text search), the currency field's decimals,
|
|
8
|
-
the fields' blur rule
|
|
9
|
-
fonts
|
|
8
|
+
the file-size formatter, the fields' blur rule, the Vite plugin that bundles
|
|
9
|
+
pdfkit's standard fonts, and the Node-only resolution of those fonts that the
|
|
10
|
+
Next.js helper and the Nuxt module run at build time.
|
|
10
11
|
|
|
11
12
|
**You usually do not install it yourself.** Both libraries depend on it and
|
|
12
13
|
re-export what they always exported, at the same subpaths:
|
|
13
14
|
`@nxgt/material/print`, `@nxgt/material-vue/pdf`, `/lib` and `/vite` read
|
|
14
|
-
from here, and so do their `PdfReader`, `CurrencyField
|
|
15
|
+
from here, and so do their `PdfReader`, `CurrencyField`, form fields, file
|
|
16
|
+
list and upload field (`formatFileSize`), `@nxgt/material/next` and
|
|
17
|
+
`@nxgt/material-vue/nuxt`. Import it directly when you want the model or a formatter without
|
|
15
18
|
a UI library.
|
|
16
19
|
|
|
17
20
|
```ts
|
|
@@ -42,7 +45,10 @@ files are plain ES modules and also load in Node without a bundler.
|
|
|
42
45
|
| `vite@^6 \|\| ^7 \|\| ^8` | `@nxgt/material-core/vite` — its declarations name Vite's `Plugin` type (types only); the plugin itself runs in your Vite config |
|
|
43
46
|
|
|
44
47
|
Every other subpath imports none of them, and is safe to import on a server
|
|
45
|
-
with no DOM.
|
|
48
|
+
with no DOM. One subpath is **Node only**: `/pdfkit-fonts` imports `node:module`
|
|
49
|
+
and `node:path`, for a framework's config at build time — never import it
|
|
50
|
+
from code a browser bundle can reach. No other subpath imports a `node:`
|
|
51
|
+
built-in.
|
|
46
52
|
|
|
47
53
|
## Subpaths
|
|
48
54
|
|
|
@@ -64,7 +70,9 @@ with no DOM.
|
|
|
64
70
|
| `/pdf-viewer` | The PDF viewer's pure half: page geometry and fit (`readerFitScale`, `placeholderSize`, `rotatedSize`, `PdfPageSize`, `FitMode`), page sizes (`readPageSizes`, `createPageSizesLoader`), the scroll spy (`createScrollSpy`, `revealHit`), text search (`pageTextFromItems`, `findTextMatches`, `searchDocument`), `escapeHtml`, `mapPdfOutline` |
|
|
65
71
|
| `/currency-digits` | `currencyFractionDigits` — the decimals `CurrencyField` shows |
|
|
66
72
|
| `/field-blur-layers` | `layerOf`, `openerOf`, `FieldLayers` — whose overlay a layer of the page is, for a field's blur |
|
|
73
|
+
| `/format-file-size` | `formatFileSize` — a byte count as `'1.5 KB'` |
|
|
67
74
|
| `/vite` | `pdfkitStandardFonts()` — see below |
|
|
75
|
+
| `/pdfkit-fonts` | **Node only.** `pdfkitStandardFontDirs`, `pdfkitStandardFontFiles`, `PDFKIT_STANDARD_FONTS`, the types `PdfkitStandardFont` and `PdfkitFontsWarn` — where the app's pdfkit keeps its standard fonts, for a server tracer |
|
|
68
76
|
|
|
69
77
|
## Usage
|
|
70
78
|
|
|
@@ -279,6 +287,23 @@ currencyFractionDigits('KWD'); // 3
|
|
|
279
287
|
currencyFractionDigits('EUR', 0); // 0 — an explicit value wins, as in formatAmount
|
|
280
288
|
```
|
|
281
289
|
|
|
290
|
+
### A file's size: `/format-file-size`
|
|
291
|
+
|
|
292
|
+
1024-based, one decimal above bytes, capped at GB, locale-free: a server and
|
|
293
|
+
a browser print the same string. What both libraries' `FileList`,
|
|
294
|
+
`NetworkUploadField` (and its size limit message), `FileCard` and chat
|
|
295
|
+
attachments show; both re-export it as `formatFileSize`.
|
|
296
|
+
|
|
297
|
+
```ts
|
|
298
|
+
import { formatFileSize } from '@nxgt/material-core/format-file-size';
|
|
299
|
+
|
|
300
|
+
formatFileSize(0); // '0 B'
|
|
301
|
+
formatFileSize(512); // '512 B'
|
|
302
|
+
formatFileSize(1536); // '1.5 KB'
|
|
303
|
+
formatFileSize(5 * 1024 ** 2); // '5.0 MB'
|
|
304
|
+
formatFileSize(-1); // '' — as for NaN and Infinity
|
|
305
|
+
```
|
|
306
|
+
|
|
282
307
|
### A field's blur across overlays: `/field-blur-layers`
|
|
283
308
|
|
|
284
309
|
A field whose popover, listbox or dialog renders into `<body>` must not count
|
|
@@ -317,12 +342,53 @@ export default defineConfig({ plugins: [pdfkitStandardFonts()] });
|
|
|
317
342
|
function. The doc comment on `pdfkitStandardFonts` explains when you need it
|
|
318
343
|
and when keeping the library external is the lighter answer.
|
|
319
344
|
|
|
345
|
+
### Tracing pdfkit's fonts: `/pdfkit-fonts` (Node only)
|
|
346
|
+
|
|
347
|
+
A server that keeps `node_modules` but copies only what a tracer finds
|
|
348
|
+
(`next build` with `output: 'standalone'`, Nitro's `.output/server`) gets
|
|
349
|
+
pdfkit without its fonts: pdfkit loads them with a runtime
|
|
350
|
+
`require('#standard-fonts/<Name>')` no tracer follows, and every PDF then
|
|
351
|
+
fails with `Cannot find module '…/pdfkit/js/standard-fonts/Helvetica.cjs'`.
|
|
352
|
+
These functions find the real files, as the app at a project directory
|
|
353
|
+
loads them — through `@react-pdf/renderer` and through `@react-pdf/font`,
|
|
354
|
+
each of which may nest its own pdfkit — for you to hand to the tracer.
|
|
355
|
+
|
|
356
|
+
```ts
|
|
357
|
+
// A build script or a framework config: Node code.
|
|
358
|
+
import { pdfkitStandardFontDirs, pdfkitStandardFontFiles } from '@nxgt/material-core/pdfkit-fonts';
|
|
359
|
+
|
|
360
|
+
const warn = (message: string) => console.warn(`[my-build] ${message}`);
|
|
361
|
+
|
|
362
|
+
pdfkitStandardFontDirs(process.cwd(), warn);
|
|
363
|
+
// ['/app/node_modules/pdfkit/js/standard-fonts'] — one per distinct pdfkit;
|
|
364
|
+
// each also holds the chunks/ the fonts require
|
|
365
|
+
|
|
366
|
+
pdfkitStandardFontFiles(process.cwd(), warn);
|
|
367
|
+
// ['/app/node_modules/pdfkit/js/standard-fonts/Courier.cjs', … 14 per pdfkit]
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
- **Without `@react-pdf/renderer`** (an optional peer: the app does not
|
|
371
|
+
print), both return `[]` and never call `warn`.
|
|
372
|
+
- **Otherwise, whatever fails** (`@react-pdf/font` or pdfkit not
|
|
373
|
+
resolvable, a font missing) reaches `warn` **once per call**, every problem
|
|
374
|
+
in one line (each error's first line, without Node's `Require stack:`),
|
|
375
|
+
and the rest is still returned. Prefix it with your
|
|
376
|
+
tool's name; a font that cannot be traced is a PDF route that fails in
|
|
377
|
+
production.
|
|
378
|
+
- A relative project directory is taken from the working directory. The
|
|
379
|
+
paths are real paths (symlinks resolved), as pnpm and bun lay them out.
|
|
380
|
+
|
|
381
|
+
You rarely call it yourself: `withNxgtPrint` (`@nxgt/material/next`) turns
|
|
382
|
+
the directories into `outputFileTracingIncludes` globs, and the Nuxt module
|
|
383
|
+
of `@nxgt/material-vue` adds the files to `nitro.externals.traceInclude`.
|
|
384
|
+
|
|
320
385
|
## Traps
|
|
321
386
|
|
|
322
387
|
| Symptom | Fix |
|
|
323
388
|
| --- | --- |
|
|
324
389
|
| `Cannot find package '@react-pdf/renderer'` (or `'react'`) when importing `/pdf` or `/pdf/render` | `bun add react @react-pdf/renderer@^4.9` — or import from `/pdf/model` where you only build documents |
|
|
325
390
|
| `Cannot find module '#standard-fonts/Helvetica'` on every request of a bundled server | `pdfkitStandardFonts()` from `/vite`, or keep the renderer external |
|
|
391
|
+
| `Cannot find module '…/pdfkit/js/standard-fonts/Helvetica.cjs'` from a traced server output | add `pdfkitStandardFontFiles()` (or the directories' `**/*.cjs`) to the tracer's includes — `withNxgtPrint` and the Nuxt module do |
|
|
326
392
|
|
|
327
393
|
Every message, with its cause, is in [troubleshooting](https://cdn.jsdelivr.net/npm/@nxgt/material-core@0/docs/troubleshooting.md).
|
|
328
394
|
|
|
@@ -51,7 +51,7 @@ function definePdfDocument2(build) {
|
|
|
51
51
|
function dataTable2(columns, rows, options = {}) {
|
|
52
52
|
const { currency, totalLabel, ...layout } = options;
|
|
53
53
|
const table = resolvePrintTable2(columns, rows, { currency, totalLabel });
|
|
54
|
-
const labelTotals = totalLabel === undefined &&
|
|
54
|
+
const labelTotals = totalLabel === undefined && columns[0] !== undefined && !columns[0].total;
|
|
55
55
|
const footer = labelTotals ? table.footer.map(([, ...rest]) => [null, ...rest]) : table.footer;
|
|
56
56
|
return {
|
|
57
57
|
type: "table",
|
|
@@ -72,5 +72,5 @@ function keyValueOf2(fields, data, options = {}) {
|
|
|
72
72
|
|
|
73
73
|
export { text2, heading2, stack2, row2, section2, image2, link2, spacer2, divider2, pageBreak2, table2, keyValue2, totals2, metric2, badge2, header2, pageNumber2, page2, pdfDocument2, definePdfDocument2, dataTable2, keyValueOf2 };
|
|
74
74
|
|
|
75
|
-
//# debugId=
|
|
76
|
-
//# sourceMappingURL=index-
|
|
75
|
+
//# debugId=0A73B8345AA198A764756E2164756E21
|
|
76
|
+
//# sourceMappingURL=index-fp0822sa.js.map
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
"sources": ["../src/pdf/model/builders.ts", "../src/pdf/model/data-table.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * Plain functions that return model nodes, so a document reads as code\n * rather than as nested object literals. Each returns data only.\n */\nimport type {\n\tPdfDocument,\n\tPdfInline,\n\tPdfNode,\n\tPdfPage,\n\tPrintValue,\n} from './types';\n\ntype NodeOf<T extends PdfNode['type']> = Extract<PdfNode, { type: T }>;\ntype Options<T extends PdfNode['type'], K extends string = never> = Omit<\n\tNodeOf<T>,\n\t'type' | K\n>;\n\nexport const text = (\n\tcontent: string | PdfInline[],\n\toptions: Omit<Options<'text'>, 'content'> = {},\n): NodeOf<'text'> => ({ type: 'text', content, ...options });\n\nexport const heading = (text: string, level?: 1 | 2 | 3): NodeOf<'heading'> =>\n\tlevel ? { type: 'heading', text, level } : { type: 'heading', text };\n\nexport const stack = (\n\tchildren: PdfNode[],\n\toptions: Omit<Options<'stack'>, 'children'> = {},\n): NodeOf<'stack'> => ({ type: 'stack', children, ...options });\n\nexport const row = (\n\tchildren: PdfNode[],\n\toptions: Omit<Options<'row'>, 'children'> = {},\n): NodeOf<'row'> => ({ type: 'row', children, ...options });\n\nexport const section = (\n\ttitle: string,\n\tchildren: PdfNode[],\n): NodeOf<'section'> => ({ type: 'section', title, children });\n\nexport const image = (\n\tsrc: string,\n\toptions: Omit<Options<'image'>, 'src'> = {},\n): NodeOf<'image'> => ({ type: 'image', src, ...options });\n\nexport const link = (href: string, text: string): NodeOf<'link'> => ({\n\ttype: 'link',\n\thref,\n\ttext,\n});\n\nexport const spacer = (size: number): NodeOf<'spacer'> => ({\n\ttype: 'spacer',\n\tsize,\n});\n\nexport const divider = (): NodeOf<'divider'> => ({ type: 'divider' });\n\nexport const pageBreak = (): NodeOf<'pageBreak'> => ({ type: 'pageBreak' });\n\nexport const table = (options: Options<'table'>): NodeOf<'table'> => ({\n\ttype: 'table',\n\t...options,\n});\n\nexport const keyValue = (\n\titems: { label: string; value: PrintValue }[],\n\toptions: Omit<Options<'keyValue'>, 'items'> = {},\n): NodeOf<'keyValue'> => ({ type: 'keyValue', items, ...options });\n\nexport const totals = (rows: NodeOf<'totals'>['rows']): NodeOf<'totals'> => ({\n\ttype: 'totals',\n\trows,\n});\n\nexport const metric = (options: Options<'metric'>): NodeOf<'metric'> => ({\n\ttype: 'metric',\n\t...options,\n});\n\nexport const badge = (text: string, color?: string): NodeOf<'badge'> =>\n\tcolor ? { type: 'badge', text, color } : { type: 'badge', text };\n\nexport const header = (options: Options<'header'>): NodeOf<'header'> => ({\n\ttype: 'header',\n\t...options,\n});\n\nexport const pageNumber = (\n\toptions: Options<'pageNumber'> = {},\n): NodeOf<'pageNumber'> => ({ type: 'pageNumber', ...options });\n\nexport const page = (options: PdfPage): PdfPage => options;\n\n/** A whole document; `version` is stamped for you. */\nexport const pdfDocument = (\n\toptions: Omit<PdfDocument, 'version'>,\n): PdfDocument => ({ ...options, version: 1 });\n\n/**\n * What `definePdfDocument` accepts: a function from your data (and more\n * parameters, if you like) to a document without its `version`. A method\n * signature, so that its parameters are checked both ways: an annotated\n * `(inv: Invoice)` fits, while an unannotated first parameter is typed\n * `unknown` (use it only after narrowing) and a later one with a default\n * (`language = 'en'`) takes its type from the default.\n */\ntype PdfTemplate = {\n\tbuild(data: unknown, ...rest: never[]): Omit<PdfDocument, 'version'>;\n}['build'];\n\n/**\n * Types a template: a function from your data to a document. It returns the\n * function unchanged, stamping `version` on what it builds. Annotate the\n * data parameter; the others may have defaults (`language = 'en'`). Left\n * unannotated, the data is `unknown`, so reading a property of it fails to\n * compile in the template rather than where the template is called.\n *\n * @example\n * const invoicePdf = definePdfDocument((inv: Invoice, language = 'en') => ({\n * language,\n * pages: [page({ pageNumbers: true, body: [heading(inv.number)] })],\n * }));\n */\nexport function definePdfDocument<F extends PdfTemplate>(\n\tbuild: F,\n): (...args: Parameters<F>) => PdfDocument {\n\t// `F`'s own parameters are what the returned function takes.\n\tconst run = build as unknown as (\n\t\t...args: Parameters<F>\n\t) => Omit<PdfDocument, 'version'>;\n\treturn (...args) => ({ ...run(...args), version: 1 });\n}\n",
|
|
6
|
-
"import {\n\ttype PrintColumn,\n\ttype PrintTableOptions,\n\tresolvePrintFields,\n\tresolvePrintTable,\n} from '../../lib/print-table.utils';\nimport type { PdfNode } from './types';\n\ntype TableNode = Extract<PdfNode, { type: 'table' }>;\ntype KeyValueNode = Extract<PdfNode, { type: 'keyValue' }>;\n\nexport type DataTableOptions = PrintTableOptions &\n\tPick<\n\t\tTableNode,\n\t\t'striped' | 'repeatHeader' | 'keepRowsWhole' | 'emptyText' | 'hideWhenEmpty'\n\t>;\n\n/**\n * A `table` node from column definitions and plain rows — the model twin of\n * `PrintDataTable`. Without `totalLabel`, the totals row reads \"Total\" in the\n * document's language.\n *\n * @example\n * dataTable(definePrintColumns<Line>([\n * { key: 'item', label: 'Item', flex: 3 },\n * { key: 'amount', label: 'Amount', format: 'amount', total: 'sum' },\n * ]), invoice.lines, { currency: 'EUR' })\n */\nexport function dataTable<T>(\n\tcolumns: PrintColumn<T>[],\n\trows: T[],\n\toptions: DataTableOptions = {},\n): TableNode {\n\tconst { currency, totalLabel, ...layout } = options;\n\tconst table = resolvePrintTable(columns, rows, { currency, totalLabel });\n\tconst labelTotals =\n\t\ttotalLabel === undefined &&
|
|
6
|
+
"import {\n\ttype PrintColumn,\n\ttype PrintTableOptions,\n\tresolvePrintFields,\n\tresolvePrintTable,\n} from '../../lib/print-table.utils';\nimport type { PdfNode } from './types';\n\ntype TableNode = Extract<PdfNode, { type: 'table' }>;\ntype KeyValueNode = Extract<PdfNode, { type: 'keyValue' }>;\n\nexport type DataTableOptions = PrintTableOptions &\n\tPick<\n\t\tTableNode,\n\t\t'striped' | 'repeatHeader' | 'keepRowsWhole' | 'emptyText' | 'hideWhenEmpty'\n\t>;\n\n/**\n * A `table` node from column definitions and plain rows — the model twin of\n * `PrintDataTable`. Without `totalLabel`, the totals row reads \"Total\" in the\n * document's language.\n *\n * @example\n * dataTable(definePrintColumns<Line>([\n * { key: 'item', label: 'Item', flex: 3 },\n * { key: 'amount', label: 'Amount', format: 'amount', total: 'sum' },\n * ]), invoice.lines, { currency: 'EUR' })\n */\nexport function dataTable<T>(\n\tcolumns: PrintColumn<T>[],\n\trows: T[],\n\toptions: DataTableOptions = {},\n): TableNode {\n\tconst { currency, totalLabel, ...layout } = options;\n\tconst table = resolvePrintTable(columns, rows, { currency, totalLabel });\n\tconst labelTotals =\n\t\ttotalLabel === undefined && columns[0] !== undefined && !columns[0].total;\n\tconst footer = labelTotals\n\t\t? table.footer.map(([, ...rest]) => [null, ...rest])\n\t\t: table.footer;\n\treturn {\n\t\ttype: 'table',\n\t\tcolumns: table.columns,\n\t\trows: table.rows,\n\t\t...(footer.length > 0 && { footer, ...(labelTotals && { labelTotals }) }),\n\t\t...layout,\n\t};\n}\n\n/** A `keyValue` node from one row, read through column definitions. */\nexport function keyValueOf<T>(\n\tfields: PrintColumn<T>[],\n\tdata: T,\n\toptions: Pick<PrintTableOptions, 'currency'> &\n\t\tPick<KeyValueNode, 'columns' | 'keepEmpty'> = {},\n): KeyValueNode {\n\tconst { currency, ...layout } = options;\n\treturn {\n\t\ttype: 'keyValue',\n\t\titems: resolvePrintFields(fields, data, { currency }),\n\t\t...layout,\n\t};\n}\n"
|
|
7
7
|
],
|
|
8
|
-
"mappings": ";;;;;;AAkBO,IAAM,QAAO,CACnB,SACA,UAA4C,CAAC,OACxB,EAAE,MAAM,QAAQ,YAAY,QAAQ;AAEnD,IAAM,WAAU,CAAC,MAAc,UACrC,QAAQ,EAAE,MAAM,WAAW,MAAM,MAAM,IAAI,EAAE,MAAM,WAAW,KAAK;AAE7D,IAAM,SAAQ,CACpB,UACA,UAA8C,CAAC,OACzB,EAAE,MAAM,SAAS,aAAa,QAAQ;AAEtD,IAAM,OAAM,CAClB,UACA,UAA4C,CAAC,OACzB,EAAE,MAAM,OAAO,aAAa,QAAQ;AAElD,IAAM,WAAU,CACtB,OACA,cACwB,EAAE,MAAM,WAAW,OAAO,SAAS;AAErD,IAAM,SAAQ,CACpB,KACA,UAAyC,CAAC,OACpB,EAAE,MAAM,SAAS,QAAQ,QAAQ;AAEjD,IAAM,QAAO,CAAC,MAAc,UAAkC;AAAA,EACpE,MAAM;AAAA,EACN;AAAA,EACA;AACD;AAEO,IAAM,UAAS,CAAC,UAAoC;AAAA,EAC1D,MAAM;AAAA,EACN;AACD;AAEO,IAAM,WAAU,OAA0B,EAAE,MAAM,UAAU;AAE5D,IAAM,aAAY,OAA4B,EAAE,MAAM,YAAY;AAElE,IAAM,SAAQ,CAAC,aAAgD;AAAA,EACrE,MAAM;AAAA,KACH;AACJ;AAEO,IAAM,YAAW,CACvB,OACA,UAA8C,CAAC,OACtB,EAAE,MAAM,YAAY,UAAU,QAAQ;AAEzD,IAAM,UAAS,CAAC,UAAsD;AAAA,EAC5E,MAAM;AAAA,EACN;AACD;AAEO,IAAM,UAAS,CAAC,aAAkD;AAAA,EACxE,MAAM;AAAA,KACH;AACJ;AAEO,IAAM,SAAQ,CAAC,MAAc,UACnC,QAAQ,EAAE,MAAM,SAAS,MAAM,MAAM,IAAI,EAAE,MAAM,SAAS,KAAK;AAEzD,IAAM,UAAS,CAAC,aAAkD;AAAA,EACxE,MAAM;AAAA,KACH;AACJ;AAEO,IAAM,cAAa,CACzB,UAAiC,CAAC,OACP,EAAE,MAAM,iBAAiB,QAAQ;AAEtD,IAAM,QAAO,CAAC,YAA8B;AAG5C,IAAM,eAAc,CAC1B,aACkB,KAAK,SAAS,SAAS,EAAE;AA2BrC,SAAS,kBAAwC,CACvD,OAC0C;AAAA,EAE1C,MAAM,MAAM;AAAA,EAGZ,OAAO,IAAI,UAAU,KAAK,IAAI,GAAG,IAAI,GAAG,SAAS,EAAE;AAAA;;;ACxG7C,SAAS,UAAY,CAC3B,SACA,MACA,UAA4B,CAAC,GACjB;AAAA,EACZ,QAAQ,UAAU,eAAe,WAAW;AAAA,EAC5C,MAAM,QAAQ,mBAAkB,SAAS,MAAM,EAAE,UAAU,WAAW,CAAC;AAAA,EACvE,MAAM,cACL,eAAe,aAAa,QAAQ,
|
|
9
|
-
"debugId": "
|
|
8
|
+
"mappings": ";;;;;;AAkBO,IAAM,QAAO,CACnB,SACA,UAA4C,CAAC,OACxB,EAAE,MAAM,QAAQ,YAAY,QAAQ;AAEnD,IAAM,WAAU,CAAC,MAAc,UACrC,QAAQ,EAAE,MAAM,WAAW,MAAM,MAAM,IAAI,EAAE,MAAM,WAAW,KAAK;AAE7D,IAAM,SAAQ,CACpB,UACA,UAA8C,CAAC,OACzB,EAAE,MAAM,SAAS,aAAa,QAAQ;AAEtD,IAAM,OAAM,CAClB,UACA,UAA4C,CAAC,OACzB,EAAE,MAAM,OAAO,aAAa,QAAQ;AAElD,IAAM,WAAU,CACtB,OACA,cACwB,EAAE,MAAM,WAAW,OAAO,SAAS;AAErD,IAAM,SAAQ,CACpB,KACA,UAAyC,CAAC,OACpB,EAAE,MAAM,SAAS,QAAQ,QAAQ;AAEjD,IAAM,QAAO,CAAC,MAAc,UAAkC;AAAA,EACpE,MAAM;AAAA,EACN;AAAA,EACA;AACD;AAEO,IAAM,UAAS,CAAC,UAAoC;AAAA,EAC1D,MAAM;AAAA,EACN;AACD;AAEO,IAAM,WAAU,OAA0B,EAAE,MAAM,UAAU;AAE5D,IAAM,aAAY,OAA4B,EAAE,MAAM,YAAY;AAElE,IAAM,SAAQ,CAAC,aAAgD;AAAA,EACrE,MAAM;AAAA,KACH;AACJ;AAEO,IAAM,YAAW,CACvB,OACA,UAA8C,CAAC,OACtB,EAAE,MAAM,YAAY,UAAU,QAAQ;AAEzD,IAAM,UAAS,CAAC,UAAsD;AAAA,EAC5E,MAAM;AAAA,EACN;AACD;AAEO,IAAM,UAAS,CAAC,aAAkD;AAAA,EACxE,MAAM;AAAA,KACH;AACJ;AAEO,IAAM,SAAQ,CAAC,MAAc,UACnC,QAAQ,EAAE,MAAM,SAAS,MAAM,MAAM,IAAI,EAAE,MAAM,SAAS,KAAK;AAEzD,IAAM,UAAS,CAAC,aAAkD;AAAA,EACxE,MAAM;AAAA,KACH;AACJ;AAEO,IAAM,cAAa,CACzB,UAAiC,CAAC,OACP,EAAE,MAAM,iBAAiB,QAAQ;AAEtD,IAAM,QAAO,CAAC,YAA8B;AAG5C,IAAM,eAAc,CAC1B,aACkB,KAAK,SAAS,SAAS,EAAE;AA2BrC,SAAS,kBAAwC,CACvD,OAC0C;AAAA,EAE1C,MAAM,MAAM;AAAA,EAGZ,OAAO,IAAI,UAAU,KAAK,IAAI,GAAG,IAAI,GAAG,SAAS,EAAE;AAAA;;;ACxG7C,SAAS,UAAY,CAC3B,SACA,MACA,UAA4B,CAAC,GACjB;AAAA,EACZ,QAAQ,UAAU,eAAe,WAAW;AAAA,EAC5C,MAAM,QAAQ,mBAAkB,SAAS,MAAM,EAAE,UAAU,WAAW,CAAC;AAAA,EACvE,MAAM,cACL,eAAe,aAAa,QAAQ,OAAO,aAAa,CAAC,QAAQ,GAAG;AAAA,EACrE,MAAM,SAAS,cACZ,MAAM,OAAO,IAAI,OAAO,UAAU,CAAC,MAAM,GAAG,IAAI,CAAC,IACjD,MAAM;AAAA,EACT,OAAO;AAAA,IACN,MAAM;AAAA,IACN,SAAS,MAAM;AAAA,IACf,MAAM,MAAM;AAAA,OACR,OAAO,SAAS,KAAK,EAAE,WAAY,eAAe,EAAE,YAAY,EAAG;AAAA,OACpE;AAAA,EACJ;AAAA;AAIM,SAAS,WAAa,CAC5B,QACA,MACA,UAC+C,CAAC,GACjC;AAAA,EACf,QAAQ,aAAa,WAAW;AAAA,EAChC,OAAO;AAAA,IACN,MAAM;AAAA,IACN,OAAO,oBAAmB,QAAQ,MAAM,EAAE,SAAS,CAAC;AAAA,OACjD;AAAA,EACJ;AAAA;",
|
|
9
|
+
"debugId": "0A73B8345AA198A764756E2164756E21",
|
|
10
10
|
"names": []
|
|
11
11
|
}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/lib/print-format.utils.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * Amount and date formatting, written for printed documents and used\n * everywhere.\n *\n * This lives in `lib/` because it depends on nothing but `Intl`, so a screen\n * that formats an amount never imports the print entry and its optional\n * peers. The print entry re-exports it.\n *\n * Without a `locale`, the runtime's locale applies (as before); pass one, or\n * use `useFormatters()`, for output that is the same on a server and in the\n * browser.\n */\n\nimport { fractionDigitsOption } from './print-fraction-digits';\n\nconst EMPTY = '—';\nconst DATE_ONLY = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\nexport type FormatAmountOptions = {\n\t/** BCP 47 locale, such as `'fr-FR'`. Defaults to the runtime's locale. */\n\tlocale?: string;\n\t/**\n\t * Decimals to show, 0 to 20. With a currency it defaults to the\n\t * currency's own (ISO 4217: JPY 0, EUR 2, KWD 3); without one, to 2. Pass\n\t * `2` to keep two decimals whatever the currency. `NaN` or `Infinity`\n\t * counts as not given.\n\t */\n\tfractionDigits?: number;\n};\n\nexport type FormatDateOptions = {\n\t/** BCP 47 locale, such as `'fr-FR'`. Defaults to the runtime's locale. */\n\tlocale?: string;\n\t/**\n\t * IANA time zone for values with a time, such as `'Europe/Paris'`.\n\t * Defaults to the runtime's. A date-only value (`'2026-03-01'`) ignores it\n\t * and always shows its own calendar day.\n\t */\n\ttimeZone?: string;\n\t/** Defaults to `'medium'` (`Mar 1, 2026`). */\n\tdateStyle?: 'full' | 'long' | 'medium' | 'short';\n\t/** Adds the time; ignored for a date-only value. */\n\ttimeStyle?: 'full' | 'long' | 'medium' | 'short';\n};\n\nexport type DateInput = string | number | Date | null | undefined;\n\n/**\n * Formats an amount, in a currency when one is given. `null` and\n * `undefined` give `'—'`.\n *\n * @example formatAmount(1234.5, 'EUR', { locale: 'fr-FR' }) // '1 234,50 €'\n * @example formatAmount(1234.5, 'JPY', { locale: 'en-US' }) // '¥1,235'\n */\nexport function formatAmount(\n\tvalue: number | null | undefined,\n\tcurrency?: string | null,\n\toptions: FormatAmountOptions = {},\n): string {\n\tif (value == null) return EMPTY;\n\tconst { locale, fractionDigits } = options;\n\tconst digits =\n\t\tfractionDigitsOption(fractionDigits) ?? (currency ? undefined : 2);\n\ttry {\n\t\treturn new Intl.NumberFormat(locale, {\n\t\t\tstyle: currency ? 'currency' : 'decimal',\n\t\t\tcurrency: currency || undefined,\n\t\t\tminimumFractionDigits: digits,\n\t\t\tmaximumFractionDigits: digits,\n\t\t}).format(value);\n\t} catch {\n\t\treturn `${value.toFixed(digits ?? 2)}${currency ? ` ${currency}` : ''}`;\n\t}\n}\n\n/**\n * Formats a date. A date-only string (`YYYY-MM-DD`) keeps its calendar day\n * in every time zone; other values are shown in `timeZone`. Empty values\n * give `'—'`; a string that is not a date is returned as it is.\n *\n * @example formatDate('2026-03-01', { locale: 'en-US' }) // 'Mar 1, 2026'\n */\nexport function formatDate(\n\tvalue: DateInput,\n\toptions: FormatDateOptions = {},\n): string {\n\tif (value == null || value === '') return EMPTY;\n\tconst { locale, timeZone, dateStyle = 'medium', timeStyle } = options;\n\tconst dateOnly = typeof value === 'string' ? DATE_ONLY.exec(value) : null;\n\ttry {\n\t\tif (dateOnly) {\n\t\t\tconst [, year, month, day] = dateOnly;\n\t\t\tconst utc = new Date(0);\n\t\t\tutc.setUTCFullYear(+year, +month - 1, +day);\n\t\t\t// `2024-02-31` or `2024-13-01` rolls over: not a date.\n\t\t\tif (utc.getUTCMonth() !== +month - 1 || utc.getUTCDate() !== +day) {\n\t\t\t\treturn value as string;\n\t\t\t}\n\t\t\treturn new Intl.DateTimeFormat(locale, {\n\t\t\t\tdateStyle,\n\t\t\t\ttimeZone: 'UTC',\n\t\t\t}).format(utc);\n\t\t}\n\t\tconst date = value instanceof Date ? value : new Date(value);\n\t\tif (Number.isNaN(date.getTime())) {\n\t\t\treturn typeof value === 'string' ? value : EMPTY;\n\t\t}\n\t\treturn new Intl.DateTimeFormat(locale, {\n\t\t\tdateStyle,\n\t\t\ttimeStyle,\n\t\t\ttimeZone,\n\t\t}).format(date);\n\t} catch {\n\t\treturn typeof value === 'string' ? value : EMPTY;\n\t}\n}\n\nexport type FormattersOptions = {\n\tlocale?: string;\n\ttimeZone?: string;\n};\n\nexport type Formatters = {\n\tformatAmount: (\n\t\tvalue: number | null | undefined,\n\t\tcurrency?: string | null,\n\t\toptions?: FormatAmountOptions,\n\t) => string;\n\tformatDate: (value: DateInput, options?: FormatDateOptions) => string;\n};\n\n/**\n * `formatAmount` and `formatDate` bound to a locale and a time zone, for a\n * server route or a document builder. Options given per call win, unless\n * they are `undefined`.\n *\n * @example\n * const { formatAmount, formatDate } = createFormatters({ locale: 'fr-FR', timeZone: 'Europe/Paris' });\n */\nexport function createFormatters(defaults: FormattersOptions = {}): Formatters {\n\treturn {\n\t\tformatAmount: (value, currency, options) =>\n\t\t\tformatAmount(value, currency, {\n\t\t\t\t...options,\n\t\t\t\tlocale: options?.locale ?? defaults.locale,\n\t\t\t}),\n\t\tformatDate: (value, options) =>\n\t\t\tformatDate(value, {\n\t\t\t\t...options,\n\t\t\t\tlocale: options?.locale ?? defaults.locale,\n\t\t\t\ttimeZone: options?.timeZone ?? defaults.timeZone,\n\t\t\t}),\n\t};\n}\n"
|
|
5
|
+
"/**\n * Amount and date formatting, written for printed documents and used\n * everywhere.\n *\n * This lives in `lib/` because it depends on nothing but `Intl`, so a screen\n * that formats an amount never imports the print entry and its optional\n * peers. The print entry re-exports it.\n *\n * Without a `locale`, the runtime's locale applies (as before); pass one, or\n * use `useFormatters()`, for output that is the same on a server and in the\n * browser.\n */\n\nimport { fractionDigitsOption } from './print-fraction-digits';\n\nconst EMPTY = '—';\nconst DATE_ONLY = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\nexport type FormatAmountOptions = {\n\t/** BCP 47 locale, such as `'fr-FR'`. Defaults to the runtime's locale. */\n\tlocale?: string;\n\t/**\n\t * Decimals to show, 0 to 20. With a currency it defaults to the\n\t * currency's own (ISO 4217: JPY 0, EUR 2, KWD 3); without one, to 2. Pass\n\t * `2` to keep two decimals whatever the currency. `NaN` or `Infinity`\n\t * counts as not given.\n\t */\n\tfractionDigits?: number;\n};\n\nexport type FormatDateOptions = {\n\t/** BCP 47 locale, such as `'fr-FR'`. Defaults to the runtime's locale. */\n\tlocale?: string;\n\t/**\n\t * IANA time zone for values with a time, such as `'Europe/Paris'`.\n\t * Defaults to the runtime's. A date-only value (`'2026-03-01'`) ignores it\n\t * and always shows its own calendar day.\n\t */\n\ttimeZone?: string;\n\t/** Defaults to `'medium'` (`Mar 1, 2026`). */\n\tdateStyle?: 'full' | 'long' | 'medium' | 'short';\n\t/** Adds the time; ignored for a date-only value. */\n\ttimeStyle?: 'full' | 'long' | 'medium' | 'short';\n};\n\nexport type DateInput = string | number | Date | null | undefined;\n\n/**\n * Formats an amount, in a currency when one is given. `null` and\n * `undefined` give `'—'`.\n *\n * @example formatAmount(1234.5, 'EUR', { locale: 'fr-FR' }) // '1 234,50 €'\n * @example formatAmount(1234.5, 'JPY', { locale: 'en-US' }) // '¥1,235'\n */\nexport function formatAmount(\n\tvalue: number | null | undefined,\n\tcurrency?: string | null,\n\toptions: FormatAmountOptions = {},\n): string {\n\tif (value == null) return EMPTY;\n\tconst { locale, fractionDigits } = options;\n\tconst digits =\n\t\tfractionDigitsOption(fractionDigits) ?? (currency ? undefined : 2);\n\ttry {\n\t\treturn new Intl.NumberFormat(locale, {\n\t\t\tstyle: currency ? 'currency' : 'decimal',\n\t\t\tcurrency: currency || undefined,\n\t\t\tminimumFractionDigits: digits,\n\t\t\tmaximumFractionDigits: digits,\n\t\t}).format(value);\n\t} catch {\n\t\treturn `${value.toFixed(digits ?? 2)}${currency ? ` ${currency}` : ''}`;\n\t}\n}\n\n/**\n * Formats a date. A date-only string (`YYYY-MM-DD`) keeps its calendar day\n * in every time zone; other values are shown in `timeZone`. Empty values\n * give `'—'`; a string that is not a date is returned as it is.\n *\n * @example formatDate('2026-03-01', { locale: 'en-US' }) // 'Mar 1, 2026'\n */\nexport function formatDate(\n\tvalue: DateInput,\n\toptions: FormatDateOptions = {},\n): string {\n\tif (value == null || value === '') return EMPTY;\n\tconst { locale, timeZone, dateStyle = 'medium', timeStyle } = options;\n\tconst dateOnly = typeof value === 'string' ? DATE_ONLY.exec(value) : null;\n\ttry {\n\t\tif (dateOnly) {\n\t\t\t// DATE_ONLY's three groups are not optional: a match holds all three.\n\t\t\tconst [, year, month, day] = dateOnly as unknown as [\n\t\t\t\tstring,\n\t\t\t\tstring,\n\t\t\t\tstring,\n\t\t\t\tstring,\n\t\t\t];\n\t\t\tconst utc = new Date(0);\n\t\t\tutc.setUTCFullYear(+year, +month - 1, +day);\n\t\t\t// `2024-02-31` or `2024-13-01` rolls over: not a date.\n\t\t\tif (utc.getUTCMonth() !== +month - 1 || utc.getUTCDate() !== +day) {\n\t\t\t\treturn value as string;\n\t\t\t}\n\t\t\treturn new Intl.DateTimeFormat(locale, {\n\t\t\t\tdateStyle,\n\t\t\t\ttimeZone: 'UTC',\n\t\t\t}).format(utc);\n\t\t}\n\t\tconst date = value instanceof Date ? value : new Date(value);\n\t\tif (Number.isNaN(date.getTime())) {\n\t\t\treturn typeof value === 'string' ? value : EMPTY;\n\t\t}\n\t\treturn new Intl.DateTimeFormat(locale, {\n\t\t\tdateStyle,\n\t\t\ttimeStyle,\n\t\t\ttimeZone,\n\t\t}).format(date);\n\t} catch {\n\t\treturn typeof value === 'string' ? value : EMPTY;\n\t}\n}\n\nexport type FormattersOptions = {\n\tlocale?: string;\n\ttimeZone?: string;\n};\n\nexport type Formatters = {\n\tformatAmount: (\n\t\tvalue: number | null | undefined,\n\t\tcurrency?: string | null,\n\t\toptions?: FormatAmountOptions,\n\t) => string;\n\tformatDate: (value: DateInput, options?: FormatDateOptions) => string;\n};\n\n/**\n * `formatAmount` and `formatDate` bound to a locale and a time zone, for a\n * server route or a document builder. Options given per call win, unless\n * they are `undefined`.\n *\n * @example\n * const { formatAmount, formatDate } = createFormatters({ locale: 'fr-FR', timeZone: 'Europe/Paris' });\n */\nexport function createFormatters(defaults: FormattersOptions = {}): Formatters {\n\treturn {\n\t\tformatAmount: (value, currency, options) =>\n\t\t\tformatAmount(value, currency, {\n\t\t\t\t...options,\n\t\t\t\tlocale: options?.locale ?? defaults.locale,\n\t\t\t}),\n\t\tformatDate: (value, options) =>\n\t\t\tformatDate(value, {\n\t\t\t\t...options,\n\t\t\t\tlocale: options?.locale ?? defaults.locale,\n\t\t\t\ttimeZone: options?.timeZone ?? defaults.timeZone,\n\t\t\t}),\n\t};\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;AAeA,IAAM,QAAQ;AACd,IAAM,YAAY;AAsCX,SAAS,aAAY,CAC3B,OACA,UACA,UAA+B,CAAC,GACvB;AAAA,EACT,IAAI,SAAS;AAAA,IAAM,OAAO;AAAA,EAC1B,QAAQ,QAAQ,mBAAmB;AAAA,EACnC,MAAM,SACL,sBAAqB,cAAc,MAAM,WAAW,YAAY;AAAA,EACjE,IAAI;AAAA,IACH,OAAO,IAAI,KAAK,aAAa,QAAQ;AAAA,MACpC,OAAO,WAAW,aAAa;AAAA,MAC/B,UAAU,YAAY;AAAA,MACtB,uBAAuB;AAAA,MACvB,uBAAuB;AAAA,IACxB,CAAC,EAAE,OAAO,KAAK;AAAA,IACd,MAAM;AAAA,IACP,OAAO,GAAG,MAAM,QAAQ,UAAU,CAAC,IAAI,WAAW,IAAI,aAAa;AAAA;AAAA;AAW9D,SAAS,WAAU,CACzB,OACA,UAA6B,CAAC,GACrB;AAAA,EACT,IAAI,SAAS,QAAQ,UAAU;AAAA,IAAI,OAAO;AAAA,EAC1C,QAAQ,QAAQ,UAAU,YAAY,UAAU,cAAc;AAAA,EAC9D,MAAM,WAAW,OAAO,UAAU,WAAW,UAAU,KAAK,KAAK,IAAI;AAAA,EACrE,IAAI;AAAA,IACH,IAAI,UAAU;AAAA,
|
|
7
|
+
"mappings": ";;;;;AAeA,IAAM,QAAQ;AACd,IAAM,YAAY;AAsCX,SAAS,aAAY,CAC3B,OACA,UACA,UAA+B,CAAC,GACvB;AAAA,EACT,IAAI,SAAS;AAAA,IAAM,OAAO;AAAA,EAC1B,QAAQ,QAAQ,mBAAmB;AAAA,EACnC,MAAM,SACL,sBAAqB,cAAc,MAAM,WAAW,YAAY;AAAA,EACjE,IAAI;AAAA,IACH,OAAO,IAAI,KAAK,aAAa,QAAQ;AAAA,MACpC,OAAO,WAAW,aAAa;AAAA,MAC/B,UAAU,YAAY;AAAA,MACtB,uBAAuB;AAAA,MACvB,uBAAuB;AAAA,IACxB,CAAC,EAAE,OAAO,KAAK;AAAA,IACd,MAAM;AAAA,IACP,OAAO,GAAG,MAAM,QAAQ,UAAU,CAAC,IAAI,WAAW,IAAI,aAAa;AAAA;AAAA;AAW9D,SAAS,WAAU,CACzB,OACA,UAA6B,CAAC,GACrB;AAAA,EACT,IAAI,SAAS,QAAQ,UAAU;AAAA,IAAI,OAAO;AAAA,EAC1C,QAAQ,QAAQ,UAAU,YAAY,UAAU,cAAc;AAAA,EAC9D,MAAM,WAAW,OAAO,UAAU,WAAW,UAAU,KAAK,KAAK,IAAI;AAAA,EACrE,IAAI;AAAA,IACH,IAAI,UAAU;AAAA,MAEb,SAAS,MAAM,OAAO,OAAO;AAAA,MAM7B,MAAM,MAAM,IAAI,KAAK,CAAC;AAAA,MACtB,IAAI,eAAe,CAAC,MAAM,CAAC,QAAQ,GAAG,CAAC,GAAG;AAAA,MAE1C,IAAI,IAAI,YAAY,MAAM,CAAC,QAAQ,KAAK,IAAI,WAAW,MAAM,CAAC,KAAK;AAAA,QAClE,OAAO;AAAA,MACR;AAAA,MACA,OAAO,IAAI,KAAK,eAAe,QAAQ;AAAA,QACtC;AAAA,QACA,UAAU;AAAA,MACX,CAAC,EAAE,OAAO,GAAG;AAAA,IACd;AAAA,IACA,MAAM,OAAO,iBAAiB,OAAO,QAAQ,IAAI,KAAK,KAAK;AAAA,IAC3D,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,GAAG;AAAA,MACjC,OAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,IAC5C;AAAA,IACA,OAAO,IAAI,KAAK,eAAe,QAAQ;AAAA,MACtC;AAAA,MACA;AAAA,MACA;AAAA,IACD,CAAC,EAAE,OAAO,IAAI;AAAA,IACb,MAAM;AAAA,IACP,OAAO,OAAO,UAAU,WAAW,QAAQ;AAAA;AAAA;AA0BtC,SAAS,iBAAgB,CAAC,WAA8B,CAAC,GAAe;AAAA,EAC9E,OAAO;AAAA,IACN,cAAc,CAAC,OAAO,UAAU,YAC/B,cAAa,OAAO,UAAU;AAAA,SAC1B;AAAA,MACH,QAAQ,SAAS,UAAU,SAAS;AAAA,IACrC,CAAC;AAAA,IACF,YAAY,CAAC,OAAO,YACnB,YAAW,OAAO;AAAA,SACd;AAAA,MACH,QAAQ,SAAS,UAAU,SAAS;AAAA,MACpC,UAAU,SAAS,YAAY,SAAS;AAAA,IACzC,CAAC;AAAA,EACH;AAAA;",
|
|
8
8
|
"debugId": "DD36C19E6625613264756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A byte count as people read it: `'512 B'`, `'1.5 KB'`, `'2.0 MB'`,
|
|
3
|
+
* `'1.0 GB'` (1024-based, one decimal above bytes, capped at GB), and `''`
|
|
4
|
+
* for a negative, `NaN` or infinite size. Locale-free, so a server and a
|
|
5
|
+
* browser print the same thing. The file list, the upload field and its
|
|
6
|
+
* constraints, the file card and the chat attachment chip of both libraries
|
|
7
|
+
* use it.
|
|
8
|
+
*/
|
|
9
|
+
export declare function formatFileSize(bytes: number): string;
|
|
10
|
+
//# sourceMappingURL=format-file-size.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-file-size.d.ts","sourceRoot":"","sources":["../../src/lib/format-file-size.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUpD"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// src/lib/format-file-size.ts
|
|
2
|
+
function formatFileSize(bytes) {
|
|
3
|
+
if (bytes < 0 || !Number.isFinite(bytes))
|
|
4
|
+
return "";
|
|
5
|
+
if (bytes === 0)
|
|
6
|
+
return "0 B";
|
|
7
|
+
const units = ["B", "KB", "MB", "GB"];
|
|
8
|
+
const exponent = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
|
|
9
|
+
const value = bytes / 1024 ** exponent;
|
|
10
|
+
return `${exponent === 0 ? value : value.toFixed(1)} ${units[exponent]}`;
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
formatFileSize
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
//# debugId=5CC787DB991D0F4A64756E2164756E21
|
|
17
|
+
//# sourceMappingURL=format-file-size.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/lib/format-file-size.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * A byte count as people read it: `'512 B'`, `'1.5 KB'`, `'2.0 MB'`,\n * `'1.0 GB'` (1024-based, one decimal above bytes, capped at GB), and `''`\n * for a negative, `NaN` or infinite size. Locale-free, so a server and a\n * browser print the same thing. The file list, the upload field and its\n * constraints, the file card and the chat attachment chip of both libraries\n * use it.\n */\nexport function formatFileSize(bytes: number): string {\n\tif (bytes < 0 || !Number.isFinite(bytes)) return '';\n\tif (bytes === 0) return '0 B';\n\tconst units = ['B', 'KB', 'MB', 'GB'];\n\tconst exponent = Math.min(\n\t\tMath.floor(Math.log(bytes) / Math.log(1024)),\n\t\tunits.length - 1,\n\t);\n\tconst value = bytes / 1024 ** exponent;\n\treturn `${exponent === 0 ? value : value.toFixed(1)} ${units[exponent]}`;\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";AAQO,SAAS,cAAc,CAAC,OAAuB;AAAA,EACrD,IAAI,QAAQ,KAAK,CAAC,OAAO,SAAS,KAAK;AAAA,IAAG,OAAO;AAAA,EACjD,IAAI,UAAU;AAAA,IAAG,OAAO;AAAA,EACxB,MAAM,QAAQ,CAAC,KAAK,MAAM,MAAM,IAAI;AAAA,EACpC,MAAM,WAAW,KAAK,IACrB,KAAK,MAAM,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,IAAI,CAAC,GAC3C,MAAM,SAAS,CAChB;AAAA,EACA,MAAM,QAAQ,QAAQ,QAAQ;AAAA,EAC9B,OAAO,GAAG,aAAa,IAAI,QAAQ,MAAM,QAAQ,CAAC,KAAK,MAAM;AAAA;",
|
|
8
|
+
"debugId": "5CC787DB991D0F4A64756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"print-format.utils.d.ts","sourceRoot":"","sources":["../../src/lib/print-format.utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,MAAM,MAAM,mBAAmB,GAAG;IACjC,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC/B,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACjD,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;AAElE;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC3B,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,EACxB,OAAO,GAAE,mBAAwB,GAC/B,MAAM,CAeR;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACzB,KAAK,EAAE,SAAS,EAChB,OAAO,GAAE,iBAAsB,GAC7B,MAAM,
|
|
1
|
+
{"version":3,"file":"print-format.utils.d.ts","sourceRoot":"","sources":["../../src/lib/print-format.utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,MAAM,MAAM,mBAAmB,GAAG;IACjC,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC/B,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACjD,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;AAElE;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC3B,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,EACxB,OAAO,GAAE,mBAAwB,GAC/B,MAAM,CAeR;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACzB,KAAK,EAAE,SAAS,EAChB,OAAO,GAAE,iBAAsB,GAC7B,MAAM,CAoCR;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACxB,YAAY,EAAE,CACb,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,EACxB,OAAO,CAAC,EAAE,mBAAmB,KACzB,MAAM,CAAC;IACZ,UAAU,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,iBAAiB,KAAK,MAAM,CAAC;CACtE,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,GAAE,iBAAsB,GAAG,UAAU,CAc7E"}
|
package/dist/pdf/index.js
CHANGED
package/dist/pdf/model/index.js
CHANGED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where an app's pdfkit keeps its fourteen standard fonts, resolved the way
|
|
3
|
+
* that app loads them. Build-time code for a framework's config: the Next.js
|
|
4
|
+
* helper of `@nxgt/material` (`@nxgt/material/next`, which turns the
|
|
5
|
+
* directories into `outputFileTracingIncludes` globs) and the Nuxt module of
|
|
6
|
+
* `@nxgt/material-vue` (which adds the files to Nitro's `traceInclude`).
|
|
7
|
+
*
|
|
8
|
+
* **Node only.** This is the one subpath of `@nxgt/material-core` that
|
|
9
|
+
* imports `node:*` built-ins (`node:module`, `node:path`); `verify:ssr` fails
|
|
10
|
+
* the build if any other reaches one. Never import it from code that can end
|
|
11
|
+
* up in a browser bundle.
|
|
12
|
+
*
|
|
13
|
+
* Why it exists: pdfkit registers its fonts with a runtime
|
|
14
|
+
* `require('#standard-fonts/<Name>')`, a package-`imports` specifier private
|
|
15
|
+
* to pdfkit. A server tracer (Next.js's, Nitro's) does not follow a runtime
|
|
16
|
+
* `require`, so a traced server output has pdfkit but not its `.cjs` fonts,
|
|
17
|
+
* and every PDF rendered there fails with
|
|
18
|
+
* `Cannot find module '…/pdfkit/js/standard-fonts/Helvetica.cjs'`.
|
|
19
|
+
*
|
|
20
|
+
* pdfkit is found through `@react-pdf/renderer` and through
|
|
21
|
+
* `@react-pdf/font` (resolved from the renderer), since each can nest a
|
|
22
|
+
* pdfkit of its own. Resolving `pdfkit/standard-fonts/<Name>` from them
|
|
23
|
+
* under the `require` condition lands on the `.cjs` file pdfkit's runtime
|
|
24
|
+
* `require` reads, as a real path, under npm, pnpm and bun alike.
|
|
25
|
+
*
|
|
26
|
+
* ```ts
|
|
27
|
+
* import { pdfkitStandardFontDirs } from '@nxgt/material-core/pdfkit-fonts';
|
|
28
|
+
*
|
|
29
|
+
* pdfkitStandardFontDirs(process.cwd(), (message) => console.warn(message));
|
|
30
|
+
* // ['/app/node_modules/pdfkit/js/standard-fonts']
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
/** The fourteen standard PDF fonts, as pdfkit exports them. */
|
|
34
|
+
export declare const PDFKIT_STANDARD_FONTS: readonly ["Courier", "CourierBold", "CourierBoldOblique", "CourierOblique", "Helvetica", "HelveticaBold", "HelveticaBoldOblique", "HelveticaOblique", "Symbol", "TimesBold", "TimesBoldItalic", "TimesItalic", "TimesRoman", "ZapfDingbats"];
|
|
35
|
+
export type PdfkitStandardFont = (typeof PDFKIT_STANDARD_FONTS)[number];
|
|
36
|
+
/** Receives the one warning a call can give. */
|
|
37
|
+
export type PdfkitFontsWarn = (message: string) => void;
|
|
38
|
+
/**
|
|
39
|
+
* pdfkit's `js/standard-fonts` directories, real paths, as the app at
|
|
40
|
+
* `projectDir` loads them: the one of the pdfkit `@react-pdf/renderer`
|
|
41
|
+
* depends on and the one of `@react-pdf/font`'s, without duplicates (one
|
|
42
|
+
* directory when both share a pdfkit, as they usually do). Each directory
|
|
43
|
+
* also holds the `chunks/` the fonts `require`.
|
|
44
|
+
*
|
|
45
|
+
* `[]`, silently, when `@react-pdf/renderer` is not installed. Anything else
|
|
46
|
+
* that fails is passed to `warn`, once per call: a font that cannot be traced
|
|
47
|
+
* is a PDF route that fails in production.
|
|
48
|
+
*/
|
|
49
|
+
export declare function pdfkitStandardFontDirs(projectDir: string, warn?: PdfkitFontsWarn): string[];
|
|
50
|
+
/**
|
|
51
|
+
* pdfkit's fourteen standard-font modules (`.cjs`, real paths), as the app
|
|
52
|
+
* at `projectDir` loads them: through pdfkit's own `standard-fonts/<Name>`
|
|
53
|
+
* exports under the `require` condition, for the pdfkit
|
|
54
|
+
* `@react-pdf/renderer` depends on and the one `@react-pdf/font` depends on,
|
|
55
|
+
* without duplicates.
|
|
56
|
+
*
|
|
57
|
+
* `[]`, silently, when `@react-pdf/renderer` is not installed. Anything else
|
|
58
|
+
* that fails is passed to `warn`, once per call.
|
|
59
|
+
*/
|
|
60
|
+
export declare function pdfkitStandardFontFiles(projectDir: string, warn?: PdfkitFontsWarn): string[];
|
|
61
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pdfkit-fonts/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAKH,+DAA+D;AAC/D,eAAO,MAAM,qBAAqB,8OAexB,CAAC;AAEX,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE,gDAAgD;AAChD,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAyDxD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CACrC,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,eAA0B,GAC9B,MAAM,EAAE,CAYV;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACtC,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,eAA0B,GAC9B,MAAM,EAAE,CAcV"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// src/pdfkit-fonts/index.ts
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
var PDFKIT_STANDARD_FONTS = [
|
|
5
|
+
"Courier",
|
|
6
|
+
"CourierBold",
|
|
7
|
+
"CourierBoldOblique",
|
|
8
|
+
"CourierOblique",
|
|
9
|
+
"Helvetica",
|
|
10
|
+
"HelveticaBold",
|
|
11
|
+
"HelveticaBoldOblique",
|
|
12
|
+
"HelveticaOblique",
|
|
13
|
+
"Symbol",
|
|
14
|
+
"TimesBold",
|
|
15
|
+
"TimesBoldItalic",
|
|
16
|
+
"TimesItalic",
|
|
17
|
+
"TimesRoman",
|
|
18
|
+
"ZapfDingbats"
|
|
19
|
+
];
|
|
20
|
+
var isNotFound = (error) => error?.code === "MODULE_NOT_FOUND";
|
|
21
|
+
var firstLine = (error) => String(error).split(`
|
|
22
|
+
`, 1)[0] ?? "";
|
|
23
|
+
function fromEachPdfkit(projectDir, warn, collect) {
|
|
24
|
+
const problems = [];
|
|
25
|
+
let renderer;
|
|
26
|
+
try {
|
|
27
|
+
renderer = createRequire(join(resolve(projectDir), "package.json")).resolve("@react-pdf/renderer");
|
|
28
|
+
} catch (error) {
|
|
29
|
+
if (!isNotFound(error)) {
|
|
30
|
+
warn(`could not resolve @react-pdf/renderer: ${firstLine(error)}`);
|
|
31
|
+
}
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const fromRenderer = createRequire(renderer);
|
|
35
|
+
const owners = [["@react-pdf/renderer", fromRenderer]];
|
|
36
|
+
try {
|
|
37
|
+
owners.push([
|
|
38
|
+
"@react-pdf/font",
|
|
39
|
+
createRequire(fromRenderer.resolve("@react-pdf/font"))
|
|
40
|
+
]);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
problems.push(`could not resolve @react-pdf/font: ${firstLine(error)}`);
|
|
43
|
+
}
|
|
44
|
+
for (const [owner, from] of owners)
|
|
45
|
+
collect(owner, from, problems);
|
|
46
|
+
if (problems.length > 0)
|
|
47
|
+
warn(problems.join("; "));
|
|
48
|
+
}
|
|
49
|
+
function pdfkitStandardFontDirs(projectDir, warn = () => {}) {
|
|
50
|
+
const dirs = new Set;
|
|
51
|
+
fromEachPdfkit(projectDir, warn, (owner, from, problems) => {
|
|
52
|
+
try {
|
|
53
|
+
dirs.add(dirname(from.resolve("pdfkit/standard-fonts/Helvetica")));
|
|
54
|
+
} catch (error) {
|
|
55
|
+
problems.push(`could not resolve pdfkit's fonts for ${owner}: ${firstLine(error)}`);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
return [...dirs];
|
|
59
|
+
}
|
|
60
|
+
function pdfkitStandardFontFiles(projectDir, warn = () => {}) {
|
|
61
|
+
const files = new Set;
|
|
62
|
+
fromEachPdfkit(projectDir, warn, (owner, from, problems) => {
|
|
63
|
+
for (const font of PDFKIT_STANDARD_FONTS) {
|
|
64
|
+
try {
|
|
65
|
+
files.add(from.resolve(`pdfkit/standard-fonts/${font}`));
|
|
66
|
+
} catch (error) {
|
|
67
|
+
problems.push(`could not resolve pdfkit's ${font} font for ${owner}: ${firstLine(error)}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
return [...files];
|
|
72
|
+
}
|
|
73
|
+
export {
|
|
74
|
+
PDFKIT_STANDARD_FONTS,
|
|
75
|
+
pdfkitStandardFontDirs,
|
|
76
|
+
pdfkitStandardFontFiles
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
//# debugId=D12CCCD8FE08400864756E2164756E21
|
|
80
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/pdfkit-fonts/index.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * Where an app's pdfkit keeps its fourteen standard fonts, resolved the way\n * that app loads them. Build-time code for a framework's config: the Next.js\n * helper of `@nxgt/material` (`@nxgt/material/next`, which turns the\n * directories into `outputFileTracingIncludes` globs) and the Nuxt module of\n * `@nxgt/material-vue` (which adds the files to Nitro's `traceInclude`).\n *\n * **Node only.** This is the one subpath of `@nxgt/material-core` that\n * imports `node:*` built-ins (`node:module`, `node:path`); `verify:ssr` fails\n * the build if any other reaches one. Never import it from code that can end\n * up in a browser bundle.\n *\n * Why it exists: pdfkit registers its fonts with a runtime\n * `require('#standard-fonts/<Name>')`, a package-`imports` specifier private\n * to pdfkit. A server tracer (Next.js's, Nitro's) does not follow a runtime\n * `require`, so a traced server output has pdfkit but not its `.cjs` fonts,\n * and every PDF rendered there fails with\n * `Cannot find module '…/pdfkit/js/standard-fonts/Helvetica.cjs'`.\n *\n * pdfkit is found through `@react-pdf/renderer` and through\n * `@react-pdf/font` (resolved from the renderer), since each can nest a\n * pdfkit of its own. Resolving `pdfkit/standard-fonts/<Name>` from them\n * under the `require` condition lands on the `.cjs` file pdfkit's runtime\n * `require` reads, as a real path, under npm, pnpm and bun alike.\n *\n * ```ts\n * import { pdfkitStandardFontDirs } from '@nxgt/material-core/pdfkit-fonts';\n *\n * pdfkitStandardFontDirs(process.cwd(), (message) => console.warn(message));\n * // ['/app/node_modules/pdfkit/js/standard-fonts']\n * ```\n */\n\nimport { createRequire } from 'node:module';\nimport { dirname, join, resolve } from 'node:path';\n\n/** The fourteen standard PDF fonts, as pdfkit exports them. */\nexport const PDFKIT_STANDARD_FONTS = [\n\t'Courier',\n\t'CourierBold',\n\t'CourierBoldOblique',\n\t'CourierOblique',\n\t'Helvetica',\n\t'HelveticaBold',\n\t'HelveticaBoldOblique',\n\t'HelveticaOblique',\n\t'Symbol',\n\t'TimesBold',\n\t'TimesBoldItalic',\n\t'TimesItalic',\n\t'TimesRoman',\n\t'ZapfDingbats',\n] as const;\n\nexport type PdfkitStandardFont = (typeof PDFKIT_STANDARD_FONTS)[number];\n\n/** Receives the one warning a call can give. */\nexport type PdfkitFontsWarn = (message: string) => void;\n\ntype Require = ReturnType<typeof createRequire>;\n\nconst isNotFound = (error: unknown) =>\n\t(error as { code?: string } | null)?.code === 'MODULE_NOT_FOUND';\n\n/**\n * An error as one line: its text up to the first newline. Node's\n * `Cannot find module` error appends a multi-line `Require stack:`, and the\n * warning joins every problem into ONE line: kept whole, a single failure\n * buried the others under a dozen stack paths.\n */\nconst firstLine = (error: unknown): string =>\n\tString(error).split('\\n', 1)[0] ?? '';\n\n/**\n * Runs `collect` with the `require` of each package that depends on pdfkit\n * (`@react-pdf/renderer`, then `@react-pdf/font`), and hands every problem\n * met on the way to `warn` as ONE message, joined by `; `, each error cut\n * to its first line (`firstLine`). None, silently,\n * when the app does not install `@react-pdf/renderer`: it is an optional\n * peer, and an app that does not print has no fonts to find.\n */\nfunction fromEachPdfkit(\n\tprojectDir: string,\n\twarn: PdfkitFontsWarn,\n\tcollect: (owner: string, from: Require, problems: string[]) => void,\n): void {\n\tconst problems: string[] = [];\n\tlet renderer: string;\n\ttry {\n\t\t// createRequire takes an absolute path only: a relative `projectDir`\n\t\t// is taken from the working directory.\n\t\trenderer = createRequire(join(resolve(projectDir), 'package.json')).resolve(\n\t\t\t'@react-pdf/renderer',\n\t\t);\n\t} catch (error) {\n\t\tif (!isNotFound(error)) {\n\t\t\twarn(`could not resolve @react-pdf/renderer: ${firstLine(error)}`);\n\t\t}\n\t\treturn;\n\t}\n\tconst fromRenderer = createRequire(renderer);\n\tconst owners: [string, Require][] = [['@react-pdf/renderer', fromRenderer]];\n\ttry {\n\t\towners.push([\n\t\t\t'@react-pdf/font',\n\t\t\tcreateRequire(fromRenderer.resolve('@react-pdf/font')),\n\t\t]);\n\t} catch (error) {\n\t\tproblems.push(`could not resolve @react-pdf/font: ${firstLine(error)}`);\n\t}\n\tfor (const [owner, from] of owners) collect(owner, from, problems);\n\tif (problems.length > 0) warn(problems.join('; '));\n}\n\n/**\n * pdfkit's `js/standard-fonts` directories, real paths, as the app at\n * `projectDir` loads them: the one of the pdfkit `@react-pdf/renderer`\n * depends on and the one of `@react-pdf/font`'s, without duplicates (one\n * directory when both share a pdfkit, as they usually do). Each directory\n * also holds the `chunks/` the fonts `require`.\n *\n * `[]`, silently, when `@react-pdf/renderer` is not installed. Anything else\n * that fails is passed to `warn`, once per call: a font that cannot be traced\n * is a PDF route that fails in production.\n */\nexport function pdfkitStandardFontDirs(\n\tprojectDir: string,\n\twarn: PdfkitFontsWarn = () => {},\n): string[] {\n\tconst dirs = new Set<string>();\n\tfromEachPdfkit(projectDir, warn, (owner, from, problems) => {\n\t\ttry {\n\t\t\tdirs.add(dirname(from.resolve('pdfkit/standard-fonts/Helvetica')));\n\t\t} catch (error) {\n\t\t\tproblems.push(\n\t\t\t\t`could not resolve pdfkit's fonts for ${owner}: ${firstLine(error)}`,\n\t\t\t);\n\t\t}\n\t});\n\treturn [...dirs];\n}\n\n/**\n * pdfkit's fourteen standard-font modules (`.cjs`, real paths), as the app\n * at `projectDir` loads them: through pdfkit's own `standard-fonts/<Name>`\n * exports under the `require` condition, for the pdfkit\n * `@react-pdf/renderer` depends on and the one `@react-pdf/font` depends on,\n * without duplicates.\n *\n * `[]`, silently, when `@react-pdf/renderer` is not installed. Anything else\n * that fails is passed to `warn`, once per call.\n */\nexport function pdfkitStandardFontFiles(\n\tprojectDir: string,\n\twarn: PdfkitFontsWarn = () => {},\n): string[] {\n\tconst files = new Set<string>();\n\tfromEachPdfkit(projectDir, warn, (owner, from, problems) => {\n\t\tfor (const font of PDFKIT_STANDARD_FONTS) {\n\t\t\ttry {\n\t\t\t\tfiles.add(from.resolve(`pdfkit/standard-fonts/${font}`));\n\t\t\t} catch (error) {\n\t\t\t\tproblems.push(\n\t\t\t\t\t`could not resolve pdfkit's ${font} font for ${owner}: ${firstLine(error)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t});\n\treturn [...files];\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";AAiCA;AACA;AAGO,IAAM,wBAAwB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AASA,IAAM,aAAa,CAAC,UAClB,OAAoC,SAAS;AAQ/C,IAAM,YAAY,CAAC,UAClB,OAAO,KAAK,EAAE,MAAM;AAAA,GAAM,CAAC,EAAE,MAAM;AAUpC,SAAS,cAAc,CACtB,YACA,MACA,SACO;AAAA,EACP,MAAM,WAAqB,CAAC;AAAA,EAC5B,IAAI;AAAA,EACJ,IAAI;AAAA,IAGH,WAAW,cAAc,KAAK,QAAQ,UAAU,GAAG,cAAc,CAAC,EAAE,QACnE,qBACD;AAAA,IACC,OAAO,OAAO;AAAA,IACf,IAAI,CAAC,WAAW,KAAK,GAAG;AAAA,MACvB,KAAK,0CAA0C,UAAU,KAAK,GAAG;AAAA,IAClE;AAAA,IACA;AAAA;AAAA,EAED,MAAM,eAAe,cAAc,QAAQ;AAAA,EAC3C,MAAM,SAA8B,CAAC,CAAC,uBAAuB,YAAY,CAAC;AAAA,EAC1E,IAAI;AAAA,IACH,OAAO,KAAK;AAAA,MACX;AAAA,MACA,cAAc,aAAa,QAAQ,iBAAiB,CAAC;AAAA,IACtD,CAAC;AAAA,IACA,OAAO,OAAO;AAAA,IACf,SAAS,KAAK,sCAAsC,UAAU,KAAK,GAAG;AAAA;AAAA,EAEvE,YAAY,OAAO,SAAS;AAAA,IAAQ,QAAQ,OAAO,MAAM,QAAQ;AAAA,EACjE,IAAI,SAAS,SAAS;AAAA,IAAG,KAAK,SAAS,KAAK,IAAI,CAAC;AAAA;AAc3C,SAAS,sBAAsB,CACrC,YACA,OAAwB,MAAM,IACnB;AAAA,EACX,MAAM,OAAO,IAAI;AAAA,EACjB,eAAe,YAAY,MAAM,CAAC,OAAO,MAAM,aAAa;AAAA,IAC3D,IAAI;AAAA,MACH,KAAK,IAAI,QAAQ,KAAK,QAAQ,iCAAiC,CAAC,CAAC;AAAA,MAChE,OAAO,OAAO;AAAA,MACf,SAAS,KACR,wCAAwC,UAAU,UAAU,KAAK,GAClE;AAAA;AAAA,GAED;AAAA,EACD,OAAO,CAAC,GAAG,IAAI;AAAA;AAaT,SAAS,uBAAuB,CACtC,YACA,OAAwB,MAAM,IACnB;AAAA,EACX,MAAM,QAAQ,IAAI;AAAA,EAClB,eAAe,YAAY,MAAM,CAAC,OAAO,MAAM,aAAa;AAAA,IAC3D,WAAW,QAAQ,uBAAuB;AAAA,MACzC,IAAI;AAAA,QACH,MAAM,IAAI,KAAK,QAAQ,yBAAyB,MAAM,CAAC;AAAA,QACtD,OAAO,OAAO;AAAA,QACf,SAAS,KACR,8BAA8B,iBAAiB,UAAU,UAAU,KAAK,GACzE;AAAA;AAAA,IAEF;AAAA,GACA;AAAA,EACD,OAAO,CAAC,GAAG,KAAK;AAAA;",
|
|
8
|
+
"debugId": "D12CCCD8FE08400864756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
package/docs/roadmap.md
CHANGED
|
@@ -5,12 +5,7 @@ version an item shipped in is the only number on this page.
|
|
|
5
5
|
|
|
6
6
|
## Now
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
shared file by file — the PDF model and renderer, the print formatters, the
|
|
10
|
-
PDF file helpers, the PDF reader's framework-free modules (`/pdf-viewer`:
|
|
11
|
-
search, geometry, page sizes, scroll spy), the currency digits, the fields'
|
|
12
|
-
blur layers and the fonts plugin — is this one package, and both libraries
|
|
13
|
-
depend on it.
|
|
8
|
+
Nothing in progress right now; see Next.
|
|
14
9
|
|
|
15
10
|
## Next
|
|
16
11
|
|
|
@@ -33,3 +28,17 @@ version an item shipped in is the only number on this page.
|
|
|
33
28
|
- **Test helpers.** Reading a rendered PDF back and the fake DOM the
|
|
34
29
|
libraries' tests use are the repository's own, in a private package that is
|
|
35
30
|
never published.
|
|
31
|
+
|
|
32
|
+
## Shipped
|
|
33
|
+
|
|
34
|
+
- **A first release** — the PDF model and renderer, the print formatters,
|
|
35
|
+
the PDF file helpers, the PDF reader's framework-free modules
|
|
36
|
+
(`/pdf-viewer`: search, geometry, page sizes, scroll spy), the currency
|
|
37
|
+
digits, the fields' blur layers and the fonts plugin, which
|
|
38
|
+
`@nxgt/material` and `@nxgt/material-vue` shared file by file, are this one
|
|
39
|
+
package, and both libraries depend on it. 0.1.0.
|
|
40
|
+
- **`formatFileSize` and the pdfkit fonts resolution** — the byte-count
|
|
41
|
+
formatter both libraries' file list and upload field use
|
|
42
|
+
(`/format-file-size`), and the Node-only resolution of pdfkit's standard
|
|
43
|
+
fonts behind `@nxgt/material/next` and `@nxgt/material-vue`'s Nuxt module
|
|
44
|
+
(`/pdfkit-fonts`), each kept once instead of in both libraries. 0.2.0.
|
package/docs/troubleshooting.md
CHANGED
|
@@ -21,6 +21,9 @@ file) is an example — search for the words around it.
|
|
|
21
21
|
|
|
22
22
|
- [`… still references '#standard-fonts/' after the transform — …`](#-still-references-standard-fonts-after-the-transform--)
|
|
23
23
|
- [`Cannot find module '#standard-fonts/Helvetica' from '…'`](#cannot-find-module-standard-fontshelvetica-from-)
|
|
24
|
+
- [`Cannot find module '…/pdfkit/js/standard-fonts/Helvetica.cjs'`](#cannot-find-module-pdfkitjsstandard-fontshelveticacjs)
|
|
25
|
+
- [`could not resolve …` (`@react-pdf/renderer`, `@react-pdf/font`, pdfkit's fonts)](#could-not-resolve-)
|
|
26
|
+
- [`Module "node:module" has been externalized for browser compatibility`](#module-nodemodule-has-been-externalized-for-browser-compatibility)
|
|
24
27
|
|
|
25
28
|
## Install
|
|
26
29
|
|
|
@@ -103,3 +106,65 @@ rather than the server at its first request. Pin the previous
|
|
|
103
106
|
A server bundle that contains pdfkit, run without `node_modules`. Add
|
|
104
107
|
`pdfkitStandardFonts()` to that build (see the README's `/vite` section), or
|
|
105
108
|
keep the library external so pdfkit loads from `node_modules`.
|
|
109
|
+
|
|
110
|
+
### `Cannot find module '…/pdfkit/js/standard-fonts/Helvetica.cjs'`
|
|
111
|
+
|
|
112
|
+
**When:** on every PDF a traced server output renders — `.next/standalone`
|
|
113
|
+
(`output: 'standalone'`), Nitro's `.output/server` — while the dev server
|
|
114
|
+
renders fine. The path points into the output's own `node_modules/pdfkit/`.
|
|
115
|
+
**Why:** the tracer copies pdfkit, but pdfkit loads its fonts with a runtime
|
|
116
|
+
`require('#standard-fonts/<Name>')` it never follows, so the `.cjs` fonts
|
|
117
|
+
(and the `chunks/` they `require`) are left behind.
|
|
118
|
+
**Fix:** hand the tracer the files. With `@nxgt/material`, wrap the Next.js
|
|
119
|
+
config in `withNxgtPrint` (`@nxgt/material/next`); with
|
|
120
|
+
`@nxgt/material-vue`, use its Nuxt module. Anything else calls
|
|
121
|
+
`/pdfkit-fonts` in its config:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import { pdfkitStandardFontDirs } from '@nxgt/material-core/pdfkit-fonts';
|
|
125
|
+
|
|
126
|
+
// every .cjs under each directory, chunks/ included
|
|
127
|
+
const include = pdfkitStandardFontDirs(process.cwd(), console.warn).map(
|
|
128
|
+
(dir) => `${dir}/**/*.cjs`,
|
|
129
|
+
);
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### `could not resolve …`
|
|
133
|
+
|
|
134
|
+
**When:** at build, from `pdfkitStandardFontDirs` or
|
|
135
|
+
`pdfkitStandardFontFiles` — through `withNxgtPrint`
|
|
136
|
+
(`[@nxgt/material/next] …`), the Nuxt module (`pdf fonts: …`) or your own
|
|
137
|
+
`warn`. Every problem goes into one line, joined by `; `, each error cut to
|
|
138
|
+
its first line (Node's `Require stack:` is left out):
|
|
139
|
+
`could not resolve @react-pdf/renderer: …`,
|
|
140
|
+
`could not resolve @react-pdf/font: …`,
|
|
141
|
+
`could not resolve pdfkit's fonts for @react-pdf/renderer: …`,
|
|
142
|
+
`could not resolve pdfkit's Courier font for …`.
|
|
143
|
+
Without `@react-pdf/renderer` installed at all, nothing is printed.
|
|
144
|
+
**Why:** `@react-pdf/renderer` is installed, but resolving it, the
|
|
145
|
+
`@react-pdf/font` it uses or the pdfkit either depends on fails: a broken or
|
|
146
|
+
partial install, or a layout that hides them from the renderer.
|
|
147
|
+
**Fix:** reinstall (`rm -rf node_modules && <your package manager> install`),
|
|
148
|
+
and check that `node -e "require.resolve('pdfkit/standard-fonts/Helvetica', { paths: [require.resolve('@react-pdf/renderer')] })"`
|
|
149
|
+
prints a `.cjs` path. What could be resolved is still returned: the warning
|
|
150
|
+
names only what a PDF route will miss.
|
|
151
|
+
|
|
152
|
+
### `Module "node:module" has been externalized for browser compatibility`
|
|
153
|
+
|
|
154
|
+
**When:** Vite (or a similar bundler) prints this, or a browser console shows
|
|
155
|
+
`createRequire is not a function`, in an app that imports
|
|
156
|
+
`@nxgt/material-core/pdfkit-fonts`.
|
|
157
|
+
**Why:** `/pdfkit-fonts` is Node-only: it resolves files on disk with
|
|
158
|
+
`node:module` and `node:path`. Imported from code that reaches the browser, the
|
|
159
|
+
bundler swaps those built-ins for empty shims.
|
|
160
|
+
**Fix:** import it only from build-time Node code — `next.config.ts`, a Nuxt
|
|
161
|
+
module, a Vite config, a script. In a Next.js app use `withNxgtPrint` from
|
|
162
|
+
`@nxgt/material/next`; in Nuxt the `@nxgt/material-vue` module already calls
|
|
163
|
+
it.
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
// next.config.ts: runs in Node, never in the browser
|
|
167
|
+
import { withNxgtPrint } from '@nxgt/material/next';
|
|
168
|
+
|
|
169
|
+
export default withNxgtPrint({ output: 'standalone' });
|
|
170
|
+
```
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nxgt/material-core",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "The framework-free core of @nxgt/material and @nxgt/material-vue: the PDF document model and its react-pdf renderer, print formatters, PDF file helpers, the PDF viewer's pure modules, the currency digits, the field-blur layers and the pdfkit fonts
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "The framework-free core of @nxgt/material and @nxgt/material-vue: the PDF document model and its react-pdf renderer, print formatters, PDF file helpers, the PDF viewer's pure modules, the currency digits, the file-size formatter, the field-blur layers, the pdfkit fonts Vite plugin and the Node-only pdfkit fonts resolution for Next.js and Nuxt builds",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bugs": {
|
|
7
7
|
"email": "stevegires@gmail.com"
|
|
@@ -92,6 +92,11 @@
|
|
|
92
92
|
"import": "./dist/lib/field-blur-layers.js",
|
|
93
93
|
"default": "./dist/lib/field-blur-layers.js"
|
|
94
94
|
},
|
|
95
|
+
"./format-file-size": {
|
|
96
|
+
"types": "./dist/lib/format-file-size.d.ts",
|
|
97
|
+
"import": "./dist/lib/format-file-size.js",
|
|
98
|
+
"default": "./dist/lib/format-file-size.js"
|
|
99
|
+
},
|
|
95
100
|
"./pdf-viewer": {
|
|
96
101
|
"types": "./dist/pdf-viewer/index.d.ts",
|
|
97
102
|
"import": "./dist/pdf-viewer/index.js",
|
|
@@ -102,6 +107,11 @@
|
|
|
102
107
|
"import": "./dist/vite/index.js",
|
|
103
108
|
"default": "./dist/vite/index.js"
|
|
104
109
|
},
|
|
110
|
+
"./pdfkit-fonts": {
|
|
111
|
+
"types": "./dist/pdfkit-fonts/index.d.ts",
|
|
112
|
+
"import": "./dist/pdfkit-fonts/index.js",
|
|
113
|
+
"default": "./dist/pdfkit-fonts/index.js"
|
|
114
|
+
},
|
|
105
115
|
"./package.json": "./package.json"
|
|
106
116
|
},
|
|
107
117
|
"sideEffects": false,
|
|
@@ -115,11 +125,6 @@
|
|
|
115
125
|
"framework-agnostic",
|
|
116
126
|
"typescript"
|
|
117
127
|
],
|
|
118
|
-
"repository": {
|
|
119
|
-
"type": "git",
|
|
120
|
-
"url": "git+https://github.com/softistx/nxgt-material.git",
|
|
121
|
-
"directory": "packages/core"
|
|
122
|
-
},
|
|
123
128
|
"publishConfig": {
|
|
124
129
|
"registry": "https://registry.npmjs.org",
|
|
125
130
|
"access": "public"
|
|
@@ -151,8 +156,10 @@
|
|
|
151
156
|
"src/lib/pdf-download.ts",
|
|
152
157
|
"src/lib/currency-digits.ts",
|
|
153
158
|
"src/lib/field-blur-layers.ts",
|
|
159
|
+
"src/lib/format-file-size.ts",
|
|
154
160
|
"src/pdf-viewer/index.ts",
|
|
155
|
-
"src/vite/index.ts"
|
|
161
|
+
"src/vite/index.ts",
|
|
162
|
+
"src/pdfkit-fonts/index.ts"
|
|
156
163
|
]
|
|
157
164
|
},
|
|
158
165
|
"dependencies": {
|