datastake-daf 0.6.254 → 0.6.255

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.
@@ -525,8 +525,293 @@ const PdfForm = ({
525
525
 
526
526
  const organizedForm = useMemo(() => organizeFormByHeaders(form), [form]);
527
527
 
528
+ // Constants for height calculations (same as PdfView)
529
+ const PAGE_HEIGHT = 1587;
530
+ const FOOTER_HEIGHT = 70;
531
+ const HEADER_HEIGHT = 100;
532
+
533
+ // Detect if running in headless/Puppeteer environment (more conservative detection)
534
+ const isPuppeteerEnvironment = () => {
535
+ if (typeof window === 'undefined') return false;
536
+
537
+ // Only trigger on explicit URL parameters (most reliable)
538
+ return (
539
+ window.location.search.includes('puppeteer=true') ||
540
+ window.location.search.includes('headless=true') ||
541
+ window.location.search.includes('pdf=true') ||
542
+ // Only very specific headless browser indicators
543
+ (window.navigator.webdriver === true && window.navigator.userAgent.includes('HeadlessChrome'))
544
+ );
545
+ };
546
+
547
+ // Debug function to log detection results (can be removed later)
548
+ const debugEnvironment = () => {
549
+ if (typeof window !== 'undefined' && window.console) {
550
+ console.log('Environment Detection:', {
551
+ isPuppeteer: isPuppeteerEnvironment(),
552
+ userAgent: window.navigator.userAgent,
553
+ webdriver: window.navigator.webdriver,
554
+ resizeObserver: !!window.ResizeObserver,
555
+ urlParams: window.location.search
556
+ });
557
+ }
558
+ };
559
+
560
+ // Conservative height estimation for Puppeteer compatibility
561
+ const estimateTreeNodeHeight = (key, config, value, level = 0) => {
562
+ const isPuppeteer = isPuppeteerEnvironment();
563
+ // Call debug only once to avoid spam
564
+ if (level === 0 && key === Object.keys(form)[0]) {
565
+ debugEnvironment();
566
+ }
567
+
568
+ // Appropriate base heights for each environment
569
+ const baseHeight = isPuppeteer ? 35 : 25; // Less aggressive for normal browsers
570
+ const indentHeight = level * (isPuppeteer ? 3 : 2); // Normal indent for browsers
571
+ let totalHeight = baseHeight + indentHeight;
572
+
573
+ // Type-based adjustments - less aggressive for normal browsers
574
+ if (config?.type === 'header') {
575
+ totalHeight += isPuppeteer ? 25 : 12;
576
+ } else if (config?.type === 'textarea') {
577
+ totalHeight += isPuppeteer ? 60 : 30;
578
+ } else if (config?.type === 'dataLink' || config?.type === 'dataLinkGroup') {
579
+ totalHeight += isPuppeteer ? 35 : 15;
580
+ } else if (config?.type === 'groupInputs') {
581
+ totalHeight += isPuppeteer ? 40 : 20;
582
+ }
583
+
584
+ // Content height estimation - appropriate for each environment
585
+ if (value && typeof value === 'string') {
586
+ if (value.length > 100) {
587
+ const multiplier = isPuppeteer ? 20 : 12; // Less aggressive for browsers
588
+ totalHeight += Math.ceil(value.length / 50) * multiplier;
589
+ } else if (value.length > 30) {
590
+ totalHeight += isPuppeteer ? 25 : 10; // Much less for normal browsers
591
+ }
592
+ }
593
+
594
+ // Add height for children recursively with appropriate multiplier
595
+ if (config?.inputs) {
596
+ const childKeys = Object.keys(config.inputs)
597
+ .filter(childKey => {
598
+ const childConfig = config.inputs[childKey];
599
+ // Check showIf condition
600
+ if (childConfig?.showIf && !evaluateShowIfCondition(childConfig.showIf, data)) {
601
+ return false;
602
+ }
603
+ return true;
604
+ })
605
+ .sort((a, b) => {
606
+ const positionA = config.inputs[a]?.position || 0;
607
+ const positionB = config.inputs[b]?.position || 0;
608
+ return positionA - positionB;
609
+ });
610
+
611
+ let childrenHeight = 0;
612
+ childKeys.forEach(childKey => {
613
+ const childConfig = config.inputs[childKey];
614
+ const childValue = value?.[childKey] || data?.[childKey];
615
+ childrenHeight += estimateTreeNodeHeight(childKey, childConfig, childValue, level + 1);
616
+ });
617
+
618
+ // Only add safety multiplier for Puppeteer
619
+ totalHeight += childrenHeight * (isPuppeteer ? 1.3 : 1.0);
620
+ }
621
+
622
+ // Handle array/repeated content
623
+ if (Array.isArray(value)) {
624
+ value.forEach(itemValue => {
625
+ const multiplier = isPuppeteer ? 1.1 : 1.0; // No buffer for normal browsers
626
+ totalHeight += estimateTreeNodeHeight(key, config, itemValue, level) * multiplier;
627
+ });
628
+ }
629
+
630
+ return Math.ceil(totalHeight);
631
+ };
632
+
633
+ // Helper function to split section based on height constraints (goes deep if needed)
634
+ const createHeightConstrainedSections = (sectionKey, section) => {
635
+ const isPuppeteer = isPuppeteerEnvironment();
636
+
637
+ // Environment-appropriate height limits
638
+ const BASE_BUFFER = isPuppeteer ? 300 : 100; // Much smaller buffer for normal browsers
639
+ const MAX_SECTION_HEIGHT = PAGE_HEIGHT - HEADER_HEIGHT - FOOTER_HEIGHT - BASE_BUFFER;
640
+ const subSections = [];
641
+
642
+ // Get all top-level items in the section with detailed analysis
643
+ const topLevelItems = Object.keys(section)
644
+ .filter(key => !(key === 'id' || key === 'label' || key === 'position' || key === 'subTitle'))
645
+ .map(key => ({
646
+ key,
647
+ config: section[key],
648
+ estimatedHeight: estimateTreeNodeHeight(key, section[key], data?.[key]),
649
+ canSplit: section[key]?.inputs && Object.keys(section[key].inputs).length > 1 // Can this item be further split?
650
+ }))
651
+ .sort((a, b) => (a.config?.position || 0) - (b.config?.position || 0));
652
+
653
+ let currentSubSection = {
654
+ ...section,
655
+ };
656
+
657
+ // Remove all items from the base section structure
658
+ Object.keys(section).forEach(key => {
659
+ if (!(key === 'id' || key === 'label' || key === 'position' || key === 'subTitle')) {
660
+ delete currentSubSection[key];
661
+ }
662
+ });
663
+
664
+ let currentHeight = 80; // Base height for section header
665
+ let subSectionIndex = 0;
666
+
667
+ topLevelItems.forEach((item, index) => {
668
+ const { key, config, estimatedHeight, canSplit } = item;
669
+
670
+ // Environment-appropriate splitting thresholds
671
+ const SPLIT_THRESHOLD = isPuppeteer ? 0.6 : 0.85; // Less aggressive for browsers
672
+ const CHILD_MAX_HEIGHT = isPuppeteer ? 0.4 : 0.7;
673
+
674
+ // If a single item is too large and can be split, split it at the child level
675
+ if (estimatedHeight > MAX_SECTION_HEIGHT * SPLIT_THRESHOLD && canSplit) {
676
+ // Split this large item into smaller parts
677
+ const childSplits = splitLargeItem(key, config, data?.[key], MAX_SECTION_HEIGHT * CHILD_MAX_HEIGHT);
678
+
679
+ childSplits.forEach((splitItem, splitIndex) => {
680
+ // Check if current subsection has room
681
+ if (currentHeight + splitItem.estimatedHeight > MAX_SECTION_HEIGHT && Object.keys(currentSubSection).length > 4) {
682
+ // Save current sub-section
683
+ subSections.push({
684
+ key: `${sectionKey}_part_${subSectionIndex}`,
685
+ section: { ...currentSubSection },
686
+ title: section.label
687
+ });
688
+
689
+ // Start new sub-section
690
+ currentSubSection = {
691
+ id: section.id,
692
+ label: section.label,
693
+ position: section.position + subSectionIndex + 1,
694
+ subTitle: section.subTitle
695
+ };
696
+ currentHeight = 80;
697
+ subSectionIndex++;
698
+ }
699
+
700
+ // Add split item to current sub-section
701
+ currentSubSection[splitItem.key] = splitItem.config;
702
+ currentHeight += splitItem.estimatedHeight;
703
+ });
704
+ } else {
705
+ // Regular processing for items that fit or can't be split
706
+ // Check if adding this item would exceed height limit
707
+ if (currentHeight + estimatedHeight > MAX_SECTION_HEIGHT && Object.keys(currentSubSection).length > 4) {
708
+ // Save current sub-section
709
+ subSections.push({
710
+ key: `${sectionKey}_part_${subSectionIndex}`,
711
+ section: { ...currentSubSection },
712
+ title: section.label
713
+ });
714
+
715
+ // Start new sub-section
716
+ currentSubSection = {
717
+ id: section.id,
718
+ label: section.label,
719
+ position: section.position + subSectionIndex + 1,
720
+ subTitle: section.subTitle
721
+ };
722
+ currentHeight = 80;
723
+ subSectionIndex++;
724
+ }
725
+
726
+ // Add item to current sub-section
727
+ currentSubSection[key] = config;
728
+ currentHeight += estimatedHeight;
729
+ }
730
+ });
731
+
732
+ // Add the final sub-section if it has content
733
+ if (Object.keys(currentSubSection).length > 4) {
734
+ subSections.push({
735
+ key: subSectionIndex === 0 ? sectionKey : `${sectionKey}_part_${subSectionIndex}`,
736
+ section: currentSubSection,
737
+ title: section.label
738
+ });
739
+ }
740
+
741
+ return subSections.length > 0 ? subSections : [{
742
+ key: sectionKey,
743
+ section: section,
744
+ title: section.label
745
+ }];
746
+ };
747
+
748
+ // Helper function to split large items at the child level
749
+ const splitLargeItem = (parentKey, parentConfig, parentValue, maxHeight) => {
750
+ if (!parentConfig?.inputs) {
751
+ return [{ key: parentKey, config: parentConfig, estimatedHeight: estimateTreeNodeHeight(parentKey, parentConfig, parentValue) }];
752
+ }
753
+
754
+ const childItems = Object.keys(parentConfig.inputs)
755
+ .filter(childKey => {
756
+ const childConfig = parentConfig.inputs[childKey];
757
+ return !childConfig?.showIf || evaluateShowIfCondition(childConfig.showIf, data);
758
+ })
759
+ .map(childKey => ({
760
+ key: childKey,
761
+ config: parentConfig.inputs[childKey],
762
+ estimatedHeight: estimateTreeNodeHeight(childKey, parentConfig.inputs[childKey], parentValue?.[childKey])
763
+ }))
764
+ .sort((a, b) => (a.config?.position || 0) - (b.config?.position || 0));
765
+
766
+ const splits = [];
767
+ let currentSplit = {
768
+ key: `${parentKey}_part_0`,
769
+ config: {
770
+ ...parentConfig,
771
+ inputs: {}
772
+ },
773
+ estimatedHeight: 40 // Base height for parent structure
774
+ };
775
+ let splitIndex = 0;
776
+
777
+ childItems.forEach(child => {
778
+ if (currentSplit.estimatedHeight + child.estimatedHeight > maxHeight && Object.keys(currentSplit.config.inputs).length > 0) {
779
+ splits.push(currentSplit);
780
+ splitIndex++;
781
+ currentSplit = {
782
+ key: `${parentKey}_part_${splitIndex}`,
783
+ config: {
784
+ ...parentConfig,
785
+ label: parentConfig.label,
786
+ inputs: {}
787
+ },
788
+ estimatedHeight: 40
789
+ };
790
+ }
791
+
792
+ currentSplit.config.inputs[child.key] = child.config;
793
+ currentSplit.estimatedHeight += child.estimatedHeight;
794
+ });
795
+
796
+ if (Object.keys(currentSplit.config.inputs).length > 0) {
797
+ splits.push(currentSplit);
798
+ }
799
+
800
+ return splits.length > 0 ? splits : [{ key: parentKey, config: parentConfig, estimatedHeight: estimateTreeNodeHeight(parentKey, parentConfig, parentValue) }];
801
+ };
802
+
528
803
  const pdfConfig = useMemo(() => {
529
804
  const sections = [];
805
+ const isPuppeteer = isPuppeteerEnvironment();
806
+
807
+ // Apply Puppeteer-specific class to document body if needed
808
+ if (typeof document !== 'undefined') {
809
+ if (isPuppeteer) {
810
+ document.body.setAttribute('data-puppeteer', 'true');
811
+ } else {
812
+ document.body.removeAttribute('data-puppeteer');
813
+ }
814
+ }
530
815
 
531
816
  Object.keys(organizedForm).forEach((sectionKey) => {
532
817
  const section = organizedForm[sectionKey];
@@ -535,27 +820,32 @@ const PdfForm = ({
535
820
  return;
536
821
  }
537
822
 
538
- sections.push({
539
- render: () => (
540
- <div key={sectionKey} className="pdf-form-section">
541
- <PdfFormContent
542
- form={{ [sectionKey]: section }}
543
- data={data}
544
- t={t}
545
- user={user}
546
- title={formName}
547
- source={source}
548
- version={version}
549
- getApiBaseUrl={getApiBaseUrl}
550
- getAppHeader={getAppHeader}
551
- app={app}
552
- />
553
- </div>
554
- ),
555
- style: {
556
- marginBottom: '20px',
557
- padding: '0 20px'
558
- }
823
+ // Create height-constrained sub-sections
824
+ const subSections = createHeightConstrainedSections(sectionKey, section);
825
+
826
+ subSections.forEach(({ key, section: subSection, title }) => {
827
+ sections.push({
828
+ render: () => (
829
+ <div key={key} className={`pdf-form-section ${isPuppeteer ? 'puppeteer-mode' : ''}`}>
830
+ <PdfFormContent
831
+ form={{ [key]: { ...subSection, label: title } }}
832
+ data={data}
833
+ t={t}
834
+ user={user}
835
+ title={formName}
836
+ source={source}
837
+ version={version}
838
+ getApiBaseUrl={getApiBaseUrl}
839
+ getAppHeader={getAppHeader}
840
+ app={app}
841
+ />
842
+ </div>
843
+ ),
844
+ style: {
845
+ marginBottom: '20px',
846
+ padding: '0 20px'
847
+ }
848
+ });
559
849
  });
560
850
  });
561
851
 
@@ -482,12 +482,13 @@
482
482
 
483
483
  @media print {
484
484
  .pdf-form-section {
485
- // page-break-inside: avoid;
486
- margin-bottom: 20px;
485
+ page-break-inside: avoid;
486
+ margin-bottom: 30px;
487
+ padding-bottom: 20px; // Extra space before potential breaks
487
488
  }
488
489
 
489
490
  .pdf-tree .tree-node {
490
- // page-break-inside: avoid;
491
+ page-break-inside: avoid;
491
492
 
492
493
  &::after,
493
494
  .tree-indent .indent-line::before,
@@ -497,9 +498,52 @@
497
498
  -webkit-print-color-adjust: exact;
498
499
  }
499
500
 
500
- // &.parent {
501
- // page-break-after: avoid;
502
- // }
501
+ // Force page breaks for deeply nested content in print
502
+ &.level-0,
503
+ &.level-1 {
504
+ &.parent {
505
+ page-break-after: avoid;
506
+ margin-bottom: 15px;
507
+ }
508
+ }
509
+
510
+ // More conservative spacing for print
511
+ .tree-node-content {
512
+ padding: 6px 0; // Slightly more padding
513
+
514
+ .tree-node-title {
515
+ min-height: 28px; // Ensure minimum height
516
+ }
517
+ }
518
+ }
519
+ }
520
+
521
+ // Only add extra spacing when explicitly running in headless/PDF mode
522
+ &.puppeteer-mode,
523
+ body[data-puppeteer="true"] & {
524
+ .pdf-form-section {
525
+ margin-bottom: 40px;
526
+ padding: 10px 0;
527
+
528
+ &:last-child {
529
+ margin-bottom: 60px;
530
+ }
531
+ }
532
+
533
+ .pdf-tree .tree-node {
534
+ margin-bottom: 12px;
535
+
536
+ .tree-node-content {
537
+ padding: 8px 0;
538
+ }
539
+
540
+ &.level-0 {
541
+ margin-bottom: 25px;
542
+ }
543
+
544
+ &.level-1 {
545
+ margin-bottom: 18px;
546
+ }
503
547
  }
504
548
  }
505
549
  }
package/.env DELETED
@@ -1,8 +0,0 @@
1
- REACT_APP_API_KEY=
2
- REACT_APP_AUTH_DOMAIN=
3
- REACT_APP_PROJECT_ID=
4
- REACT_APP_STORAGE_BUCKED=
5
- REACT_APP_SENDER_ID=
6
- REACT_APP_APP_ID=
7
- REACT_APP_MEASUREMENT_ID=
8
- REACT_APP_VAPID_KEY=
@@ -1,13 +0,0 @@
1
- {
2
- "cSpell.words": ["cukura"],
3
- "files.autoSave": "afterDelay",
4
- "editor.wordWrap": "on",
5
- "editor.autoClosingBrackets": "always",
6
- "editor.autoClosingComments": "always",
7
- "editor.autoClosingQuotes": "always",
8
- "editor.defaultFormatter": "esbenp.prettier-vscode",
9
- "editor.formatOnPaste": true,
10
- "editor.formatOnSave": true,
11
- "notebook.defaultFormatter": "esbenp.prettier-vscode",
12
- "javascript.format.semicolons": "insert"
13
- }