datastake-daf 0.6.464 → 0.6.465

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.
@@ -21,9 +21,29 @@ require('deepmerge');
21
21
  var countriesList = require('countries-list');
22
22
  require('country-city-location');
23
23
  require('leaflet-editable');
24
+ var htmlToImage = require('html-to-image');
25
+ var docx = require('docx');
24
26
 
25
27
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
26
28
 
29
+ function _interopNamespace(e) {
30
+ if (e && e.__esModule) return e;
31
+ var n = Object.create(null);
32
+ if (e) {
33
+ Object.keys(e).forEach(function (k) {
34
+ if (k !== 'default') {
35
+ var d = Object.getOwnPropertyDescriptor(e, k);
36
+ Object.defineProperty(n, k, d.get ? d : {
37
+ enumerable: true,
38
+ get: function () { return e[k]; }
39
+ });
40
+ }
41
+ });
42
+ }
43
+ n["default"] = e;
44
+ return Object.freeze(n);
45
+ }
46
+
27
47
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
28
48
  var PropTypes__default = /*#__PURE__*/_interopDefaultLegacy(PropTypes);
29
49
  var ___default = /*#__PURE__*/_interopDefaultLegacy(_$2);
@@ -31,6 +51,7 @@ var dot__default = /*#__PURE__*/_interopDefaultLegacy(dot);
31
51
  var moment__default = /*#__PURE__*/_interopDefaultLegacy(moment);
32
52
  var dayjs__default = /*#__PURE__*/_interopDefaultLegacy(dayjs);
33
53
  var L__default = /*#__PURE__*/_interopDefaultLegacy(L$2);
54
+ var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
34
55
 
