@json-to-office/core-docx 1.11.0 → 2.1.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.
Files changed (39) hide show
  1. package/dist/core/tableModel.d.ts +1 -1
  2. package/dist/core/tableModel.d.ts.map +1 -1
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +357 -548
  6. package/dist/index.js.map +1 -1
  7. package/dist/plugin/example/index.d.ts.map +1 -1
  8. package/dist/plugin/example/index.js +586 -863
  9. package/dist/plugin/example/index.js.map +1 -1
  10. package/dist/plugin/example/plugin-demo.json +16 -93
  11. package/dist/plugin/example/weather.component.d.ts +73 -9
  12. package/dist/plugin/example/weather.component.d.ts.map +1 -1
  13. package/dist/styles/index.d.ts +1 -1
  14. package/dist/styles/index.d.ts.map +1 -1
  15. package/dist/templates/documents/field-review.docx.json +1148 -0
  16. package/dist/templates/documents/index.d.ts +2 -2
  17. package/dist/templates/documents/index.d.ts.map +1 -1
  18. package/dist/templates/documents/practice-note.docx.json +917 -0
  19. package/dist/templates/themes/devportal.docx.theme.json +110 -44
  20. package/dist/templates/themes/index.d.ts +2 -2
  21. package/dist/templates/themes/index.d.ts.map +1 -1
  22. package/dist/templates/themes/minimal.docx.theme.json +124 -127
  23. package/dist/templates/themes/vermilion.docx.theme.json +82 -1
  24. package/dist/tsconfig.tsbuildinfo +1 -1
  25. package/dist/utils/listLevels.d.ts.map +1 -1
  26. package/package.json +3 -3
  27. package/dist/plugin/example/columns-layout.component.d.ts +0 -29
  28. package/dist/plugin/example/columns-layout.component.d.ts.map +0 -1
  29. package/dist/plugin/example/eldermoor-census.component.d.ts +0 -32
  30. package/dist/plugin/example/eldermoor-census.component.d.ts.map +0 -1
  31. package/dist/plugin/example/nested-section.component.d.ts +0 -16
  32. package/dist/plugin/example/nested-section.component.d.ts.map +0 -1
  33. package/dist/plugin/example/text-space-after.component.d.ts +0 -22
  34. package/dist/plugin/example/text-space-after.component.d.ts.map +0 -1
  35. package/dist/templates/documents/proposal.docx.json +0 -8205
  36. package/dist/templates/documents/technical-guide.docx.json +0 -10220
  37. package/dist/templates/themes/apex.docx.theme.json +0 -117
  38. package/dist/templates/themes/corporate.docx.theme.json +0 -114
  39. package/dist/templates/themes/modern.docx.theme.json +0 -109
