orz-paged 0.2.0 → 0.4.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.
@@ -0,0 +1,9 @@
1
+ /** A stylesheet for paged.js: a URL (fetched) or inline CSS as `{ name: cssText }`. */
2
+ export type PagedStylesheet = string | Record<string, string>;
3
+ /**
4
+ * Flow `content` (body HTML) into `target` as `.pagedjs_page` boxes, applying
5
+ * `stylesheets` (the `@page` rules + content/theme CSS). Clears `target` first.
6
+ */
7
+ export declare function paginate(content: string, stylesheets: PagedStylesheet[], target: HTMLElement): Promise<void>;
8
+ /** Export to PDF via the browser's own print engine (no Puppeteer). */
9
+ export declare function printDocument(): void;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Assembler — A1.
3
+ *
4
+ * `assemble(source)` turns a Markdown source into a {@link PagedAssembly}: pure
5
+ * data (CSS, font URLs, theme, body HTML, resolved settings) that the browser
6
+ * engine then hands to paged.js for pagination. No DOM here.
7
+ *
8
+ * Pipeline (DESIGN §3/§6):
9
+ * 1. `parseDocSettings` extracts + strips the `{{nyml kind: document}}` block.
10
+ * 2. Merge DEFAULTS ← template layer ← user overrides → resolved settings.
11
+ * 3. Scan the remaining body for `{{nyml kind: element}}` blocks, render each
12
+ * via `renderElement`, and replace it with a placeholder token.
13
+ * 4. Render the placeholdered body Markdown, then swap each placeholder for
14
+ * its element's HTML (so element HTML is never re-parsed as Markdown).
15
+ * 5. Compose page CSS + deduped element CSS + custom CSS; collect font URLs.
16
+ */
17
+ import type { PagedAssembly } from './types.js';
18
+ /**
19
+ * Assemble a Markdown source into a {@link PagedAssembly}.
20
+ */
21
+ export declare function assemble(source: string): PagedAssembly;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Builds the self-contained `.paged.html` shell (A3):
3
+ * <head> editor-chrome CSS (the document/page CSS is applied by the engine via
4
+ * paged.js' polisher, not here)
5
+ * <body> an empty #orz-pages render target, the editor chrome (edit FAB +
6
+ * docked CodeMirror panel + brand header + banners), the embedded
7
+ * Markdown source in <script id="orz-src">, the engine bundle (inline or
8
+ * CDN), the __ORZ_PAGED__ config, the boot call, and the in-file app.
9
+ *
10
+ * The source in #orz-src is the single source of truth: the engine renders it on
11
+ * load and the editor re-serialises it on save (self-reproducing). Mirrors
12
+ * orz-slides' template (live preview = the real rendered pages).
13
+ */
14
+ export type RendererSpec = {
15
+ mode: 'inline';
16
+ js: string;
17
+ } | {
18
+ mode: 'cdn';
19
+ src: string;
20
+ };
21
+ export interface ThemeAsset {
22
+ id: string;
23
+ css: string;
24
+ }
25
+ /** A template + its starter skeleton, for the in-editor template picker. */
26
+ export interface TemplateAsset {
27
+ id: string;
28
+ label: string;
29
+ description: string;
30
+ group: string;
31
+ skeleton: string;
32
+ }
33
+ export interface BuildOptions {
34
+ source: string;
35
+ title: string;
36
+ rendererVersion: string;
37
+ renderer: RendererSpec;
38
+ /** assets/themes/base.css text. */
39
+ baseCss: string;
40
+ /** all curated themes, inlined so the editor can switch with no network. */
41
+ themes: ThemeAsset[];
42
+ /** default theme id (informational; the document's settings decide). */
43
+ defaultTheme: string;
44
+ /** CDN URLs needed at view time. */
45
+ cdn: {
46
+ katexCss: string;
47
+ mermaidJs: string;
48
+ smilesJs: string;
49
+ chartJs: string;
50
+ hljsJs: string;
51
+ hljsCss: string;
52
+ };
53
+ /** the in-file editor app (assets/app.js text). */
54
+ appJs: string;
55
+ /** orz-markdown browser runtime (copy-as-Markdown + qr). */
56
+ runtime: string;
57
+ /** template catalog for the in-editor picker (id/label/description/group/skeleton). */
58
+ templates?: TemplateAsset[];
59
+ }
60
+ export declare function buildHtml(o: BuildOptions): string;
@@ -0,0 +1,144 @@
1
+ /**
2
+ * orz-paged — LOCKED INTERFACE.
3
+ *
4
+ * Every module codes against these types and nothing else. Changing a type here
5
+ * ripples across the document layer, the assembler, and the engine — treat edits
6
+ * as a coordinated change. (Mirrors orz-slides' `src/types.ts` role.)
7
+ *
8
+ * Vocabulary follows DESIGN.md §6–§9 and docs/document-model.md (the curated
9
+ * subset). Lengths: margins in **mm**, font size in **pt**, line-height unitless.
10
+ */
11
+ /** Named page sizes; a custom CSS size string (e.g. `"210mm 297mm"`) is allowed. */
12
+ export type PageSize = 'A3' | 'A4' | 'A5' | 'Letter' | 'Legal' | (string & {});
13
+ /** Where the page number sits in the margin boxes. */
14
+ export type PageNumberPosition = 'header-left' | 'header-center' | 'header-right' | 'footer-left' | 'footer-center' | 'footer-right' | 'none';
15
+ /** How the page number renders (counter formats). */
16
+ export type PageNumberStyle = 'simple' | 'page-n' | 'page-n-of-N' | 'n-of-N' | 'n-slash-N' | 'dash-n-dash' | 'brackets' | 'parentheses';
17
+ /**
18
+ * Curated document templates. `article`/`report`/`exam` come in two variants —
19
+ * `-page` (a dedicated title/cover page) and `-section` (title-on-content) — via
20
+ * the title element's `placement`. Legacy names (`article`/`report`/`exam`) still
21
+ * resolve to the `-section` variant (see resolveTemplate).
22
+ */
23
+ export type TemplateName = 'article-page' | 'article-section' | 'report-page' | 'report-section' | 'exam-page' | 'exam-section' | 'letter' | 'cover-letter' | 'cv' | 'cv-modern' | 'cv-elegant' | 'note';
24
+ /** Curated, light-only themes (DESIGN §8). `none` = plain. */
25
+ export type ThemeName = 'none' | 'light-academic-1' | 'light-academic-2' | 'light-neat-1' | 'light-neat-2' | 'light-neat-3' | 'beige-decent-1' | 'beige-decent-2';
26
+ /** Curated CDN font presets (DESIGN §4, §8). */
27
+ export type FontPresetName = 'system-serif' | 'source-serif-4' | 'lora' | 'crimson-pro' | 'noto-serif' | 'inter' | 'ibm-plex-sans' | 'roboto' | 'raleway' | 'noto-sans' | 'courier-prime';
28
+ /** Curated document elements (DESIGN §8). */
29
+ export type ElementKind = 'article-title' | 'report-title' | 'exam-title' | 'abstract' | 'letterhead' | 'letter-inside-address' | 'letter-signature' | 'toc' | 'cv-header' | 'question-mc' | 'question-open' | 'timestamp';
30
+ /** A title/cover element renders either as its own page or inline (DESIGN §8). */
31
+ export type Placement = 'page' | 'section';
32
+ /**
33
+ * Raw `{{nyml kind: document}}` payload — snake_case keys, loosely typed, every
34
+ * field optional. M1 (`settings`) parses this from the source.
35
+ */
36
+ export type RawDocSettings = Record<string, string | number | boolean | undefined>;
37
+ /**
38
+ * Fully-normalized document settings — every field resolved with defaults
39
+ * applied (after merging template + user layers). M5 (`page-css`) consumes this.
40
+ */
41
+ export interface DocSettings {
42
+ pageSize: PageSize;
43
+ marginTop: number;
44
+ marginBottom: number;
45
+ marginLeft: number;
46
+ marginRight: number;
47
+ pageBackground?: string;
48
+ fontPreset?: FontPresetName;
49
+ fontFamily?: string;
50
+ fontHeadingPreset?: FontPresetName;
51
+ fontMarginBoxPreset?: FontPresetName;
52
+ fontSize: number;
53
+ lineHeight: number;
54
+ decorationColor?: string;
55
+ pageNumberPosition: PageNumberPosition;
56
+ pageNumberStyle: PageNumberStyle;
57
+ pageNumberStartPage: number;
58
+ firstPageSkipNumber: boolean;
59
+ headerLeft: string;
60
+ headerCenter: string;
61
+ headerRight: string;
62
+ headerRule: boolean;
63
+ headerRuleColor?: string;
64
+ headerFontSize: number;
65
+ footerLeft: string;
66
+ footerCenter: string;
67
+ footerRight: string;
68
+ footerRule: boolean;
69
+ footerRuleColor?: string;
70
+ footerFontSize: number;
71
+ firstPageHideHeader: boolean;
72
+ firstPageHideFooter: boolean;
73
+ /** Strip header/footer/number from every `placement: page` front-matter page
74
+ * (title / abstract / toc on their own pages) and restart the page count so
75
+ * the first main-content page is 1. */
76
+ frontMatterClean: boolean;
77
+ limitImageToPage: boolean;
78
+ keepImageTogether: boolean;
79
+ repeatTableHeader: boolean;
80
+ avoidTableRowBreaks: boolean;
81
+ theme: ThemeName;
82
+ template?: TemplateName;
83
+ customCss?: string;
84
+ /** Dynamic switch — a key→value map driving conditional content. Elements
85
+ * carry `data-show-when="key=value"` / `data-hide-when="key=value"`; at render
86
+ * time non-matching ones are removed. Lets one source print several versions
87
+ * (e.g. `answer-key: hide` for the student copy, `show` for the key). */
88
+ dynamicChoices: Record<string, string>;
89
+ }
90
+ /** A partial settings layer (template defaults / user overrides) for merging. */
91
+ export type DocSettingsLayer = Partial<DocSettings>;
92
+ /** One `{{nyml kind: element}}` block: its kind + raw field map. */
93
+ export interface ElementSpec {
94
+ kind: ElementKind;
95
+ /** snake_case field → raw string value (multiline values preserved). */
96
+ fields: Record<string, string>;
97
+ /** parsed `placement:` if present (title/cover elements). */
98
+ placement?: Placement;
99
+ }
100
+ /** Capabilities an element renderer may use (injected — no hard orz-markdown dep). */
101
+ export interface ElementCtx {
102
+ /** Render inline Markdown (no wrapping `<p>`). */
103
+ renderInline(md: string): string;
104
+ /** Render block Markdown. */
105
+ renderBlock(md: string): string;
106
+ /** The resolved document settings (for accent color, fonts, etc.). */
107
+ settings: DocSettings;
108
+ }
109
+ /** Output of rendering one element. */
110
+ export interface ElementResult {
111
+ /** The element's HTML, placed into the document flow. */
112
+ html: string;
113
+ /** Scoped CSS for this element kind; injected **once** per kind (dedupe by kind). */
114
+ css?: string;
115
+ /** `page` → on its own page; `section` → inline. Defaults to `section`. */
116
+ placement: Placement;
117
+ }
118
+ /** A resolved font preset: a CDN stylesheet to load + the CSS family stack. */
119
+ export interface FontPreset {
120
+ /** `<link rel="stylesheet">` href (e.g. an @fontsource / Google Fonts URL). */
121
+ cssUrl: string;
122
+ /** the `font-family` value to use. */
123
+ family: string;
124
+ }
125
+ /**
126
+ * Result of assembling a document (A1) — everything the engine/template needs to
127
+ * render the paginated document. Pure data; no DOM.
128
+ */
129
+ export interface PagedAssembly {
130
+ /** The page CSS (from M5) + element scoped CSS + theme hook + custom CSS. */
131
+ css: string;
132
+ /** Font stylesheet URLs to `<link>` in <head> (from M3, deduped). */
133
+ fontCssUrls: string[];
134
+ /** Theme name to load its stylesheet. */
135
+ theme: ThemeName;
136
+ /** The document body HTML (content + elements), pre-pagination. */
137
+ bodyHtml: string;
138
+ /** The fully-resolved settings (for the editor settings panel + runtime). */
139
+ settings: DocSettings;
140
+ }
141
+ declare global {
142
+ /** Injected by esbuild at bundle time (build/bundle.ts). */
143
+ const __ORZPAGED_VERSION__: string;
144
+ }
package/package.json CHANGED
@@ -1,8 +1,16 @@
1
1
  {
2
2
  "name": "orz-paged",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Self-contained, editable HTML documents (.paged.html) — Markdown shown as print pages via paged.js, edited in-browser, exported to PDF by printing. Sibling of orz-mdhtml and orz-slides.",
5
5
  "type": "module",
6
+ "main": "./dist/lib.js",
7
+ "types": "./dist/lib.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/lib.d.ts",
11
+ "default": "./dist/lib.js"
12
+ }
13
+ },
6
14
  "bin": {
7
15
  "orz-paged": "dist/cli.js"
8
16
  },
@@ -37,7 +45,7 @@
37
45
  "url": "https://github.com/wangyu16/orz-paged"
38
46
  },
39
47
  "dependencies": {
40
- "orz-markdown": "^1.3.0",
48
+ "orz-markdown": "^1.3.2",
41
49
  "pagedjs": "^0.4.3"
42
50
  },
43
51
  "devDependencies": {