35
56
  const mmtTheme = {
36
57
  // Base
@@ -12617,14 +12638,655 @@ function displayMessage(type, m) {
12617
12638
  antd.message[type](m);
12618
12639
  }
12619
12640
 
12641
+ /**
12642
+ * Captures one or multiple DOM elements and returns their images as base64 strings.
12643
+ *
12644
+ * @param elements - A single element or an array of elements (or refs)
12645
+ * @param options - Optional html-to-image options (e.g., { cacheBust: true })
12646
+ * @returns Promise<string[]> - Array of base64 PNG strings (same order as input)
12647
+ */
12648
+ async function captureElementsAsImages(elements, options = {
12649
+ cacheBust: true
12650
+ }) {
12651
+ const targets = Array.isArray(elements) ? elements : [elements];
12652
+ const validElements = targets.filter(Boolean);
12653
+ const captures = await Promise.all(validElements.map(async el => {
12654
+ try {
12655
+ return await htmlToImage.toPng(el, options);
12656
+ } catch (err) {
12657
+ console.error("Error capturing element as image:", err);
12658
+ return "";
12659
+ }
12660
+ }));
12661
+ return captures;
12662
+ }
12663
+
12664
+ /**
12665
+ * Renders different types of document elements based on type
12666
+ * @param {Object} item - Configuration item
12667
+ * @param {string} item.type - Type of element (paragraph, heading, table, image, etc.)
12668
+ * @param {any} item.data - Data for the element
12669
+ * @param {Object} item.meta - Metadata/styling for text runs
12670
+ * @param {Object} item.style - Style properties for the element
12671
+ * @returns {docx element} The rendered document element
12672
+ */
12673
+ const renderElement = item => {
12674
+ const {
12675
+ type = 'paragraph',
12676
+ data,
12677
+ meta = {},
12678
+ style = {}
12679
+ } = item;
12680
+ switch (type) {
12681
+ case 'paragraph':
12682
+ return new docx__namespace.Paragraph({
12683
+ children: [new docx__namespace.TextRun({
12684
+ text: data,
12685
+ ...meta
12686
+ })],
12687
+ ...style
12688
+ });
12689
+ case 'heading':
12690
+ return new docx__namespace.Paragraph({
12691
+ text: data,
12692
+ heading: style.heading || docx__namespace.HeadingLevel.HEADING_1,
12693
+ ...style
12694
+ });
12695
+ case 'table':
12696
+ return new docx__namespace.Table({
12697
+ rows: data.map(row => new docx__namespace.TableRow({
12698
+ children: row.map(cell => new docx__namespace.TableCell({
12699
+ children: [new docx__namespace.Paragraph(cell)]
12700
+ }))
12701
+ })),
12702
+ ...style
12703
+ });
12704
+ case 'image':
12705
+ return new docx__namespace.Paragraph({
12706
+ children: [new docx__namespace.ImageRun({
12707
+ data: data,
12708
+ transformation: {
12709
+ width: style.width || 100,
12710
+ height: style.height || 100
12711
+ },
12712
+ ...meta
12713
+ })],
12714
+ ...style
12715
+ });
12716
+ case 'imageWithText':
12717
+ {
12718
+ // Creates a table with image and text side by side
12719
+ // imagePosition: 'left' (default) or 'right'
12720
+ const imagePosition = data.imagePosition || 'left';
12721
+
12722
+ // Create image cell
12723
+ const imageCell = new docx__namespace.TableCell({
12724
+ children: [...(data.image ? [new docx__namespace.Paragraph({
12725
+ children: [new docx__namespace.ImageRun({
12726
+ data: data.image,
12727
+ transformation: {
12728
+ width: data.imageWidth || 250,
12729
+ height: data.imageHeight || 200
12730
+ }
12731
+ })]
12732
+ })] : [new docx__namespace.Paragraph({
12733
+ text: '[Image placeholder]',
12734
+ shading: {
12735
+ fill: 'F0F0F0'
12736
+ }
12737
+ })])],
12738
+ width: {
12739
+ size: 50,
12740
+ type: docx__namespace.WidthType.PERCENTAGE
12741
+ },
12742
+ borders: {
12743
+ top: {
12744
+ style: docx__namespace.BorderStyle.SINGLE,
12745
+ size: 1,
12746
+ color: 'CCCCCC'
12747
+ },
12748
+ bottom: {
12749
+ style: docx__namespace.BorderStyle.SINGLE,
12750
+ size: 1,
12751
+ color: 'CCCCCC'
12752
+ },
12753
+ left: {
12754
+ style: docx__namespace.BorderStyle.SINGLE,
12755
+ size: 1,
12756
+ color: 'CCCCCC'
12757
+ },
12758
+ right: {
12759
+ style: docx__namespace.BorderStyle.SINGLE,
12760
+ size: 1,
12761
+ color: 'CCCCCC'
12762
+ }
12763
+ }
12764
+ });
12765
+
12766
+ // Create text cell
12767
+ const textCell = new docx__namespace.TableCell({
12768
+ children: [new docx__namespace.Paragraph({
12769
+ children: [new docx__namespace.TextRun({
12770
+ text: data.text || '',
12771
+ size: 22
12772
+ })]
12773
+ })],
12774
+ width: {
12775
+ size: 50,
12776
+ type: docx__namespace.WidthType.PERCENTAGE
12777
+ },
12778
+ borders: {
12779
+ top: {
12780
+ style: docx__namespace.BorderStyle.SINGLE,
12781
+ size: 1,
12782
+ color: 'CCCCCC'
12783
+ },
12784
+ bottom: {
12785
+ style: docx__namespace.BorderStyle.SINGLE,
12786
+ size: 1,
12787
+ color: 'CCCCCC'
12788
+ },
12789
+ left: {
12790
+ style: docx__namespace.BorderStyle.SINGLE,
12791
+ size: 1,
12792
+ color: 'CCCCCC'
12793
+ },
12794
+ right: {
12795
+ style: docx__namespace.BorderStyle.SINGLE,
12796
+ size: 1,
12797
+ color: 'CCCCCC'
12798
+ }
12799
+ }
12800
+ });
12801
+
12802
+ // Arrange cells based on image position
12803
+ const cells = imagePosition === 'right' ? [textCell, imageCell] : [imageCell, textCell];
12804
+ const table = new docx__namespace.Table({
12805
+ rows: [new docx__namespace.TableRow({
12806
+ children: cells
12807
+ })],
12808
+ width: {
12809
+ size: 100,
12810
+ type: docx__namespace.WidthType.PERCENTAGE
12811
+ },
12812
+ ...style
12813
+ });
12814
+
12815
+ // Add spacing paragraph after the table
12816
+ return [table, ...(data.hasSpacing ? [new docx__namespace.Paragraph({
12817
+ spacing: {
12818
+ after: 200
12819
+ }
12820
+ })] : [])];
12821
+ }
12822
+ case 'borderedSection':
12823
+ {
12824
+ // Creates a bordered section (like the editable areas)
12825
+ const table = new docx__namespace.Table({
12826
+ rows: [new docx__namespace.TableRow({
12827
+ children: [new docx__namespace.TableCell({
12828
+ children: [new docx__namespace.Paragraph({
12829
+ children: [new docx__namespace.TextRun({
12830
+ text: data.title || '',
12831
+ bold: true,
12832
+ size: 24
12833
+ })],
12834
+ spacing: {
12835
+ after: 200
12836
+ }
12837
+ }), new docx__namespace.Paragraph({
12838
+ children: [new docx__namespace.TextRun({
12839
+ text: data.content || 'Editable - to be filled by the user',
12840
+ italic: true,
12841
+ size: 22,
12842
+ color: '666666'
12843
+ })]
12844
+ })],
12845
+ borders: {
12846
+ top: {
12847
+ style: docx__namespace.BorderStyle.SINGLE,
12848
+ size: 6,
12849
+ color: 'CCCCCC'
12850
+ },
12851
+ bottom: {
12852
+ style: docx__namespace.BorderStyle.SINGLE,
12853
+ size: 6,
12854
+ color: 'CCCCCC'
12855
+ },
12856
+ left: {
12857
+ style: docx__namespace.BorderStyle.SINGLE,
12858
+ size: 6,
12859
+ color: 'CCCCCC'
12860
+ },
12861
+ right: {
12862
+ style: docx__namespace.BorderStyle.SINGLE,
12863
+ size: 6,
12864
+ color: 'CCCCCC'
12865
+ }
12866
+ },
12867
+ shading: {
12868
+ fill: 'F9F9F9'
12869
+ }
12870
+ })]
12871
+ })],
12872
+ width: {
12873
+ size: 100,
12874
+ type: docx__namespace.WidthType.PERCENTAGE
12875
+ },
12876
+ ...style
12877
+ });
12878
+
12879
+ // Add spacing paragraph after the table
12880
+ return [table, new docx__namespace.Paragraph({
12881
+ spacing: {
12882
+ after: 400
12883
+ }
12884
+ })];
12885
+ }
12886
+ case 'documentHeader':
12887
+ {
12888
+ // Creates a document header with title, optional icon, and dynamic info fields
12889
+ // data structure: { title, icon, infoFields: [{ label, value }] }
12890
+ const {
12891
+ title,
12892
+ icon,
12893
+ infoFields = [],
12894
+ titleTextColor = '000000'
12895
+ } = data;
12896
+ const headerCells = [];
12897
+
12898
+ // Title cell (left side)
12899
+ const titleCell = new docx__namespace.TableCell({
12900
+ children: [new docx__namespace.Paragraph({
12901
+ children: [new docx__namespace.TextRun({
12902
+ text: title || 'Document Title',
12903
+ bold: true,
12904
+ size: 28,
12905
+ color: titleTextColor
12906
+ })],
12907
+ alignment: docx__namespace.AlignmentType.LEFT
12908
+ })],
12909
+ verticalAlign: docx__namespace.VerticalAlign.CENTER,
12910
+ margins: {
12911
+ top: 0,
12912
+ bottom: 0,
12913
+ left: 0,
12914
+ right: 0
12915
+ },
12916
+ borders: {
12917
+ top: {
12918
+ style: docx__namespace.BorderStyle.NONE
12919
+ },
12920
+ bottom: {
12921
+ style: docx__namespace.BorderStyle.NONE
12922
+ },
12923
+ left: {
12924
+ style: docx__namespace.BorderStyle.NONE
12925
+ },
12926
+ right: {
12927
+ style: docx__namespace.BorderStyle.NONE
12928
+ }
12929
+ }
12930
+ });
12931
+ headerCells.push(titleCell);
12932
+
12933
+ // Icon cell (right side) - optional
12934
+ if (icon) {
12935
+ const iconCell = new docx__namespace.TableCell({
12936
+ children: [new docx__namespace.Paragraph({
12937
+ children: [new docx__namespace.ImageRun({
12938
+ data: icon,
12939
+ transformation: {
12940
+ width: data.iconWidth || 80,
12941
+ height: data.iconHeight || 80
12942
+ }
12943
+ })],
12944
+ alignment: docx__namespace.AlignmentType.RIGHT
12945
+ })],
12946
+ verticalAlign: docx__namespace.VerticalAlign.CENTER,
12947
+ width: {
12948
+ size: 15,
12949
+ type: docx__namespace.WidthType.PERCENTAGE
12950
+ },
12951
+ margins: {
12952
+ top: 0,
12953
+ bottom: 0,
12954
+ left: 0,
12955
+ right: 0
12956
+ },
12957
+ borders: {
12958
+ top: {
12959
+ style: docx__namespace.BorderStyle.NONE
12960
+ },
12961
+ bottom: {
12962
+ style: docx__namespace.BorderStyle.NONE
12963
+ },
12964
+ left: {
12965
+ style: docx__namespace.BorderStyle.NONE
12966
+ },
12967
+ right: {
12968
+ style: docx__namespace.BorderStyle.NONE
12969
+ }
12970
+ }
12971
+ });
12972
+ headerCells.push(iconCell);
12973
+ }
12974
+
12975
+ // Create title row
12976
+ const titleRow = new docx__namespace.TableRow({
12977
+ children: headerCells
12978
+ });
12979
+
12980
+ // Create info fields row if provided
12981
+ const rows = [titleRow];
12982
+ if (infoFields && infoFields.length > 0) {
12983
+ // Build the info text with dynamic fields
12984
+ const infoTextRuns = [];
12985
+ infoFields.forEach((field, index) => {
12986
+ // Add label (bold)
12987
+ infoTextRuns.push(new docx__namespace.TextRun({
12988
+ text: field.label,
12989
+ bold: true,
12990
+ size: 20
12991
+ }));
12992
+ // Add value (normal)
12993
+ infoTextRuns.push(new docx__namespace.TextRun({
12994
+ text: ` ${field.value}`,
12995
+ size: 20
12996
+ }));
12997
+ // Add separator if not last item
12998
+ if (index < infoFields.length - 1) {
12999
+ infoTextRuns.push(new docx__namespace.TextRun({
13000
+ text: ' | ',
13001
+ size: 20
13002
+ }));
13003
+ }
13004
+ });
13005
+ const infoRow = new docx__namespace.TableRow({
13006
+ children: [new docx__namespace.TableCell({
13007
+ children: [new docx__namespace.Paragraph({
13008
+ children: infoTextRuns,
13009
+ spacing: {
13010
+ before: 50,
13011
+ after: 0
13012
+ }
13013
+ })],
13014
+ columnSpan: headerCells.length,
13015
+ margins: {
13016
+ top: 0,
13017
+ bottom: 0,
13018
+ left: 0,
13019
+ right: 0
13020
+ },
13021
+ borders: {
13022
+ top: {
13023
+ style: docx__namespace.BorderStyle.NONE
13024
+ },
13025
+ bottom: {
13026
+ style: docx__namespace.BorderStyle.NONE
13027
+ },
13028
+ left: {
13029
+ style: docx__namespace.BorderStyle.NONE
13030
+ },
13031
+ right: {
13032
+ style: docx__namespace.BorderStyle.NONE
13033
+ }
13034
+ }
13035
+ })]
13036
+ });
13037
+ rows.push(infoRow);
13038
+ }
13039
+ const table = new docx__namespace.Table({
13040
+ rows: rows,
13041
+ width: {
13042
+ size: 100,
13043
+ type: docx__namespace.WidthType.PERCENTAGE
13044
+ },
13045
+ borders: {
13046
+ top: {
13047
+ style: docx__namespace.BorderStyle.NONE
13048
+ },
13049
+ bottom: {
13050
+ style: docx__namespace.BorderStyle.NONE
13051
+ },
13052
+ left: {
13053
+ style: docx__namespace.BorderStyle.NONE
13054
+ },
13055
+ right: {
13056
+ style: docx__namespace.BorderStyle.NONE
13057
+ },
13058
+ insideHorizontal: {
13059
+ style: docx__namespace.BorderStyle.NONE
13060
+ },
13061
+ insideVertical: {
13062
+ style: docx__namespace.BorderStyle.NONE
13063
+ }
13064
+ },
13065
+ ...style
13066
+ });
13067
+
13068
+ // Add spacing paragraph after the header
13069
+ return [table, new docx__namespace.Paragraph({
13070
+ spacing: {
13071
+ after: 200
13072
+ }
13073
+ })];
13074
+ }
13075
+ case 'commentSection':
13076
+ {
13077
+ // Creates a bordered section with heading and auto-filled comments
13078
+ const sectionChildren = [];
13079
+
13080
+ // Create title paragraph with percentage if provided
13081
+ if (data.percentage !== undefined) {
13082
+ sectionChildren.push(new docx__namespace.Paragraph({
13083
+ children: [new docx__namespace.TextRun({
13084
+ text: data.title,
13085
+ bold: true,
13086
+ size: 24
13087
+ }), new docx__namespace.TextRun({
13088
+ text: "\t\t\t\t\t\t\t\t\t\t\t\t\t\t"
13089
+ }), new docx__namespace.TextRun({
13090
+ text: `○ ${data.percentage}%`,
13091
+ color: 'FFA500',
13092
+ size: 20,
13093
+ bold: false
13094
+ })],
13095
+ spacing: {
13096
+ after: 100
13097
+ }
13098
+ }));
13099
+ } else {
13100
+ sectionChildren.push(new docx__namespace.Paragraph({
13101
+ text: data.title,
13102
+ bold: true,
13103
+ size: 24,
13104
+ spacing: {
13105
+ after: 100
13106
+ }
13107
+ }));
13108
+ }
13109
+
13110
+ // Add description with bottom border
13111
+ sectionChildren.push(new docx__namespace.Paragraph({
13112
+ children: [new docx__namespace.TextRun({
13113
+ text: data.description,
13114
+ size: 20
13115
+ })],
13116
+ spacing: {
13117
+ after: 150
13118
+ },
13119
+ border: {
13120
+ bottom: {
13121
+ style: docx__namespace.BorderStyle.SINGLE,
13122
+ size: 6,
13123
+ color: 'CCCCCC'
13124
+ }
13125
+ }
13126
+ }));
13127
+
13128
+ // Add bullet points
13129
+ if (data.comments && Array.isArray(data.comments)) {
13130
+ data.comments.forEach((comment, index) => {
13131
+ sectionChildren.push(new docx__namespace.Paragraph({
13132
+ text: comment,
13133
+ bullet: {
13134
+ level: 0
13135
+ },
13136
+ spacing: {
13137
+ before: index === 0 ? 100 : 0,
13138
+ after: index === data.comments.length - 1 ? 100 : 50
13139
+ }
13140
+ }));
13141
+ });
13142
+ }
13143
+
13144
+ // Wrap everything in a bordered table
13145
+ const table = new docx__namespace.Table({
13146
+ rows: [new docx__namespace.TableRow({
13147
+ children: [new docx__namespace.TableCell({
13148
+ children: sectionChildren,
13149
+ borders: {
13150
+ top: {
13151
+ style: docx__namespace.BorderStyle.SINGLE,
13152
+ size: 6,
13153
+ color: '000000'
13154
+ },
13155
+ bottom: {
13156
+ style: docx__namespace.BorderStyle.SINGLE,
13157
+ size: 6,
13158
+ color: '000000'
13159
+ },
13160
+ left: {
13161
+ style: docx__namespace.BorderStyle.SINGLE,
13162
+ size: 6,
13163
+ color: '000000'
13164
+ },
13165
+ right: {
13166
+ style: docx__namespace.BorderStyle.SINGLE,
13167
+ size: 6,
13168
+ color: '000000'
13169
+ }
13170
+ },
13171
+ margins: {
13172
+ top: 100,
13173
+ bottom: 100,
13174
+ left: 100,
13175
+ right: 100
13176
+ }
13177
+ })]
13178
+ })],
13179
+ width: {
13180
+ size: 100,
13181
+ type: docx__namespace.WidthType.PERCENTAGE
13182
+ },
13183
+ ...style
13184
+ });
13185
+
13186
+ // Add minimal spacing after comment sections (they look good close together)
13187
+ return table;
13188
+ }
13189
+ case 'bulletList':
13190
+ return new docx__namespace.Paragraph({
13191
+ text: data,
13192
+ bullet: {
13193
+ level: style.level || 0
13194
+ },
13195
+ ...style
13196
+ });
13197
+ case 'numberedList':
13198
+ return new docx__namespace.Paragraph({
13199
+ text: data,
13200
+ numbering: {
13201
+ reference: style.reference || "default-numbering",
13202
+ level: style.level || 0
13203
+ },
13204
+ ...style
13205
+ });
13206
+ case 'pageBreak':
13207
+ return new docx__namespace.Paragraph({
13208
+ children: [new docx__namespace.PageBreak()]
13209
+ });
13210
+ case 'textRun':
13211
+ return new docx__namespace.Paragraph({
13212
+ children: [new docx__namespace.TextRun({
13213
+ text: data,
13214
+ ...meta
13215
+ })],
13216
+ ...style
13217
+ });
13218
+ default:
13219
+ // Default to paragraph if type is unknown
13220
+ return new docx__namespace.Paragraph({
13221
+ children: [new docx__namespace.TextRun({
13222
+ text: data,
13223
+ ...meta
13224
+ })],
13225
+ ...style
13226
+ });
13227
+ }
13228
+ };
13229
+
13230
+ /**
13231
+ * Creates a Word document with the provided content
13232
+ * @param {Object} options - Configuration options for the document
13233
+ * @param {string} options.title - The main title of the document
13234
+ * @param {string} options.content - Additional content to include
13235
+ * @param {Array} options.config - Array of configuration items with type, data, meta, style, and optional title
13236
+ * @returns {docx.Document} The created Word document
13237
+ */
13238
+ const createDocument = ({
13239
+ title = "React Word Document Example",
13240
+ content = "This is a sample Word document created with docx library.",
13241
+ config = []
13242
+ }) => {
13243
+ // Process config items - add section titles if provided
13244
+ const children = config.flatMap(item => {
13245
+ const elements = [];
13246
+
13247
+ // If item has a title property, add it as a section heading
13248
+ if (item.title) {
13249
+ elements.push(new docx__namespace.Paragraph({
13250
+ children: [new docx__namespace.TextRun({
13251
+ text: item.title,
13252
+ bold: true,
13253
+ size: 26,
13254
+ color: '000000'
13255
+ })],
13256
+ spacing: {
13257
+ before: item.titleSpacing?.before || 300,
13258
+ after: item.titleSpacing?.after || 150
13259
+ },
13260
+ ...item.titleStyle
13261
+ }));
13262
+ }
13263
+
13264
+ // Add the actual element content
13265
+ const renderedElement = renderElement(item);
13266
+ if (Array.isArray(renderedElement)) {
13267
+ elements.push(...renderedElement);
13268
+ } else {
13269
+ elements.push(renderedElement);
13270
+ }
13271
+ return elements;
13272
+ });
13273
+ return new docx__namespace.Document({
13274
+ sections: [{
13275
+ children: children
13276
+ }]
13277
+ });
13278
+ };
13279
+
12620
13280
  exports.ErrorFormat = ErrorFormat;
12621
13281
  exports.MessageTypes = MessageTypes;
12622
13282
  exports.btn = button;
12623
13283
  exports.camelCaseToTitle = camelCaseToTitle;
12624
13284
  exports.capitalize = capitalize;
12625
13285
  exports.capitalizeAll = capitalizeAll;
13286
+ exports.captureElementsAsImages = captureElementsAsImages;
12626
13287
  exports.changeInputMeta = changeInputMeta;
12627
13288
  exports.convertUndefinedToNull = convertUndefinedToNull;
13289
+ exports.createDocument = createDocument;
12628
13290
  exports.defaultFilterKeys = defaultFilterKeys;
12629
13291
  exports.defaultMapConfig = defaultMapConfig;
12630
13292
  exports.defaultTheme = mmtTheme;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datastake-daf",
3
- "version": "0.6.464",
3
+ "version": "0.6.465",
4
4
  "dependencies": {
5
5
  "@ant-design/icons": "^5.2.5",
6
6
  "@antv/g2": "^5.1.1",
@@ -22,6 +22,7 @@
22
22
  "docx-preview": "^0.3.7",
23
23
  "dot-object": "^2.1.5",
24
24
  "file-saver": "^2.0.5",
25
+ "html-to-image": "^1.11.13",
25
26
  "leaflet": "^1.0.3",
26
27
  "leaflet-editable": "^1.3.0",
27
28
  "leaflet-geosearch": "^3.1.0",
package/rollup.config.js CHANGED
@@ -40,6 +40,10 @@ const external = [
40
40
  "@xyflow/react",
41
41
  "zustand/shallow",
42
42
  "@elfalem/leaflet-curve",
43
+ "html-to-image",
44
+ "docx",
45
+ "docx-preview",
46
+ "file-saver",
43
47
  ];
44
48
 
45
49
  // Four builds, components, utils, hooks, context
@@ -1,4 +1,6 @@
1
1
  import WordDocumentPreview from "./index";
2
+ import React, { useRef, useState, useEffect } from 'react';
3
+ import { captureElementsAsImages } from '../../../../../../helpers/componentsToImages';
2
4
 
3
5
  export default {
4
6
  title: "Core/Document/WordDocument",
@@ -439,3 +441,200 @@ export const SectionTitlesExample = {
439
441
  ]
440
442
  }
441
443
  };
444
+
445
+ // Custom render function to capture components as images
446
+ const ComponentToImageStory = () => {
447
+ const chartRef = useRef(null);
448
+ const cardRef = useRef(null);
449
+ const [config, setConfig] = useState([
450
+ {
451
+ type: 'heading',
452
+ data: 'Component to Image Demo',
453
+ style: { heading: 'HEADING_1', spacing: { after: 200 } }
454
+ },
455
+ {
456
+ type: 'paragraph',
457
+ data: 'Loading component images...',
458
+ meta: { size: 22 }
459
+ }
460
+ ]);
461
+
462
+ useEffect(() => {
463
+ const captureComponents = async () => {
464
+ // Wait for components to render
465
+ await new Promise(resolve => setTimeout(resolve, 500));
466
+
467
+ // Capture the components as images
468
+ const images = await captureElementsAsImages([chartRef.current, cardRef.current]);
469
+
470
+ // Create new config with the captured images
471
+ const newConfig = [
472
+ {
473
+ type: 'heading',
474
+ data: 'Component to Image Demo',
475
+ style: { heading: 'HEADING_1', spacing: { after: 200 } }
476
+ },
477
+ {
478
+ type: 'paragraph',
479
+ data: 'Below are React components that were captured and converted to images using the captureElementsAsImages helper:',
480
+ meta: { size: 22 },
481
+ style: { spacing: { after: 300 } }
482
+ },
483
+ {
484
+ type: 'heading',
485
+ data: 'Chart Component',
486
+ style: { heading: 'HEADING_2', spacing: { after: 200 } }
487
+ },
488
+ {
489
+ type: 'image',
490
+ data: images[0], // Base64 image of the chart
491
+ style: {
492
+ width: 400,
493
+ height: 250,
494
+ }
495
+ },
496
+ {
497
+ type: 'paragraph',
498
+ data: 'The above chart was rendered as a React component and captured as an image.',
499
+ meta: { size: 20 },
500
+ style: { spacing: { before: 200, after: 300 } }
501
+ },
502
+ {
503
+ type: 'heading',
504
+ data: 'Card Component',
505
+ style: { heading: 'HEADING_2', spacing: { after: 200 } }
506
+ },
507
+ {
508
+ type: 'image',
509
+ data: images[1], // Base64 image of the card
510
+ style: {
511
+ width: 350,
512
+ height: 200,
513
+ }
514
+ },
515
+ {
516
+ type: 'paragraph',
517
+ data: 'The above card component was also captured and converted to an image for the document.',
518
+ meta: { size: 20 },
519
+ style: { spacing: { before: 200 } }
520
+ }
521
+ ];
522
+
523
+ setConfig(newConfig);
524
+ };
525
+
526
+ captureComponents();
527
+ }, []);
528
+
529
+ return (
530
+ <div>
531
+ {/* Hidden components that will be captured as images */}
532
+ <div style={{ position: 'absolute', left: '-9999px', top: '-9999px' }}>
533
+ {/* Sample Chart Component */}
534
+ <div ref={chartRef} style={{
535
+ width: '600px',
536
+ height: '400px',
537
+ background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
538
+ borderRadius: '10px',
539
+ padding: '30px',
540
+ boxShadow: '0 10px 30px rgba(0,0,0,0.2)',
541
+ color: 'white',
542
+ fontFamily: 'Arial, sans-serif'
543
+ }}>
544
+ <h2 style={{ margin: '0 0 20px 0', fontSize: '28px' }}>Performance Chart</h2>
545
+ <div style={{ display: 'flex', justifyContent: 'space-around', alignItems: 'flex-end', height: '250px', marginTop: '40px' }}>
546
+ <div style={{
547
+ width: '80px',
548
+ height: '60%',
549
+ background: 'rgba(255,255,255,0.8)',
550
+ borderRadius: '5px',
551
+ display: 'flex',
552
+ alignItems: 'flex-end',
553
+ justifyContent: 'center',
554
+ paddingBottom: '10px',
555
+ fontWeight: 'bold',
556
+ color: '#667eea'
557
+ }}>Q1</div>
558
+ <div style={{
559
+ width: '80px',
560
+ height: '75%',
561
+ background: 'rgba(255,255,255,0.8)',
562
+ borderRadius: '5px',
563
+ display: 'flex',
564
+ alignItems: 'flex-end',
565
+ justifyContent: 'center',
566
+ paddingBottom: '10px',
567
+ fontWeight: 'bold',
568
+ color: '#667eea'
569
+ }}>Q2</div>
570
+ <div style={{
571
+ width: '80px',
572
+ height: '85%',
573
+ background: 'rgba(255,255,255,0.8)',
574
+ borderRadius: '5px',
575
+ display: 'flex',
576
+ alignItems: 'flex-end',
577
+ justifyContent: 'center',
578
+ paddingBottom: '10px',
579
+ fontWeight: 'bold',
580
+ color: '#667eea'
581
+ }}>Q3</div>
582
+ <div style={{
583
+ width: '80px',
584
+ height: '95%',
585
+ background: 'rgba(255,255,255,0.8)',
586
+ borderRadius: '5px',
587
+ display: 'flex',
588
+ alignItems: 'flex-end',
589
+ justifyContent: 'center',
590
+ paddingBottom: '10px',
591
+ fontWeight: 'bold',
592
+ color: '#667eea'
593
+ }}>Q4</div>
594
+ </div>
595
+ </div>
596
+
597
+ {/* Sample Card Component */}
598
+ <div ref={cardRef} style={{
599
+ width: '500px',
600
+ height: '300px',
601
+ background: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',
602
+ borderRadius: '15px',
603
+ padding: '40px',
604
+ boxShadow: '0 10px 30px rgba(0,0,0,0.2)',
605
+ color: 'white',
606
+ fontFamily: 'Arial, sans-serif',
607
+ display: 'flex',
608
+ flexDirection: 'column',
609
+ justifyContent: 'space-between'
610
+ }}>
611
+ <div>
612
+ <h2 style={{ margin: '0 0 15px 0', fontSize: '32px' }}>Dashboard Card</h2>
613
+ <p style={{ margin: '0', fontSize: '18px', opacity: 0.9 }}>Total Users: 1,234</p>
614
+ </div>
615
+ <div style={{
616
+ background: 'rgba(255,255,255,0.2)',
617
+ borderRadius: '10px',
618
+ padding: '20px',
619
+ backdropFilter: 'blur(10px)'
620
+ }}>
621
+ <div style={{ fontSize: '48px', fontWeight: 'bold', marginBottom: '5px' }}>+15%</div>
622
+ <div style={{ fontSize: '16px', opacity: 0.9 }}>Growth this month</div>
623
+ </div>
624
+ </div>
625
+ </div>
626
+
627
+ {/* The Word Document Preview */}
628
+ <WordDocumentPreview
629
+ title="Components to Images"
630
+ fileName="components-to-images.docx"
631
+ config={config}
632
+ />
633
+ </div>
634
+ );
635
+ };
636
+
637
+ export const ComponentsToImagesExample = {
638
+ name: "Components to Images",
639
+ render: () => <ComponentToImageStory />
640
+ };
@@ -370,10 +370,13 @@ const renderElement = (item) => {
370
370
  new docx.Paragraph({
371
371
  children: [
372
372
  new docx.TextRun({
373
- text: data.title + ' ',
373
+ text: data.title,
374
374
  bold: true,
375
375
  size: 24
376
- }),
376
+ }),
377
+ new docx.TextRun({
378
+ text: "\t\t\t\t\t\t\t\t\t\t\t\t\t\t",
379
+ }),
377
380
  new docx.TextRun({
378
381
  text: `○ ${data.percentage}%`,
379
382
  color: 'FFA500',
@@ -0,0 +1,29 @@
1
+ import { toPng } from "html-to-image";
2
+
3
+ /**
4
+ * Captures one or multiple DOM elements and returns their images as base64 strings.
5
+ *
6
+ * @param elements - A single element or an array of elements (or refs)
7
+ * @param options - Optional html-to-image options (e.g., { cacheBust: true })
8
+ * @returns Promise<string[]> - Array of base64 PNG strings (same order as input)
9
+ */
10
+ export async function captureElementsAsImages(
11
+ elements,
12
+ options = { cacheBust: true }
13
+ ) {
14
+ const targets = Array.isArray(elements) ? elements : [elements];
15
+ const validElements = targets.filter(Boolean);
16
+
17
+ const captures = await Promise.all(
18
+ validElements.map(async (el) => {
19
+ try {
20
+ return await toPng(el, options);
21
+ } catch (err) {
22
+ console.error("Error capturing element as image:", err);
23
+ return "";
24
+ }
25
+ })
26
+ );
27
+
28
+ return captures;
29
+ }
package/src/utils.js CHANGED
@@ -34,3 +34,7 @@ export { default as ErrorFormat, formatErrors } from './helpers/ErrorFormater'
34
34
  export { renderNumber, renderPercentage } from "./@daf/utils/numbers.js"
35
35
 
36
36
  export { MessageTypes, displayMessage} from './helpers/messages.js'
37
+
38
+ export { captureElementsAsImages } from './helpers/componentsToImages.js'
39
+
40
+ export { createDocument } from './@daf/core/components/Document/WordDocument/createDocument.js'