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/dist/components/index.js +609 -567
- package/dist/utils/index.js +422 -449
- package/package.json +1 -1
- package/src/@daf/core/components/Dashboard/PdfView/PdfView.stories.js +12 -2
- package/src/@daf/core/components/Dashboard/PdfView/index.jsx +208 -105
- package/src/@daf/core/components/Icon/configs/index.js +0 -2
- package/dist/style/datastake/mapbox-gl.css +0 -330
- package/src/@daf/core/components/Icon/configs/Straatos.js +0 -16
package/package.json
CHANGED
|
@@ -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
|
|
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
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
59
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// ref.current.style.marginTop = '15px';
|
|
65
|
-
})
|
|
73
|
+
traverse(section);
|
|
74
|
+
return elements;
|
|
75
|
+
}, []);
|
|
66
76
|
|
|
67
|
-
|
|
68
|
-
|
|
77
|
+
const paginateContent = useCallback(() => {
|
|
78
|
+
const sections = sectionsRef.current.filter(Boolean);
|
|
79
|
+
if (sections.length === 0) return;
|
|
69
80
|
|
|
70
|
-
|
|
71
|
-
ref.current.style.marginTop = `${HEADER_HEIGHT}px`;
|
|
72
|
-
incrHeight += HEADER_HEIGHT;
|
|
73
|
-
}
|
|
81
|
+
resetPaginationStyles(sections);
|
|
74
82
|
|
|
75
|
-
|
|
83
|
+
// Force layout recalc
|
|
84
|
+
sections.forEach(s => s.offsetHeight);
|
|
76
85
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
86
|
+
let currentPage = 1;
|
|
87
|
+
let currentPageHeight = 0;
|
|
88
|
+
const breaks = [];
|
|
80
89
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
110
|
+
// Not first item on page - add gap
|
|
111
|
+
section.style.marginTop = `${SECTION_GAP}px`;
|
|
95
112
|
}
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
-
|
|
104
|
-
|
|
189
|
+
const sections = sectionsRef.current.filter(Boolean);
|
|
190
|
+
if (sections.length === 0) return undefined;
|
|
105
191
|
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
|
|
113
|
-
|
|
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
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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={{
|
|
147
|
-
|
|
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={{
|
|
159
|
-
|
|
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;
|