datastake-daf 0.6.421 → 0.6.422

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datastake-daf",
3
- "version": "0.6.421",
3
+ "version": "0.6.422",
4
4
  "dependencies": {
5
5
  "@ant-design/icons": "^5.2.5",
6
6
  "@antv/g2": "^5.1.1",
@@ -189,5 +189,15 @@ export const Primary = {
189
189
  },
190
190
  ],
191
191
  },
192
- }
193
-
192
+ render: (args) => (
193
+ <div style={{
194
+ height: '100vh',
195
+ overflowY: 'auto',
196
+ background: "#f8f8f8",
197
+ padding: "20px",
198
+ }}
199
+ >
200
+ <PdfView {...args} />
201
+ </div>
202
+ ),
203
+ };
@@ -1,41 +1,17 @@
1
1
  import moment from "moment";
2
2
  import PropTypes from 'prop-types';
3
- import { useCallback, useEffect, useRef, useState } from "react";
3
+ import { Fragment, useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
4
4
  import { formatClassname } from "../../../../../helpers/ClassesHelper";
5
5
 
6
6
  const PAGE_HEIGHT = 1587;
7
- // margin-top: 20, bottom: 20;
8
7
  const FOOTER_HEIGHT = 70;
9
8
  const HEADER_HEIGHT = 100;
9
+ const PAGE_MARGIN_TOP = 20;
10
+ const PAGE_MARGIN_BOTTOM = 20;
11
+ const CONTENT_HEIGHT = 1200; // 1397px
12
+ const SECTION_GAP = 24;
10
13
 
11
- const Row = ({ widgets, i, onChangeHeight = () => { } }) => {
12
- const ref = useRef();
13
- const [height, setHeight] = useState(0);
14
-
15
- useEffect(() => {
16
- const observer = new ResizeObserver((entries) => {
17
- for (const entry of entries) {
18
- setHeight(entry.contentRect.height);
19
- }
20
- });
21
-
22
- observer.observe(ref.current);
23
-
24
- return () => observer.disconnect();
25
- }, []);
26
-
27
- useEffect(() => {
28
- if (height) {
29
- onChangeHeight(i, { height, ref });
30
- }
31
- }, [height])
32
-
33
- return (
34
- <section ref={ref} style={widgets.style}>
35
- {typeof widgets.render === 'function' ? widgets.render() : null}
36
- </section>
37
- )
38
- };
14
+ const isHTMLElement = (node) => node instanceof HTMLElement;
39
15
 
40
16
  export default function PdfView({
41
17
  config = [],
@@ -47,104 +23,224 @@ export default function PdfView({
47
23
  documentId = 'IDD-0000000',
48
24
  downloadId = 'DWL-00000123',
49
25
  }) {
50
- const [sectionsConfig, setSectionsConfig] = useState({});
51
26
  const [pages, setPages] = useState([1]);
27
+ const contentRef = useRef(null);
28
+ const sectionsRef = useRef([]);
29
+
30
+ const resetPaginationStyles = useCallback((sections) => {
31
+ sections.forEach((section) => {
32
+ if (!section) return;
33
+ section.style.marginTop = '';
34
+ section.style.marginBottom = '';
35
+ section.style.pageBreakBefore = '';
36
+ section.style.breakBefore = '';
37
+ section.removeAttribute('data-pdf-page');
38
+
39
+ // Reset all children
40
+ const allElements = section.querySelectorAll('*');
41
+ allElements.forEach((el) => {
42
+ if (!isHTMLElement(el)) return;
43
+ el.style.marginTop = '';
44
+ el.style.marginBottom = '';
45
+ el.style.pageBreakBefore = '';
46
+ el.style.breakBefore = '';
47
+ el.removeAttribute('data-pdf-page');
48
+ });
49
+ });
50
+ }, []);
52
51
 
53
- const doSizing = useCallback(() => {
54
- const keys = Object.keys(sectionsConfig);
55
- let _pages = [1];
56
- let _page = 1;
52
+ const getAllBreakableElements = useCallback((section) => {
53
+ const elements = [];
54
+
55
+ const shouldInclude = (el) => {
56
+ if (!isHTMLElement(el)) return false;
57
+ const style = window.getComputedStyle(el);
58
+ if (style.display === 'inline' || style.display === 'contents') return false;
59
+ if (style.position === 'absolute' || style.position === 'fixed') return false;
60
+ if (el.offsetHeight === 0) return false;
61
+ return true;
62
+ };
57
63
 
58
- if (keys.length === config.length) {
59
- let incrHeight = 0;
64
+ const traverse = (parent) => {
65
+ Array.from(parent.children).forEach((child) => {
66
+ if (shouldInclude(child)) {
67
+ elements.push(child);
68
+ traverse(child);
69
+ }
70
+ });
71
+ };
60
72
 
61
- keys.forEach(k => {
62
- const { ref } = sectionsConfig[k];
63
- ref.current.style.marginBottom = '0px';
64
- // ref.current.style.marginTop = '15px';
65
- })
73
+ traverse(section);
74
+ return elements;
75
+ }, []);
66
76
 
67
- keys.forEach((k, i) => {
68
- const { height, ref } = sectionsConfig[k];
77
+ const paginateContent = useCallback(() => {
78
+ const sections = sectionsRef.current.filter(Boolean);
79
+ if (sections.length === 0) return;
69
80
 
70
- if (i === 0) {
71
- ref.current.style.marginTop = `${HEADER_HEIGHT}px`;
72
- incrHeight += HEADER_HEIGHT;
73
- }
81
+ resetPaginationStyles(sections);
74
82
 
75
- const newHeight = incrHeight + height;
83
+ // Force layout recalc
84
+ sections.forEach(s => s.offsetHeight);
76
85
 
77
- if (i === keys.length - 1) {
78
- ref.current.style.paddingBottom = '30px';
79
- }
86
+ let currentPage = 1;
87
+ let currentPageHeight = 0;
88
+ const breaks = [];
80
89
 
81
- if (newHeight > PAGE_HEIGHT - 30 - FOOTER_HEIGHT - HEADER_HEIGHT) {
82
- const dif = Math.abs(PAGE_HEIGHT - incrHeight);
83
- ref.current.style.marginTop = '30px';
84
- _page += 1;
85
- _pages.push(_page);
86
-
87
- if (sectionsConfig[keys[i - 1]]) {
88
- const { ref: topRef } = sectionsConfig[keys[i - 1]];
89
- topRef.current.style.marginBottom = `${dif + HEADER_HEIGHT - 24}px`;
90
- incrHeight = height + 24 + HEADER_HEIGHT;
91
- // console.log('margin', dif);
90
+ sections.forEach((section, sectionIndex) => {
91
+ // Measure height after reset
92
+ const sectionHeight = section.offsetHeight;
93
+ const isFirstOnPage = currentPageHeight === 0;
94
+ const gapBefore = isFirstOnPage ? 0 : SECTION_GAP;
95
+
96
+ if (currentPageHeight + gapBefore + sectionHeight <= CONTENT_HEIGHT) {
97
+ // Fits in current page
98
+ section.setAttribute('data-pdf-page', currentPage.toString());
99
+
100
+ if (isFirstOnPage) {
101
+ // First item on page
102
+ if (currentPage === 1) {
103
+ // Very first section on first page - needs to be below header
104
+ section.style.marginTop = '0px'; // Container padding handles this
105
+ } else {
106
+ // First section on subsequent pages - no margin (container padding handles it)
107
+ section.style.marginTop = '0px';
92
108
  }
93
109
  } else {
94
- incrHeight = newHeight + 24;
110
+ // Not first item on page - add gap
111
+ section.style.marginTop = `${SECTION_GAP}px`;
95
112
  }
96
- // console.groupEnd();
97
- })
98
- setPages(_pages);
99
- }
100
- }, [sectionsConfig]);
113
+ currentPageHeight += gapBefore + sectionHeight;
114
+ } else {
115
+ // Doesn't fit - need to move to next page
116
+ const remainingSpace = CONTENT_HEIGHT - currentPageHeight;
117
+
118
+ // Calculate margin needed to push this section to the next page
119
+ // remainingSpace = space left on current page
120
+ // Then we need to skip: footer margin + footer + header margin + header
121
+ const pushMargin = remainingSpace + PAGE_MARGIN_BOTTOM + FOOTER_HEIGHT + PAGE_MARGIN_TOP + HEADER_HEIGHT;
122
+
123
+ // Move entire section to next page
124
+ currentPage += 1;
125
+ breaks.push({ section, type: 'section', page: currentPage });
126
+ section.setAttribute('data-pdf-page', currentPage.toString());
127
+ section.style.pageBreakBefore = 'always';
128
+ section.style.breakBefore = 'page';
129
+ section.style.marginTop = `${pushMargin}px`;
130
+
131
+ // Start fresh height counter for new page
132
+ currentPageHeight = sectionHeight;
133
+
134
+ // Check if section is too tall and needs internal breaks
135
+ if (sectionHeight > CONTENT_HEIGHT) {
136
+ // Try to break within section
137
+ const innerElements = getAllBreakableElements(section);
138
+ let pageHeightInSection = 0;
139
+ let sectionPage = currentPage;
140
+
141
+ for (const el of innerElements) {
142
+ const rect = el.getBoundingClientRect();
143
+ const sectionRect = section.getBoundingClientRect();
144
+ const relativeTop = rect.top - sectionRect.top;
145
+ const elHeight = rect.height;
146
+
147
+ // Check if this element would exceed the page
148
+ if (pageHeightInSection + elHeight > CONTENT_HEIGHT && relativeTop > 50) {
149
+ // Calculate remaining space on this page within the section
150
+ const remainingInSection = CONTENT_HEIGHT - pageHeightInSection;
151
+ const pushMarginInner = remainingInSection + PAGE_MARGIN_BOTTOM + FOOTER_HEIGHT + PAGE_MARGIN_TOP + HEADER_HEIGHT;
152
+
153
+ sectionPage += 1;
154
+ breaks.push({ element: el, type: 'inner', page: sectionPage });
155
+ el.setAttribute('data-pdf-page', sectionPage.toString());
156
+ el.style.pageBreakBefore = 'always';
157
+ el.style.breakBefore = 'page';
158
+ el.style.marginTop = `${pushMarginInner}px`;
159
+
160
+ // Reset page height for new page within section
161
+ pageHeightInSection = elHeight;
162
+ } else {
163
+ pageHeightInSection += elHeight;
164
+ }
165
+ }
166
+
167
+ // Update current page if we created additional pages
168
+ if (sectionPage > currentPage) {
169
+ currentPage = sectionPage;
170
+ currentPageHeight = pageHeightInSection;
171
+ }
172
+ }
173
+ }
174
+ });
175
+
176
+ setPages(Array.from({ length: currentPage }, (_, idx) => idx + 1));
177
+ }, [getAllBreakableElements, resetPaginationStyles]);
178
+
179
+ useLayoutEffect(() => {
180
+ // Use requestAnimationFrame to ensure DOM is painted
181
+ const rafId = requestAnimationFrame(() => {
182
+ paginateContent();
183
+ });
184
+
185
+ return () => cancelAnimationFrame(rafId);
186
+ }, [paginateContent, config]);
101
187
 
102
188
  useEffect(() => {
103
- doSizing();
104
- }, [doSizing]);
189
+ const sections = sectionsRef.current.filter(Boolean);
190
+ if (sections.length === 0) return undefined;
105
191
 
106
- const onChangeHeight = useCallback((index, conf) => {
107
- setSectionsConfig((prev) => ({ ...prev, [index]: conf }))
108
- }, []);
192
+ const observer = new ResizeObserver(() => {
193
+ paginateContent();
194
+ });
195
+
196
+ sections.forEach(section => observer.observe(section));
197
+
198
+ return () => observer.disconnect();
199
+ }, [paginateContent, config.length]);
109
200
 
110
201
  const contClassName = formatClassname(['daf-analysis daf-pdf-view', customClassName]);
111
202
 
112
- const renderDashboard = useCallback(() => {
113
- return (
203
+ return (
204
+ <div className={contClassName} style={{ position: 'relative', minHeight: `${PAGE_HEIGHT}px` }}>
114
205
  <div className="view-content">
115
206
  <div className="daf-analysis-layout">
116
- <div className='sections-cont'>
117
- {config.map((widgets, i) => (
118
- <Row
119
- widgets={widgets}
120
- key={`dashboard-sections=${i + 1}`}
121
- i={i}
122
- onChangeHeight={onChangeHeight}
123
- />
207
+ <div
208
+ className='sections-cont'
209
+ ref={contentRef}
210
+ data-pdf-content-root="true"
211
+ style={{
212
+ marginTop: `${HEADER_HEIGHT + PAGE_MARGIN_TOP}px`,
213
+ // paddingBottom: `${FOOTER_HEIGHT + PAGE_MARGIN_BOTTOM}px !important`,
214
+ position: 'relative',
215
+ }}
216
+ >
217
+ {config.map((widgets, index) => (
218
+ <section
219
+ key={`dashboard-section-${index + 1}`}
220
+ ref={(el) => {
221
+ sectionsRef.current[index] = el;
222
+ }}
223
+ style={widgets.style}
224
+ data-pdf-section="true"
225
+ >
226
+ {typeof widgets.render === 'function' ? widgets.render() : null}
227
+ </section>
124
228
  ))}
125
229
  </div>
126
230
  </div>
127
231
  </div>
128
- );
129
- }, [config, onChangeHeight]);
130
-
131
- // <div className="daf-analysis">
132
- // <Header title={t('Dashboard Title')} />
133
-
134
- // <div className="content">
135
- // <div className="view-content">
136
- // <div className="daf-analysis-layout">
137
- // <div className='sections-cont w-pt'>
138
- // <section>
139
-
140
- return (
141
- <div className={contClassName} style={{ position: 'relative' }}>
142
- {renderDashboard()}
143
232
  {pages.map((page) => (
144
- <>
233
+ <Fragment key={`pdf-decor-${page}`}>
145
234
  <div
146
- style={{ top: ((page - 1) * PAGE_HEIGHT), width: '100%', height: HEADER_HEIGHT - 24, position: 'absolute', left: 0, zIndex: 1000000 }}
147
- key={`headers-${page}`}
235
+ style={{
236
+ top: ((page - 1) * PAGE_HEIGHT) + PAGE_MARGIN_TOP,
237
+ width: '100%',
238
+ height: HEADER_HEIGHT,
239
+ position: 'absolute',
240
+ left: 0,
241
+ zIndex: 1000000,
242
+ pointerEvents: 'none'
243
+ }}
148
244
  className="flex-row dashboard-header"
149
245
  >
150
246
  <div className="flex flex-column justify-center flex-1">
@@ -155,8 +251,15 @@ export default function PdfView({
155
251
  </div>
156
252
  </div>
157
253
  <div
158
- style={{ top: (page * PAGE_HEIGHT) - FOOTER_HEIGHT, width: '100%', height: FOOTER_HEIGHT, position: 'absolute', left: 0, zIndex: 1000000 }}
159
- key={`footers-${page}`}
254
+ style={{
255
+ top: (page * PAGE_HEIGHT) - FOOTER_HEIGHT - PAGE_MARGIN_BOTTOM,
256
+ width: '100%',
257
+ height: FOOTER_HEIGHT,
258
+ position: 'absolute',
259
+ left: 0,
260
+ zIndex: 1000000,
261
+ pointerEvents: 'none'
262
+ }}
160
263
  className="dashboard-footer flex-row"
161
264
  >
162
265
  <div className="flex flex-column justify-center">
@@ -190,7 +293,7 @@ export default function PdfView({
190
293
  <h5>{page}</h5>
191
294
  </div>
192
295
  </div>
193
- </>
296
+ </Fragment>
194
297
  ))}
195
298
  </div>
196
299
  );
@@ -209,7 +209,6 @@ import Hedera01 from "./Hedera01";
209
209
  import Records from "./Records";
210
210
  import Lightning from "./Lightning";
211
211
  import MagicWand from "./MagicWant";
212
- import Straatos from "./Straatos";
213
212
 
214
213
  const config = {
215
214
  Right,
@@ -423,7 +422,6 @@ const config = {
423
422
  Records,
424
423
  Lightning,
425
424
  MagicWand,
426
- Straatos,
427
425
  };
428
426
 
429
427
  export default config;