medical-form-printer 0.2.0 → 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/README.md CHANGED
@@ -8,6 +8,17 @@ A schema-driven medical form print renderer that transforms structured form data
8
8
 
9
9
  [中文文档](./README.zh-CN.md)
10
10
 
11
+ ## Table of Contents
12
+
13
+ - [Features](#features)
14
+ - [Installation](#installation)
15
+ - [Quick Start](#quick-start)
16
+ - [Design Philosophy](#design-philosophy)
17
+ - [Section Types](#section-types)
18
+ - [API Reference](#api-reference)
19
+ - [CSS Isolation](#css-isolation)
20
+ - [Examples](#examples)
21
+
11
22
  ## Features
12
23
 
13
24
  - 🖨️ **Dual Environment** - Works seamlessly in both browser and Node.js
@@ -23,17 +34,7 @@ A schema-driven medical form print renderer that transforms structured form data
23
34
  ## Installation
24
35
 
25
36
  ```bash
26
- # npm
27
37
  npm install medical-form-printer
28
-
29
- # yarn
30
- yarn add medical-form-printer
31
-
32
- # pnpm
33
- pnpm add medical-form-printer
34
-
35
- # bun
36
- bun add medical-form-printer
37
38
  ```
38
39
 
39
40
  For PDF generation in Node.js, install Puppeteer as a peer dependency:
@@ -49,12 +50,11 @@ npm install puppeteer
49
50
  ```typescript
50
51
  import { renderToHtml } from 'medical-form-printer'
51
52
 
52
- const printSchema = {
53
+ const schema = {
53
54
  pageSize: 'A4',
54
55
  orientation: 'portrait',
55
56
  header: {
56
57
  hospital: 'Sample Hospital',
57
- department: 'Postpartum Care Center',
58
58
  title: 'Patient Assessment Form',
59
59
  },
60
60
  sections: [
@@ -62,487 +62,370 @@ const printSchema = {
62
62
  type: 'info-grid',
63
63
  config: {
64
64
  columns: 4,
65
- rows: [
66
- {
67
- cells: [
68
- { label: 'Name', field: 'name', type: 'text' },
69
- { label: 'Age', field: 'age', type: 'number' },
70
- { label: 'Date', field: 'admissionDate', type: 'date' },
71
- { label: 'Room', field: 'roomNumber', type: 'text' },
72
- ]
73
- }
74
- ]
65
+ rows: [{
66
+ cells: [
67
+ { label: 'Name', field: 'name' },
68
+ { label: 'Age', field: 'age' },
69
+ { label: 'Date', field: 'date', type: 'date' },
70
+ { label: 'Room', field: 'room' },
71
+ ]
72
+ }]
75
73
  }
76
74
  }
77
- ],
78
- footer: {
79
- showPageNumber: true
80
- }
75
+ ]
81
76
  }
82
77
 
83
- const formData = {
84
- name: 'Jane Doe',
85
- age: 28,
86
- admissionDate: '2024-01-15',
87
- roomNumber: 'A-101'
88
- }
89
-
90
- // Render to HTML
91
- const html = renderToHtml(printSchema, formData, {
92
- watermark: 'Internal Use Only'
93
- })
94
-
95
- // Display in iframe or div
96
- document.getElementById('preview').innerHTML = html
78
+ const data = { name: 'Jane Doe', age: 28, date: '2024-01-15', room: 'A-101' }
79
+ const html = renderToHtml(schema, data)
97
80
  ```
98
81
 
99
- ### Node.js Usage (PDF Generation)
82
+ ### Node.js Usage (PDF)
100
83
 
101
84
  ```typescript
102
- import { renderToPdf, mergePdfs } from 'medical-form-printer/node'
85
+ import { renderToPdf } from 'medical-form-printer/node'
103
86
  import fs from 'fs'
104
87
 
105
- // Generate single PDF
106
- const pdfBuffer = await renderToPdf(printSchema, formData, {
107
- watermark: 'Confidential'
108
- })
109
- fs.writeFileSync('assessment.pdf', pdfBuffer)
110
-
111
- // Merge multiple forms into one PDF
112
- const mergedPdf = await mergePdfs([
113
- { schema: maternalSchema, data: maternalData },
114
- { schema: newbornSchema, data: newbornData },
115
- ])
116
- fs.writeFileSync('complete-record.pdf', mergedPdf)
88
+ const pdfBuffer = await renderToPdf(schema, data)
89
+ fs.writeFileSync('form.pdf', pdfBuffer)
117
90
  ```
118
91
 
119
- ## API Reference
92
+ ## Design Philosophy
120
93
 
121
- ### Core Rendering
94
+ ### Why Flat Sections Instead of Nested Components?
122
95
 
123
- #### `renderToHtml(schema, data, options?)`
124
-
125
- Renders a print schema with form data to an HTML string.
126
-
127
- ```typescript
128
- import { renderToHtml } from 'medical-form-printer'
96
+ Many document rendering systems use deeply nested component hierarchies:
129
97
 
130
- const html = renderToHtml(printSchema, formData, {
131
- theme: customTheme,
132
- watermark: 'Draft',
133
- watermarkOpacity: 0.1
134
- })
98
+ ```
99
+ Document → Page → Container → Row → Cell → Element
135
100
  ```
136
101
 
137
- **Parameters:**
138
- - `schema: PrintSchema` - The print schema defining layout and sections
139
- - `data: FormData` - The form data to render
140
- - `options?: RenderOptions` - Optional rendering configuration
102
+ We deliberately chose a **flat section-based model**. Here's why:
141
103
 
142
- **Returns:** `string` - Complete HTML document
104
+ #### 1. Print Documents UI Components
143
105
 
144
- #### `renderToIsolatedHtml(schema, data, options?)`
106
+ Print documents are **static output**. A medical form doesn't need a `<Button>` that responds to clicks—it needs a checkbox symbol (☑/□) at the right position. Nested component trees add overhead without benefit.
145
107
 
146
- Renders with CSS isolation for consistent cross-environment styling.
108
+ #### 2. Domain-Driven Design
147
109
 
148
- ```typescript
149
- import { renderToIsolatedHtml } from 'medical-form-printer'
110
+ Sections map directly to **real-world medical form concepts**:
150
111
 
151
- const html = renderToIsolatedHtml(printSchema, formData, {
152
- watermark: 'Internal Use Only'
153
- })
154
- ```
112
+ | Section Type | Real-World Concept |
113
+ |--------------|-------------------|
114
+ | `info-grid` | Patient demographics block |
115
+ | `table` | Nursing records log |
116
+ | `checkbox-grid` | Symptom checklist |
117
+ | `signature-area` | Approval signatures |
155
118
 
156
- All content is wrapped in an isolation container with:
157
- - Namespaced CSS classes (prefixed with `mpr-`)
158
- - Embedded Source Han Serif SC font
159
- - Style containment for predictable rendering
119
+ Medical staff think in these terms, not abstract "containers" and "elements".
160
120
 
161
- #### `renderToIsolatedFragment(schema, data, options?)`
121
+ #### 3. Pagination-Friendly Architecture
162
122
 
163
- Renders an isolated HTML fragment for embedding in existing pages.
123
+ Flat sections enable **predictable pagination**:
164
124
 
165
125
  ```typescript
166
- import { renderToIsolatedFragment } from 'medical-form-printer'
167
-
168
- const fragment = renderToIsolatedFragment(printSchema, formData)
169
- document.getElementById('preview').innerHTML = fragment
126
+ type MeasurableItemType =
127
+ | 'header' // Page header - measured once
128
+ | 'section' // Atomic block - never split
129
+ | 'table-header' // Repeats on continuation pages
130
+ | 'table-row' // Can be paginated individually
131
+ | 'signature' // Usually pinned to last page
132
+ | 'footer' // Page footer - measured once
170
133
  ```
171
134
 
172
- ### PDF Generation (Node.js)
173
-
174
- #### `renderToPdf(schema, data, options?)`
175
-
176
- Generates a PDF buffer from a print schema.
135
+ #### 4. Schema Simplicity
177
136
 
178
137
  ```typescript
179
- import { renderToPdf } from 'medical-form-printer/node'
138
+ // Nested approach (verbose)
139
+ {
140
+ type: 'container',
141
+ children: [{
142
+ type: 'container',
143
+ children: [
144
+ { type: 'label', text: 'Name:' },
145
+ { type: 'field', binding: 'name' }
146
+ ]
147
+ }]
148
+ }
180
149
 
181
- const pdfBuffer = await renderToPdf(printSchema, formData, {
182
- watermark: 'Confidential',
183
- pdfOptions: {
184
- format: 'A4',
185
- printBackground: true
150
+ // Flat approach (concise)
151
+ {
152
+ type: 'info-grid',
153
+ config: {
154
+ rows: [{ cells: [{ label: 'Name', field: 'name' }] }]
186
155
  }
187
- })
156
+ }
188
157
  ```
189
158
 
190
- **Parameters:**
191
- - `schema: PrintSchema` - The print schema
192
- - `data: FormData` - The form data
193
- - `options?: RenderOptions & { pdfOptions?: PdfOptions }` - Rendering and PDF options
194
-
195
- **Returns:** `Promise<Buffer>` - PDF file buffer
196
-
197
- #### `mergePdfs(documents, options?)`
198
-
199
- Merges multiple documents into a single PDF.
159
+ #### 5. Simple Extensibility
200
160
 
201
161
  ```typescript
202
- import { mergePdfs } from 'medical-form-printer/node'
203
-
204
- const mergedPdf = await mergePdfs([
205
- { schema: schema1, data: data1 },
206
- { schema: schema2, data: data2 },
207
- ], {
208
- watermark: 'Complete Record'
162
+ registerSectionRenderer('vital-signs-chart', (config, data) => {
163
+ return '<div class="chart">...</div>'
209
164
  })
210
165
  ```
211
166
 
212
- ### Custom Section Renderers
167
+ No abstract base classes or visitor patterns needed.
213
168
 
214
- #### `registerSectionRenderer(type, renderer)`
169
+ ### Trade-offs
215
170
 
216
- Registers a custom section renderer for specialized content.
171
+ This design optimizes for **print document generation**. For deeply nested layouts or interactive components, consider general-purpose HTML templating or UI frameworks.
217
172
 
218
- ```typescript
219
- import { registerSectionRenderer } from 'medical-form-printer'
220
-
221
- registerSectionRenderer('vital-signs-chart', (config, data, options) => {
222
- const values = data[config.dataField] || []
223
- return `
224
- <div class="vital-signs-chart">
225
- <h3>${config.title}</h3>
226
- <!-- Custom chart rendering -->
227
- </div>
228
- `
229
- })
230
- ```
173
+ ## Section Types
231
174
 
232
- #### `getSectionRenderer(type)`
175
+ | Type | Description | Use Case |
176
+ |------|-------------|----------|
177
+ | `info-grid` | Grid layout for key-value pairs | Patient demographics |
178
+ | `table` | Data table with columns | Nursing records |
179
+ | `checkbox-grid` | Grid of checkbox options | Symptom checklists |
180
+ | `signature-area` | Signature fields | Approvals |
181
+ | `notes` | Static text content | Instructions |
182
+ | `free-text` | Multi-line text input | Comments |
233
183
 
234
- Retrieves a registered section renderer.
184
+ ### Info Grid
235
185
 
236
186
  ```typescript
237
- import { getSectionRenderer } from 'medical-form-printer'
238
-
239
- const renderer = getSectionRenderer('info-grid')
187
+ {
188
+ type: 'info-grid',
189
+ config: {
190
+ columns: 4,
191
+ rows: [{
192
+ cells: [
193
+ { label: 'Name', field: 'name' },
194
+ { label: 'Age', field: 'age', type: 'number' },
195
+ { label: 'Status', field: 'status', type: 'checkbox', options: ['Active'] }
196
+ ]
197
+ }]
198
+ }
199
+ }
240
200
  ```
241
201
 
242
- ### Pagination
243
-
244
- #### `renderPaginatedHtml(config)`
245
-
246
- Renders multi-page content with smart pagination.
202
+ ### Table
247
203
 
248
204
  ```typescript
249
- import {
250
- renderPaginatedHtml,
251
- calculatePageBreaks,
252
- PAGE_A4
253
- } from 'medical-form-printer'
205
+ {
206
+ type: 'table',
207
+ title: 'Nursing Records',
208
+ config: {
209
+ dataField: 'records',
210
+ columns: [
211
+ { header: 'Date', field: 'date', type: 'date', width: '20%' },
212
+ { header: 'Notes', field: 'notes' }
213
+ ]
214
+ }
215
+ }
216
+ ```
254
217
 
255
- const pageBreaks = calculatePageBreaks(measuredItems, {
256
- pageHeight: PAGE_A4.height,
257
- headerHeight: 60,
258
- footerHeight: 40,
259
- repeatTableHeaders: true
260
- })
218
+ #### Multi-Row Headers
219
+
220
+ Tables support complex multi-row headers with colspan and rowspan:
261
221
 
262
- const html = renderPaginatedHtml({
263
- schema: printSchema,
264
- data: formData,
265
- pageBreakResult: pageBreaks,
266
- measuredItems: items,
222
+ ```typescript
223
+ {
224
+ type: 'table',
225
+ title: 'Vital Signs',
267
226
  config: {
268
- isolated: true,
269
- showHeaderOnEachPage: true,
270
- continuationSuffix: '(continued)'
227
+ dataField: 'vitalSigns',
228
+ columns: [
229
+ { header: 'Date', field: 'date', type: 'date' },
230
+ { header: 'Systolic', field: 'systolic', type: 'number' },
231
+ { header: 'Diastolic', field: 'diastolic', type: 'number' },
232
+ { header: 'Temperature', field: 'temperature', type: 'number' },
233
+ ],
234
+ headerRows: [
235
+ {
236
+ cells: [
237
+ { text: 'Date', rowspan: 2 },
238
+ { text: 'Blood Pressure (mmHg)', colspan: 2 },
239
+ { text: 'Temperature (℃)', rowspan: 2 },
240
+ ]
241
+ },
242
+ {
243
+ cells: [
244
+ { text: 'Systolic', field: 'systolic' },
245
+ { text: 'Diastolic', field: 'diastolic' },
246
+ ]
247
+ }
248
+ ]
271
249
  }
272
- })
250
+ }
273
251
  ```
274
252
 
275
- #### Page Size Presets
253
+ ### Checkbox Grid
276
254
 
277
255
  ```typescript
278
- import { PAGE_A4, PAGE_A5, PAGE_16K, PAGE_PRESETS } from 'medical-form-printer'
279
-
280
- // PAGE_A4: { width: 210, height: 297 } (mm)
281
- // PAGE_A5: { width: 148, height: 210 } (mm)
282
- // PAGE_16K: { width: 185, height: 260 } (mm)
256
+ {
257
+ type: 'checkbox-grid',
258
+ config: {
259
+ field: 'symptoms',
260
+ columns: 4,
261
+ options: [
262
+ { value: 'fever', label: 'Fever' },
263
+ { value: 'headache', label: 'Headache' }
264
+ ]
265
+ }
266
+ }
283
267
  ```
284
268
 
285
- #### Unit Conversion
269
+ ### Signature Area
286
270
 
287
271
  ```typescript
288
- import { mmToPx, pxToMm, mmToPt, ptToMm } from 'medical-form-printer'
289
-
290
- const heightPx = mmToPx(297) // 297mm → pixels
291
- const heightMm = pxToMm(1123) // pixels → mm
272
+ {
273
+ type: 'signature-area',
274
+ config: {
275
+ fields: [
276
+ { label: 'Patient', field: 'patientSig' },
277
+ { label: 'Date', field: 'sigDate', type: 'date' }
278
+ ]
279
+ }
280
+ }
292
281
  ```
293
282
 
294
- ### Styling
283
+ ## API Reference
284
+
285
+ ### Core Rendering
295
286
 
296
- #### `generateCss(theme?)`
287
+ | Function | Description |
288
+ |----------|-------------|
289
+ | `renderToHtml(schema, data, options?)` | Render to HTML string |
290
+ | `renderToIsolatedHtml(schema, data, options?)` | Render with CSS isolation |
291
+ | `renderToIsolatedFragment(schema, data, options?)` | Render isolated fragment for embedding |
297
292
 
298
- Generates CSS styles for print rendering.
293
+ ### PDF Generation (Node.js)
299
294
 
300
295
  ```typescript
301
- import { generateCss, defaultTheme } from 'medical-form-printer'
296
+ import { renderToPdf, mergePdfs } from 'medical-form-printer/node'
297
+
298
+ // Single PDF
299
+ const pdf = await renderToPdf(schema, data, { watermark: 'Draft' })
302
300
 
303
- const css = generateCss(defaultTheme)
301
+ // Merge multiple documents
302
+ const merged = await mergePdfs([
303
+ { schema: schema1, data: data1 },
304
+ { schema: schema2, data: data2 }
305
+ ])
304
306
  ```
305
307
 
306
- #### `generateIsolatedCss(theme?)`
308
+ ### Pagination (Strategy Pattern)
307
309
 
308
- Generates isolated CSS with embedded fonts and namespaced classes.
310
+ ```typescript
311
+ import {
312
+ createDefaultPaginationContext,
313
+ SmartPaginationStrategy
314
+ } from 'medical-form-printer'
315
+
316
+ // Automatic strategy selection
317
+ const context = createDefaultPaginationContext()
318
+ const html = context.render(schema, data, { isolated: true })
319
+
320
+ // Or use specific strategy
321
+ const strategy = new SmartPaginationStrategy()
322
+ if (strategy.shouldApply(schema)) {
323
+ const html = strategy.render(schema, data)
324
+ }
325
+ ```
326
+
327
+ ### Custom Section Renderers
309
328
 
310
329
  ```typescript
311
- import { generateIsolatedCss } from 'medical-form-printer'
330
+ import { registerSectionRenderer, getSectionRenderer } from 'medical-form-printer'
312
331
 
313
- const css = generateIsolatedCss()
314
- // Includes @font-face, isolation container, and all component styles
332
+ registerSectionRenderer('custom-chart', (config, data, options) => {
333
+ return `<div class="chart">${config.title}</div>`
334
+ })
315
335
  ```
316
336
 
317
- #### Theme Customization
337
+ ### Theme Customization
318
338
 
319
339
  ```typescript
320
340
  import { renderToHtml, mergeTheme, defaultTheme } from 'medical-form-printer'
321
341
 
322
- const customTheme = mergeTheme(defaultTheme, {
323
- fonts: {
324
- body: '"Microsoft YaHei", "PingFang SC", sans-serif',
325
- heading: '"Microsoft YaHei", "PingFang SC", sans-serif'
326
- },
327
- colors: {
328
- primary: '#1a1a1a',
329
- border: '#333333',
330
- background: '#ffffff'
331
- },
332
- fontSize: {
333
- body: '10pt',
334
- heading: '14pt',
335
- small: '8pt'
336
- },
337
- spacing: {
338
- section: '12pt',
339
- cell: '4pt'
340
- }
342
+ const theme = mergeTheme(defaultTheme, {
343
+ colors: { primary: '#1a1a1a', border: '#333' },
344
+ fontSize: { body: '10pt', heading: '14pt' }
341
345
  })
342
346
 
343
- const html = renderToHtml(schema, data, { theme: customTheme })
347
+ const html = renderToHtml(schema, data, { theme })
348
+ ```
349
+
350
+ ### Page Sizes & Units
351
+
352
+ ```typescript
353
+ import { PAGE_A4, PAGE_A5, PAGE_16K, mmToPx, pxToMm } from 'medical-form-printer'
354
+
355
+ // PAGE_A4: { width: 210, height: 297 } (mm)
356
+ const heightPx = mmToPx(297) // mm → pixels
344
357
  ```
345
358
 
346
359
  ### Formatters
347
360
 
348
361
  ```typescript
349
- import {
350
- formatDate,
351
- formatBoolean,
352
- formatNumber,
353
- formatValue,
354
- isChecked
355
- } from 'medical-form-printer'
362
+ import { formatDate, formatBoolean, formatNumber } from 'medical-form-printer'
356
363
 
357
- formatDate('2024-01-15') // '2024-01-15'
364
+ formatDate('2024-01-15') // '2024-01-15'
358
365
  formatDate('2024-01-15', { format: 'YYYY年MM月DD日' }) // '2024年01月15日'
359
- formatBoolean(true) // '✓'
360
- formatBoolean(false) // ''
361
- formatNumber(1234.5, { decimals: 2 }) // '1234.50'
362
- isChecked('yes', ['yes', 'true']) // true
366
+ formatBoolean(true) // '✓'
367
+ formatNumber(1234.5, { decimals: 2 }) // '1234.50'
363
368
  ```
364
369
 
365
- ### HTML Builder Utilities
370
+ ## CSS Isolation
366
371
 
367
- ```typescript
368
- import {
369
- HtmlBuilder,
370
- h,
371
- fragment,
372
- when,
373
- each,
374
- escapeHtml
375
- } from 'medical-form-printer'
372
+ For consistent cross-environment rendering:
376
373
 
377
- // Fluent HTML building
378
- const html = h('div', { class: 'container' },
379
- h('h1', {}, 'Title'),
380
- when(showContent, () => h('p', {}, 'Content')),
381
- each(items, (item) => h('li', {}, item.name))
382
- )
374
+ ```typescript
375
+ import { renderToIsolatedHtml, CSS_NAMESPACE } from 'medical-form-printer'
383
376
 
384
- // Safe HTML escaping
385
- const safe = escapeHtml('<script>alert("xss")</script>')
377
+ const html = renderToIsolatedHtml(schema, data)
378
+ // CSS_NAMESPACE = 'mpr' (all classes prefixed with mpr-)
386
379
  ```
387
380
 
381
+ Isolation mode provides:
382
+ - Namespaced CSS classes (`mpr-` prefix)
383
+ - Embedded Source Han Serif SC font
384
+ - CSS containment for predictable rendering
385
+
388
386
  ## PrintSchema Structure
389
387
 
390
388
  ```typescript
391
389
  interface PrintSchema {
392
390
  pageSize: 'A4' | 'A5' | '16K'
393
391
  orientation: 'portrait' | 'landscape'
392
+ baseUnit?: number // Scaling factor (default: 1)
394
393
  header: {
395
394
  hospital: string
396
395
  department?: string
397
396
  title: string
398
- subtitle?: string
399
397
  }
400
398
  sections: PrintSection[]
401
399
  footer?: {
402
400
  showPageNumber?: boolean
403
- pageNumberFormat?: string
404
401
  notes?: string
405
402
  }
406
403
  }
407
404
  ```
408
405
 
409
- ## Section Types
410
-
411
- | Type | Description | Use Case |
412
- |------|-------------|----------|
413
- | `info-grid` | Grid layout for key-value pairs | Patient demographics, basic info |
414
- | `table` | Data table with columns | Nursing records, medication logs |
415
- | `checkbox-grid` | Grid of checkbox options | Assessment checklists, symptoms |
416
- | `signature-area` | Signature fields with labels | Approvals, acknowledgments |
417
- | `notes` | Static text content | Instructions, disclaimers |
418
- | `free-text` | Multi-line text input | Comments, observations |
419
-
420
- ### Info Grid Section
421
-
422
- ```typescript
423
- {
424
- type: 'info-grid',
425
- config: {
426
- columns: 4,
427
- rows: [
428
- {
429
- cells: [
430
- { label: 'Name', field: 'name', type: 'text' },
431
- { label: 'Age', field: 'age', type: 'number', span: 1 },
432
- { label: 'Date', field: 'date', type: 'date' },
433
- { label: 'Status', field: 'status', type: 'checkbox', options: ['Active'] }
434
- ]
435
- }
436
- ]
437
- }
438
- }
439
- ```
440
-
441
- ### Table Section
442
-
443
- ```typescript
444
- {
445
- type: 'table',
446
- title: 'Nursing Records',
447
- config: {
448
- dataField: 'nursingRecords',
449
- columns: [
450
- { header: 'Date', field: 'date', type: 'date', width: '15%' },
451
- { header: 'Time', field: 'time', type: 'text', width: '10%' },
452
- { header: 'Temperature', field: 'temperature', type: 'number', width: '15%' },
453
- { header: 'Notes', field: 'notes', type: 'text' }
454
- ]
455
- }
456
- }
457
- ```
458
-
459
- ### Checkbox Grid Section
460
-
461
- ```typescript
462
- {
463
- type: 'checkbox-grid',
464
- title: 'Symptoms Assessment',
465
- config: {
466
- field: 'symptoms',
467
- columns: 4,
468
- options: [
469
- { value: 'fever', label: 'Fever' },
470
- { value: 'headache', label: 'Headache' },
471
- { value: 'fatigue', label: 'Fatigue' },
472
- { value: 'nausea', label: 'Nausea' }
473
- ]
474
- }
475
- }
476
- ```
477
-
478
- ### Signature Area Section
479
-
480
- ```typescript
481
- {
482
- type: 'signature-area',
483
- config: {
484
- fields: [
485
- { label: 'Patient Signature', field: 'patientSignature' },
486
- { label: 'Nurse Signature', field: 'nurseSignature' },
487
- { label: 'Date', field: 'signatureDate', type: 'date' }
488
- ]
489
- }
490
- }
491
- ```
492
-
493
- ## CSS Isolation
494
-
495
- For consistent rendering across different environments, use isolation mode:
496
-
497
- ```typescript
498
- import {
499
- renderToIsolatedHtml,
500
- CSS_NAMESPACE,
501
- ISOLATION_ROOT_CLASS,
502
- namespaceClass,
503
- namespaceClasses
504
- } from 'medical-form-printer'
505
-
506
- // CSS_NAMESPACE = 'mpr'
507
- // ISOLATION_ROOT_CLASS = 'mpr-root'
508
-
509
- // Namespace utilities
510
- namespaceClass('header') // 'mpr-header'
511
- namespaceClasses(['header', 'footer']) // ['mpr-header', 'mpr-footer']
512
- ```
513
-
514
- Isolation mode provides:
515
- - All classes prefixed with `mpr-` namespace
516
- - Embedded Source Han Serif SC font (subset for CJK support)
517
- - CSS containment (`contain: layout style`)
518
- - Consistent rendering regardless of host page styles
519
-
520
406
  ## Examples
521
407
 
522
- See the [examples](./examples) directory for complete working examples:
408
+ See the [examples](./examples) directory:
523
409
 
524
- - [Browser Example](./examples/browser) - Vanilla HTML/JS usage
525
- - [Node.js Example](./examples/node) - PDF generation with file output
410
+ - [Browser Example](./examples/browser) - Vanilla HTML/JS
411
+ - [Node.js Example](./examples/node) - PDF generation
526
412
 
527
413
  ## Storybook
528
414
 
529
- Interactive component documentation is available via Storybook:
530
-
531
415
  ```bash
532
416
  npm run storybook
533
417
  ```
534
418
 
535
419
  ## Contributing
536
420
 
537
- Contributions are welcome! Please read our [Contributing Guide](./CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
421
+ See [CONTRIBUTING.md](./CONTRIBUTING.md)
538
422
 
539
423
  ## License
540
424
 
541
- [MIT](./LICENSE) © 2024
425
+ [MIT](./LICENSE)
542
426
 
543
427
  ## Links
544
428
 
545
- - [GitHub Repository](https://github.com/wangchengshi-ship-it/medical-form-printer)
546
- - [npm Package](https://www.npmjs.com/package/medical-form-printer)
547
- - [Issue Tracker](https://github.com/wangchengshi-ship-it/medical-form-printer/issues)
429
+ - [GitHub](https://github.com/wangchengshi-ship-it/medical-form-printer)
430
+ - [npm](https://www.npmjs.com/package/medical-form-printer)
548
431
  - [Changelog](./CHANGELOG.md)