@@ -184,545 +184,181 @@ var minimal_docx_theme_default;
184
184
  var init_minimal_docx_theme = __esm({
185
185
  "src/templates/themes/minimal.docx.theme.json"() {
186
186
  minimal_docx_theme_default = {
187
- $schema: "../../../../shared/json-schemas/theme.schema.json",
188
187
  name: "minimal",
189
188
  displayName: "Minimal Clean",
190
- description: "A clean, minimalist theme focused on readability and elegant simplicity",
191
- version: "2.0.0",
189
+ description: "A quiet, warm minimal theme \u2014 Calibri throughout, sage-green ink on ivory neutrals, a large tracked-tight bold title, wide margins and hairline rules",
190
+ version: "4.0.0",
192
191
  colors: {
193
- primary: "#000000",
194
- secondary: "#666666",
195
- accent: "#2c3e50",
196
- background: "#ffffff",
197
- text: "#2c2c2c",
198
- border: "#f0f0f0",
199
- textPrimary: "#000000",
200
- textSecondary: "#4a4a4a",
201
- textMuted: "#999999",
202
- borderPrimary: "#e0e0e0",
203
- borderSecondary: "#f5f5f5",
204
- backgroundPrimary: "#ffffff",
205
- backgroundSecondary: "#fafafa"
206
- },
207
- fonts: {
208
- heading: {
209
- family: "Arial",
210
- size: 24
211
- },
212
- body: {
213
- family: "Arial",
214
- size: 11
215
- },
216
- mono: {
217
- family: "Menlo",
218
- size: 10
219
- },
220
- light: {
221
- family: "Arial",
222
- size: 24
223
- }
224
- },
225
- page: {
226
- size: "A4",
227
- margins: {
228
- top: 1440,
229
- bottom: 1440,
230
- left: 1080,
231
- right: 1080,
232
- header: 720,
233
- footer: 720,
234
- gutter: 0
235
- }
236
- },
237
- styles: {
238
- normal: {
239
- font: "body",
240
- color: "#000000",
241
- lineSpacing: {
242
- type: "multiple",
243
- value: 1.5
244
- },
245
- alignment: "justify",
246
- spacing: {
247
- after: 9
248
- }
249
- },
250
- heading1: {
251
- font: "light",
252
- size: 24,
253
- bold: false,
254
- color: "#000000",
255
- spacing: {
256
- before: 18,
257
- after: 12
258
- },
259
- keepNext: true,
260
- alignment: "left",
261
- characterSpacing: {
262
- type: "expanded",
263
- value: 1.2
264
- }
265
- },
266
- heading2: {
267
- font: "light",
268
- size: 20,
269
- bold: false,
270
- color: "#000000",
271
- spacing: {
272
- before: 12,
273
- after: 9
274
- },
275
- keepNext: true,
276
- alignment: "left",
277
- characterSpacing: {
278
- type: "expanded",
279
- value: 0.8
280
- }
281
- },
282
- heading3: {
283
- font: "heading",
284
- size: 16,
285
- bold: false,
286
- color: "#2c2c2c",
287
- spacing: {
288
- before: 9,
289
- after: 6
290
- },
291
- keepNext: true,
292
- alignment: "left"
293
- },
294
- heading4: {
295
- font: "heading",
296
- size: 14,
297
- bold: true,
298
- color: "#4a4a4a",
299
- spacing: {
300
- before: 6,
301
- after: 4
302
- },
303
- keepNext: true
304
- },
305
- heading5: {
306
- font: "heading",
307
- size: 12,
308
- bold: false,
309
- italic: true,
310
- color: "#666666",
311
- spacing: {
312
- before: 4,
313
- after: 3
314
- }
315
- },
316
- heading6: {
317
- font: "light",
318
- size: 11,
319
- bold: false,
320
- color: "#999999",
321
- spacing: {
322
- before: 3,
323
- after: 2
324
- }
325
- },
326
- title: {
327
- font: "light",
328
- bold: false,
329
- color: "#000000",
330
- alignment: "left",
331
- spacing: {
332
- before: 0,
333
- after: 24
334
- },
335
- characterSpacing: {
336
- type: "condensed",
337
- value: 20
338
- }
339
- },
340
- subtitle: {
341
- font: "light",
342
- size: 16,
343
- italic: false,
344
- color: "#666666",
345
- alignment: "left",
346
- spacing: {
347
- before: 0,
348
- after: 18
349
- }
350
- }
351
- },
352
- componentDefaults: {
353
- table: {
354
- borderColor: "#f0f0f0"
355
- },
356
- list: {
357
- format: "bullet",
358
- bullet: "\u2022"
359
- },
360
- image: {
361
- alignment: "left"
362
- },
363
- statistic: {
364
- alignment: "left"
365
- },
366
- section: {
367
- pageBreak: false
368
- }
369
- }
370
- };
371
- }
372
- });
373
-
374
- // src/templates/themes/corporate.docx.theme.json
375
- var corporate_docx_theme_default;
376
- var init_corporate_docx_theme = __esm({
377
- "src/templates/themes/corporate.docx.theme.json"() {
378
- corporate_docx_theme_default = {
379
- name: "corporate",
380
- displayName: "Corporate Professional",
381
- description: "A polished corporate theme with blue accents and structured typography",
382
- version: "2.0.0",
383
- colors: {
384
- primary: "#1a365d",
385
- secondary: "#2D3748",
386
- accent: "#3182CE",
387
- text: "#1A202C",
192
+ primary: "#2B302B",
193
+ secondary: "#4A5B4E",
194
+ accent: "#6E7F71",
195
+ text: "#3B3C38",
388
196
  background: "#FFFFFF",
389
- border: "#E2E8F0",
390
- textPrimary: "#1A202C",
391
- textSecondary: "#4A5568",
392
- textMuted: "#A0AEC0",
393
- borderPrimary: "#CBD5E0",
394
- borderSecondary: "#E2E8F0",
197
+ border: "#D8D3C8",
198
+ textPrimary: "#3B3C38",
199
+ textSecondary: "#5B5B54",
200
+ textMuted: "#75726A",
201
+ borderPrimary: "#D8D3C8",
202
+ borderSecondary: "#E9E6DE",
395
203
  backgroundPrimary: "#FFFFFF",
396
- backgroundSecondary: "#F7FAFC"
204
+ backgroundSecondary: "#F1EFE9",
205
+ accent4: "#9AA69C",
206
+ accent5: "#C9CFC7",
207
+ accent6: "#B5AC9D"
397
208
  },
398
209
  fonts: {
399
- heading: { family: "Georgia", size: 26 },
400
- body: { family: "Calibri", size: 11 },
401
- mono: { family: "Consolas", size: 10 },
402
- light: { family: "Georgia", size: 26 }
210
+ heading: { family: "Calibri", size: 21 },
211
+ body: { family: "Calibri", size: 10 },
212
+ mono: { family: "Courier New", size: 10 },
213
+ light: { family: "Calibri", size: 21 }
403
214
  },
404
215
  page: {
405
216
  size: "A4",
406
217
  margins: {
407
- top: 1440,
408
- bottom: 1440,
409
- left: 1200,
410
- right: 1200,
411
- header: 720,
412
- footer: 720,
218
+ top: 1700,
219
+ bottom: 1700,
220
+ left: 1700,
221
+ right: 1700,
222
+ header: 850,
223
+ footer: 850,
413
224
  gutter: 0
414
225
  }
415
226
  },
416
227
  styles: {
417
228
  normal: {
418
229
  font: "body",
419
- color: "#1A202C",
420
- lineSpacing: { type: "multiple", value: 1.4 },
421
- alignment: "justify",
422
- spacing: { after: 8 }
423
- },
424
- heading1: {
425
- font: "heading",
426
- size: 26,
427
- bold: false,
428
- color: "primary",
429
- spacing: { before: 24, after: 12 },
430
- keepNext: true,
230
+ color: "textPrimary",
231
+ lineSpacing: { type: "multiple", value: 1.35 },
431
232
  alignment: "left",
432
- borders: {
433
- bottom: {
434
- style: "single",
435
- size: 2,
436
- color: "primary",
437
- space: 6
438
- }
439
- }
233
+ spacing: { after: 8 }
440
234
  },
441
- heading2: {
235
+ title: {
442
236
  font: "heading",
443
- size: 18,
444
- bold: false,
445
- color: "secondary",
446
- spacing: { before: 18, after: 8 },
447
- keepNext: true,
448
- alignment: "left"
449
- },
450
- heading3: {
451
- font: "body",
452
- size: 13,
237
+ size: 34,
453
238
  bold: true,
454
- color: "accent",
455
- spacing: { before: 12, after: 6 },
456
- keepNext: true,
457
- alignment: "left"
458
- },
459
- title: {
460
- font: "light",
461
- size: 32,
462
- bold: false,
463
239
  color: "primary",
464
240
  alignment: "left",
465
- spacing: { before: 0, after: 18 }
241
+ lineSpacing: { type: "multiple", value: 1 },
242
+ characterSpacing: { type: "condensed", value: 20 },
243
+ spacing: { before: 0, after: 11 }
466
244
  },
467
245
  subtitle: {
468
246
  font: "body",
469
- size: 16,
247
+ size: 13,
470
248
  italic: false,
471
249
  color: "textSecondary",
472
250
  alignment: "left",
473
- spacing: { before: 0, after: 24 }
474
- }
475
- },
476
- componentDefaults: {
477
- table: {
478
- borderColor: "#E2E8F0"
479
- },
480
- list: {
481
- format: "bullet",
482
- bullet: "\u2022"
483
- },
484
- statistic: {
485
- alignment: "center"
486
- },
487
- section: {
488
- pageBreak: false
489
- }
490
- }
491
- };
492
- }
493
- });
494
-
495
- // src/templates/themes/modern.docx.theme.json
496
- var modern_docx_theme_default;
497
- var init_modern_docx_theme = __esm({
498
- "src/templates/themes/modern.docx.theme.json"() {
499
- modern_docx_theme_default = {
500
- name: "modern",
501
- displayName: "Modern Clean",
502
- description: "A contemporary theme with vibrant accents and generous whitespace",
503
- version: "2.0.0",
504
- colors: {
505
- primary: "#6D28D9",
506
- secondary: "#1E293B",
507
- accent: "#0891B2",
508
- text: "#0F172A",
509
- background: "#FFFFFF",
510
- border: "#E2E8F0",
511
- textPrimary: "#0F172A",
512
- textSecondary: "#475569",
513
- textMuted: "#94A3B8",
514
- borderPrimary: "#CBD5E1",
515
- borderSecondary: "#E2E8F0",
516
- backgroundPrimary: "#FFFFFF",
517
- backgroundSecondary: "#F8FAFC"
518
- },
519
- fonts: {
520
- heading: { family: "Helvetica", size: 28 },
521
- body: { family: "Helvetica", size: 11 },
522
- mono: { family: "Menlo", size: 10 },
523
- light: { family: "Helvetica", size: 28 }
524
- },
525
- page: {
526
- size: "A4",
527
- margins: {
528
- top: 1440,
529
- bottom: 1440,
530
- left: 1080,
531
- right: 1080,
532
- header: 720,
533
- footer: 720,
534
- gutter: 0
535
- }
536
- },
537
- styles: {
538
- normal: {
539
- font: "body",
540
- color: "#0F172A",
541
- lineSpacing: { type: "multiple", value: 1.5 },
542
- alignment: "left",
543
- spacing: { after: 10 }
251
+ lineSpacing: { type: "multiple", value: 1.2 },
252
+ spacing: { before: 0, after: 22 }
544
253
  },
545
254
  heading1: {
546
255
  font: "heading",
547
- size: 28,
256
+ size: 21,
548
257
  bold: true,
549
258
  color: "primary",
550
- spacing: { before: 24, after: 14 },
259
+ lineSpacing: { type: "multiple", value: 1.15 },
260
+ spacing: { before: 30, after: 10 },
551
261
  keepNext: true,
552
262
  alignment: "left"
553
263
  },
554
264
  heading2: {
555
265
  font: "heading",
556
- size: 20,
266
+ size: 14.5,
557
267
  bold: true,
558
- color: "secondary",
559
- spacing: { before: 18, after: 10 },
268
+ color: "primary",
269
+ lineSpacing: { type: "multiple", value: 1.15 },
270
+ spacing: { before: 22, after: 8 },
560
271
  keepNext: true,
561
272
  alignment: "left"
562
273
  },
563
274
  heading3: {
564
- font: "body",
565
- size: 14,
275
+ font: "heading",
276
+ size: 12,
566
277
  bold: true,
567
- color: "accent",
568
- spacing: { before: 12, after: 6 },
278
+ color: "primary",
279
+ spacing: { before: 16, after: 6 },
569
280
  keepNext: true,
570
281
  alignment: "left"
571
282
  },
572
- title: {
573
- font: "heading",
574
- size: 36,
283
+ heading4: {
284
+ font: "body",
285
+ size: 10.5,
575
286
  bold: true,
576
287
  color: "primary",
577
- alignment: "left",
578
- spacing: { before: 0, after: 12 }
579
- },
580
- subtitle: {
581
- font: "light",
582
- size: 18,
583
- italic: false,
584
- color: "textSecondary",
585
- alignment: "left",
586
- spacing: { before: 0, after: 24 }
587
- }
588
- },
589
- componentDefaults: {
590
- table: {
591
- borderColor: "#E2E8F0"
592
- },
593
- list: {
594
- format: "bullet",
595
- bullet: "\u2013"
596
- },
597
- image: {
598
- alignment: "center"
599
- },
600
- statistic: {
601
- alignment: "center"
288
+ spacing: { before: 12, after: 4 },
289
+ keepNext: true,
290
+ alignment: "left"
602
291
  },
603
- section: {
604
- pageBreak: false
605
- }
606
- }
607
- };
608
- }
609
- });
610
-
611
- // src/templates/themes/apex.docx.theme.json
612
- var apex_docx_theme_default;
613
- var init_apex_docx_theme = __esm({
614
- "src/templates/themes/apex.docx.theme.json"() {
615
- apex_docx_theme_default = {
616
- name: "apex",
617
- displayName: "Apex Consulting",
618
- description: "A premium consulting theme with deep navy, warm amber accents, and authoritative typography",
619
- version: "2.0.0",
620
- colors: {
621
- primary: "#0C2340",
622
- secondary: "#1B3A5C",
623
- accent: "#D4A843",
624
- text: "#1A1A2E",
625
- background: "#FFFFFF",
626
- border: "#D6DAE0",
627
- textPrimary: "#1A1A2E",
628
- textSecondary: "#4A5066",
629
- textMuted: "#8B91A0",
630
- borderPrimary: "#B8BCC6",
631
- borderSecondary: "#E8EAF0",
632
- backgroundPrimary: "#FFFFFF",
633
- backgroundSecondary: "#F4F5F8"
634
- },
635
- fonts: {
636
- heading: { family: "Georgia", size: 26 },
637
- body: { family: "Calibri", size: 11 },
638
- mono: { family: "Consolas", size: 10 },
639
- light: { family: "Georgia", size: 26 }
640
- },
641
- page: {
642
- size: "A4",
643
- margins: {
644
- top: 1440,
645
- bottom: 1440,
646
- left: 1200,
647
- right: 1200,
648
- header: 720,
649
- footer: 720,
650
- gutter: 0
651
- }
652
- },
653
- styles: {
654
- normal: {
292
+ heading5: {
655
293
  font: "body",
656
- color: "textPrimary",
657
- lineSpacing: { type: "multiple", value: 1.4 },
658
- alignment: "justify",
659
- spacing: { after: 8 }
660
- },
661
- heading1: {
662
- font: "heading",
663
- size: 26,
294
+ size: 10.5,
664
295
  bold: false,
665
- color: "primary",
666
- spacing: { before: 24, after: 12 },
296
+ italic: true,
297
+ color: "textSecondary",
298
+ spacing: { before: 10, after: 4 },
667
299
  keepNext: true,
668
- alignment: "left",
669
- borders: {
670
- bottom: {
671
- style: "single",
672
- size: 2,
673
- color: "accent",
674
- space: 6
675
- }
676
- }
300
+ alignment: "left"
677
301
  },
678
- heading2: {
679
- font: "heading",
680
- size: 18,
302
+ heading6: {
303
+ font: "body",
304
+ size: 10,
681
305
  bold: false,
682
- color: "secondary",
683
- spacing: { before: 18, after: 8 },
306
+ color: "textMuted",
307
+ characterSpacing: { type: "expanded", value: 20 },
308
+ spacing: { before: 10, after: 4 },
684
309
  keepNext: true,
685
310
  alignment: "left"
686
311
  },
687
- heading3: {
312
+ TOC1: {
688
313
  font: "body",
689
- size: 13,
314
+ size: 10.5,
690
315
  bold: true,
691
- color: "accent",
692
- spacing: { before: 12, after: 6 },
693
- keepNext: true,
694
- alignment: "left"
695
- },
696
- title: {
697
- font: "light",
698
- size: 36,
699
- bold: false,
700
- color: "primary",
701
- alignment: "left",
702
- spacing: { before: 0, after: 18 }
316
+ color: "textPrimary",
317
+ spacing: { before: 4, after: 3 },
318
+ tabStops: [{ type: "right", position: 8506, leader: "none" }]
703
319
  },
704
- subtitle: {
320
+ TOC2: {
705
321
  font: "body",
706
- size: 16,
707
- italic: false,
322
+ size: 10.5,
708
323
  color: "textSecondary",
709
- alignment: "left",
710
- spacing: { before: 0, after: 24 }
324
+ indent: { left: 240 },
325
+ spacing: { after: 2 },
326
+ tabStops: [{ type: "right", position: 8506, leader: "none" }]
327
+ },
328
+ TOC3: {
329
+ font: "body",
330
+ size: 10,
331
+ color: "textMuted",
332
+ indent: { left: 480 },
333
+ spacing: { after: 2 },
334
+ tabStops: [{ type: "right", position: 8506, leader: "none" }]
711
335
  }
712
336
  },
713
337
  componentDefaults: {
714
338
  table: {
715
- borderColor: "#D6DAE0"
339
+ borderColor: "#D8D3C8",
340
+ borderSize: 0.5,
341
+ hideBorders: { left: true, right: true, insideVertical: true },
342
+ cellDefaults: {
343
+ padding: { top: 3, bottom: 3 }
344
+ },
345
+ headerCellDefaults: {
346
+ font: { bold: true },
347
+ color: "#2B302B",
348
+ borderColor: { bottom: "#2B302B" },
349
+ borderSize: { bottom: 1 }
350
+ }
716
351
  },
717
352
  list: {
718
353
  format: "bullet",
719
- bullet: "\u2022"
354
+ bullet: "\u2013",
355
+ spacing: { item: 2 }
720
356
  },
721
357
  image: {
722
- alignment: "center"
358
+ alignment: "left"
723
359
  },
724
360
  statistic: {
725
- alignment: "center"
361
+ alignment: "left"
726
362
  },
727
363
  section: {
728
364
  pageBreak: false
@@ -738,29 +374,32 @@ var init_devportal_docx_theme = __esm({
738
374
  "src/templates/themes/devportal.docx.theme.json"() {
739
375
  devportal_docx_theme_default = {
740
376
  name: "devportal",
741
- displayName: "Developer Portal",
742
- description: "A modern developer-focused theme with cool grays, teal accents, and monospace code styling",
743
- version: "2.0.0",
377
+ displayName: "Field Editorial",
378
+ description: "A compact editorial theme \u2014 Helvetica in near-black ink with a burnt-orange accent, tight condensed titles, letterspaced labels, warm tinted fills and hairline rules",
379
+ version: "4.0.0",
744
380
  colors: {
745
- primary: "#0F172A",
746
- secondary: "#334155",
747
- accent: "#0D9488",
748
- text: "#0F172A",
381
+ primary: "#12191F",
382
+ secondary: "#172028",
383
+ accent: "#E35B3F",
384
+ text: "#232323",
749
385
  background: "#FFFFFF",
750
- border: "#E2E8F0",
751
- textPrimary: "#0F172A",
752
- textSecondary: "#475569",
753
- textMuted: "#94A3B8",
754
- borderPrimary: "#CBD5E1",
755
- borderSecondary: "#F1F5F9",
386
+ border: "#E2E0DD",
387
+ textPrimary: "#232323",
388
+ textSecondary: "#46494C",
389
+ textMuted: "#737373",
390
+ borderPrimary: "#D8D5D1",
391
+ borderSecondary: "#F2F3F3",
756
392
  backgroundPrimary: "#FFFFFF",
757
- backgroundSecondary: "#F8FAFC"
393
+ backgroundSecondary: "#F7ECE7",
394
+ accent4: "#46494C",
395
+ accent5: "#8A9299",
396
+ accent6: "#E8A18D"
758
397
  },
759
398
  fonts: {
760
- heading: { family: "Helvetica", size: 24 },
761
- body: { family: "Calibri", size: 11 },
762
- mono: { family: "Consolas", size: 10 },
763
- light: { family: "Helvetica", size: 24 }
399
+ heading: { family: "Helvetica", size: 23 },
400
+ body: { family: "Helvetica", size: 9.5 },
401
+ mono: { family: "Courier New", size: 10 },
402
+ light: { family: "Helvetica", size: 23 }
764
403
  },
765
404
  page: {
766
405
  size: "A4",
@@ -778,22 +417,42 @@ var init_devportal_docx_theme = __esm({
778
417
  normal: {
779
418
  font: "body",
780
419
  color: "textPrimary",
781
- lineSpacing: { type: "multiple", value: 1.5 },
420
+ lineSpacing: { type: "multiple", value: 1.3 },
782
421
  alignment: "left",
783
- spacing: { after: 8 }
422
+ spacing: { after: 7 }
423
+ },
424
+ title: {
425
+ font: "heading",
426
+ size: 29,
427
+ bold: true,
428
+ color: "primary",
429
+ alignment: "left",
430
+ lineSpacing: { type: "multiple", value: 1.02 },
431
+ characterSpacing: { type: "condensed", value: 8 },
432
+ spacing: { before: 0, after: 10 }
433
+ },
434
+ subtitle: {
435
+ font: "body",
436
+ size: 10.5,
437
+ italic: false,
438
+ color: "textSecondary",
439
+ alignment: "left",
440
+ lineSpacing: { type: "multiple", value: 1.25 },
441
+ spacing: { before: 0, after: 12 }
784
442
  },
785
443
  heading1: {
786
444
  font: "heading",
787
- size: 24,
445
+ size: 21,
788
446
  bold: true,
789
447
  color: "primary",
790
- spacing: { before: 24, after: 12 },
448
+ lineSpacing: { type: "multiple", value: 1.15 },
449
+ spacing: { before: 26, after: 12 },
791
450
  keepNext: true,
792
451
  alignment: "left",
793
452
  borders: {
794
453
  bottom: {
795
454
  style: "single",
796
- size: 1,
455
+ size: 4,
797
456
  color: "accent",
798
457
  space: 6
799
458
  }
@@ -801,54 +460,97 @@ var init_devportal_docx_theme = __esm({
801
460
  },
802
461
  heading2: {
803
462
  font: "heading",
804
- size: 18,
463
+ size: 15.5,
805
464
  bold: true,
806
465
  color: "secondary",
807
- spacing: { before: 18, after: 8 },
466
+ lineSpacing: { type: "multiple", value: 1.15 },
467
+ spacing: { before: 20, after: 8 },
808
468
  keepNext: true,
809
469
  alignment: "left"
810
470
  },
811
471
  heading3: {
812
472
  font: "body",
813
- size: 13,
473
+ size: 12.5,
814
474
  bold: true,
815
- color: "accent",
816
- spacing: { before: 12, after: 6 },
475
+ color: "secondary",
476
+ spacing: { before: 14, after: 6 },
817
477
  keepNext: true,
818
478
  alignment: "left"
819
479
  },
820
480
  heading4: {
821
481
  font: "body",
822
- size: 12,
482
+ size: 11.5,
483
+ bold: true,
484
+ color: "textPrimary",
485
+ spacing: { before: 12, after: 4 },
486
+ keepNext: true,
487
+ alignment: "left"
488
+ },
489
+ heading5: {
490
+ font: "mono",
491
+ size: 10.5,
823
492
  bold: true,
493
+ color: "secondary",
494
+ spacing: { before: 10, after: 4 },
495
+ keepNext: true,
496
+ alignment: "left"
497
+ },
498
+ heading6: {
499
+ font: "body",
500
+ size: 10.5,
501
+ bold: false,
824
502
  color: "textSecondary",
825
- spacing: { before: 8, after: 4 },
826
- keepNext: true
503
+ characterSpacing: { type: "expanded", value: 20 },
504
+ spacing: { before: 10, after: 4 },
505
+ keepNext: true,
506
+ alignment: "left"
827
507
  },
828
- title: {
829
- font: "heading",
830
- size: 32,
508
+ TOC1: {
509
+ font: "body",
510
+ size: 11,
831
511
  bold: true,
832
512
  color: "primary",
833
- alignment: "left",
834
- spacing: { before: 0, after: 12 }
513
+ spacing: { before: 5, after: 3 },
514
+ tabStops: [{ type: "right", position: 9746, leader: "dot" }]
835
515
  },
836
- subtitle: {
837
- font: "light",
838
- size: 16,
839
- italic: false,
516
+ TOC2: {
517
+ font: "body",
518
+ size: 10.5,
519
+ color: "textPrimary",
520
+ indent: { left: 240 },
521
+ spacing: { after: 2 },
522
+ tabStops: [{ type: "right", position: 9746, leader: "dot" }]
523
+ },
524
+ TOC3: {
525
+ font: "body",
526
+ size: 10,
840
527
  color: "textSecondary",
841
- alignment: "left",
842
- spacing: { before: 0, after: 24 }
528
+ indent: { left: 480 },
529
+ spacing: { after: 2 },
530
+ tabStops: [{ type: "right", position: 9746, leader: "dot" }]
843
531
  }
844
532
  },
845
533
  componentDefaults: {
846
534
  table: {
847
- borderColor: "#E2E8F0"
535
+ width: 100,
536
+ borderColor: "#E2E0DD",
537
+ borderSize: 0.5,
538
+ hideBorders: { left: true, right: true, insideVertical: true },
539
+ cellDefaults: {
540
+ padding: { top: 3, bottom: 3 }
541
+ },
542
+ headerCellDefaults: {
543
+ font: { bold: true },
544
+ color: "#172028",
545
+ backgroundColor: "#F7ECE7",
546
+ borderColor: { bottom: "#D8D5D1" },
547
+ borderSize: { bottom: 1 }
548
+ }
848
549
  },
849
550
  list: {
850
551
  format: "bullet",
851
- bullet: "\u2013"
552
+ bullet: "\u2014",
553
+ spacing: { item: 2 }
852
554
  },
853
555
  image: {
854
556
  alignment: "center"
@@ -898,7 +600,7 @@ var init_vermilion_docx_theme = __esm({
898
600
  size: 10.5
899
601
  },
900
602
  mono: {
901
- family: "Consolas",
603
+ family: "Courier New",
902
604
  size: 10
903
605
  },
904
606
  light: {
@@ -975,6 +677,47 @@ var init_vermilion_docx_theme = __esm({
975
677
  keepNext: true,
976
678
  alignment: "left"
977
679
  },
680
+ heading4: {
681
+ font: "body",
682
+ size: 10.5,
683
+ bold: true,
684
+ color: "textSecondary",
685
+ spacing: {
686
+ before: 10,
687
+ after: 4
688
+ },
689
+ keepNext: true,
690
+ alignment: "left"
691
+ },
692
+ heading5: {
693
+ font: "body",
694
+ size: 10.5,
695
+ bold: false,
696
+ italic: true,
697
+ color: "textSecondary",
698
+ spacing: {
699
+ before: 9,
700
+ after: 4
701
+ },
702
+ keepNext: true,
703
+ alignment: "left"
704
+ },
705
+ heading6: {
706
+ font: "body",
707
+ size: 10,
708
+ bold: true,
709
+ color: "textMuted",
710
+ characterSpacing: {
711
+ type: "expanded",
712
+ value: 30
713
+ },
714
+ spacing: {
715
+ before: 9,
716
+ after: 4
717
+ },
718
+ keepNext: true,
719
+ alignment: "left"
720
+ },
978
721
  title: {
979
722
  font: "heading",
980
723
  size: 38,
@@ -996,6 +739,46 @@ var init_vermilion_docx_theme = __esm({
996
739
  after: 10
997
740
  }
998
741
  }
742
+ },
743
+ componentDefaults: {
744
+ table: {
745
+ width: 100,
746
+ borderColor: "#C7C8CA",
747
+ borderSize: 0.5,
748
+ hideBorders: {
749
+ top: true,
750
+ left: true,
751
+ right: true,
752
+ insideVertical: true
753
+ },
754
+ cellDefaults: {
755
+ font: { size: 9.5 },
756
+ padding: { top: 7, bottom: 7 },
757
+ verticalAlignment: "middle"
758
+ },
759
+ headerCellDefaults: {
760
+ color: "#EF4130",
761
+ font: { size: 9.5, bold: true },
762
+ padding: { top: 0, bottom: 8 },
763
+ verticalAlignment: "bottom",
764
+ borderColor: { bottom: "#EF4130" },
765
+ borderSize: { bottom: 0.5 }
766
+ }
767
+ },
768
+ list: {
769
+ format: "bullet",
770
+ bullet: "\u2014",
771
+ spacing: { item: 2 }
772
+ },
773
+ image: {
774
+ alignment: "center"
775
+ },
776
+ statistic: {
777
+ alignment: "center"
778
+ },
779
+ section: {
780
+ pageBreak: false
781
+ }
999
782
  }
1000
783
  };
1001
784
  }
@@ -1014,9 +797,6 @@ function loadThemesFromJson() {
1014
797
  }
1015
798
  const themes2 = {
1016
799
  minimal: ensureThemeDefaults(minimal_docx_theme_default),
1017
- corporate: ensureThemeDefaults(corporate_docx_theme_default),
1018
- modern: ensureThemeDefaults(modern_docx_theme_default),
1019
- apex: ensureThemeDefaults(apex_docx_theme_default),
1020
800
  devportal: ensureThemeDefaults(devportal_docx_theme_default),
1021
801
  vermilion: ensureThemeDefaults(vermilion_docx_theme_default)
1022
802
  };
@@ -1056,15 +836,12 @@ function loadThemesFromJson() {
1056
836
  _themesCache = themes2;
1057
837
  return themes2;
1058
838
  }
1059
- var _themesCache, themes, getTheme, getThemeWithFallback, hasTheme, getThemeNames, minimalTheme, corporateTheme, modernTheme;
839
+ var _themesCache, themes, getTheme, getThemeWithFallback, hasTheme, getThemeNames, minimalTheme, devportalTheme, vermilionTheme;
1060
840
  var init_themes = __esm({
1061
841
  "src/templates/themes/index.ts"() {
1062
842
  "use strict";
1063
843
  init_defaults();
1064
844
  init_minimal_docx_theme();
1065
- init_corporate_docx_theme();
1066
- init_modern_docx_theme();
1067
- init_apex_docx_theme();
1068
845
  init_devportal_docx_theme();
1069
846
  init_vermilion_docx_theme();
1070
847
  _themesCache = null;
@@ -1088,8 +865,8 @@ var init_themes = __esm({
1088
865
  return Object.keys(themes);
1089
866
  };
1090
867
  minimalTheme = themes["minimal"];
1091
- corporateTheme = themes["corporate"];
1092
- modernTheme = themes["modern"];
868
+ devportalTheme = themes["devportal"];
869
+ vermilionTheme = themes["vermilion"];
1093
870
  }
1094
871
  });
1095
872
 
@@ -7013,6 +6790,9 @@ function createLevelsFromSimplifiedProps(props) {
7013
6790
  text = "";
7014
6791
  } else {
7015
6792
  format2 = props.format;
6793
+ if (format2 === "bullet") {
6794
+ text = props.bullet || "\u2022";
6795
+ }
7016
6796
  }
7017
6797
  } else {
7018
6798
  format2 = "bullet";
@@ -7224,7 +7004,7 @@ function outerBorderOverride(position, tableBorderColor, tableBorderSize) {
7224
7004
  const color = normalizeBorderColor(tableBorderColor);
7225
7005
  if (tableBorderColor && color) {
7226
7006
  result.borderColor = {};
7227
- if (position.isHeader && color.top !== UNSET_COLOR) {
7007
+ if ((position.isHeader || position.isFirstRow) && color.top !== UNSET_COLOR) {
7228
7008
  result.borderColor.top = color.top;
7229
7009
  }
7230
7010
  if (position.isFirstCol && color.left !== UNSET_COLOR) {
@@ -7240,7 +7020,7 @@ function outerBorderOverride(position, tableBorderColor, tableBorderSize) {
7240
7020
  const size = normalizeBorderSize(tableBorderSize);
7241
7021
  if (tableBorderSize && size) {
7242
7022
  result.borderSize = {};
7243
- if (position.isHeader && size.top !== UNSET_SIZE) {
7023
+ if ((position.isHeader || position.isFirstRow) && size.top !== UNSET_SIZE) {
7244
7024
  result.borderSize.top = size.top;
7245
7025
  }
7246
7026
  if (position.isFirstCol && size.left !== UNSET_SIZE) {
@@ -7460,6 +7240,7 @@ function resolveTableModel(source, theme, themeName, options = {}) {
7460
7240
  (max, height) => height === void 0 ? max : max === void 0 ? height : Math.max(max, height),
7461
7241
  void 0
7462
7242
  );
7243
+ const hasHeader = columns.some((column) => column.header !== void 0);
7463
7244
  const headerMerges = columns.map(
7464
7245
  (column, colIndex) => mergeHeaderCellDefaults(
7465
7246
  source.cellDefaults,
@@ -7501,6 +7282,7 @@ function resolveTableModel(source, theme, themeName, options = {}) {
7501
7282
  };
7502
7283
  const rows = Array.from({ length: rowCount }, (_, rowIndex) => {
7503
7284
  const isLastRow = rowIndex === rowCount - 1;
7285
+ const isFirstRow = !hasHeader && rowIndex === 0;
7504
7286
  const rowProps = source.rows?.[rowIndex];
7505
7287
  const merges = columns.map(
7506
7288
  (column, colIndex) => mergeCellDefaults(
@@ -7508,6 +7290,7 @@ function resolveTableModel(source, theme, themeName, options = {}) {
7508
7290
  column.cellDefaults,
7509
7291
  column.cells?.[rowIndex],
7510
7292
  {
7293
+ isFirstRow,
7511
7294
  isFirstCol: colIndex === 0,
7512
7295
  isLastCol: colIndex === columnCount - 1,
7513
7296
  isLastRow
@@ -7534,8 +7317,7 @@ function resolveTableModel(source, theme, themeName, options = {}) {
7534
7317
  const cell = column.cells?.[rowIndex];
7535
7318
  const merged = merges[colIndex];
7536
7319
  const position = {
7537
- // Data rows are never the first row; the header is.
7538
- isFirstRow: false,
7320
+ isFirstRow,
7539
7321
  isFirstCol: colIndex === 0,
7540
7322
  isLastCol: colIndex === columnCount - 1,
7541
7323
  isLastRow
@@ -7565,10 +7347,10 @@ function resolveTableModel(source, theme, themeName, options = {}) {
7565
7347
  };
7566
7348
  return row;
7567
7349
  });
7568
- adjudicateInteriorEdges([header, ...rows]);
7350
+ adjudicateInteriorEdges([...hasHeader ? [header] : [], ...rows]);
7569
7351
  return {
7570
7352
  ...resolveWidths(source, columns, theme, themeName),
7571
- header,
7353
+ ...hasHeader ? { header } : {},
7572
7354
  rows,
7573
7355
  repeatHeader: source.repeatHeaderOnPageBreak ?? true
7574
7356
  };
@@ -8449,18 +8231,32 @@ function compileDocument(structure, layout, warnings = [], images = /* @__PURE__
8449
8231
  };
8450
8232
  }
8451
8233
  var AFTER_TABLE_TWIPS = 120;
8234
+ var BEFORE_TABLE_TWIPS = 240;
8452
8235
  var BODY_STYLE_IDS = /* @__PURE__ */ new Set([void 0, "Normal"]);
8453
- function separateFromTables(blocks) {
8236
+ function separateFromTables(blocks, bodyAfterTwips) {
8454
8237
  for (let i = 1; i < blocks.length; i += 1) {
8455
8238
  const block2 = blocks[i];
8456
- if (blocks[i - 1].kind !== "table") continue;
8457
- if (block2.kind !== "paragraph") continue;
8458
- if (!BODY_STYLE_IDS.has(block2.styleId)) continue;
8459
- if (block2.formatting?.spacing?.beforeTwips !== void 0) continue;
8460
- block2.formatting = {
8461
- ...block2.formatting,
8462
- spacing: { ...block2.formatting?.spacing, beforeTwips: AFTER_TABLE_TWIPS }
8463
- };
8239
+ const previous = blocks[i - 1];
8240
+ if (previous.kind === "table" && block2.kind === "paragraph" && BODY_STYLE_IDS.has(block2.styleId) && // An author who stated their own space-before has already answered this.
8241
+ block2.formatting?.spacing?.beforeTwips === void 0) {
8242
+ block2.formatting = {
8243
+ ...block2.formatting,
8244
+ spacing: {
8245
+ ...block2.formatting?.spacing,
8246
+ beforeTwips: AFTER_TABLE_TWIPS
8247
+ }
8248
+ };
8249
+ }
8250
+ if (block2.kind === "table" && previous.kind === "paragraph" && BODY_STYLE_IDS.has(previous.styleId) && // Same rule as below: a stated space-after is the author's answer.
8251
+ previous.formatting?.spacing?.afterTwips === void 0) {
8252
+ previous.formatting = {
8253
+ ...previous.formatting,
8254
+ spacing: {
8255
+ ...previous.formatting?.spacing,
8256
+ afterTwips: Math.max(bodyAfterTwips, BEFORE_TABLE_TWIPS)
8257
+ }
8258
+ };
8259
+ }
8464
8260
  }
8465
8261
  }
8466
8262
  function collectOutline(layout, warnings) {
@@ -8539,7 +8335,10 @@ function compileSection(section2, index, ordinal, chrome, ctx) {
8539
8335
  })
8540
8336
  );
8541
8337
  });
8542
- separateFromTables(children);
8338
+ separateFromTables(
8339
+ children,
8340
+ pointsToTwips2(getNormalStyle(ctx.theme).spacing?.after ?? 0)
8341
+ );
8543
8342
  const compiled = {
8544
8343
  id: `s${index}`,
8545
8344
  path: path3,
@@ -9558,8 +9357,10 @@ function itemSpacing(spacing, index, count) {
9558
9357
  if (index === 0 && spacing?.before !== void 0) {
9559
9358
  out.beforeTwips = pointsToTwips2(spacing.before);
9560
9359
  }
9561
- if (index === count - 1 && spacing?.after !== void 0) {
9562
- out.afterTwips = pointsToTwips2(spacing.after);
9360
+ if (index === count - 1) {
9361
+ if (spacing?.after !== void 0) {
9362
+ out.afterTwips = pointsToTwips2(spacing.after);
9363
+ }
9563
9364
  } else if (spacing?.item !== void 0) {
9564
9365
  out.afterTwips = pointsToTwips2(spacing.item);
9565
9366
  }
@@ -10639,13 +10440,20 @@ function compileTable(component, scope) {
10639
10440
  return [];
10640
10441
  }
10641
10442
  const rows = [
10642
- compileTableRow(model.header, style.headerParagraph, style.tableHeader, {
10643
- ctx,
10644
- path: `${path3}.header`,
10645
- id: `${scope.id}:h`,
10646
- // Headers repeat across page breaks unless the source disabled it.
10647
- isHeader: model.repeatHeader
10648
- }),
10443
+ ...model.header ? [
10444
+ compileTableRow(
10445
+ model.header,
10446
+ style.headerParagraph,
10447
+ style.tableHeader,
10448
+ {
10449
+ ctx,
10450
+ path: `${path3}.header`,
10451
+ id: `${scope.id}:h`,
10452
+ // Headers repeat across page breaks unless the source disabled it.
10453
+ isHeader: model.repeatHeader
10454
+ }
10455
+ )
10456
+ ] : [],
10649
10457
  ...model.rows.map(
10650
10458
  (row, index) => compileTableRow(row, style.cellParagraph, style.tableCell, {
10651
10459
  ctx,
@@ -10707,9 +10515,10 @@ function tableSource(props) {
10707
10515
  };
10708
10516
  }
10709
10517
  function tableBlocker(model, path3) {
10710
- const rows = [model.header, ...model.rows];
10518
+ const headerRows = model.header ? [model.header] : [];
10519
+ const rows = [...headerRows, ...model.rows];
10711
10520
  for (const [rowIndex, row] of rows.entries()) {
10712
- const rowPath = row.isHeader ? `${path3}.header` : `${path3}.rows[${rowIndex - 1}]`;
10521
+ const rowPath = row.isHeader ? `${path3}.header` : `${path3}.rows[${rowIndex - headerRows.length}]`;
10713
10522
  for (const [colIndex, cell] of row.cells.entries()) {
10714
10523
  const cellPath = `${rowPath}.cells[${colIndex}]`;
10715
10524
  const content = cell.content;
@@ -12643,167 +12452,262 @@ function createDocumentGenerator(options) {
12643
12452
 
12644
12453
  // src/plugin/example/weather.component.ts
12645
12454
  import { Type as Type2 } from "@sinclair/typebox";
12646
-
12647
- // src/plugin/createComponent.ts
12648
- import {
12649
- createVersion as sharedCreateVersion,
12650
- createComponent as sharedCreateComponent
12651
- } from "@json-to-office/shared/plugin";
12652
- function createVersion(version) {
12653
- return sharedCreateVersion(version);
12654
- }
12655
- function createComponent(component) {
12656
- return sharedCreateComponent(component);
12657
- }
12658
-
12659
- // src/plugin/example/weather.component.ts
12455
+ import { createComponent, createVersion } from "@json-to-office/core-docx";
12456
+ var WEATHER_API_HOSTS = [
12457
+ "https://geocoding-api.open-meteo.com",
12458
+ "https://api.open-meteo.com"
12459
+ ];
12460
+ var GEOCODING_URL = "https://geocoding-api.open-meteo.com/v1/search";
12461
+ var FORECAST_URL = "https://api.open-meteo.com/v1/forecast";
12462
+ var REQUEST_TIMEOUT_MS = 8e3;
12463
+ var UnitsSchema = Type2.Optional(
12464
+ Type2.Union([Type2.Literal("metric"), Type2.Literal("imperial")], {
12465
+ default: "metric",
12466
+ description: "metric = \xB0C and km/h, imperial = \xB0F and mph"
12467
+ })
12468
+ );
12660
12469
  var WeatherV1PropsSchema = Type2.Object(
12661
12470
  {
12662
12471
  city: Type2.String({
12663
- description: "City name for weather data"
12472
+ minLength: 1,
12473
+ description: 'City to look up, e.g. "Milan" or "Milan, Italy"'
12664
12474
  }),
12665
- units: Type2.Optional(
12666
- Type2.Union([Type2.Literal("metric"), Type2.Literal("imperial")], {
12667
- default: "metric",
12668
- description: "Temperature units"
12669
- })
12670
- ),
12475
+ units: UnitsSchema,
12671
12476
  showDetails: Type2.Optional(
12672
12477
  Type2.Boolean({
12673
12478
  default: true,
12674
- description: "Show detailed weather information"
12479
+ description: "Show humidity, wind and pressure under the reading"
12675
12480
  })
12676
12481
  )
12677
12482
  },
12678
- {
12679
- additionalProperties: false
12680
- }
12483
+ { additionalProperties: false }
12681
12484
  );
12682
12485
  var WeatherV2PropsSchema = Type2.Object(
12683
12486
  {
12684
12487
  city: Type2.String({
12685
- description: "City name for weather data"
12488
+ minLength: 1,
12489
+ description: 'City to look up, e.g. "Milan" or "Milan, Italy"'
12686
12490
  }),
12687
- units: Type2.Optional(
12688
- Type2.Union([Type2.Literal("metric"), Type2.Literal("imperial")], {
12689
- default: "metric",
12690
- description: "Temperature units"
12691
- })
12692
- ),
12491
+ units: UnitsSchema,
12693
12492
  days: Type2.Optional(
12694
12493
  Type2.Number({
12695
- default: 1,
12494
+ default: 3,
12696
12495
  minimum: 1,
12697
- maximum: 5,
12698
- description: "Number of forecast days (1-5)"
12496
+ maximum: 7,
12497
+ description: "Number of forecast days (1-7)"
12699
12498
  })
12700
12499
  )
12701
12500
  },
12702
- {
12703
- additionalProperties: false
12704
- }
12501
+ { additionalProperties: false }
12705
12502
  );
12706
- async function fetchWeather(city, units) {
12707
- await new Promise((resolve2) => setTimeout(resolve2, 100));
12708
- const mockData = {
12709
- London: {
12710
- temperature: units === "imperial" ? 59 : 15,
12711
- description: "Partly cloudy",
12712
- humidity: 65,
12713
- windSpeed: units === "imperial" ? 10 : 16,
12714
- pressure: 1013
12715
- },
12716
- "New York": {
12717
- temperature: units === "imperial" ? 72 : 22,
12718
- description: "Sunny",
12719
- humidity: 45,
12720
- windSpeed: units === "imperial" ? 8 : 13,
12721
- pressure: 1015
12722
- },
12723
- Tokyo: {
12724
- temperature: units === "imperial" ? 68 : 20,
12725
- description: "Clear",
12726
- humidity: 55,
12727
- windSpeed: units === "imperial" ? 5 : 8,
12728
- pressure: 1012
12729
- }
12730
- };
12731
- return mockData[city] || {
12732
- temperature: units === "imperial" ? 70 : 21,
12733
- description: "Clear",
12734
- humidity: 50,
12735
- windSpeed: units === "imperial" ? 7 : 11,
12736
- pressure: 1013
12737
- };
12738
- }
12739
- async function fetchForecast(city, units, days) {
12740
- await new Promise((resolve2) => setTimeout(resolve2, 50));
12741
- const dayNames = ["Mon", "Tue", "Wed", "Thu", "Fri"];
12742
- const base = units === "imperial" ? 65 : 18;
12743
- return dayNames.slice(0, days).map((day, i) => ({
12744
- day,
12745
- high: base + (5 - i) * (units === "imperial" ? 2 : 1),
12746
- low: base - (3 + i) * (units === "imperial" ? 2 : 1),
12747
- description: ["Sunny", "Partly cloudy", "Cloudy", "Showers", "Clear"][i]
12503
+ var WEATHER_CODES = {
12504
+ 0: "Clear sky",
12505
+ 1: "Mainly clear",
12506
+ 2: "Partly cloudy",
12507
+ 3: "Overcast",
12508
+ 45: "Fog",
12509
+ 48: "Depositing rime fog",
12510
+ 51: "Light drizzle",
12511
+ 53: "Moderate drizzle",
12512
+ 55: "Dense drizzle",
12513
+ 56: "Light freezing drizzle",
12514
+ 57: "Dense freezing drizzle",
12515
+ 61: "Slight rain",
12516
+ 63: "Moderate rain",
12517
+ 65: "Heavy rain",
12518
+ 66: "Light freezing rain",
12519
+ 67: "Heavy freezing rain",
12520
+ 71: "Slight snow",
12521
+ 73: "Moderate snow",
12522
+ 75: "Heavy snow",
12523
+ 77: "Snow grains",
12524
+ 80: "Slight rain showers",
12525
+ 81: "Moderate rain showers",
12526
+ 82: "Violent rain showers",
12527
+ 85: "Slight snow showers",
12528
+ 86: "Heavy snow showers",
12529
+ 95: "Thunderstorm",
12530
+ 96: "Thunderstorm with slight hail",
12531
+ 99: "Thunderstorm with heavy hail"
12532
+ };
12533
+ function describeCode(code) {
12534
+ return typeof code === "number" && WEATHER_CODES[code] ? WEATHER_CODES[code] : "Unknown conditions";
12535
+ }
12536
+ var WeatherLookupError = class extends Error {
12537
+ constructor(message) {
12538
+ super(message);
12539
+ this.name = "WeatherLookupError";
12540
+ }
12541
+ };
12542
+ async function getJson(url, what) {
12543
+ let response;
12544
+ try {
12545
+ response = await fetch(url, {
12546
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
12547
+ headers: { accept: "application/json" }
12548
+ });
12549
+ } catch (error) {
12550
+ const reason = error instanceof Error ? error.message : String(error);
12551
+ throw new WeatherLookupError(
12552
+ `Could not reach Open-Meteo for ${what}: ${reason}. In the playground, list ${WEATHER_API_HOSTS.join(" and ")} under this plugin's Network switch.`
12553
+ );
12554
+ }
12555
+ if (!response.ok) {
12556
+ throw new WeatherLookupError(
12557
+ `Open-Meteo answered ${response.status} for ${what}.`
12558
+ );
12559
+ }
12560
+ return response.json();
12561
+ }
12562
+ async function geocode(city) {
12563
+ const url = `${GEOCODING_URL}?name=${encodeURIComponent(city)}&count=1&language=en&format=json`;
12564
+ const body = await getJson(url, `"${city}"`);
12565
+ const first = body.results?.[0];
12566
+ if (!first || typeof first.latitude !== "number") {
12567
+ throw new WeatherLookupError(
12568
+ `Open-Meteo has no place called "${city}". Try adding a country, e.g. "${city}, Italy".`
12569
+ );
12570
+ }
12571
+ return {
12572
+ name: String(first.name ?? city),
12573
+ country: typeof first.country === "string" ? first.country : void 0,
12574
+ admin1: typeof first.admin1 === "string" ? first.admin1 : void 0,
12575
+ latitude: first.latitude,
12576
+ longitude: first.longitude,
12577
+ timezone: typeof first.timezone === "string" ? first.timezone : void 0
12578
+ };
12579
+ }
12580
+ function placeLabel(place) {
12581
+ return [place.name, place.admin1, place.country].filter(Boolean).join(", ");
12582
+ }
12583
+ function unitParams(units) {
12584
+ return units === "imperial" ? "&temperature_unit=fahrenheit&wind_speed_unit=mph&precipitation_unit=inch" : "";
12585
+ }
12586
+ async function fetchCurrent(place, units) {
12587
+ const url = `${FORECAST_URL}?latitude=${place.latitude}&longitude=${place.longitude}&current=temperature_2m,apparent_temperature,relative_humidity_2m,wind_speed_10m,surface_pressure,weather_code&timezone=auto${unitParams(units)}`;
12588
+ const body = await getJson(url, `weather in ${place.name}`);
12589
+ const current = body.current;
12590
+ if (!current || typeof current.temperature_2m !== "number") {
12591
+ throw new WeatherLookupError(
12592
+ `Open-Meteo returned no current reading for ${place.name}.`
12593
+ );
12594
+ }
12595
+ const round = (value, fallback = 0) => typeof value === "number" ? Math.round(value) : fallback;
12596
+ return {
12597
+ temperature: Math.round(current.temperature_2m),
12598
+ apparent: round(
12599
+ current.apparent_temperature,
12600
+ Math.round(current.temperature_2m)
12601
+ ),
12602
+ conditions: describeCode(current.weather_code),
12603
+ humidity: round(current.relative_humidity_2m),
12604
+ windSpeed: round(current.wind_speed_10m),
12605
+ pressure: round(current.surface_pressure),
12606
+ observedAt: typeof current.time === "string" ? current.time : ""
12607
+ };
12608
+ }
12609
+ async function fetchForecast(place, units, days) {
12610
+ const url = `${FORECAST_URL}?latitude=${place.latitude}&longitude=${place.longitude}&daily=weather_code,temperature_2m_max,temperature_2m_min,precipitation_probability_max&forecast_days=${days}&timezone=auto${unitParams(units)}`;
12611
+ const body = await getJson(url, `the forecast for ${place.name}`);
12612
+ const daily = body.daily;
12613
+ const dates = daily?.time;
12614
+ if (!Array.isArray(dates) || dates.length === 0) {
12615
+ throw new WeatherLookupError(
12616
+ `Open-Meteo returned no forecast for ${place.name}.`
12617
+ );
12618
+ }
12619
+ const at = (key, i) => daily?.[key]?.[i];
12620
+ return dates.slice(0, days).map((date, i) => ({
12621
+ date: String(date),
12622
+ high: Math.round(Number(at("temperature_2m_max", i) ?? 0)),
12623
+ low: Math.round(Number(at("temperature_2m_min", i) ?? 0)),
12624
+ conditions: describeCode(at("weather_code", i)),
12625
+ precipitation: Math.round(
12626
+ Number(at("precipitation_probability_max", i) ?? 0)
12627
+ )
12748
12628
  }));
12749
12629
  }
12630
+ function formatDay(iso) {
12631
+ const date = /* @__PURE__ */ new Date(`${iso}T00:00:00Z`);
12632
+ if (Number.isNaN(date.getTime())) return iso;
12633
+ return date.toLocaleDateString("en-GB", {
12634
+ weekday: "short",
12635
+ day: "numeric",
12636
+ month: "short",
12637
+ timeZone: "UTC"
12638
+ });
12639
+ }
12750
12640
  var weatherComponent = createComponent({
12751
12641
  name: "weather",
12752
12642
  versions: {
12753
12643
  "1.0.0": createVersion({
12754
12644
  propsSchema: WeatherV1PropsSchema,
12755
- description: "Displays current weather information for a city",
12645
+ description: "Current weather for a city, fetched live from Open-Meteo (needs network access to api.open-meteo.com and geocoding-api.open-meteo.com)",
12756
12646
  render: async ({ props, addWarning }) => {
12757
- const weather = await fetchWeather(props.city, props.units || "metric");
12758
- addWarning("Fetched weather data", { city: props.city });
12759
- const tempUnit = props.units === "imperial" ? "\xB0F" : "\xB0C";
12760
- const speedUnit = props.units === "imperial" ? "mph" : "km/h";
12647
+ const units = props.units ?? "metric";
12648
+ const place = await geocode(props.city);
12649
+ const weather = await fetchCurrent(place, units);
12650
+ addWarning(`Fetched live weather from Open-Meteo`, {
12651
+ place: placeLabel(place),
12652
+ observedAt: weather.observedAt
12653
+ });
12654
+ const degrees = units === "imperial" ? "\xB0F" : "\xB0C";
12655
+ const speed = units === "imperial" ? "mph" : "km/h";
12761
12656
  const components = [
12762
12657
  {
12763
12658
  name: "heading",
12764
- props: {
12765
- level: 3,
12766
- text: `Weather in ${props.city}`
12767
- }
12659
+ props: { level: 3, text: `Weather in ${placeLabel(place)}` }
12768
12660
  },
12769
12661
  {
12770
12662
  name: "paragraph",
12771
12663
  props: {
12772
- text: `${weather.temperature}${tempUnit} - ${weather.description}`,
12664
+ text: `${weather.temperature}${degrees} \u2014 ${weather.conditions}`,
12773
12665
  font: { bold: true, size: 14 }
12774
12666
  }
12775
12667
  }
12776
12668
  ];
12777
- if (props.showDetails) {
12669
+ if (props.showDetails ?? true) {
12778
12670
  components.push({
12779
12671
  name: "list",
12780
12672
  props: {
12781
12673
  items: [
12674
+ `Feels like: ${weather.apparent}${degrees}`,
12782
12675
  `Humidity: ${weather.humidity}%`,
12783
- `Wind Speed: ${weather.windSpeed} ${speedUnit}`,
12676
+ `Wind: ${weather.windSpeed} ${speed}`,
12784
12677
  `Pressure: ${weather.pressure} hPa`
12785
12678
  ]
12786
12679
  }
12787
12680
  });
12788
12681
  }
12682
+ components.push({
12683
+ name: "paragraph",
12684
+ props: {
12685
+ text: `Source: Open-Meteo${weather.observedAt ? `, observed ${weather.observedAt.replace("T", " ")}` : ""}`,
12686
+ font: { size: 8, italic: true }
12687
+ }
12688
+ });
12789
12689
  return components;
12790
12690
  }
12791
12691
  }),
12792
12692
  "2.0.0": createVersion({
12793
12693
  propsSchema: WeatherV2PropsSchema,
12794
- description: "Multi-day forecast displayed as a table",
12694
+ description: "Multi-day forecast table for a city, fetched live from Open-Meteo",
12795
12695
  render: async ({ props, addWarning }) => {
12796
- const units = props.units || "metric";
12797
- const days = props.days || 3;
12798
- const tempUnit = units === "imperial" ? "\xB0F" : "\xB0C";
12799
- const forecast = await fetchForecast(props.city, units, days);
12800
- addWarning("Fetched forecast data", { city: props.city, days });
12801
- const components = [
12696
+ const units = props.units ?? "metric";
12697
+ const days = props.days ?? 3;
12698
+ const place = await geocode(props.city);
12699
+ const forecast = await fetchForecast(place, units, days);
12700
+ addWarning("Fetched live forecast from Open-Meteo", {
12701
+ place: placeLabel(place),
12702
+ days: forecast.length
12703
+ });
12704
+ const degrees = units === "imperial" ? "\xB0F" : "\xB0C";
12705
+ return [
12802
12706
  {
12803
12707
  name: "heading",
12804
12708
  props: {
12805
12709
  level: 3,
12806
- text: `${days}-Day Forecast for ${props.city}`
12710
+ text: `${forecast.length}-day forecast for ${placeLabel(place)}`
12807
12711
  }
12808
12712
  },
12809
12713
  {
@@ -12812,53 +12716,37 @@ var weatherComponent = createComponent({
12812
12716
  columns: [
12813
12717
  {
12814
12718
  header: { content: "Day" },
12815
- cells: forecast.map((f) => ({ content: f.day }))
12719
+ cells: forecast.map((day) => ({
12720
+ content: formatDay(day.date)
12721
+ }))
12722
+ },
12723
+ {
12724
+ header: { content: `High (${degrees})` },
12725
+ cells: forecast.map((day) => ({ content: String(day.high) }))
12816
12726
  },
12817
12727
  {
12818
- header: { content: `High (${tempUnit})` },
12819
- cells: forecast.map((f) => ({ content: String(f.high) }))
12728
+ header: { content: `Low (${degrees})` },
12729
+ cells: forecast.map((day) => ({ content: String(day.low) }))
12820
12730
  },
12821
12731
  {
12822
- header: { content: `Low (${tempUnit})` },
12823
- cells: forecast.map((f) => ({ content: String(f.low) }))
12732
+ header: { content: "Rain" },
12733
+ cells: forecast.map((day) => ({
12734
+ content: `${day.precipitation}%`
12735
+ }))
12824
12736
  },
12825
12737
  {
12826
12738
  header: { content: "Conditions" },
12827
- cells: forecast.map((f) => ({ content: f.description }))
12739
+ cells: forecast.map((day) => ({ content: day.conditions }))
12828
12740
  }
12829
12741
  ]
12830
12742
  }
12831
- }
12832
- ];
12833
- return components;
12834
- }
12835
- })
12836
- }
12837
- });
12838
-
12839
- // src/plugin/example/columns-layout.component.ts
12840
- import { Type as Type3 } from "@sinclair/typebox";
12841
- var ColumnsLayoutPropsSchema = Type3.Object(
12842
- {},
12843
- {
12844
- additionalProperties: false
12845
- }
12846
- );
12847
- var columnsLayoutComponent = createComponent({
12848
- name: "columnsLayout",
12849
- versions: {
12850
- "1.0.0": createVersion({
12851
- propsSchema: ColumnsLayoutPropsSchema,
12852
- hasChildren: true,
12853
- description: "Renders a list of components in a 2-column layout",
12854
- render: async ({ children }) => {
12855
- return [
12743
+ },
12856
12744
  {
12857
- name: "columns",
12745
+ name: "paragraph",
12858
12746
  props: {
12859
- columns: 2
12860
- },
12861
- children: children || []
12747
+ text: "Source: Open-Meteo",
12748
+ font: { size: 8, italic: true }
12749
+ }
12862
12750
  }
12863
12751
  ];
12864
12752
  }
@@ -12866,91 +12754,6 @@ var columnsLayoutComponent = createComponent({
12866
12754
  }
12867
12755
  });
12868
12756
 
12869
- // src/plugin/example/nested-section.component.ts
12870
- import { Type as Type4 } from "@sinclair/typebox";
12871
- var NestedSectionsSchema = Type4.Object(
12872
- {},
12873
- {
12874
- additionalProperties: false
12875
- }
12876
- );
12877
- var nestedSectionsComponent = createComponent({
12878
- name: "nestedSections",
12879
- versions: {
12880
- "1.0.0": createVersion({
12881
- propsSchema: NestedSectionsSchema,
12882
- description: "Generates nested sections for embedding in documents",
12883
- render: async () => {
12884
- const components = [];
12885
- components.push({
12886
- name: "section",
12887
- props: {
12888
- meta: { title: "First level 1 section" }
12889
- },
12890
- children: [
12891
- {
12892
- name: "heading",
12893
- props: { text: "First level 1 section", level: 1 }
12894
- },
12895
- {
12896
- name: "heading",
12897
- props: {
12898
- text: "Level 2 heading of first level 1 section",
12899
- level: 2
12900
- }
12901
- },
12902
- {
12903
- name: "paragraph",
12904
- props: {
12905
- text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
12906
- }
12907
- },
12908
- {
12909
- name: "heading",
12910
- props: {
12911
- text: "Level 2 heading of first level 1 section",
12912
- level: 2
12913
- }
12914
- },
12915
- {
12916
- name: "paragraph",
12917
- props: {
12918
- text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
12919
- }
12920
- }
12921
- ]
12922
- });
12923
- components.push({
12924
- name: "section",
12925
- props: {
12926
- meta: { title: "Second level 1 section" }
12927
- },
12928
- children: [
12929
- {
12930
- name: "heading",
12931
- props: { text: "Second level 1 section", level: 1 }
12932
- },
12933
- {
12934
- name: "heading",
12935
- props: {
12936
- text: "Level 2 heading of second level 1 section",
12937
- level: 2
12938
- }
12939
- },
12940
- {
12941
- name: "paragraph",
12942
- props: {
12943
- text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
12944
- }
12945
- }
12946
- ]
12947
- });
12948
- return components;
12949
- }
12950
- })
12951
- }
12952
- });
12953
-
12954
12757
  // src/plugin/example/index.ts
12955
12758
  init_themes();
12956
12759
  import * as fs3 from "fs/promises";
@@ -12963,48 +12766,43 @@ var plugin_demo_default = {
12963
12766
  $schema: "../../../../../output/examples/plugin-demo-schema.json",
12964
12767
  name: "docx",
12965
12768
  props: {
12966
- title: "Plugin Demo"
12769
+ title: "Weather Plugin Demo"
12967
12770
  },
12968
12771
  children: [
12969
- {
12970
- name: "nestedSections",
12971
- props: {}
12972
- },
12973
12772
  {
12974
12773
  name: "section",
12975
12774
  props: {
12976
12775
  meta: {
12977
- title: "Weather Information"
12776
+ title: "Today"
12978
12777
  }
12979
12778
  },
12980
12779
  children: [
12981
12780
  {
12982
12781
  name: "heading",
12983
12782
  props: {
12984
- text: "Weather Information",
12783
+ text: "Today",
12985
12784
  level: 1,
12986
- spacing: {
12987
- before: 0,
12988
- after: 0
12989
- }
12785
+ spacing: { before: 0, after: 0 }
12990
12786
  }
12991
12787
  },
12992
12788
  {
12993
12789
  name: "paragraph",
12994
12790
  props: {
12995
- content: "Here's the current weather for major cities:"
12791
+ content: "Each block below is rendered by the weather plugin, which calls Open-Meteo while the document is generated."
12996
12792
  }
12997
12793
  },
12998
12794
  {
12999
12795
  name: "weather",
12796
+ version: "1.0.0",
13000
12797
  props: {
13001
- city: "London",
12798
+ city: "Milan",
13002
12799
  units: "metric",
13003
12800
  showDetails: true
13004
12801
  }
13005
12802
  },
13006
12803
  {
13007
12804
  name: "weather",
12805
+ version: "1.0.0",
13008
12806
  props: {
13009
12807
  city: "New York",
13010
12808
  units: "imperial",
@@ -13017,97 +12815,25 @@ var plugin_demo_default = {
13017
12815
  name: "section",
13018
12816
  props: {
13019
12817
  meta: {
13020
- title: "Sales Data"
13021
- }
13022
- },
13023
- children: [
13024
- {
13025
- name: "heading",
13026
- props: {
13027
- text: "Sales Data",
13028
- level: 1,
13029
- spacing: {
13030
- before: 0,
13031
- after: 0
13032
- }
13033
- }
13034
- },
13035
- {
13036
- name: "paragraph",
13037
- props: {
13038
- content: "Recent sales performance:"
13039
- }
13040
- },
13041
- {
13042
- name: "dataTable",
13043
- props: {
13044
- query: "SELECT * FROM sales ORDER BY date DESC",
13045
- title: "Q1 Sales Report",
13046
- showRowNumbers: true,
13047
- maxRows: 10
13048
- }
13049
- }
13050
- ]
13051
- },
13052
- {
13053
- name: "section",
13054
- props: {
13055
- meta: {
13056
- title: "Quick Links"
13057
- }
13058
- },
13059
- children: [
13060
- {
13061
- name: "heading",
13062
- props: {
13063
- text: "Quick Links",
13064
- level: 1,
13065
- spacing: {
13066
- before: 0,
13067
- after: 0
13068
- }
13069
- }
13070
- },
13071
- {
13072
- name: "paragraph",
13073
- props: {
13074
- content: "Scan these QR codes to access our resources:"
13075
- }
13076
- }
13077
- ]
13078
- },
13079
- {
13080
- name: "section",
13081
- props: {
13082
- meta: {
13083
- title: "More Data Examples"
12818
+ title: "The week ahead"
13084
12819
  }
13085
12820
  },
13086
12821
  children: [
13087
12822
  {
13088
12823
  name: "heading",
13089
12824
  props: {
13090
- text: "More Data Examples",
12825
+ text: "The week ahead",
13091
12826
  level: 1,
13092
- spacing: {
13093
- before: 0,
13094
- after: 0
13095
- }
12827
+ spacing: { before: 0, after: 0 }
13096
12828
  }
13097
12829
  },
13098
12830
  {
13099
- name: "dataTable",
13100
- props: {
13101
- query: 'SELECT * FROM users WHERE role = "Admin"',
13102
- title: "System Administrators"
13103
- }
13104
- },
13105
- {
13106
- name: "dataTable",
12831
+ name: "weather",
12832
+ version: "2.0.0",
13107
12833
  props: {
13108
- query: "SELECT * FROM inventory WHERE stock < 50",
13109
- title: "Low Stock Items",
13110
- showRowNumbers: false
12834
+ city: "Tokyo",
12835
+ units: "metric",
12836
+ days: 5
13111
12837
  }
13112
12838
  }
13113
12839
  ]
@@ -13125,7 +12851,7 @@ async function runPluginDemo() {
13125
12851
  theme: minimalTheme,
13126
12852
  debug: true
13127
12853
  // Enable debug logging
13128
- }).addComponent(weatherComponent).addComponent(columnsLayoutComponent).addComponent(nestedSectionsComponent);
12854
+ }).addComponent(weatherComponent);
13129
12855
  console.log(
13130
12856
  "\u2705 Registered components:",
13131
12857
  generator.getComponentNames().join(", ")
@@ -13173,10 +12899,7 @@ async function runPluginDemo() {
13173
12899
  await fs3.writeFile(outputPath, new Uint8Array(result.buffer));
13174
12900
  console.log(`\u2705 Document saved to: ${outputPath}`);
13175
12901
  const schemaPath = path2.join(outputDir, "plugin-demo-schema.json");
13176
- await exportPluginSchema(
13177
- [weatherComponent, columnsLayoutComponent, nestedSectionsComponent],
13178
- schemaPath
13179
- );
12902
+ await exportPluginSchema([weatherComponent], schemaPath);
13180
12903
  console.log(`\u2705 Schema saved to: ${schemaPath}`);
13181
12904
  } catch (error) {
13182
12905
  console.error("\u274C Error generating document:", error);