@uurtech/jdf 0.1.13 → 0.1.16

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/jdfjs.css CHANGED
@@ -223,3 +223,138 @@ jdf {
223
223
  width: 100%;
224
224
  min-height: 600px;
225
225
  }
226
+
227
+ /* === Form elements ====================================================== */
228
+ .jdfjs-form-field {
229
+ display: flex;
230
+ flex-direction: column;
231
+ gap: 4px;
232
+ font-family: "Inter", -apple-system, sans-serif;
233
+ font-size: 12px;
234
+ color: var(--jdfjs-text);
235
+ width: 100%;
236
+ height: 100%;
237
+ }
238
+
239
+ .jdfjs-form-label {
240
+ font-size: 11px;
241
+ font-weight: 600;
242
+ color: var(--jdfjs-text-soft);
243
+ letter-spacing: 0.02em;
244
+ }
245
+
246
+ .jdfjs-form-control {
247
+ display: block;
248
+ width: 100%;
249
+ padding: 6px 10px;
250
+ font: inherit;
251
+ color: var(--jdfjs-text);
252
+ background: var(--jdfjs-bg);
253
+ border: 1px solid var(--jdfjs-border);
254
+ border-radius: 6px;
255
+ transition: border-color 0.12s ease, box-shadow 0.12s ease;
256
+ box-sizing: border-box;
257
+ }
258
+ .jdfjs-form-control:focus {
259
+ outline: none;
260
+ border-color: var(--jdfjs-brand);
261
+ box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.16);
262
+ }
263
+ .jdfjs-form-control[readonly],
264
+ .jdfjs-form-control:disabled {
265
+ background: var(--jdfjs-bg-soft, #f3f4f6);
266
+ color: var(--jdfjs-text-soft);
267
+ cursor: not-allowed;
268
+ }
269
+
270
+ textarea.jdfjs-form-control {
271
+ resize: vertical;
272
+ min-height: 60px;
273
+ line-height: 1.4;
274
+ }
275
+
276
+ .jdfjs-form-checkbox {
277
+ flex-direction: row;
278
+ align-items: center;
279
+ gap: 8px;
280
+ cursor: pointer;
281
+ }
282
+ .jdfjs-form-checkbox input[type="checkbox"] {
283
+ width: 16px; height: 16px;
284
+ margin: 0;
285
+ cursor: pointer;
286
+ accent-color: var(--jdfjs-brand);
287
+ }
288
+ .jdfjs-form-checkbox-label {
289
+ font-size: 13px;
290
+ color: var(--jdfjs-text);
291
+ user-select: none;
292
+ }
293
+
294
+ select.jdfjs-form-control {
295
+ appearance: none;
296
+ -webkit-appearance: none;
297
+ background-image: linear-gradient(45deg, transparent 50%, var(--jdfjs-text-soft) 50%),
298
+ linear-gradient(135deg, var(--jdfjs-text-soft) 50%, transparent 50%);
299
+ background-position: calc(100% - 16px) 50%, calc(100% - 11px) 50%;
300
+ background-size: 5px 5px, 5px 5px;
301
+ background-repeat: no-repeat;
302
+ padding-right: 28px;
303
+ }
304
+
305
+ .jdfjs-form-signature-canvas {
306
+ border: 1px dashed var(--jdfjs-border);
307
+ border-radius: 6px;
308
+ background: var(--jdfjs-bg);
309
+ cursor: crosshair;
310
+ touch-action: none;
311
+ }
312
+ .jdfjs-form-signature-clear {
313
+ align-self: flex-start;
314
+ margin-top: 4px;
315
+ padding: 2px 10px;
316
+ font-size: 11px;
317
+ color: var(--jdfjs-text-soft);
318
+ background: transparent;
319
+ border: 1px solid var(--jdfjs-border);
320
+ border-radius: 4px;
321
+ cursor: pointer;
322
+ }
323
+ .jdfjs-form-signature-clear:hover {
324
+ color: var(--jdfjs-text);
325
+ border-color: var(--jdfjs-text-soft);
326
+ }
327
+
328
+ /* === Save button (auto-init's `save-button` attribute) ================= */
329
+ .jdfjs-save-button {
330
+ position: absolute;
331
+ bottom: 16px;
332
+ right: 16px;
333
+ z-index: 5;
334
+ padding: 8px 16px;
335
+ font-family: "Inter", -apple-system, sans-serif;
336
+ font-size: 13px;
337
+ font-weight: 600;
338
+ color: #fff;
339
+ background: var(--jdfjs-brand);
340
+ border: 0;
341
+ border-radius: 8px;
342
+ box-shadow: 0 4px 14px rgba(37, 99, 235, 0.25);
343
+ cursor: pointer;
344
+ transition: transform 0.12s ease, box-shadow 0.12s ease, opacity 0.12s ease;
345
+ }
346
+ .jdfjs-save-button:hover {
347
+ transform: translateY(-1px);
348
+ box-shadow: 0 6px 18px rgba(37, 99, 235, 0.35);
349
+ }
350
+ .jdfjs-save-button:active {
351
+ transform: translateY(0);
352
+ }
353
+
354
+ .jdfjs-dark .jdfjs-save-button {
355
+ background: #3b82f6;
356
+ }
357
+ .jdfjs-dark .jdfjs-form-control[readonly],
358
+ .jdfjs-dark .jdfjs-form-control:disabled {
359
+ background: #1f2937;
360
+ }
package/dist/jdfjs.d.cts CHANGED
@@ -45,11 +45,21 @@ interface JDFViewerOptions {
45
45
  onLoad?: (doc: JdfDocument) => void;
46
46
  /** Called on any rendering error */
47
47
  onError?: (err: Error) => void;
48
+ /**
49
+ * Called when a form field's value changes. Useful for live previews,
50
+ * dirty-state tracking, or auto-saving filled forms to a backend instead
51
+ * of triggering a manual download.
52
+ */
53
+ onFormChange?: (doc: JdfDocument, change: {
54
+ path: (string | number)[];
55
+ field: string;
56
+ value: unknown;
57
+ }) => void;
48
58
  }
49
59
  interface JDFViewerInstance {
50
60
  /** The container element */
51
61
  container: HTMLElement;
52
- /** The current document */
62
+ /** The current document — reflects user form input as the user types. */
53
63
  document: JdfDocument;
54
64
  /** Get / set zoom (1 = 100%) */
55
65
  setZoom: (zoom: number) => void;
@@ -61,11 +71,30 @@ interface JDFViewerInstance {
61
71
  setDocument: (doc: JdfDocument) => void;
62
72
  /** Tear down — removes DOM and event listeners */
63
73
  destroy: () => void;
74
+ /**
75
+ * Return the current document as a Blob — ready to attach to a form-data
76
+ * upload, save through `URL.createObjectURL`, or hand to a Worker. The
77
+ * blob reflects user form input (whatever the user has typed / ticked /
78
+ * selected). Pass `{ pretty: false }` for a compact JSON.
79
+ */
80
+ exportJdf: (options?: {
81
+ pretty?: boolean;
82
+ }) => Blob;
83
+ /** Return the current document as a JSON string (form-filled state). */
84
+ toJSON: (options?: {
85
+ pretty?: boolean;
86
+ }) => string;
87
+ /**
88
+ * Trigger a browser download of the current document. The host page's
89
+ * "Save" button can call this directly: `viewer.downloadJdf("form.jdf")`.
90
+ * Default filename is `<title>.jdf` from `meta.title`.
91
+ */
92
+ downloadJdf: (filename?: string) => void;
93
+ /** Read the value of a single form field by `name`. */
94
+ getFormValue: (name: string) => unknown;
95
+ /** Read every form field's value as a flat `{ [name]: value }` map. */
96
+ getFormValues: () => Record<string, unknown>;
64
97
  }
65
- /**
66
- * Embed a JDF document into a container by URL.
67
- * The simplest "PDF.js-like" usage.
68
- */
69
98
  declare function embed(container: HTMLElement | string, url: string, options?: JDFViewerOptions): Promise<JDFViewerInstance>;
70
99
  /**
71
100
  * Render a JDF document directly into a container. No fetch.
@@ -86,10 +115,20 @@ declare class JDFViewer {
86
115
  private sidebarEl;
87
116
  private root;
88
117
  private observer;
118
+ private darkModeMql;
119
+ private darkModeListener;
120
+ private windowResizeListener;
89
121
  constructor(container: HTMLElement, doc: JdfDocument, options?: JDFViewerOptions);
90
122
  private applyContainerSize;
91
123
  private mount;
92
124
  private setupResizeObserver;
125
+ /**
126
+ * Apply the current `darkMode` option to the container. For `auto`, also
127
+ * subscribe to system colour-scheme changes so the embed flips when the
128
+ * user toggles their OS theme. Replaces a one-shot read at mount that
129
+ * froze the embed on its boot-time value.
130
+ */
131
+ private applyDarkMode;
93
132
  /** Auto-zoom for fit modes. */
94
133
  private applyFit;
95
134
  private buildToolbar;
@@ -106,6 +145,31 @@ declare class JDFViewer {
106
145
  goToPage(idx: number): void;
107
146
  getCurrentPage(): number;
108
147
  setDocument(doc: JdfDocument): void;
148
+ /**
149
+ * Apply a form-field value mutation to the in-memory document. Called by
150
+ * every form renderer on every keystroke / toggle / selection — the
151
+ * document carries the user's current state so `exportJdf()` returns a
152
+ * filled JDF that's identical in shape to the source, just with values.
153
+ *
154
+ * No re-render: the DOM input already shows what the user typed, and a
155
+ * full re-render mid-typing would lose focus. The mutation only matters
156
+ * at export time.
157
+ */
158
+ private handleFormChange;
159
+ /**
160
+ * Walk every page's elements and yield each form element with its
161
+ * resolved name. Used by getFormValues / downloadJdf consumers.
162
+ */
163
+ private iterFormFields;
164
+ toJSON(options?: {
165
+ pretty?: boolean;
166
+ }): string;
167
+ exportJdf(options?: {
168
+ pretty?: boolean;
169
+ }): Blob;
170
+ downloadJdf(filename?: string): void;
171
+ getFormValue(name: string): unknown;
172
+ getFormValues(): Record<string, unknown>;
109
173
  destroy(): void;
110
174
  getInstance(): JDFViewerInstance;
111
175
  }
package/dist/jdfjs.d.ts CHANGED
@@ -45,11 +45,21 @@ interface JDFViewerOptions {
45
45
  onLoad?: (doc: JdfDocument) => void;
46
46
  /** Called on any rendering error */
47
47
  onError?: (err: Error) => void;
48
+ /**
49
+ * Called when a form field's value changes. Useful for live previews,
50
+ * dirty-state tracking, or auto-saving filled forms to a backend instead
51
+ * of triggering a manual download.
52
+ */
53
+ onFormChange?: (doc: JdfDocument, change: {
54
+ path: (string | number)[];
55
+ field: string;
56
+ value: unknown;
57
+ }) => void;
48
58
  }
49
59
  interface JDFViewerInstance {
50
60
  /** The container element */
51
61
  container: HTMLElement;
52
- /** The current document */
62
+ /** The current document — reflects user form input as the user types. */
53
63
  document: JdfDocument;
54
64
  /** Get / set zoom (1 = 100%) */
55
65
  setZoom: (zoom: number) => void;
@@ -61,11 +71,30 @@ interface JDFViewerInstance {
61
71
  setDocument: (doc: JdfDocument) => void;
62
72
  /** Tear down — removes DOM and event listeners */
63
73
  destroy: () => void;
74
+ /**
75
+ * Return the current document as a Blob — ready to attach to a form-data
76
+ * upload, save through `URL.createObjectURL`, or hand to a Worker. The
77
+ * blob reflects user form input (whatever the user has typed / ticked /
78
+ * selected). Pass `{ pretty: false }` for a compact JSON.
79
+ */
80
+ exportJdf: (options?: {
81
+ pretty?: boolean;
82
+ }) => Blob;
83
+ /** Return the current document as a JSON string (form-filled state). */
84
+ toJSON: (options?: {
85
+ pretty?: boolean;
86
+ }) => string;
87
+ /**
88
+ * Trigger a browser download of the current document. The host page's
89
+ * "Save" button can call this directly: `viewer.downloadJdf("form.jdf")`.
90
+ * Default filename is `<title>.jdf` from `meta.title`.
91
+ */
92
+ downloadJdf: (filename?: string) => void;
93
+ /** Read the value of a single form field by `name`. */
94
+ getFormValue: (name: string) => unknown;
95
+ /** Read every form field's value as a flat `{ [name]: value }` map. */
96
+ getFormValues: () => Record<string, unknown>;
64
97
  }
65
- /**
66
- * Embed a JDF document into a container by URL.
67
- * The simplest "PDF.js-like" usage.
68
- */
69
98
  declare function embed(container: HTMLElement | string, url: string, options?: JDFViewerOptions): Promise<JDFViewerInstance>;
70
99
  /**
71
100
  * Render a JDF document directly into a container. No fetch.
@@ -86,10 +115,20 @@ declare class JDFViewer {
86
115
  private sidebarEl;
87
116
  private root;
88
117
  private observer;
118
+ private darkModeMql;
119
+ private darkModeListener;
120
+ private windowResizeListener;
89
121
  constructor(container: HTMLElement, doc: JdfDocument, options?: JDFViewerOptions);
90
122
  private applyContainerSize;
91
123
  private mount;
92
124
  private setupResizeObserver;
125
+ /**
126
+ * Apply the current `darkMode` option to the container. For `auto`, also
127
+ * subscribe to system colour-scheme changes so the embed flips when the
128
+ * user toggles their OS theme. Replaces a one-shot read at mount that
129
+ * froze the embed on its boot-time value.
130
+ */
131
+ private applyDarkMode;
93
132
  /** Auto-zoom for fit modes. */
94
133
  private applyFit;
95
134
  private buildToolbar;
@@ -106,6 +145,31 @@ declare class JDFViewer {
106
145
  goToPage(idx: number): void;
107
146
  getCurrentPage(): number;
108
147
  setDocument(doc: JdfDocument): void;
148
+ /**
149
+ * Apply a form-field value mutation to the in-memory document. Called by
150
+ * every form renderer on every keystroke / toggle / selection — the
151
+ * document carries the user's current state so `exportJdf()` returns a
152
+ * filled JDF that's identical in shape to the source, just with values.
153
+ *
154
+ * No re-render: the DOM input already shows what the user typed, and a
155
+ * full re-render mid-typing would lose focus. The mutation only matters
156
+ * at export time.
157
+ */
158
+ private handleFormChange;
159
+ /**
160
+ * Walk every page's elements and yield each form element with its
161
+ * resolved name. Used by getFormValues / downloadJdf consumers.
162
+ */
163
+ private iterFormFields;
164
+ toJSON(options?: {
165
+ pretty?: boolean;
166
+ }): string;
167
+ exportJdf(options?: {
168
+ pretty?: boolean;
169
+ }): Blob;
170
+ downloadJdf(filename?: string): void;
171
+ getFormValue(name: string): unknown;
172
+ getFormValues(): Record<string, unknown>;
109
173
  destroy(): void;
110
174
  getInstance(): JDFViewerInstance;
111
175
  }