@dimm-city/print-md 0.1.13 → 0.3.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/dist/cli.js CHANGED
@@ -755,7 +755,7 @@ function registerImageRule(md) {
755
755
  }
756
756
  var PREFIX_PATTERNS;
757
757
  var init_images = __esm(() => {
758
- PREFIX_PATTERNS = [/^\.?\/?temp\/images\//, /^\.?\/?images\//];
758
+ PREFIX_PATTERNS = [/^(?:\.\/|\/)?temp\/images\//, /^(?:\.\/|\/)?images\//];
759
759
  });
760
760
 
761
761
  // ../lib/src/lib/markdown/plugins.ts
@@ -991,7 +991,8 @@ function execCapture(cmd, args) {
991
991
  p.stdout.on("data", (d) => stdout += d.toString());
992
992
  p.stderr.on("data", (d) => stderr += d.toString());
993
993
  p.on("error", reject);
994
- p.on("exit", (code) => code === 0 ? resolve3({ stdout, stderr }) : reject(new Error(`${cmd} exited ${code}
994
+ p.on("exit", (code, signal) => code === 0 ? resolve3({ stdout, stderr }) : reject(new Error(code === null ? `${cmd} was killed by signal ${signal}
995
+ ${stderr}` : `${cmd} exited ${code}
995
996
  ${stderr}`)));
996
997
  });
997
998
  }
@@ -22628,8 +22629,11 @@ async function convertToPdfxCmyk(inputPdf, outPdf, config) {
22628
22629
  tmpDef,
22629
22630
  inputPdf
22630
22631
  ];
22631
- await run("gs", args);
22632
- await unlink(tmpDef).catch(() => {});
22632
+ try {
22633
+ await run("gs", args);
22634
+ } finally {
22635
+ await unlink(tmpDef).catch(() => {});
22636
+ }
22633
22637
  }
22634
22638
  var init_ghostscript = __esm(() => {
22635
22639
  init_exec();
@@ -22640,16 +22644,18 @@ var package_default;
22640
22644
  var init_package = __esm(() => {
22641
22645
  package_default = {
22642
22646
  name: "@dimm-city/print-md-lib",
22643
- version: "0.1.13",
22647
+ version: "0.3.0",
22644
22648
  private: true,
22645
22649
  type: "module",
22646
22650
  main: "dist/index.js",
22647
22651
  exports: {
22648
22652
  ".": {
22653
+ types: "./dist/index.d.ts",
22649
22654
  bun: "./src/index.ts",
22650
22655
  default: "./dist/index.js"
22651
22656
  },
22652
22657
  "./api": {
22658
+ types: "./dist/api/index.d.ts",
22653
22659
  bun: "./src/api/index.ts",
22654
22660
  default: "./dist/api/index.js"
22655
22661
  }
@@ -22687,7 +22693,9 @@ var init_package = __esm(() => {
22687
22693
  devDependencies: {
22688
22694
  "@types/bun": "latest",
22689
22695
  "@types/markdown-it": "^14.1.2",
22690
- "@types/ws": "^8.5.13"
22696
+ "@types/node": "^22.0.0",
22697
+ "@types/ws": "^8.5.13",
22698
+ typescript: "^5"
22691
22699
  }
22692
22700
  };
22693
22701
  });
@@ -22883,7 +22891,7 @@ var manifest_schema_default = "./manifest.schema-16z94mx1.json";
22883
22891
  var init_manifest_schema = () => {};
22884
22892
 
22885
22893
  // ../lib/src/assets/preview/scripts/pagedjs-interface.js
22886
- var pagedjs_interface_default = "./pagedjs-interface-vzkzgeb9.js";
22894
+ var pagedjs_interface_default = "./pagedjs-interface-9w9r490k.js";
22887
22895
  var init_pagedjs_interface = () => {};
22888
22896
 
22889
22897
  // ../lib/src/assets/preview/scripts/pagedjs-bridge.js
@@ -22904,6 +22912,7 @@ __export(exports_embedded_assets, {
22904
22912
  getAssetsDir: () => getAssetsDir,
22905
22913
  getAssetPath: () => getAssetPath
22906
22914
  });
22915
+ import { existsSync as existsSync6 } from "node:fs";
22907
22916
  import { mkdtemp, mkdir as mkdir4, writeFile as writeFile5, readFile as readFile5 } from "node:fs/promises";
22908
22917
  import { tmpdir } from "node:os";
22909
22918
  import { dirname as dirname3, join as join7, resolve as resolve4 } from "node:path";
@@ -22919,16 +22928,23 @@ async function extractAssets() {
22919
22928
  return root;
22920
22929
  }
22921
22930
  async function getAssetsDir() {
22922
- if (!extractPromise) {
22923
- extractPromise = extractAssets();
22931
+ if (extractPromise) {
22932
+ try {
22933
+ const root = await extractPromise;
22934
+ if (existsSync6(join7(root, SENTINEL_ASSET))) {
22935
+ return root;
22936
+ }
22937
+ } catch {}
22938
+ extractPromise = null;
22924
22939
  }
22940
+ extractPromise = extractAssets();
22925
22941
  return extractPromise;
22926
22942
  }
22927
22943
  async function getAssetPath(relPath) {
22928
22944
  const root = await getAssetsDir();
22929
22945
  return join7(root, relPath);
22930
22946
  }
22931
- var __libdir, abs = (p) => resolve4(__libdir, p), filePath = (v) => v, EMBEDDED_ASSETS, extractPromise = null;
22947
+ var __libdir, abs = (p) => resolve4(__libdir, p), filePath = (v) => v, EMBEDDED_ASSETS, extractPromise = null, SENTINEL_ASSET = "vendor/paged.polyfill.js";
22932
22948
  var init_embedded_assets = __esm(() => {
22933
22949
  init_favicon();
22934
22950
  init_manifest_schema();
@@ -26489,7 +26505,7 @@ var require_source_map = __commonJS((exports) => {
26489
26505
 
26490
26506
  // ../../node_modules/.bun/postcss@8.5.15/node_modules/postcss/lib/previous-map.js
26491
26507
  var require_previous_map = __commonJS((exports, module) => {
26492
- var { existsSync: existsSync6, readFileSync } = __require("fs");
26508
+ var { existsSync: existsSync7, readFileSync } = __require("fs");
26493
26509
  var { dirname: dirname4, join: join8 } = __require("path");
26494
26510
  var { SourceMapConsumer, SourceMapGenerator } = require_source_map();
26495
26511
  function fromBase64(str) {
@@ -26566,7 +26582,7 @@ var require_previous_map = __commonJS((exports, module) => {
26566
26582
  }
26567
26583
  }
26568
26584
  this.root = dirname4(path2);
26569
- if (existsSync6(path2)) {
26585
+ if (existsSync7(path2)) {
26570
26586
  this.mapFile = path2;
26571
26587
  return readFileSync(path2, "utf-8").toString().trim();
26572
26588
  }
@@ -28811,11 +28827,15 @@ function splitSelectorList(selectorList) {
28811
28827
  let quote = null;
28812
28828
  for (let i = 0;i < selectorList.length; i += 1) {
28813
28829
  const char = selectorList[i];
28814
- const prev = i > 0 ? selectorList[i - 1] : "";
28815
28830
  current += char;
28816
28831
  if (quote) {
28817
- if (char === quote && prev !== "\\")
28818
- quote = null;
28832
+ if (char === quote) {
28833
+ let backslashes = 0;
28834
+ for (let j = i - 1;j >= 0 && selectorList[j] === "\\"; j -= 1)
28835
+ backslashes += 1;
28836
+ if (backslashes % 2 === 0)
28837
+ quote = null;
28838
+ }
28819
28839
  continue;
28820
28840
  }
28821
28841
  if (char === '"' || char === "'") {
@@ -88846,18 +88866,18 @@ var init_exports_sync = __esm(() => {
88846
88866
  });
88847
88867
 
88848
88868
  // ../lib/src/checks/source/markdownlint.ts
88849
- import { existsSync as existsSync6 } from "node:fs";
88869
+ import { existsSync as existsSync7 } from "node:fs";
88850
88870
  import { readFile as readFile10 } from "node:fs/promises";
88851
88871
  import { resolve as resolve6 } from "node:path";
88852
88872
  import { parse as parseYaml2 } from "yaml";
88853
88873
  function findConfig(inputDir, explicit) {
88854
88874
  if (explicit) {
88855
88875
  const p10 = resolve6(inputDir, explicit);
88856
- return existsSync6(p10) ? p10 : null;
88876
+ return existsSync7(p10) ? p10 : null;
88857
88877
  }
88858
88878
  for (const name of CONFIG_NAMES) {
88859
88879
  const p10 = resolve6(inputDir, name);
88860
- if (existsSync6(p10))
88880
+ if (existsSync7(p10))
88861
88881
  return p10;
88862
88882
  }
88863
88883
  return null;
@@ -91432,17 +91452,17 @@ var require_htmlhint = __commonJS((exports, module) => {
91432
91452
  });
91433
91453
 
91434
91454
  // ../lib/src/checks/source/htmlhint.ts
91435
- import { existsSync as existsSync7 } from "node:fs";
91455
+ import { existsSync as existsSync8 } from "node:fs";
91436
91456
  import { readFile as readFile11 } from "node:fs/promises";
91437
91457
  import { resolve as resolve7 } from "node:path";
91438
91458
  function findConfig2(inputDir, explicit) {
91439
91459
  if (explicit) {
91440
91460
  const p10 = resolve7(inputDir, explicit);
91441
- return existsSync7(p10) ? p10 : null;
91461
+ return existsSync8(p10) ? p10 : null;
91442
91462
  }
91443
91463
  for (const name of CONFIG_NAMES2) {
91444
91464
  const p10 = resolve7(inputDir, name);
91445
- if (existsSync7(p10))
91465
+ if (existsSync8(p10))
91446
91466
  return p10;
91447
91467
  }
91448
91468
  return null;
@@ -91463,7 +91483,7 @@ var init_htmlhint = __esm(() => {
91463
91483
  const sourceConfig = ctx.config.validate.source;
91464
91484
  if (sourceConfig.htmlhint === false)
91465
91485
  return [];
91466
- if (!ctx.htmlPath || !existsSync7(ctx.htmlPath))
91486
+ if (!ctx.htmlPath || !existsSync8(ctx.htmlPath))
91467
91487
  return [];
91468
91488
  const configPath = typeof sourceConfig.htmlhint === "string" ? sourceConfig.htmlhint : null;
91469
91489
  const resolvedConfig = findConfig2(ctx.inputDir, configPath);
@@ -91529,7 +91549,7 @@ var init_stylelint = __esm(() => {
91529
91549
  });
91530
91550
 
91531
91551
  // ../lib/src/checks/source/local-refs.ts
91532
- import { existsSync as existsSync8 } from "node:fs";
91552
+ import { existsSync as existsSync9 } from "node:fs";
91533
91553
  import { readFile as readFile13 } from "node:fs/promises";
91534
91554
  import { dirname as dirname4, resolve as resolve8 } from "node:path";
91535
91555
  function stripInlineCode(line) {
@@ -91589,7 +91609,7 @@ function isLocalRef(ref) {
91589
91609
  }
91590
91610
  function localRefExists(ref, sourceFile) {
91591
91611
  const candidate = resolve8(dirname4(sourceFile), ref);
91592
- return existsSync8(candidate);
91612
+ return existsSync9(candidate);
91593
91613
  }
91594
91614
  var check19;
91595
91615
  var init_local_refs = __esm(() => {
@@ -91847,7 +91867,7 @@ function parseImage(b) {
91847
91867
  if (b.length > 3 && b[0] === 255 && b[1] === 216 && b[2] === 255) {
91848
91868
  return parseJpeg(b);
91849
91869
  }
91850
- if (b.length > 8 && (b[0] === 73 && b[1] === 73 && b[2] === 42 || b[0] === 77 && b[1] === 77 && b[3] === 42)) {
91870
+ if (b.length > 8 && (b[0] === 73 && b[1] === 73 && b[2] === 42 || b[0] === 77 && b[1] === 77 && b[2] === 0 && b[3] === 42)) {
91851
91871
  return parseTiff(b);
91852
91872
  }
91853
91873
  return null;
@@ -92278,7 +92298,7 @@ var init_approved_fonts = __esm(() => {
92278
92298
 
92279
92299
  // ../lib/src/checks/asset/missing-font-refs.ts
92280
92300
  import { readFile as readFile17 } from "node:fs/promises";
92281
- import { existsSync as existsSync9 } from "node:fs";
92301
+ import { existsSync as existsSync10 } from "node:fs";
92282
92302
  import { resolve as resolve9, dirname as dirname5 } from "node:path";
92283
92303
  var FONT_FACE_PATTERN, URL_PATTERN, check28;
92284
92304
  var init_missing_font_refs = __esm(() => {
@@ -92314,7 +92334,7 @@ var init_missing_font_refs = __esm(() => {
92314
92334
  continue;
92315
92335
  const cleanUrl = fontUrl.split("?")[0].split("#")[0];
92316
92336
  const fontPath = resolve9(cssDir, cleanUrl);
92317
- if (!existsSync9(fontPath)) {
92337
+ if (!existsSync10(fontPath)) {
92318
92338
  results.push({
92319
92339
  checkId: check28.id,
92320
92340
  severity: "error",
@@ -92333,7 +92353,7 @@ var init_missing_font_refs = __esm(() => {
92333
92353
  });
92334
92354
 
92335
92355
  // ../lib/src/checks/asset/font-license.ts
92336
- import { existsSync as existsSync10 } from "node:fs";
92356
+ import { existsSync as existsSync11 } from "node:fs";
92337
92357
  import { resolve as resolve10 } from "node:path";
92338
92358
  var LICENSE_NAMES, check29;
92339
92359
  var init_font_license = __esm(() => {
@@ -92371,7 +92391,7 @@ var init_font_license = __esm(() => {
92371
92391
  }
92372
92392
  const results = [];
92373
92393
  for (const fontDir of fontDirs) {
92374
- const hasLicense = LICENSE_NAMES.some((name) => existsSync10(resolve10(fontDir, name)));
92394
+ const hasLicense = LICENSE_NAMES.some((name) => existsSync11(resolve10(fontDir, name)));
92375
92395
  if (!hasLicense) {
92376
92396
  results.push({
92377
92397
  checkId: check29.id,
@@ -92607,7 +92627,7 @@ var init_heuristic = __esm(() => {
92607
92627
  });
92608
92628
 
92609
92629
  // ../lib/src/lib/validation-exec.ts
92610
- import { existsSync as existsSync11 } from "node:fs";
92630
+ import { existsSync as existsSync12 } from "node:fs";
92611
92631
  import { join as join8, resolve as resolve11 } from "node:path";
92612
92632
  function parseCsv(value) {
92613
92633
  if (!value)
@@ -92661,7 +92681,7 @@ async function executeValidation(args) {
92661
92681
  if (profile) {
92662
92682
  config = applyValidationProfile(config, profile);
92663
92683
  }
92664
- if (pdfPath && !existsSync11(pdfPath)) {
92684
+ if (pdfPath && !existsSync12(pdfPath)) {
92665
92685
  throw new Error(`File not found: ${pdfPath}`);
92666
92686
  }
92667
92687
  const categories = parseCsv(typeof args.category === "string" ? args.category : undefined)?.map((s) => s);
@@ -92696,7 +92716,7 @@ async function executeValidation(args) {
92696
92716
  assetDirs = config.source.assets.map((assetDir) => resolve11(inputDir, assetDir));
92697
92717
  const outDir = resolve11(config.output.dir);
92698
92718
  const possibleHtml = join8(outDir, BOOK_HTML_FILENAME);
92699
- if (existsSync11(possibleHtml)) {
92719
+ if (existsSync12(possibleHtml)) {
92700
92720
  htmlPath = possibleHtml;
92701
92721
  }
92702
92722
  }
@@ -93298,7 +93318,7 @@ var init_constants3 = __esm(() => {
93298
93318
 
93299
93319
  // ../lib/src/preview/file-watcher.ts
93300
93320
  import { watch } from "chokidar";
93301
- import { existsSync as existsSync12 } from "node:fs";
93321
+ import { existsSync as existsSync13 } from "node:fs";
93302
93322
  import fsp2 from "node:fs/promises";
93303
93323
  import path6 from "path";
93304
93324
  function resolveExternalAssetRoots(inputPath, assets) {
@@ -93308,7 +93328,7 @@ function resolveExternalAssetRoots(inputPath, assets) {
93308
93328
  const roots = [];
93309
93329
  for (const assetPath of assets) {
93310
93330
  const src = path6.resolve(path6.join(inputPath, assetPath));
93311
- if (!existsSync12(src))
93331
+ if (!existsSync13(src))
93312
93332
  continue;
93313
93333
  if (src === inputResolved || src.startsWith(inputResolved + path6.sep))
93314
93334
  continue;
@@ -93371,12 +93391,11 @@ function createFileWatcher(state) {
93371
93391
  pollInterval: 50
93372
93392
  }
93373
93393
  });
93374
- let rebuildTimer = null;
93375
93394
  watcher.on("all", async (event, filePath2) => {
93376
93395
  debug2(`File ${event}: ${filePath2}`);
93377
- if (rebuildTimer)
93378
- clearTimeout(rebuildTimer);
93379
- rebuildTimer = setTimeout(async () => {
93396
+ if (state.rebuildTimer)
93397
+ clearTimeout(state.rebuildTimer);
93398
+ state.rebuildTimer = setTimeout(async () => {
93380
93399
  if (state.isRebuilding)
93381
93400
  return;
93382
93401
  state.isRebuilding = true;
@@ -93412,6 +93431,10 @@ function startFileWatcher(state) {
93412
93431
  state.currentWatcher = createFileWatcher(state);
93413
93432
  }
93414
93433
  async function stopFileWatcher(state) {
93434
+ if (state.rebuildTimer) {
93435
+ clearTimeout(state.rebuildTimer);
93436
+ state.rebuildTimer = null;
93437
+ }
93415
93438
  if (state.currentWatcher) {
93416
93439
  await state.currentWatcher.close();
93417
93440
  state.currentWatcher = null;
@@ -93581,6 +93604,7 @@ function createServerState(inputPath, tempDir, assetsSourceDir, config, options)
93581
93604
  return {
93582
93605
  currentInputPath: inputPath,
93583
93606
  currentWatcher: null,
93607
+ rebuildTimer: null,
93584
93608
  isRebuilding: false,
93585
93609
  previewServer: null,
93586
93610
  isShuttingDown: false,
@@ -93876,7 +93900,7 @@ var init_http_server = __esm(() => {
93876
93900
  });
93877
93901
 
93878
93902
  // ../lib/src/server.ts
93879
- import { existsSync as existsSync13 } from "node:fs";
93903
+ import { existsSync as existsSync14 } from "node:fs";
93880
93904
  import { resolve as resolve12 } from "node:path";
93881
93905
  async function startPreviewServer(options) {
93882
93906
  const inputPath = options.input ?? "";
@@ -93887,7 +93911,7 @@ async function startPreviewServer(options) {
93887
93911
  info("Starting preview server (no input directory)");
93888
93912
  }
93889
93913
  const config = await initializeConfiguration(inputPath, options);
93890
- const missingSharedAssets = inputPath ? config.source.assets.filter((a) => a.startsWith("..") && !existsSync13(resolve12(inputPath, a))) : [];
93914
+ const missingSharedAssets = inputPath ? config.source.assets.filter((a) => a.startsWith("..") && !existsSync14(resolve12(inputPath, a))) : [];
93891
93915
  if (missingSharedAssets.length > 0) {
93892
93916
  warn(`Shared asset folder(s) not found — fonts/styles may be missing or wrong: ` + missingSharedAssets.map((a) => `"${a}"`).join(", ") + `. Check that the shared directory exists next to this project.`);
93893
93917
  }
@@ -93984,11 +94008,22 @@ var init_src = __esm(() => {
93984
94008
  // src/commands/preview.ts
93985
94009
  var exports_preview = {};
93986
94010
  __export(exports_preview, {
94011
+ resolvePort: () => resolvePort,
93987
94012
  default: () => preview_default
93988
94013
  });
93989
94014
  import { defineCommand } from "citty";
93990
94015
  import path9 from "node:path";
93991
94016
  import fs5 from "node:fs";
94017
+ function resolvePort(raw) {
94018
+ if (raw === undefined || raw === "")
94019
+ return 3579;
94020
+ const n = Number(raw);
94021
+ if (!Number.isFinite(n) || n < 0) {
94022
+ log.error(`Invalid --port value: "${raw}". Expected a non-negative number (0 = OS-assigned).`);
94023
+ process.exit(2);
94024
+ }
94025
+ return n;
94026
+ }
93992
94027
  function parseFormat(raw) {
93993
94028
  if (raw === undefined || raw === "")
93994
94029
  return "html";
@@ -94045,7 +94080,7 @@ var init_preview = __esm(() => {
94045
94080
  if (format === "html") {
94046
94081
  await startPreviewServer({
94047
94082
  input: inputPath,
94048
- port: Number(args.port) || 3579,
94083
+ port: resolvePort(args.port),
94049
94084
  host: args.host || "127.0.0.1",
94050
94085
  noWatch: !!args["no-watch"],
94051
94086
  verbose: !!args.verbose,
@@ -94175,7 +94210,7 @@ __export(exports_lint, {
94175
94210
  default: () => lint_default
94176
94211
  });
94177
94212
  import { defineCommand as defineCommand3 } from "citty";
94178
- import { existsSync as existsSync14, statSync as statSync2 } from "node:fs";
94213
+ import { existsSync as existsSync15, statSync as statSync2 } from "node:fs";
94179
94214
  import { join as join9 } from "node:path";
94180
94215
  var lint_default;
94181
94216
  var init_lint = __esm(() => {
@@ -94199,7 +94234,7 @@ var init_lint = __esm(() => {
94199
94234
  async run({ args }) {
94200
94235
  const filesArg = typeof args.files === "string" ? args.files : undefined;
94201
94236
  const manifestArg = typeof args.manifest === "string" ? args.manifest : undefined;
94202
- const filesArgIsManifestDir = filesArg && existsSync14(filesArg) && statSync2(filesArg).isDirectory() && (existsSync14(join9(filesArg, "manifest.yaml")) || existsSync14(join9(filesArg, "manifest.yml")));
94237
+ const filesArgIsManifestDir = filesArg && existsSync15(filesArg) && statSync2(filesArg).isDirectory() && (existsSync15(join9(filesArg, "manifest.yaml")) || existsSync15(join9(filesArg, "manifest.yml")));
94203
94238
  const result = await runLint({
94204
94239
  files: filesArgIsManifestDir ? undefined : filesArg,
94205
94240
  manifest: manifestArg ?? (filesArgIsManifestDir ? filesArg : undefined)
@@ -0,0 +1,175 @@
1
+ // Interface adapter: exposes window.previewAPI for the parent toolbar.
2
+ // Paged.js paginates into .pagedjs_page elements. We use PagedConfig.after
3
+ // to know when rendering is done.
4
+
5
+ (function () {
6
+ 'use strict';
7
+
8
+ var pages = [];
9
+ var currentPage = 1;
10
+ var debugMode = false;
11
+ var currentViewMode = 'two-column';
12
+ var ignoreScrollUntil = 0;
13
+
14
+ function refreshPages() {
15
+ pages = Array.from(document.querySelectorAll('.pagedjs_page'));
16
+ return pages;
17
+ }
18
+
19
+ function clampPage(n) {
20
+ if (pages.length === 0) return 1;
21
+ var page = Number(n);
22
+ if (!Number.isFinite(page)) page = 1;
23
+ return Math.max(1, Math.min(Math.round(page), pages.length));
24
+ }
25
+
26
+ function detectVisiblePage() {
27
+ if (pages.length === 0) return 1;
28
+ var scrollTop = window.scrollY || document.documentElement.scrollTop;
29
+ var threshold = scrollTop + window.innerHeight / 3;
30
+ var page = 1;
31
+ var pageTop = pages[0].offsetTop;
32
+ for (var i = pages.length - 1; i >= 0; i--) {
33
+ if (pages[i].offsetTop <= threshold) {
34
+ pageTop = pages[i].offsetTop;
35
+ break;
36
+ }
37
+ }
38
+ for (var j = 0; j < pages.length; j++) {
39
+ if (Math.abs(pages[j].offsetTop - pageTop) < 2) {
40
+ page = j + 1;
41
+ break;
42
+ }
43
+ }
44
+ return page;
45
+ }
46
+
47
+ function scrollToCurrentPage() {
48
+ if (pages.length === 0) return;
49
+ var page = clampPage(currentPage);
50
+ currentPage = page;
51
+ ignoreScrollUntil = Date.now() + 300;
52
+ pages[page - 1].scrollIntoView({ behavior: 'instant', block: 'start', inline: 'nearest' });
53
+ }
54
+
55
+ function pageStep(mode) {
56
+ return (mode || currentViewMode) === 'single' ? 1 : 2;
57
+ }
58
+
59
+ var api = {
60
+ getTotalPages: function () { refreshPages(); return pages.length; },
61
+ getCurrentPage: function () { return currentPage; },
62
+ goToPage: function (n) {
63
+ refreshPages();
64
+ currentPage = clampPage(n);
65
+ scrollToCurrentPage();
66
+ return api.notifyPageChange();
67
+ },
68
+ getPageDimensions: function () {
69
+ refreshPages();
70
+ var page = pages[0] || null;
71
+ var pagesEl = document.querySelector('.pagedjs_pages');
72
+ if (!page) return null;
73
+ return {
74
+ width: currentViewMode === 'single' ? page.offsetWidth : (pagesEl ? pagesEl.scrollWidth : page.offsetWidth),
75
+ height: page.offsetHeight
76
+ };
77
+ },
78
+ firstPage: function () { return api.goToPage(1); },
79
+ prevPage: function (mode) { return api.goToPage(currentPage - pageStep(mode)); },
80
+ nextPage: function (mode) { return api.goToPage(currentPage + pageStep(mode)); },
81
+ lastPage: function () { refreshPages(); return api.goToPage(pages.length); },
82
+ setViewMode: function (mode) {
83
+ refreshPages();
84
+ currentViewMode = mode || 'two-column';
85
+ document.body.classList.remove('view-single', 'view-spread', 'view-two-column');
86
+ if (mode) document.body.classList.add('view-' + mode);
87
+ scrollToCurrentPage();
88
+ return api.notifyPageChange();
89
+ },
90
+ setZoom: function (z) {
91
+ document.documentElement.style.setProperty('--pmd-zoom', z);
92
+ },
93
+ toggleDebugMode: function () {
94
+ debugMode = !debugMode;
95
+ document.body.classList.toggle('debug', debugMode);
96
+ return debugMode;
97
+ },
98
+ notifyPageChange: function () {
99
+ var detail = { currentPage: api.getCurrentPage(), totalPages: pages.length };
100
+ window.dispatchEvent(new CustomEvent('pageChanged', { detail: detail }));
101
+ return detail;
102
+ },
103
+ notifyRenderingComplete: function () {
104
+ window.dispatchEvent(new CustomEvent('renderingComplete', {
105
+ detail: { totalPages: pages.length }
106
+ }));
107
+ }
108
+ };
109
+
110
+ window.previewAPI = api;
111
+
112
+ var observedPageCount = 0;
113
+ var pageObserverQueued = false;
114
+ function publishObservedPageCount() {
115
+ pageObserverQueued = false;
116
+ if (window.__PAGED_RENDERED__ === true) return;
117
+ var count = refreshPages().length;
118
+ if (count > observedPageCount) {
119
+ observedPageCount = count;
120
+ window.dispatchEvent(new CustomEvent('pageChanged', {
121
+ detail: { currentPage: count, totalPages: count }
122
+ }));
123
+ }
124
+ }
125
+ var pageObserver = new MutationObserver(function () {
126
+ if (window.__PAGED_RENDERED__ === true) return;
127
+ if (pageObserverQueued) return;
128
+ pageObserverQueued = true;
129
+ window.requestAnimationFrame(publishObservedPageCount);
130
+ });
131
+
132
+ function startPageObserver() {
133
+ var target = document.body || document.documentElement;
134
+ if (!target) return false;
135
+ pageObserver.observe(target, { childList: true, subtree: true });
136
+ return true;
137
+ }
138
+
139
+ if (!startPageObserver()) {
140
+ document.addEventListener('DOMContentLoaded', function onReady() {
141
+ document.removeEventListener('DOMContentLoaded', onReady);
142
+ startPageObserver();
143
+ });
144
+ }
145
+
146
+ // Scroll tracking
147
+ var scrollTimer = null;
148
+ window.addEventListener('scroll', function () {
149
+ if (pages.length === 0) refreshPages();
150
+ if (pages.length === 0) return;
151
+ if (scrollTimer) clearTimeout(scrollTimer);
152
+ scrollTimer = setTimeout(function () {
153
+ if (Date.now() < ignoreScrollUntil) return;
154
+ var page = detectVisiblePage();
155
+ if (page !== currentPage) {
156
+ currentPage = page;
157
+ api.notifyPageChange();
158
+ }
159
+ }, 150);
160
+ });
161
+
162
+ // Paged.js calls this when rendering is complete
163
+ window.PagedConfig = window.PagedConfig || {};
164
+ window.PagedConfig.after = function (flow) {
165
+ refreshPages();
166
+ observedPageCount = pages.length;
167
+ pageObserver.disconnect();
168
+ currentPage = 1;
169
+ ignoreScrollUntil = Date.now() + 300;
170
+ window.scrollTo(0, 0);
171
+ console.log('Paged.js rendered ' + pages.length + ' pages');
172
+ api.notifyRenderingComplete();
173
+ setTimeout(api.notifyPageChange, 0);
174
+ };
175
+ })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dimm-city/print-md",
3
- "version": "0.1.13",
3
+ "version": "0.3.0",
4
4
  "description": "Markdown-to-PDF converter for professional print layout using Paged.js and Ghostscript.",
5
5
  "author": "itlackey",
6
6
  "license": "MPL-2.0",
@@ -1,94 +0,0 @@
1
- // Interface adapter: exposes window.previewAPI for the parent toolbar.
2
- // Paged.js paginates into .pagedjs_page elements. We use PagedConfig.after
3
- // to know when rendering is done.
4
-
5
- (function () {
6
- 'use strict';
7
-
8
- var pages = [];
9
- var currentIndex = 0;
10
- var debugMode = false;
11
-
12
- function refreshPages() {
13
- pages = Array.from(document.querySelectorAll('.pagedjs_page'));
14
- return pages;
15
- }
16
-
17
- function detectCurrentPage() {
18
- if (pages.length === 0) return 0;
19
- var scrollTop = window.scrollY || document.documentElement.scrollTop;
20
- var threshold = scrollTop + window.innerHeight / 3;
21
- for (var i = pages.length - 1; i >= 0; i--) {
22
- if (pages[i].offsetTop <= threshold) return i;
23
- }
24
- return 0;
25
- }
26
-
27
- var api = {
28
- getTotalPages: function () { refreshPages(); return pages.length; },
29
- getCurrentPage: function () { return currentIndex + 1; },
30
- goToPage: function (n) {
31
- refreshPages();
32
- currentIndex = Math.max(0, Math.min(n - 1, pages.length - 1));
33
- // Use 'instant' so the scroll completes synchronously before notifyPageChange
34
- // fires. 'smooth' interacts with the scroll-listener debounce timer and causes
35
- // the parent Svelte toolbar to receive a stale page number on fast navigation.
36
- pages[currentIndex].scrollIntoView({ behavior: 'instant', block: 'start' });
37
- api.notifyPageChange();
38
- },
39
- getPageDimensions: function () {
40
- var page = document.querySelector('.pagedjs_page');
41
- return page ? { width: page.offsetWidth, height: page.offsetHeight } : null;
42
- },
43
- firstPage: function () { api.goToPage(1); },
44
- prevPage: function () { api.goToPage(currentIndex); },
45
- nextPage: function () { api.goToPage(currentIndex + 2); },
46
- lastPage: function () { api.goToPage(pages.length); },
47
- setViewMode: function (mode) {
48
- document.body.classList.remove('view-single', 'view-spread', 'view-two-column');
49
- if (mode) document.body.classList.add('view-' + mode);
50
- },
51
- setZoom: function (z) {
52
- document.documentElement.style.setProperty('--pmd-zoom', z);
53
- },
54
- toggleDebugMode: function () {
55
- debugMode = !debugMode;
56
- document.body.classList.toggle('debug', debugMode);
57
- return debugMode;
58
- },
59
- notifyPageChange: function () {
60
- window.dispatchEvent(new CustomEvent('pageChanged', {
61
- detail: { currentPage: api.getCurrentPage(), totalPages: pages.length }
62
- }));
63
- },
64
- notifyRenderingComplete: function () {
65
- window.dispatchEvent(new CustomEvent('renderingComplete', {
66
- detail: { totalPages: pages.length }
67
- }));
68
- }
69
- };
70
-
71
- window.previewAPI = api;
72
-
73
- // Scroll tracking
74
- var scrollTimer = null;
75
- window.addEventListener('scroll', function () {
76
- if (pages.length === 0) return;
77
- if (scrollTimer) clearTimeout(scrollTimer);
78
- scrollTimer = setTimeout(function () {
79
- var idx = detectCurrentPage();
80
- if (idx !== currentIndex) {
81
- currentIndex = idx;
82
- api.notifyPageChange();
83
- }
84
- }, 150);
85
- });
86
-
87
- // Paged.js calls this when rendering is complete
88
- window.PagedConfig = window.PagedConfig || {};
89
- window.PagedConfig.after = function (flow) {
90
- refreshPages();
91
- console.log('Paged.js rendered ' + pages.length + ' pages');
92
- api.notifyRenderingComplete();
93
- };
94
- })();