@magicfeedback/popup-sdk 1.3.0 → 1.5.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.
@@ -182,7 +182,7 @@ var init_font = __esm({
182
182
  var style_default;
183
183
  var init_style = __esm({
184
184
  "src/assets/style.css"() {
185
- style_default = '.magicfeedback-container {\n width: 100%;\n}\n\n\n.magicfeedback-success-message,\n.magicfeedback-info-message,\n.magicfeedback-start-message,\n.magicfeedback-container{\n animation-duration: 0.5s;\n animation-name: animate-fade;\n animation-delay: 0.25s;\n animation-fill-mode: backwards;\n\n font-style: normal;\n text-align: justify;\n font-weight: 400;\n font-size: 1.2rem;\n color: #475569;\n line-height: 1.5;\n}\n\n@keyframes animate-fade {\n 0% { opacity: 0; }\n 100% { opacity: 1; }\n}\n\n.magicfeedback-form {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: center;\n width: 100%;\n}\n.magicfeedback-questions {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: flex-start;\n width: 100%;\n}\n\n.magicfeedback-div {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: flex-start;\n margin-bottom: 10px;\n width: 100%;\n}\n\n.magicfeedback-label {\n margin-bottom: 25px;\n margin-top: 20px;\n font-weight: 400;\n font-family: inherit;\n font-size: 1.2rem;\n color: #212529;\n text-align: start;\n word-wrap: break-word;\n white-space: normal;\n\n}\n\n.magicfeedback-checkbox {\n display: flex;\n flex-direction: column;\n flex-wrap: wrap;\n width: 100%;\n}\n\n.magicfeedback-checkbox-container {\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n margin-bottom: 5px;\n margin-top: 5px;\n}\n\n/* Cualificado con `div`: @magicfeedback/native reutiliza la clase "magicfeedback-radio"\n tambi\xE9n en el <input> de cada opci\xF3n (rating), y sin el tag este selector lo capturaba\n tambi\xE9n, rompiendo su tama\xF1o (el input pasaba a display:flex; width:100%). */\ndiv.magicfeedback-radio {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n flex-wrap: wrap;\n width: 100%;\n margin-right: 5px;\n padding: 5px;\n box-sizing: border-box;\n}\n\n.magicfeedback-checkbox-container,\n.magicfeedback-radio-container {\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n margin: 5px;\n padding: 5px 0;\n background-color: #fff;\n border-radius: 5px;\n box-shadow: 0 0 3px #ccc;\n}\n\n.deepdots-popup input::-webkit-outer-spin-button,\n.deepdots-popup input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n -moz-appearance: textfield;\n}\n\n.magicfeedback-checkbox input[type="checkbox"] {\n margin-right: 5px;\n margin-left: 5px;\n width: 20px;\n height: 20px;\n cursor: pointer;\n}\n\n\n.magicfeedback-checkbox label,\n.magicfeedback-radio-container label {\n margin-left: 5px;\n font-weight: 400;\n font-family: inherit;\n font-size: 16px;\n color: #212529;\n text-align: start;\n width: 100%;\n}\n\n.deepdots-popup p {\n margin-bottom: 0px;\n font-size: 12px;\n}\n\n.deepdots-popup h2 {\n line-height: 1.66;\n margin: 0;\n padding: 0;\n font-weight: 900;\n color: #222;\n font-family: var(--deepdots-font, \'Montserrat\');\n font-size: 18px;\n text-transform: uppercase;\n text-align: center;\n margin-bottom: 40px;\n}\n\n/* Los controles de formulario no heredan font-family por defecto: cuando hay\n fuente custom (clase deepdots-has-font), los forzamos a usar la del contenedor. */\n.deepdots-popup.deepdots-has-font button,\n.deepdots-popup.deepdots-has-font input,\n.deepdots-popup.deepdots-has-font textarea,\n.deepdots-popup.deepdots-has-font select {\n font-family: var(--deepdots-font, inherit);\n}\n\n.deepdots-popup h6 {\n margin-bottom: 1rem;\n}\n\n.deepdots-popup input[type="date"],\n.deepdots-popup input[type="text"],\n.deepdots-popup input[type="number"],\n.deepdots-popup input[type="email"],\n.deepdots-popup input[type="password"],\n.deepdots-popup textarea,\n.deepdots-popup select {\n box-sizing: border-box;\n padding: 10px;\n margin: 10px 0;\n width: 100%;\n border: 2px solid #ccc; /* Default border color - you can customize this */\n border-radius: 5px;\n font-size: 18px;\n outline: none;\n transition: border-color 0.3s ease;\n min-height: 50px;\n font-family: inherit;\n -webkit-appearance: none;\n}\n\n.deepdots-popup select {\n background-image: linear-gradient(45deg, transparent 50%, gray 50%),\n linear-gradient(135deg, gray 50%, transparent 50%),\n linear-gradient(to right, #ccc, #ccc);\n background-position: calc(100% - 20px) calc(1em + 2px),\n calc(100% - 15px) calc(1em + 2px),\n calc(100% - 2.5em) 0.5em;\n background-size: 5px 5px,\n 5px 5px,\n 1px 1.5em;\n background-repeat: no-repeat;\n}\n\n.magicfeedback-boolean-container {\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n margin: 10px 0;\n width: 100%;\n}\n\n.magicfeedback-boolean-container label {\n margin-left: 10px;\n font-weight: 400;\n font-size: 16px;\n width: 100%;\n padding-top: 5px;\n}\n\n.magicfeedback-boolean-option {\n margin-right: 10px;\n margin-left: 10px;\n width: 100%;\n height: 38px;\n border-radius: 8px;\n font-size: 16px;\n cursor: pointer;\n border: 1px solid #ced4da !important;\n}\n\n.magicfeedback-boolean-option label {\n font-weight: 400;\n font-size: 16px;\n color: #475569;\n cursor: pointer;\n width: 100%;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n border-radius: inherit;\n}\n\n.magicfeedback-boolean-option input[type=radio] + label:hover {\n color: #007bff;\n}\n\n.magicfeedback-boolean-option input[type=radio]:checked + label {\n color: #007bff;\n background-color: #cadff8;\n}\n\n.deepdots-popup input[type="radio"] {\n padding: 20px;\n margin: 10px 0 10px 15px;\n width: 40px;\n background-color: #fff;\n box-shadow: none;\n}\n\n/* Style for focused input/select */\n.deepdots-popup input:focus, .deepdots-popup select:focus {\n border-color: #4CAF50; /* Highlight color when focused - you can customize this */\n}\n\n/* Style for invalid input (example: validation error) */\n.deepdots-popup input.error, .deepdots-popup select.error {\n border-color: #ff3333; /* Red color for error state - you can customize this */\n}\n\n.magicfeedback-action-container {\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n margin-top: 10px;\n width: 100%;\n}\n\n.magicfeedback-action-container .magicfeedback-submit {\n cursor: pointer;\n padding: 10px;\n margin: 10px 0;\n width: 100px;\n border-radius: 8px;\n font-size: 16px;\n outline: none;\n transition: border-color 0.3s ease;\n background-color: #1E293B;\n color: white;\n}\n\n.magicfeedback-action-container .magicfeedback-back {\n cursor: pointer;\n padding: 10px;\n margin: 10px 0;\n width: 100px;\n border: 0;\n border-radius: 8px;\n font-size: 16px;\n outline: none;\n transition: border-color 0.3s ease;\n background-color: transparent;\n color: #212529;\n}\n\n\n\n/* Rating styles */\n.magicfeedback-rating {\n width: 100%;\n}\n\n.magicfeedback-rating-container {\n display: flex;\n flex-direction: row;\n justify-content: space-around;\n flex-wrap: wrap;\n align-items: center;\n\n margin: 15px 5px;\n padding: 0;\n\n list-style: none;\n font-size: 1.5rem;\n cursor: pointer;\n user-select: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n}\n\n.magicfeedback-rating-placeholder-value,\n.magicfeedback-rating-placeholder{\n text-align: center;\n align-content: center;\n justify-content: center;\n text-wrap: wrap;\n}\n\n.magicfeedback-rating-option {\n margin: 0 0.5rem;\n padding: 0;\n}\n\n@media (max-width: 1024px) {\n .magicfeedback-rating-option {\n margin: 10px 0;\n padding: 0;\n width: 20%;\n display: flex;\n justify-content: center;\n }\n\n .magicfeedback-rating-placeholder-value {\n font-size: 0.75rem;\n margin-bottom: 1px;\n }\n .magicfeedback-rating-placeholder{\n justify-content: center;\n }\n\n .magicfeedback-rating-container {\n flex-wrap: wrap;\n justify-content: flex-start;\n }\n}\n\n\n.magicfeedback-rating-option-label-container {\n display: flex;\n flex-direction: column;\n}\n\n\n.magicfeedback-rating-option-label-container label {\n display: inline-block;\n text-align: center;\n margin-bottom: 0;\n font-weight: 600;\n font-size: 18px;\n color: #475569;\n}\n\n.magicfeedback-rating-option-label-container input[type=radio] {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n}\n\n/* IMAGE STYLES */\n.magicfeedback-rating-option-label-container input[type=radio] + img {\n cursor: pointer;\n height: 48px;\n width: 48px;\n}\n\n/* LABEL STYLES */\n.magicfeedback-rating-option-label-container input[type=radio] + label {\n cursor: pointer;\n}\n\n/* CHECKED STYLES */\n.magicfeedback-rating-option-label-container input[type=radio]:checked + img {\n box-shadow: #007bff 0px 1px 4px, #007BFFA0 0px 0px 0px 2px;\n border-radius: 50%;\n}\n\n.magicfeedback-rating-number {\n width: 100%;\n}\n.magicfeedback-rating-container,\n.magicfeedback-rating-number-container {\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n\n margin: 15px 0;\n padding: 0;\n\n list-style: none;\n font-size: 1.5rem;\n cursor: pointer;\n user-select: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n}\n\n/* Cuando hay placeholders (Very bad / Very good), el placeholder ocupa\n el 100% de la primera l\xEDnea y los boxes bajan a la siguiente */\n.magicfeedback-rating-number-container--with-placeholder {\n flex-wrap: wrap;\n align-items: flex-start;\n}\n\n.magicfeedback-rating-number-container--with-placeholder .magicfeedback-rating-placeholder {\n width: 100%;\n margin-bottom: 8px;\n}\n\n.magicfeedback-rating-number-container--with-placeholder .magicfeedback-rating-number-option {\n width: auto;\n flex: 1;\n}\n\n.magicfeedback-rating-number-option {\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n margin: 5px;\n padding: 0;\n list-style: none;\n font-size: 1.5rem;\n cursor: pointer;\n user-select: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n width: 100%;\n}\n\n.magicfeedback-rating-number-option-row{\n max-width: 100% !important;\n}\n\n.magicfeedback-rating-number-top-placeholder,\n.magicfeedback-rating-number-bottom-placeholder{\n text-align: center !important;\n align-content: center;\n justify-content: center;\n text-wrap: wrap;\n\n font-size: 15px;\n color: #475569;\n\n width: 100%;\n margin: auto;\n}\n\n@media (min-width: 650px) {\n .magicfeedback-rating-number-option-row +.magicfeedback-rating-number-container-ltr:first-child,\n .magicfeedback-rating-number-option-row + +.magicfeedback-rating-number-container-rtl:last-child {\n margin-left: 0;\n width: calc(100% - 10px);\n }\n\n .magicfeedback-rating-number-option-row +.magicfeedback-rating-number-container-rtl:first-child,\n .magicfeedback-rating-number-option-row + +.magicfeedback-rating-number-container-ltr:last-child {\n margin-right: 0;\n width: calc(100% - 10px);\n }\n}\n\n\n.magicfeedback-rating-number-option-label-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n}\n\n.magicfeedback-rating-number-option-label-container label {\n display: flex;\n align-items: center;\n justify-content: center;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n margin: 0 10px;\n font-weight: 600;\n font-size: 14px;\n color: #475569;\n cursor: pointer;\n width: 100%;\n height: 100%;\n min-height: 50px;\n text-align: center;\n padding: 0;\n border-radius: 4px;\n border: 1px solid #ced4da;\n background-color: rgba(246, 246, 246, 0.3);\n transition: background-color 0.15s ease-in-out;\n}\n\n.magicfeedback-rating-number-option-label-container input[type=radio] {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n}\n\n.magicfeedback-rating-number-option-label-container input[type=radio] + label {\n cursor: pointer;\n}\n\n.magicfeedback-rating-number-option-label-container input[type=radio] + label:hover,\n.magicfeedback-rating-number-option-label-container input[type=radio]:checked + label {\n color: #007bff;\n border: 1px solid #007bff;\n background-color: rgba(86, 168, 253, 0.29);\n}\n\n.magicfeedback-rating-number-container-column{\n align-items: flex-start !important;\n}\n\n@media (max-width: 650px) {\n .magicfeedback-rating-number-container-ltr {\n justify-content: center;\n flex-wrap: wrap;\n }\n\n .magicfeedback-rating-number-container-rtl {\n justify-content: center;\n flex-wrap: wrap-reverse;\n }\n\n .magicfeedback-rating-number-option {\n max-width: 100%;\n height: 55px;\n margin: 5px 0;\n }\n}\n\n.magicfeedback-rating-star {\n width: 100%;\n}\n\n.magicfeedback-rating-star-container {\n display: flex !important;\n flex-direction: row !important;\n justify-content: center !important;\n align-items: center !important;\n flex-wrap: wrap;\n margin: 15px 5px;\n padding: 0;\n list-style: none;\n font-size: 1.5rem;\n cursor: pointer;\n user-select: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n}\n\n.magicfeedback-rating-star-option:not(:checked) > .rating__star {\n float: right;\n width: 1em;\n overflow: hidden;\n white-space: nowrap;\n cursor: pointer;\n font-size: 30px;\n color: #ccc;\n margin: 0 10px;\n}\n\n.magicfeedback-rating-star-option:not(:checked) > .rating__star:hover,\n.magicfeedback-rating-star-option:not(:checked) > .rating__star:hover ~ span {\n color: #deb217 !important;\n}\n\n.magicfeedback-rating-star-selected {\n color: #ffc700 !important;\n}\n\n\n/* Style for multiple choice image */\n.magicfeedback-image-option-label-container:hover {\n cursor: pointer;\n border: 0 !important;\n}\n\n.magicfeedback-image-option-label-container input[type=radio]:checked + img,\n.magicfeedback-image-option-label-container input[type=checkbox]:checked + img {\n border: 1px solid #007bff !important;\n box-shadow: 0 0 3px #007bff !important;\n}\n\n.magicfeedback-image-option-label-container input[type=radio] + img,\n.magicfeedback-image-option-label-container input[type=checkbox] + img {\n border: 1px solid transparent !important;\n}\n\n.magicfeedback-image-option-label-container{\n margin: 10px !important;\n height: calc(100% - 20px) !important;\n width: calc(100% - 20px) !important;\n}\n\n.magicfeedback-multiple-choice-image-option {\n display: flex;\n height: auto !important;\n box-shadow: 0 0 3px #ccc;\n}\n\n.magicfeedback-multiple-choice-image-label {\n font-size: 1rem;\n}\n\n.magicfeedback-consent-container {\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n margin: 10px 0;\n width: 100%;\n}\n\n.magicfeedback-consent-container label {\n margin-left: 10px;\n}\n\n.magicfeedback-start-message-container {\n /* ... add your start message container styles here ... */\n}\n\n.magicfeedback-success-message,\n.magicfeedback-info-message,\n.magicfeedback-start-message {\n margin: 35px 5px;\n}\n\n.magicfeedback-success-message p,\n.magicfeedback-info-message p,\n.magicfeedback-start-message p {\n font-style: normal;\n text-align: start;\n font-weight: 400;\n font-size: 16px;\n color: #475569;\n line-height: 1.5;\n}\n\n.magicfeedback-success-message img,\n.magicfeedback-info-message img,\n.magicfeedback-start-message img {\n width: 400px;\n max-width: 80%;\n height: auto;\n margin: 10px auto;\n}\n\n.magicfeedback-counter,\n.magicfeedback-point-system-total {\n margin: 10px 0 0 0 !important;\n display: flex !important;\n justify-content: right !important;\n align-items: center !important;\n width: 100%;\n}\n\n.magicfeedback-skip-container {\n background-color: transparent !important;\n border: 0 !important;\n color: #999999FF !important;\n padding: 0 !important;\n margin: 0 !important;\n cursor: pointer !important;\n font-size: 0.5em !important;\n font-weight: 400 !important;\n box-shadow: 0 0 0 !important;\n\n &:hover {\n color: #0066ff;\n }\n}\n\n.magicfeedback-skip-container input[type=checkbox] {\n border-color: #999999FF !important;\n border: 0 !important;\n cursor: pointer !important;\n\n}\n\n.magicfeedback-multi-question-matrix,\n.magicfeedback-point-system,\n.magicfeedback-priority-list {\n width: 100% !important;\n}\n\n.magicfeedback-multi-question-matrix-container,\n.magicfeedback-point-system-container,\n.magicfeedback-priority-list-container {\n width: 100% !important;\n overflow-x: auto;\n}\n\n.magicfeedback-point-system-list,\n.magicfeedback-priority-list-list,\n.magicfeedback-multi-question-matrix-table {\n width: 100% !important;\n padding: 0 !important;\n overflow-x: auto;\n}\n\n.magicfeedback-multi-question-matrix {\n position: relative !important;\n}\n\n.magicfeedback-multi-question-matrix-container {\n overflow: auto !important;\n padding-bottom: 10px;\n}\n\n.magicfeedback-multi-question-matrix-label{\n text-align: left !important;\n}\n.magicfeedback-priority-list-item {\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 10px 0 10px 10px;\n\n border: 1px solid #ced4da;\n border-radius: 5px;\n margin: 10px 0 !important;\n}\n\n.magicfeedback-point-system-item {\n height: 45px;\n margin: 5px 0 !important;\n}\n\n.magicfeedback-point-system-item label,\n.magicfeedback-priority-list-item-label {\n font-family: inherit;\n font-size: 18px !important;\n color: #212529;\n text-align: start;\n word-wrap: break-word;\n white-space: normal;\n padding: 0 10px 0 0;\n}\n\n.magicfeedback-point-system-input-container {\n padding: 0 10px 0 0;\n border-radius: 5px;\n font-size: 14px;\n border: 1px solid #ced4da;\n height: 42px;\n margin: auto 0;\n}\n\n.magicfeedback-multi-question-matrix-table thead {\n margin-bottom: 20px;\n}\n\n.magicfeedback-multi-question-matrix-table th{\n text-align: center;\n font-weight: 400 !important;\n font-size: 1rem !important;\n padding: 0 10px !important;\n}\n\n.magicfeedback-multi-question-matrix-table th,\n.magicfeedback-multi-question-matrix-table td label,\n.magicfeedback-priority-list-arrow-up,\n.magicfeedback-priority-list-arrow-down {\n font-style: normal !important;\n font-weight: 400 !important;\n font-size: 1rem !important;\n color: #475569 !important;\n cursor: pointer !important;\n margin: 0 !important;\n line-height: inherit;\n}\n\n.magicfeedback-multi-question-matrix-table tr {\n align-items: center;\n margin: 5px 0;\n}\n\n.magicfeedback-multi-question-matrix-row-tr{\n border-radius: 5px;\n margin: 10px 0 !important;\n}\n\n.magicfeedback-multi-question-matrix-row-tr:nth-child(odd) {\n background-color: #f1f6f6; /* Light gray background for odd rows */\n}\n\n.magicfeedback-multi-question-matrix-row-tr:nth-child(even) {\n background-color: #ffffff; /* White background for even rows */\n}\n\n.magicfeedback-multi-question-matrix-row-label {\n text-align: left !important;\n}\n\n.magicfeedback-point-system-item span {\n color: #475569 !important;\n}\n\n.magicfeedback-point-system-item input {\n padding: 0;\n margin: 0 !important;\n width: auto !important;\n min-width: 100px !important;\n height: auto !important;\n min-height: 42px;\n cursor: pointer;\n font-size: 14px;\n text-align: center !important;\n}\n\n.magicfeedback-multi-question-matrix-table input {\n margin: auto !important;\n padding: 20px !important;\n width: 100% !important;\n height: 15px;\n border: 1px solid #ced4da;\n cursor: pointer;\n}\n\n.magicfeedback-image{\n max-height: 400px !important;\n height: auto !important;\n max-width: 100% !important;\n margin: 10px auto !important;\n}\n\n.magicfeedback-error{\n margin-top: 5px;\n}';
185
+ style_default = '.magicfeedback-container {\n width: 100%;\n}\n\n\n.magicfeedback-success-message,\n.magicfeedback-info-message,\n.magicfeedback-start-message,\n.magicfeedback-container{\n animation-duration: 0.5s;\n animation-name: animate-fade;\n animation-delay: 0.25s;\n animation-fill-mode: backwards;\n\n font-style: normal;\n text-align: justify;\n font-weight: 400;\n font-size: 1.2rem;\n color: #475569;\n line-height: 1.5;\n}\n\n@keyframes animate-fade {\n 0% { opacity: 0; }\n 100% { opacity: 1; }\n}\n\n.magicfeedback-form {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: center;\n width: 100%;\n}\n.magicfeedback-questions {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: flex-start;\n width: 100%;\n}\n\n.magicfeedback-div {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: flex-start;\n margin-bottom: 10px;\n width: 100%;\n}\n\n.magicfeedback-label {\n margin-bottom: 25px;\n margin-top: 20px;\n font-weight: 400;\n font-family: inherit;\n font-size: 1.2rem;\n color: #212529;\n text-align: start;\n word-wrap: break-word;\n white-space: normal;\n\n}\n\n.magicfeedback-checkbox {\n display: flex;\n flex-direction: column;\n flex-wrap: wrap;\n width: 100%;\n}\n\n.magicfeedback-checkbox-container {\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n margin-bottom: 5px;\n margin-top: 5px;\n}\n\n/* Cualificado con `div`: @magicfeedback/native reutiliza la clase "magicfeedback-radio"\n tambi\xE9n en el <input> de cada opci\xF3n (rating), y sin el tag este selector lo capturaba\n tambi\xE9n, rompiendo su tama\xF1o (el input pasaba a display:flex; width:100%). */\ndiv.magicfeedback-radio {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n flex-wrap: wrap;\n width: 100%;\n margin-right: 5px;\n padding: 5px;\n box-sizing: border-box;\n}\n\n.magicfeedback-checkbox-container,\n.magicfeedback-radio-container {\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n margin: 5px;\n padding: 5px 0;\n background-color: #fff;\n border-radius: 5px;\n box-shadow: 0 0 3px #ccc;\n}\n\n.deepdots-popup input::-webkit-outer-spin-button,\n.deepdots-popup input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n -moz-appearance: textfield;\n}\n\n.magicfeedback-checkbox input[type="checkbox"] {\n margin-right: 5px;\n margin-left: 5px;\n width: 20px;\n height: 20px;\n cursor: pointer;\n}\n\n\n.magicfeedback-checkbox label,\n.magicfeedback-radio-container label {\n margin-left: 5px;\n font-weight: 400;\n font-family: inherit;\n font-size: 16px;\n color: #212529;\n text-align: start;\n width: 100%;\n}\n\n.deepdots-popup p {\n margin-bottom: 0px;\n font-size: 12px;\n}\n\n.deepdots-popup h2 {\n line-height: 1.66;\n margin: 0;\n padding: 0;\n font-weight: 900;\n color: #222;\n font-family: var(--deepdots-font, \'Montserrat\');\n font-size: 18px;\n text-transform: uppercase;\n text-align: center;\n margin-bottom: 40px;\n}\n\n/* Los controles de formulario no heredan font-family por defecto: cuando hay\n fuente custom (clase deepdots-has-font), los forzamos a usar la del contenedor. */\n.deepdots-popup.deepdots-has-font button,\n.deepdots-popup.deepdots-has-font input,\n.deepdots-popup.deepdots-has-font textarea,\n.deepdots-popup.deepdots-has-font select {\n font-family: var(--deepdots-font, inherit);\n}\n\n.deepdots-popup h6 {\n margin-bottom: 1rem;\n}\n\n.deepdots-popup input[type="date"],\n.deepdots-popup input[type="text"],\n.deepdots-popup input[type="number"],\n.deepdots-popup input[type="email"],\n.deepdots-popup input[type="password"],\n.deepdots-popup textarea,\n.deepdots-popup select {\n box-sizing: border-box;\n padding: 10px;\n margin: 10px 0;\n width: 100%;\n border: 2px solid #ccc; /* Default border color - you can customize this */\n border-radius: 5px;\n font-size: 18px;\n outline: none;\n transition: border-color 0.3s ease;\n min-height: 50px;\n font-family: inherit;\n -webkit-appearance: none;\n}\n\n.deepdots-popup select {\n background-image: linear-gradient(45deg, transparent 50%, gray 50%),\n linear-gradient(135deg, gray 50%, transparent 50%),\n linear-gradient(to right, #ccc, #ccc);\n background-position: calc(100% - 20px) calc(1em + 2px),\n calc(100% - 15px) calc(1em + 2px),\n calc(100% - 2.5em) 0.5em;\n background-size: 5px 5px,\n 5px 5px,\n 1px 1.5em;\n background-repeat: no-repeat;\n}\n\n.magicfeedback-boolean-container {\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n margin: 10px 0;\n width: 100%;\n}\n\n.magicfeedback-boolean-container label {\n margin-left: 10px;\n font-weight: 400;\n font-size: 16px;\n width: 100%;\n padding-top: 5px;\n}\n\n.magicfeedback-boolean-option {\n margin-right: 10px;\n margin-left: 10px;\n width: 100%;\n height: 38px;\n border-radius: 8px;\n font-size: 16px;\n cursor: pointer;\n border: 1px solid #ced4da !important;\n}\n\n.magicfeedback-boolean-option label {\n font-weight: 400;\n font-size: 16px;\n color: #475569;\n cursor: pointer;\n width: 100%;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n border-radius: inherit;\n}\n\n.magicfeedback-boolean-option input[type=radio] + label:hover {\n color: #007bff;\n}\n\n.magicfeedback-boolean-option input[type=radio]:checked + label {\n color: #007bff;\n background-color: #cadff8;\n}\n\n/* Tama\xF1o expl\xEDcito y sin padding: un radio nativo con `padding: 20px` y solo `width` (sin\n `height`) se dibujaba enorme en WebKit, que s\xED aplica el padding al control. Se ve\xEDa en\n iOS (WebView de React Native y Safari) y no en Chrome. `flex: 0 0 auto` evita que el\n contenedor flex de la opci\xF3n lo estire. */\n.deepdots-popup input[type="radio"] {\n padding: 0;\n margin: 10px 0 10px 15px;\n width: 20px;\n height: 20px;\n min-width: 20px;\n flex: 0 0 auto;\n background-color: #fff;\n box-shadow: none;\n}\n\n/* Style for focused input/select */\n.deepdots-popup input:focus, .deepdots-popup select:focus {\n border-color: #4CAF50; /* Highlight color when focused - you can customize this */\n}\n\n/* Style for invalid input (example: validation error) */\n.deepdots-popup input.error, .deepdots-popup select.error {\n border-color: #ff3333; /* Red color for error state - you can customize this */\n}\n\n.magicfeedback-action-container {\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n margin-top: 10px;\n width: 100%;\n}\n\n.magicfeedback-action-container .magicfeedback-submit {\n cursor: pointer;\n padding: 10px;\n margin: 10px 0;\n width: 100px;\n border-radius: 8px;\n font-size: 16px;\n outline: none;\n transition: border-color 0.3s ease;\n background-color: #1E293B;\n color: white;\n}\n\n.magicfeedback-action-container .magicfeedback-back {\n cursor: pointer;\n padding: 10px;\n margin: 10px 0;\n width: 100px;\n border: 0;\n border-radius: 8px;\n font-size: 16px;\n outline: none;\n transition: border-color 0.3s ease;\n background-color: transparent;\n color: #212529;\n}\n\n\n\n/* Rating styles */\n.magicfeedback-rating {\n width: 100%;\n}\n\n.magicfeedback-rating-container {\n display: flex;\n flex-direction: row;\n justify-content: space-around;\n flex-wrap: wrap;\n align-items: center;\n\n margin: 15px 5px;\n padding: 0;\n\n list-style: none;\n font-size: 1.5rem;\n cursor: pointer;\n user-select: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n}\n\n.magicfeedback-rating-placeholder-value,\n.magicfeedback-rating-placeholder{\n text-align: center;\n align-content: center;\n justify-content: center;\n text-wrap: wrap;\n}\n\n.magicfeedback-rating-option {\n margin: 0 0.5rem;\n padding: 0;\n}\n\n@media (max-width: 1024px) {\n .magicfeedback-rating-option {\n margin: 10px 0;\n padding: 0;\n width: 20%;\n display: flex;\n justify-content: center;\n }\n\n .magicfeedback-rating-placeholder-value {\n font-size: 0.75rem;\n margin-bottom: 1px;\n }\n .magicfeedback-rating-placeholder{\n justify-content: center;\n }\n\n .magicfeedback-rating-container {\n flex-wrap: wrap;\n justify-content: flex-start;\n }\n}\n\n\n.magicfeedback-rating-option-label-container {\n display: flex;\n flex-direction: column;\n}\n\n\n.magicfeedback-rating-option-label-container label {\n display: inline-block;\n text-align: center;\n margin-bottom: 0;\n font-weight: 600;\n font-size: 18px;\n color: #475569;\n}\n\n.magicfeedback-rating-option-label-container input[type=radio] {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n}\n\n/* IMAGE STYLES */\n.magicfeedback-rating-option-label-container input[type=radio] + img {\n cursor: pointer;\n height: 48px;\n width: 48px;\n}\n\n/* LABEL STYLES */\n.magicfeedback-rating-option-label-container input[type=radio] + label {\n cursor: pointer;\n}\n\n/* CHECKED STYLES */\n.magicfeedback-rating-option-label-container input[type=radio]:checked + img {\n box-shadow: #007bff 0px 1px 4px, #007BFFA0 0px 0px 0px 2px;\n border-radius: 50%;\n}\n\n.magicfeedback-rating-number {\n width: 100%;\n}\n.magicfeedback-rating-container,\n.magicfeedback-rating-number-container {\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n\n margin: 15px 0;\n padding: 0;\n\n list-style: none;\n font-size: 1.5rem;\n cursor: pointer;\n user-select: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n}\n\n/* Cuando hay placeholders (Very bad / Very good), el placeholder ocupa\n el 100% de la primera l\xEDnea y los boxes bajan a la siguiente */\n.magicfeedback-rating-number-container--with-placeholder {\n flex-wrap: wrap;\n align-items: flex-start;\n}\n\n.magicfeedback-rating-number-container--with-placeholder .magicfeedback-rating-placeholder {\n width: 100%;\n margin-bottom: 8px;\n}\n\n.magicfeedback-rating-number-container--with-placeholder .magicfeedback-rating-number-option {\n width: auto;\n flex: 1;\n}\n\n.magicfeedback-rating-number-option {\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n margin: 5px;\n padding: 0;\n list-style: none;\n font-size: 1.5rem;\n cursor: pointer;\n user-select: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n width: 100%;\n}\n\n.magicfeedback-rating-number-option-row{\n max-width: 100% !important;\n}\n\n.magicfeedback-rating-number-top-placeholder,\n.magicfeedback-rating-number-bottom-placeholder{\n text-align: center !important;\n align-content: center;\n justify-content: center;\n text-wrap: wrap;\n\n font-size: 15px;\n color: #475569;\n\n width: 100%;\n margin: auto;\n}\n\n@media (min-width: 650px) {\n .magicfeedback-rating-number-option-row +.magicfeedback-rating-number-container-ltr:first-child,\n .magicfeedback-rating-number-option-row + +.magicfeedback-rating-number-container-rtl:last-child {\n margin-left: 0;\n width: calc(100% - 10px);\n }\n\n .magicfeedback-rating-number-option-row +.magicfeedback-rating-number-container-rtl:first-child,\n .magicfeedback-rating-number-option-row + +.magicfeedback-rating-number-container-ltr:last-child {\n margin-right: 0;\n width: calc(100% - 10px);\n }\n}\n\n\n.magicfeedback-rating-number-option-label-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n}\n\n.magicfeedback-rating-number-option-label-container label {\n display: flex;\n align-items: center;\n justify-content: center;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n margin: 0 10px;\n font-weight: 600;\n font-size: 14px;\n color: #475569;\n cursor: pointer;\n width: 100%;\n height: 100%;\n min-height: 50px;\n text-align: center;\n padding: 0;\n border-radius: 4px;\n border: 1px solid #ced4da;\n background-color: rgba(246, 246, 246, 0.3);\n transition: background-color 0.15s ease-in-out;\n}\n\n.magicfeedback-rating-number-option-label-container input[type=radio] {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n}\n\n.magicfeedback-rating-number-option-label-container input[type=radio] + label {\n cursor: pointer;\n}\n\n.magicfeedback-rating-number-option-label-container input[type=radio] + label:hover,\n.magicfeedback-rating-number-option-label-container input[type=radio]:checked + label {\n color: #007bff;\n border: 1px solid #007bff;\n background-color: rgba(86, 168, 253, 0.29);\n}\n\n.magicfeedback-rating-number-container-column{\n align-items: flex-start !important;\n}\n\n@media (max-width: 650px) {\n .magicfeedback-rating-number-container-ltr {\n justify-content: center;\n flex-wrap: wrap;\n }\n\n .magicfeedback-rating-number-container-rtl {\n justify-content: center;\n flex-wrap: wrap-reverse;\n }\n\n .magicfeedback-rating-number-option {\n max-width: 100%;\n height: 55px;\n margin: 5px 0;\n }\n}\n\n.magicfeedback-rating-star {\n width: 100%;\n}\n\n.magicfeedback-rating-star-container {\n display: flex !important;\n flex-direction: row !important;\n justify-content: center !important;\n align-items: center !important;\n flex-wrap: wrap;\n margin: 15px 5px;\n padding: 0;\n list-style: none;\n font-size: 1.5rem;\n cursor: pointer;\n user-select: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n}\n\n.magicfeedback-rating-star-option:not(:checked) > .rating__star {\n float: right;\n width: 1em;\n overflow: hidden;\n white-space: nowrap;\n cursor: pointer;\n font-size: 30px;\n color: #ccc;\n margin: 0 10px;\n}\n\n.magicfeedback-rating-star-option:not(:checked) > .rating__star:hover,\n.magicfeedback-rating-star-option:not(:checked) > .rating__star:hover ~ span {\n color: #deb217 !important;\n}\n\n.magicfeedback-rating-star-selected {\n color: #ffc700 !important;\n}\n\n\n/* Style for multiple choice image */\n.magicfeedback-image-option-label-container:hover {\n cursor: pointer;\n border: 0 !important;\n}\n\n.magicfeedback-image-option-label-container input[type=radio]:checked + img,\n.magicfeedback-image-option-label-container input[type=checkbox]:checked + img {\n border: 1px solid #007bff !important;\n box-shadow: 0 0 3px #007bff !important;\n}\n\n.magicfeedback-image-option-label-container input[type=radio] + img,\n.magicfeedback-image-option-label-container input[type=checkbox] + img {\n border: 1px solid transparent !important;\n}\n\n.magicfeedback-image-option-label-container{\n margin: 10px !important;\n height: calc(100% - 20px) !important;\n width: calc(100% - 20px) !important;\n}\n\n.magicfeedback-multiple-choice-image-option {\n display: flex;\n height: auto !important;\n box-shadow: 0 0 3px #ccc;\n}\n\n.magicfeedback-multiple-choice-image-label {\n font-size: 1rem;\n}\n\n.magicfeedback-consent-container {\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n margin: 10px 0;\n width: 100%;\n}\n\n.magicfeedback-consent-container label {\n margin-left: 10px;\n}\n\n.magicfeedback-start-message-container {\n /* ... add your start message container styles here ... */\n}\n\n.magicfeedback-success-message,\n.magicfeedback-info-message,\n.magicfeedback-start-message {\n margin: 35px 5px;\n}\n\n.magicfeedback-success-message p,\n.magicfeedback-info-message p,\n.magicfeedback-start-message p {\n font-style: normal;\n text-align: start;\n font-weight: 400;\n font-size: 16px;\n color: #475569;\n line-height: 1.5;\n}\n\n.magicfeedback-success-message img,\n.magicfeedback-info-message img,\n.magicfeedback-start-message img {\n width: 400px;\n max-width: 80%;\n height: auto;\n margin: 10px auto;\n}\n\n.magicfeedback-counter,\n.magicfeedback-point-system-total {\n margin: 10px 0 0 0 !important;\n display: flex !important;\n justify-content: right !important;\n align-items: center !important;\n width: 100%;\n}\n\n.magicfeedback-skip-container {\n background-color: transparent !important;\n border: 0 !important;\n color: #999999FF !important;\n padding: 0 !important;\n margin: 0 !important;\n cursor: pointer !important;\n font-size: 0.5em !important;\n font-weight: 400 !important;\n box-shadow: 0 0 0 !important;\n\n &:hover {\n color: #0066ff;\n }\n}\n\n.magicfeedback-skip-container input[type=checkbox] {\n border-color: #999999FF !important;\n border: 0 !important;\n cursor: pointer !important;\n\n}\n\n.magicfeedback-multi-question-matrix,\n.magicfeedback-point-system,\n.magicfeedback-priority-list {\n width: 100% !important;\n}\n\n.magicfeedback-multi-question-matrix-container,\n.magicfeedback-point-system-container,\n.magicfeedback-priority-list-container {\n width: 100% !important;\n overflow-x: auto;\n}\n\n.magicfeedback-point-system-list,\n.magicfeedback-priority-list-list,\n.magicfeedback-multi-question-matrix-table {\n width: 100% !important;\n padding: 0 !important;\n overflow-x: auto;\n}\n\n.magicfeedback-multi-question-matrix {\n position: relative !important;\n}\n\n.magicfeedback-multi-question-matrix-container {\n overflow: auto !important;\n padding-bottom: 10px;\n}\n\n.magicfeedback-multi-question-matrix-label{\n text-align: left !important;\n}\n.magicfeedback-priority-list-item {\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 10px 0 10px 10px;\n\n border: 1px solid #ced4da;\n border-radius: 5px;\n margin: 10px 0 !important;\n}\n\n.magicfeedback-point-system-item {\n height: 45px;\n margin: 5px 0 !important;\n}\n\n.magicfeedback-point-system-item label,\n.magicfeedback-priority-list-item-label {\n font-family: inherit;\n font-size: 18px !important;\n color: #212529;\n text-align: start;\n word-wrap: break-word;\n white-space: normal;\n padding: 0 10px 0 0;\n}\n\n.magicfeedback-point-system-input-container {\n padding: 0 10px 0 0;\n border-radius: 5px;\n font-size: 14px;\n border: 1px solid #ced4da;\n height: 42px;\n margin: auto 0;\n}\n\n.magicfeedback-multi-question-matrix-table thead {\n margin-bottom: 20px;\n}\n\n.magicfeedback-multi-question-matrix-table th{\n text-align: center;\n font-weight: 400 !important;\n font-size: 1rem !important;\n padding: 0 10px !important;\n}\n\n.magicfeedback-multi-question-matrix-table th,\n.magicfeedback-multi-question-matrix-table td label,\n.magicfeedback-priority-list-arrow-up,\n.magicfeedback-priority-list-arrow-down {\n font-style: normal !important;\n font-weight: 400 !important;\n font-size: 1rem !important;\n color: #475569 !important;\n cursor: pointer !important;\n margin: 0 !important;\n line-height: inherit;\n}\n\n.magicfeedback-multi-question-matrix-table tr {\n align-items: center;\n margin: 5px 0;\n}\n\n.magicfeedback-multi-question-matrix-row-tr{\n border-radius: 5px;\n margin: 10px 0 !important;\n}\n\n.magicfeedback-multi-question-matrix-row-tr:nth-child(odd) {\n background-color: #f1f6f6; /* Light gray background for odd rows */\n}\n\n.magicfeedback-multi-question-matrix-row-tr:nth-child(even) {\n background-color: #ffffff; /* White background for even rows */\n}\n\n.magicfeedback-multi-question-matrix-row-label {\n text-align: left !important;\n}\n\n.magicfeedback-point-system-item span {\n color: #475569 !important;\n}\n\n.magicfeedback-point-system-item input {\n padding: 0;\n margin: 0 !important;\n width: auto !important;\n min-width: 100px !important;\n height: auto !important;\n min-height: 42px;\n cursor: pointer;\n font-size: 14px;\n text-align: center !important;\n}\n\n.magicfeedback-multi-question-matrix-table input {\n margin: auto !important;\n padding: 20px !important;\n width: 100% !important;\n height: 15px;\n border: 1px solid #ced4da;\n cursor: pointer;\n}\n\n.magicfeedback-image{\n max-height: 400px !important;\n height: auto !important;\n max-width: 100% !important;\n margin: 10px auto !important;\n}\n\n.magicfeedback-error{\n margin-top: 5px;\n}';
186
186
  }
187
187
  });
188
188
 
@@ -225,6 +225,10 @@ function ensureSpinnerStyles(_popup) {
225
225
  const style = document.createElement("style");
226
226
  style.id = "deepdots-spinner-styles";
227
227
  style.textContent = `
228
+ /* El enunciado trae margin-top:20px del CSS de surveys, que sumaba al hueco de la barra
229
+ de progreso y descompensaba la simetr\xEDa. Solo se anula en el primero: entre preguntas
230
+ de la misma p\xE1gina sigue separando. */
231
+ .deepdots-popup .magicfeedback-questions .magicfeedback-div:first-child .magicfeedback-label { margin-top: 0; }
228
232
  @keyframes ddspin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
229
233
  .mf-spinner { display:flex; justify-content:center; align-items:center; padding:8px 0; }
230
234
  .mf-spinner-circle { width:28px; height:28px; border:3px solid #e0e6ed; border-top-color:#1E293B; border-radius:50%; animation: ddspin 0.9s linear infinite; }
@@ -251,7 +255,9 @@ function ensureResponsiveStyles(_popup) {
251
255
  .deepdots-popup button { font-size: 16px !important; }
252
256
  .deepdots-popup-header button { width:48px; height:48px; }
253
257
  .deepdots-popup-header button svg { width:26px; height:26px; }
254
- .deepdots-popup-footer { flex-direction: column-reverse !important; gap: 12px !important; }
258
+ /* Apilados en el orden del DOM: la acci\xF3n principal (Send/Start/Complete) arriba y
259
+ Back debajo. */
260
+ .deepdots-popup-footer { flex-direction: column !important; gap: 4px !important; }
255
261
  .deepdots-popup-footer button { width: 100%; }
256
262
  }
257
263
  @media (max-width: 400px) {
@@ -269,6 +275,18 @@ function ensureResponsiveStyles(_popup) {
269
275
  `;
270
276
  document.head.appendChild(style);
271
277
  }
278
+ function ensureCustomCss(css) {
279
+ const STYLE_ID = "deepdots-custom-css";
280
+ const existing = document.getElementById(STYLE_ID);
281
+ if (!css) {
282
+ existing?.remove();
283
+ return;
284
+ }
285
+ const el = existing ?? document.createElement("style");
286
+ el.id = STYLE_ID;
287
+ if (el.textContent !== css) el.textContent = css;
288
+ document.head.appendChild(el);
289
+ }
272
290
  function ensureFontFace(family, url) {
273
291
  const css = buildFontFaceCss(family, url);
274
292
  if (!css) return;
@@ -281,9 +299,11 @@ function ensureFontFace(family, url) {
281
299
  }
282
300
  if (el.textContent !== css) el.textContent = css;
283
301
  }
284
- async function renderPopup(container, surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId) {
302
+ async function renderPopup(container, surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId, options) {
285
303
  let surveyCompletedEmitted = false;
286
304
  let stylesInjected = false;
305
+ let pageDepth = 0;
306
+ let onStartPage = false;
287
307
  const isDark = style?.theme === "dark";
288
308
  const theme = {
289
309
  popupBg: isDark ? "#1e1e1e" : "#fff",
@@ -294,7 +314,9 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
294
314
  colorScheme: isDark ? "dark" : "light",
295
315
  textPrimary: isDark ? "#f0f0f0" : "#111",
296
316
  closeBtnHoverBg: isDark ? "rgba(255,255,255,0.10)" : "rgba(0,0,0,0.06)",
297
- closeBtnHoverColor: isDark ? "#fff" : "#000000"
317
+ closeBtnHoverColor: isDark ? "#fff" : "#000000",
318
+ textMuted: isDark ? "#9ca3af" : "#6b7280",
319
+ progressTrack: isDark ? "#3f3f46" : "#e5e7eb"
298
320
  };
299
321
  const positionMap = {
300
322
  "center": { justifyContent: "center", alignItems: "center", background: "rgba(0,0,0,0.5)" },
@@ -307,6 +329,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
307
329
  };
308
330
  const pos = positionMap[style?.position ?? "center"] ?? positionMap["center"];
309
331
  const popup = document.createElement("div");
332
+ popup.id = "dd-popup";
310
333
  popup.className = "deepdots-popup";
311
334
  popup.style.cssText = `
312
335
  position: relative;
@@ -320,6 +343,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
320
343
  box-shadow: 0 4px 6px rgba(0,0,0,0.1);
321
344
  max-width: 600px;
322
345
  width: 90%;
346
+ max-height: 90vh;
323
347
  min-height: 200px;
324
348
  `;
325
349
  const font = style?.font;
@@ -332,8 +356,21 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
332
356
  }
333
357
  const header = document.createElement("div");
334
358
  header.className = "deepdots-popup-header";
335
- header.style.cssText = "display:flex; justify-content:flex-end; align-items:center; width:100%;";
359
+ header.style.cssText = "display:flex; justify-content:space-between; align-items:center; gap:12px; width:100%; flex:0 0 auto;";
360
+ const titleEl = document.createElement("h2");
361
+ titleEl.id = "dd-title";
362
+ titleEl.className = "deepdots-popup-title";
363
+ titleEl.style.cssText = `margin:0; font-size:17px; font-weight:600; line-height:1.3; color:${theme.textPrimary}; text-transform:none; text-align:left; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;`;
364
+ titleEl.hidden = true;
365
+ const setTitle = (value) => {
366
+ if (!value) return;
367
+ titleEl.textContent = value;
368
+ titleEl.hidden = false;
369
+ };
370
+ setTitle(options?.title);
371
+ header.appendChild(titleEl);
336
372
  const closeBtn = document.createElement("button");
373
+ closeBtn.id = "dd-close";
337
374
  closeBtn.type = "button";
338
375
  closeBtn.setAttribute("aria-label", "Close popup");
339
376
  closeBtn.innerHTML = `
@@ -370,25 +407,86 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
370
407
  emit("popup_clicked", surveyId, { action: "close_icon" });
371
408
  onClose();
372
409
  };
410
+ closeBtn.style.flex = "0 0 auto";
411
+ closeBtn.style.marginLeft = "auto";
373
412
  header.appendChild(closeBtn);
413
+ let progressEnabled = options?.showProgressBar === true;
414
+ let progressShowUnit = true;
415
+ let progressUnit = "fraction";
416
+ const progressEl = document.createElement("div");
417
+ progressEl.id = "dd-progress";
418
+ progressEl.className = "deepdots-progress";
419
+ progressEl.style.cssText = "display:none; flex-direction:column; gap:8px; width:100%; flex:0 0 auto; padding:16px 0; box-sizing:border-box;";
420
+ const progressHead = document.createElement("div");
421
+ progressHead.className = "deepdots-progress-head";
422
+ progressHead.style.cssText = "display:flex; flex-direction:row; justify-content:space-between; align-items:center; width:100%; gap:8px;";
423
+ const progressLabel = document.createElement("span");
424
+ progressLabel.id = "dd-progress-label";
425
+ progressLabel.style.cssText = "font-size:13px; line-height:1.2;";
426
+ const progressCurrent = document.createElement("span");
427
+ progressCurrent.id = "dd-progress-current";
428
+ progressCurrent.style.cssText = `font-weight:700; color:${theme.textPrimary};`;
429
+ const progressTotal = document.createElement("span");
430
+ progressTotal.id = "dd-progress-total";
431
+ progressTotal.style.cssText = `font-weight:400; color:${theme.textMuted};`;
432
+ progressLabel.appendChild(progressCurrent);
433
+ progressLabel.appendChild(progressTotal);
434
+ const progressFollowUp = document.createElement("span");
435
+ progressFollowUp.id = "dd-progress-followup";
436
+ progressFollowUp.textContent = "Follow-up";
437
+ progressFollowUp.style.cssText = "display:none; font-size:12px; font-weight:600; color:#fff; background:rgba(59,130,246,0.44); border-radius:999px; padding:2px 10px;";
438
+ progressHead.appendChild(progressLabel);
439
+ progressHead.appendChild(progressFollowUp);
440
+ const progressTrack = document.createElement("div");
441
+ progressTrack.className = "deepdots-progress-track";
442
+ progressTrack.style.cssText = `width:100%; height:4px; border-radius:999px; background:${theme.progressTrack}; overflow:hidden;`;
443
+ const progressBar = document.createElement("div");
444
+ progressBar.id = "dd-progress-bar";
445
+ progressBar.style.cssText = "height:100%; width:0%; background:#22C55E; border-radius:999px; transition:width 450ms ease;";
446
+ progressTrack.appendChild(progressBar);
447
+ progressEl.appendChild(progressHead);
448
+ progressEl.appendChild(progressTrack);
449
+ function updateProgress(p) {
450
+ const total = typeof p.total === "number" ? p.total : 0;
451
+ const progress = typeof p.progress === "number" ? p.progress : 0;
452
+ if (!progressEnabled || onStartPage || p.completed || total <= 1) {
453
+ progressEl.style.display = "none";
454
+ containerContent.style.paddingTop = "16px";
455
+ return;
456
+ }
457
+ progressEl.style.display = "flex";
458
+ containerContent.style.paddingTop = "0";
459
+ const current = Math.min(total, Math.max(1, progress + 1));
460
+ const pct = Math.min(100, Math.max(0, current / total * 100));
461
+ progressBar.style.width = `${pct}%`;
462
+ const label = Math.min(total, Math.max(1, Math.floor(progress) + 1));
463
+ progressLabel.style.display = progressShowUnit ? "block" : "none";
464
+ if (progressUnit === "percentage") {
465
+ progressCurrent.textContent = `${Math.round(pct)}%`;
466
+ progressTotal.textContent = "";
467
+ } else {
468
+ progressCurrent.textContent = `Question ${label}`;
469
+ progressTotal.textContent = ` of ${total}`;
470
+ }
471
+ progressFollowUp.style.display = p.followup ? "inline-block" : "none";
472
+ }
374
473
  ensureMagicFeedbackStyles(popup);
375
474
  ensureSpinnerStyles(popup);
376
475
  ensureResponsiveStyles(popup);
476
+ ensureCustomCss(options?.surveyCss);
377
477
  const containerContent = document.createElement("div");
378
- containerContent.className = "deepdots-popup-container-conetent";
379
- containerContent.style.cssText = `
380
- display:flex;
381
- flex-direction:column;
382
- padding: 0 20px 12px 20px;
383
- max-height: 80vh; /* l\xEDmite general del popup */
384
- overflow: hidden; /* quita scroll del contenedor principal */
385
- `;
478
+ containerContent.id = "dd-content";
479
+ containerContent.className = "deepdots-popup-container-content";
480
+ containerContent.style.cssText = "display:flex; flex-direction:column; flex:1 1 auto; min-height:0; padding:16px 0 0 0; overflow:hidden;";
386
481
  const main = document.createElement("div");
482
+ main.id = "dd-main";
387
483
  main.className = "deepdots-popup-main";
388
- main.style.cssText = "display:flex; flex-direction:column; width:100%; max-height:80vh; overflow-y:auto;";
484
+ main.style.cssText = "display:flex; flex-direction:column; width:100%; flex:1 1 auto; min-height:0; overflow-y:auto;";
389
485
  const formWrapper = document.createElement("div");
486
+ formWrapper.id = "dd-form-wrapper";
390
487
  formWrapper.style.cssText = "width:100%; flex: 1 1 auto;";
391
488
  const errorHint = document.createElement("div");
489
+ errorHint.id = "dd-error";
392
490
  errorHint.className = "deepdots-error-hint";
393
491
  errorHint.style.cssText = `
394
492
  display: none;
@@ -417,20 +515,24 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
417
515
  main.appendChild(formWrapper);
418
516
  main.appendChild(errorHint);
419
517
  const footer = document.createElement("div");
518
+ footer.id = "dd-footer";
420
519
  footer.className = "deepdots-popup-footer";
421
520
  footer.setAttribute("data-actions-wrapper", "true");
422
- footer.style.cssText = "display:flex; flex-direction: row-reverse ;justify-content:space-between; align-items:center; gap:8px; margin-top:auto; width:100%; padding-top:16px;";
521
+ footer.style.cssText = "display:flex; flex-direction: row-reverse ;justify-content:space-between; align-items:center; gap:4px; margin-top:auto; width:100%; padding-top:12px;";
423
522
  const backButton = document.createElement("button");
523
+ backButton.id = "dd-back";
524
+ backButton.className = "dd-nav-btn";
424
525
  backButton.textContent = actions?.back ? actions.back.label : "Back";
425
526
  backButton.style.cssText = `
426
527
  background: transparent;
427
- color: #333;
428
- border: 1px solid #999;
528
+ color: ${theme.textMuted};
529
+ border: none;
530
+ min-height: 44px;
429
531
  padding: 12px 24px;
430
- border-radius: 4px;
532
+ border-radius: 6px;
431
533
  cursor: pointer;
432
- font-size: 14px;
433
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
534
+ font-size: 15px;
535
+ font-weight: 600;
434
536
  transition: filter .15s ease;
435
537
  display: inline-flex;
436
538
  align-items: center;
@@ -448,15 +550,19 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
448
550
  formInstance?.back?.();
449
551
  };
450
552
  const startButton = document.createElement("button");
553
+ startButton.id = "dd-start";
554
+ startButton.className = "dd-nav-btn";
451
555
  startButton.textContent = actions?.start ? actions.start.label : "Start survey";
452
556
  startButton.style.cssText = `
453
557
  background: #1E293B;
454
558
  color: #fff;
455
559
  border: none;
560
+ min-height: 44px;
456
561
  padding: 12px 24px;
457
- border-radius: 4px;
562
+ border-radius: 6px;
458
563
  cursor: pointer;
459
- font-size: 14px;
564
+ font-size: 15px;
565
+ font-weight: 600;
460
566
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
461
567
  transition: filter .15s ease;
462
568
  display: inline-flex;
@@ -467,17 +573,23 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
467
573
  startButton.onclick = () => {
468
574
  emit("popup_clicked", surveyId, { action: "start_survey" });
469
575
  formInstance?.startForm?.();
576
+ onStartPage = false;
577
+ updateProgress({ progress: formInstance?.progress, total: formInstance?.total });
470
578
  };
471
579
  const closeButton = document.createElement("button");
580
+ closeButton.id = "dd-complete";
581
+ closeButton.className = "dd-nav-btn";
472
582
  closeButton.textContent = actions?.complete ? actions.complete.label : "Complete survey";
473
583
  closeButton.style.cssText = `
474
584
  background: #1E293B;
475
585
  color: #fff;
476
586
  border: none;
587
+ min-height: 44px;
477
588
  padding: 12px 24px;
478
- border-radius: 4px;
589
+ border-radius: 6px;
479
590
  cursor: pointer;
480
- font-size: 14px;
591
+ font-size: 15px;
592
+ font-weight: 600;
481
593
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
482
594
  transition: filter .15s ease;
483
595
  display: inline-flex;
@@ -496,15 +608,19 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
496
608
  onClose();
497
609
  };
498
610
  const submitButton = document.createElement("button");
611
+ submitButton.id = "dd-submit";
612
+ submitButton.className = "dd-nav-btn";
499
613
  submitButton.textContent = actions?.accept ? actions.accept.label : "Send";
500
614
  submitButton.style.cssText = `
501
615
  background: #1E293B;
502
616
  color: #fff;
503
617
  border: none;
618
+ min-height: 44px;
504
619
  padding: 12px 24px;
505
- border-radius: 4px;
620
+ border-radius: 6px;
506
621
  cursor: pointer;
507
- font-size: 14px;
622
+ font-size: 15px;
623
+ font-weight: 600;
508
624
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
509
625
  transition: filter .15s ease;
510
626
  display: inline-flex;
@@ -526,8 +642,9 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
526
642
  footer.appendChild(backButton);
527
643
  footer.appendChild(closeButton);
528
644
  footer.appendChild(startButton);
529
- main.appendChild(footer);
530
645
  containerContent.appendChild(main);
646
+ footer.style.flex = "0 0 auto";
647
+ containerContent.appendChild(footer);
531
648
  function updateButtons(state) {
532
649
  backButton.style.display = "none";
533
650
  startButton.style.display = "none";
@@ -564,7 +681,27 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
564
681
  break;
565
682
  }
566
683
  }
684
+ function updateNavButtons() {
685
+ updateButtons(pageDepth > 0 ? "in_progress_next" : "in_progress_first");
686
+ }
687
+ let successMessageHtml = "";
688
+ function showSuccessScreen() {
689
+ progressEl.style.display = "none";
690
+ formWrapper.style.display = "none";
691
+ let done = main.querySelector(".deepdots-success");
692
+ if (!done) {
693
+ done = document.createElement("div");
694
+ done.className = "deepdots-success";
695
+ done.style.cssText = `width:100%; text-align:center; padding:24px 0; color:${theme.textPrimary};`;
696
+ main.insertBefore(done, errorHint);
697
+ }
698
+ done.innerHTML = successMessageHtml || "<p>Thank you for your feedback!</p>";
699
+ done.querySelectorAll("img").forEach((img) => {
700
+ img.style.cssText = "max-width:100%; height:auto; margin:0 auto 16px auto; display:block;";
701
+ });
702
+ }
567
703
  popup.appendChild(header);
704
+ popup.appendChild(progressEl);
568
705
  popup.appendChild(containerContent);
569
706
  container.innerHTML = "";
570
707
  container.appendChild(popup);
@@ -610,15 +747,27 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
610
747
  formInstance = import_native.default.form(surveyId, productId, profile, metadata);
611
748
  const generateOptions = {
612
749
  addButton: false,
613
- getMetaData: true
750
+ getMetaData: true,
751
+ // La pantalla final la pinta el popup: `renderSuccess` de @magicfeedback/native usa
752
+ // textContent, así que el mensaje de la plataforma (HTML con imagen) no se vería, y
753
+ // su fallback es un literal genérico que ignora `style.successMessage`.
754
+ addSuccessScreen: false
614
755
  };
615
756
  generateOptions.onLoadedEvent = ({ formData }) => {
616
757
  try {
617
- } catch (e) {
758
+ } catch {
618
759
  }
619
760
  const s = formData?.style;
620
761
  if (s && !stylesInjected) {
621
762
  stylesInjected = true;
763
+ if (s.successMessage) successMessageHtml = s.successMessage;
764
+ if (options?.showProgressBar === void 0) progressEnabled = s.showProgressBar === true;
765
+ if (s.showProgressUnit !== void 0) progressShowUnit = s.showProgressUnit !== false;
766
+ if (s.progressUnit) progressUnit = s.progressUnit;
767
+ if (s.loadingBarColor) {
768
+ progressBar.style.background = s.loadingBarColor;
769
+ progressFollowUp.style.background = s.loadingBarColor;
770
+ }
622
771
  if (s.boxBackgroundColor) {
623
772
  popup.style.background = s.boxBackgroundColor;
624
773
  }
@@ -637,9 +786,9 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
637
786
  closeButton.style.color = "#fff";
638
787
  }
639
788
  if (s.buttonSecondaryColor) {
640
- backButton.style.background = "#fff";
789
+ backButton.style.background = "transparent";
641
790
  backButton.style.color = s.buttonSecondaryColor;
642
- backButton.style.border = `1px solid ${s.buttonSecondaryColor}`;
791
+ backButton.style.border = "none";
643
792
  }
644
793
  if (s.logo) {
645
794
  if (!document.getElementById("deepdots-popup-logo")) {
@@ -684,6 +833,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
684
833
  }
685
834
  if (s.startMessage && s.startMessage !== "") {
686
835
  sdkLog(s.startMessage);
836
+ onStartPage = true;
687
837
  updateButtons("start");
688
838
  } else {
689
839
  updateButtons("in_progress_first");
@@ -691,6 +841,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
691
841
  } else {
692
842
  updateButtons("in_progress_first");
693
843
  }
844
+ updateProgress({ progress: formInstance.progress, total: formInstance.total });
694
845
  emit("popup_clicked", surveyId, { action: "loaded" });
695
846
  setLoading(false);
696
847
  };
@@ -698,7 +849,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
698
849
  setLoading(true);
699
850
  emit("popup_clicked", surveyId, { action: "before_submit" });
700
851
  };
701
- generateOptions.afterSubmitEvent = ({ error, completed, total, progress }) => {
852
+ generateOptions.afterSubmitEvent = ({ error, completed, total, progress, followup }) => {
702
853
  const errText = error ? typeof error === "string" ? error : error.message ?? String(error) : "";
703
854
  if (errText) {
704
855
  setLoading(false);
@@ -706,7 +857,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
706
857
  errorHint.textContent = "Please answer the required question to continue.";
707
858
  errorHint.style.display = "block";
708
859
  emit("popup_clicked", surveyId, { action: "validation_error_required" });
709
- updateButtons("in_progress_next");
860
+ updateNavButtons();
710
861
  return;
711
862
  }
712
863
  errorHint.textContent = "An error occurred while submitting. Please try again or close the popup.";
@@ -719,23 +870,21 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
719
870
  if (completed) {
720
871
  emit("survey_completed", surveyId, { action: "completed" });
721
872
  surveyCompletedEmitted = true;
873
+ showSuccessScreen();
722
874
  updateButtons("completed");
875
+ updateProgress({ progress, total, completed: true });
723
876
  return;
724
877
  }
725
878
  emit("popup_clicked", surveyId, { action: "partial" });
726
- if (total > 1 && progress > 0 && progress < total) {
727
- updateButtons("in_progress_next");
728
- } else {
729
- updateButtons("in_progress_first");
730
- }
879
+ pageDepth++;
880
+ updateNavButtons();
881
+ updateProgress({ progress, total, followup });
731
882
  };
732
- generateOptions.onBackEvent = ({ progress }) => {
883
+ generateOptions.onBackEvent = ({ progress, error, followup }) => {
733
884
  emit("popup_clicked", surveyId, { action: "back" });
734
- if (progress === 0) {
735
- updateButtons("in_progress_first");
736
- } else {
737
- updateButtons("in_progress_next");
738
- }
885
+ if (!error) pageDepth = Math.max(0, pageDepth - 1);
886
+ updateNavButtons();
887
+ updateProgress({ progress, total: formInstance.total, followup });
739
888
  };
740
889
  formInstance.generate(formDivId, generateOptions).catch((err) => {
741
890
  sdkError("[MagicFeedback] Error generating form:", err);
@@ -779,6 +928,10 @@ var POPUP_TRIGGER_CONDITION_STATUSES = [
779
928
  ];
780
929
 
781
930
  // src/triggers/index.ts
931
+ function toNumericValue(value, fallback) {
932
+ const n = Number(value);
933
+ return Number.isFinite(n) ? n : fallback;
934
+ }
782
935
  function setupTrigger(popups, trigger) {
783
936
  switch (trigger.type) {
784
937
  case "time":
@@ -799,14 +952,14 @@ function setupTrigger(popups, trigger) {
799
952
  }
800
953
  }
801
954
  function setupTimeTrigger(popups, trigger) {
802
- const delay = trigger.value || 5e3;
955
+ const delay = toNumericValue(trigger.value, 5e3);
803
956
  setTimeout(() => {
804
957
  popups.triggerSurvey(trigger.surveyId, trigger.popupId);
805
958
  }, delay);
806
959
  popups.debug(`Time trigger set for ${delay}ms`);
807
960
  }
808
961
  function setupScrollTrigger(popups, trigger) {
809
- const threshold = trigger.value || 50;
962
+ const threshold = toNumericValue(trigger.value, 50);
810
963
  const handler = () => {
811
964
  const scrollPercentage = window.scrollY / (document.documentElement.scrollHeight - window.innerHeight) * 100;
812
965
  if (scrollPercentage >= threshold) {
@@ -970,14 +1123,17 @@ var POSITION_MAP = {
970
1123
  "top-right": { justifyContent: "flex-end", alignItems: "flex-start", padding: "16px", background: "transparent" },
971
1124
  "top-left": { justifyContent: "flex-start", alignItems: "flex-start", padding: "16px", background: "transparent" }
972
1125
  };
1126
+ function jsonForScript(value) {
1127
+ return JSON.stringify(value ?? null).replace(/</g, "\\u003C").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
1128
+ }
973
1129
  function buildSurveyHtml(opts) {
974
1130
  const env = opts.env === "development" ? "dev" : "prod";
975
1131
  const version = opts.version ?? "2.2.4";
976
1132
  const cdn = `https://cdn.jsdelivr.net/npm/@magicfeedback/native@${version}/dist/magicfeedback-sdk.browser.js`;
977
- const sid = JSON.stringify(opts.surveyId);
978
- const pid = JSON.stringify(opts.productId);
979
- const profileJson = JSON.stringify(opts.profile ?? []);
980
- const metaJson = JSON.stringify(opts.metadata ?? []);
1133
+ const sid = jsonForScript(opts.surveyId);
1134
+ const pid = jsonForScript(opts.productId);
1135
+ const profileJson = jsonForScript(opts.profile ?? []);
1136
+ const metaJson = jsonForScript(opts.metadata ?? []);
981
1137
  const fontFaceCss = opts.font ? buildFontFaceCss(opts.font.family, opts.font.url) : "";
982
1138
  const fontFamilyValue = opts.font ? buildFontFamilyValue(opts.font.family) : "-apple-system,system-ui,sans-serif";
983
1139
  const popupClass = opts.font?.family ? "deepdots-popup deepdots-has-font" : "deepdots-popup";
@@ -985,11 +1141,29 @@ function buildSurveyHtml(opts) {
985
1141
  const popupBg = isDark ? "#1e1e1e" : "#fff";
986
1142
  const colorScheme = isDark ? "dark" : "light";
987
1143
  const textPrimary = isDark ? "#f0f0f0" : "#111";
1144
+ const textMuted = isDark ? "#9ca3af" : "#6b7280";
1145
+ const trackBg = isDark ? "#3f3f46" : "#e5e7eb";
988
1146
  const pos = POSITION_MAP[opts.position ?? "center"] ?? POSITION_MAP.center;
989
- const backLabel = JSON.stringify(opts.actions?.back?.label ?? "Back");
990
- const startLabel = JSON.stringify(opts.actions?.start?.label ?? "Start survey");
991
- const completeLabel = JSON.stringify(opts.actions?.complete?.label ?? "Complete survey");
992
- const submitLabel = JSON.stringify(opts.actions?.accept?.label ?? "Send");
1147
+ const chrome = opts.chrome !== false;
1148
+ const bodyBg = chrome ? pos.background : "transparent";
1149
+ const bodyPadding = chrome ? pos.padding : "0";
1150
+ const bodyDisplay = chrome ? "flex" : "block";
1151
+ const cardBg = chrome ? popupBg : "transparent";
1152
+ const cardShadow = chrome ? "0 4px 6px rgba(0,0,0,0.1)" : "none";
1153
+ const cardRadius = chrome ? "8px" : "0";
1154
+ const cardMaxWidth = chrome ? "600px" : "none";
1155
+ const cardWidth = chrome ? "90%" : "100%";
1156
+ const cardMinHeight = chrome ? "200px" : "0";
1157
+ const cardHeight = chrome ? "auto" : "100%";
1158
+ const cardMaxHeight = chrome ? "90vh" : "100%";
1159
+ const mobileCard = chrome ? `.deepdots-popup{width:calc(100% - 24px);max-width:calc(100% - 24px);border-radius:12px;padding:calc(16px + env(safe-area-inset-top)) 16px calc(16px + env(safe-area-inset-bottom)) 16px}` : `.deepdots-popup{width:100%;max-width:100%;border-radius:0;padding:16px}`;
1160
+ const titleJson = jsonForScript(opts.title ?? "");
1161
+ const customCss = (opts.surveyCss ?? "").replace(/<\/\s*style/gi, "<\\/style");
1162
+ const progressPref = opts.showProgressBar === void 0 ? "null" : String(opts.showProgressBar);
1163
+ const backLabel = jsonForScript(opts.actions?.back?.label ?? "Back");
1164
+ const startLabel = jsonForScript(opts.actions?.start?.label ?? "Start survey");
1165
+ const completeLabel = jsonForScript(opts.actions?.complete?.label ?? "Complete survey");
1166
+ const submitLabel = jsonForScript(opts.actions?.accept?.label ?? "Send");
993
1167
  return `<!DOCTYPE html><html><head>
994
1168
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
995
1169
  <meta name="color-scheme" content="${colorScheme}"/>
@@ -997,57 +1171,98 @@ function buildSurveyHtml(opts) {
997
1171
  ${style_default}
998
1172
  ${fontFaceCss}
999
1173
  html,body{margin:0;padding:0;height:100%;font-family:${fontFamilyValue}}
1000
- body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignItems};background:${pos.background};padding:${pos.padding};box-sizing:border-box}
1001
- .deepdots-popup{position:relative;display:flex;flex-direction:column;justify-content:flex-start;background:${popupBg};color-scheme:${colorScheme};border-radius:8px;padding:24px;box-shadow:0 4px 6px rgba(0,0,0,0.1);max-width:600px;width:90%;min-height:200px;box-sizing:border-box}
1002
- .deepdots-popup-header{display:flex;justify-content:flex-end;align-items:center;width:100%}
1003
- #dd-close{background:transparent;border:none;width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:8px;cursor:pointer;color:${textPrimary};padding:4px}
1004
- .deepdots-popup-container-content{display:flex;flex-direction:column;padding:0 20px 12px 20px;max-height:80vh;overflow:hidden;box-sizing:border-box}
1005
- .deepdots-popup-main{display:flex;flex-direction:column;width:100%;max-height:80vh;overflow-y:auto;overflow-x:hidden;position:relative}
1174
+ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${pos.alignItems};background:${bodyBg};padding:${bodyPadding};box-sizing:border-box}
1175
+ .deepdots-popup{position:relative;display:flex;flex-direction:column;justify-content:flex-start;background:${cardBg};color-scheme:${colorScheme};border-radius:${cardRadius};padding:24px;box-shadow:${cardShadow};max-width:${cardMaxWidth};width:${cardWidth};min-height:${cardMinHeight};height:${cardHeight};max-height:${cardMaxHeight};box-sizing:border-box}
1176
+ .deepdots-popup-header{display:flex;justify-content:space-between;align-items:center;gap:12px;width:100%;flex:0 0 auto}
1177
+ /* Neutraliza la regla \`.deepdots-popup h2\` del CSS del survey (uppercase, centrado y
1178
+ margin-bottom 40px), pensada para los enunciados y no para el t\xEDtulo de la cabecera. */
1179
+ #dd-title{margin:0;font-family:var(--deepdots-font,'Montserrat',inherit);font-size:17px;font-weight:600;line-height:1.3;color:${textPrimary};text-transform:none;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
1180
+ #dd-close{background:transparent;border:none;width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:8px;cursor:pointer;color:${textPrimary};padding:4px;flex:0 0 auto;margin-left:auto}
1181
+ /* Progreso alineado con la cabecera: sin padding horizontal propio, lo marca la tarjeta.
1182
+ El vertical es el mismo arriba y abajo, y del mismo valor que el padding de la tarjeta. */
1183
+ .deepdots-progress{display:none;flex-direction:column;gap:8px;width:100%;flex:0 0 auto;padding:16px 0;box-sizing:border-box}
1184
+ .deepdots-progress-head{display:flex;flex-direction:row;justify-content:space-between;align-items:center;width:100%;gap:8px}
1185
+ #dd-progress-label{font-size:13px;line-height:1.2}
1186
+ /* "Question 1" en negrita y "of 3" en regular gris, como el mockup. */
1187
+ #dd-progress-current{font-weight:700;color:${textPrimary}}
1188
+ #dd-progress-total{font-weight:400;color:${textMuted}}
1189
+ #dd-progress-followup{display:none;font-size:12px;font-weight:600;color:#fff;background:rgba(59,130,246,0.44);border-radius:999px;padding:2px 10px}
1190
+ .deepdots-progress-track{width:100%;height:4px;border-radius:999px;background:${trackBg};overflow:hidden}
1191
+ #dd-progress-bar{height:100%;width:0%;background:#22C55E;border-radius:999px;transition:width 450ms ease}
1192
+ /* El popup es una columna: solo el bloque de preguntas hace scroll, para que el footer
1193
+ con las acciones quede siempre visible en el borde inferior (antes viv\xEDa dentro del
1194
+ \xE1rea scrollable y hab\xEDa que bajar hasta el final para ver "Send"). */
1195
+ /* Sin sangrado extra: el contenido se alinea con el t\xEDtulo y con la barra de progreso (antes
1196
+ sumaba 20px a los lados sobre el padding de la tarjeta y quedaba m\xE1s adentro que la cabecera). */
1197
+ /* Sin barra de progreso, este padding-top es el que separa la cabecera de la pregunta. Con
1198
+ barra, el JS lo pone a 0 y el hueco lo aporta el padding inferior del bloque de progreso,
1199
+ de modo que el espacio por arriba y por abajo de la barra es id\xE9ntico. */
1200
+ .deepdots-popup-container-content{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;padding:16px 0 0 0;overflow:hidden;box-sizing:border-box}
1201
+ /* El enunciado trae margin-top:20px del CSS de surveys, que sumaba al hueco de la barra y
1202
+ descompensaba la simetr\xEDa. Solo se anula en el primero: entre preguntas sigue separando. */
1203
+ .deepdots-popup .magicfeedback-questions .magicfeedback-div:first-child .magicfeedback-label{margin-top:0}
1204
+ .deepdots-popup-main{display:flex;flex-direction:column;width:100%;flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;position:relative}
1006
1205
  #dd-form-wrapper{width:100%;flex:1 1 auto}
1007
1206
  #mf{width:100%;box-sizing:border-box;visibility:hidden}
1008
1207
  .deepdots-popup-main *{max-width:100%;box-sizing:border-box}
1009
1208
  #dd-logo{max-height:40px;max-width:100%;object-fit:contain}
1010
1209
  .deepdots-error-hint{display:none;margin:12px 0 0 0;padding:10px 12px;border-radius:6px;background:#FEF3C7;color:#92400E;border:1px solid #FCD34D;font-size:13px}
1011
- .deepdots-popup-footer{display:flex;flex-direction:row-reverse;justify-content:space-between;align-items:center;gap:8px;margin-top:auto;width:100%;padding-top:16px}
1012
- .dd-nav-btn{display:none;border:none;padding:12px 24px;border-radius:4px;cursor:pointer;font-size:14px;box-shadow:0 2px 4px rgba(0,0,0,0.1);align-items:center;justify-content:center;text-align:center}
1013
- #dd-back{background:transparent;color:#333;border:1px solid #999}
1210
+ /* Pantalla final: el HTML del editor de la plataforma (imagen + texto), centrado. */
1211
+ .deepdots-success{display:none;width:100%;text-align:center;padding:24px 0;color:${textPrimary}}
1212
+ .deepdots-success img{max-width:100%;height:auto;margin:0 auto 16px auto;display:block}
1213
+ .deepdots-success p{margin:0;font-size:16px;font-weight:600;line-height:1.4}
1214
+ .deepdots-popup-footer{display:flex;flex-direction:row-reverse;justify-content:space-between;align-items:center;gap:4px;margin-top:auto;width:100%;padding-top:12px}
1215
+ .dd-nav-btn{display:none;border:none;min-height:44px;padding:12px 24px;border-radius:6px;cursor:pointer;font-size:15px;font-weight:600;align-items:center;justify-content:center;text-align:center}
1216
+ /* Secundario como bot\xF3n de texto: sin borde ni fondo, para que el primario sea la \xFAnica CTA. */
1217
+ #dd-back{background:transparent;color:${textMuted};border:none}
1014
1218
  #dd-start,#dd-complete,#dd-submit{background:#1E293B;color:#fff;border:none}
1015
1219
  #dd-submit:disabled,#dd-start:disabled,#dd-back:disabled,#dd-complete:disabled{opacity:0.6;cursor:not-allowed}
1016
1220
  .mf-spinner{display:none;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}
1017
1221
  .mf-spinner-circle{width:28px;height:28px;border:3px solid #e0e6ed;border-top-color:#1E293B;border-radius:50%;animation:ddspin 0.9s linear infinite}
1018
1222
  @keyframes ddspin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}
1019
1223
  @media (max-width:640px){
1020
- .deepdots-popup{width:calc(100% - 24px);max-width:calc(100% - 24px);border-radius:12px}
1021
- .deepdots-popup-footer{flex-direction:column-reverse;gap:12px}
1224
+ ${mobileCard}
1225
+ /* Apilados: la acci\xF3n principal (Send/Start/Complete) arriba y Back debajo. El orden del
1226
+ DOM ya es ese, as\xED que \`column\` (no \`column-reverse\`) es lo que lo respeta. */
1227
+ .deepdots-popup-footer{flex-direction:column;gap:4px}
1022
1228
  .dd-nav-btn{width:100%}
1023
1229
  .magicfeedback-checkbox-container,.magicfeedback-radio-container{margin:4px 0;padding:4px 8px}
1024
1230
  .magicfeedback-checkbox label,.magicfeedback-radio-container label{font-size:15px}
1025
1231
  .deepdots-popup input[type="radio"]{margin:6px 0 6px 8px}
1026
1232
  .deepdots-popup input[type="checkbox"]{width:16px;height:16px}
1027
1233
  }
1234
+ ${customCss}
1028
1235
  </style>
1029
1236
  </head><body>
1030
1237
  <div class="${popupClass}" id="dd-popup">
1031
1238
  <div class="deepdots-popup-header">
1239
+ <h2 id="dd-title" class="deepdots-popup-title" hidden></h2>
1032
1240
  <button type="button" id="dd-close" aria-label="Close popup">
1033
1241
  <svg width="28" height="28" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1034
1242
  <path d="M6 6L18 18M6 18L18 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
1035
1243
  </svg>
1036
1244
  </button>
1037
1245
  </div>
1038
- <div class="deepdots-popup-container-content">
1246
+ <div class="deepdots-progress" id="dd-progress">
1247
+ <div class="deepdots-progress-head">
1248
+ <span id="dd-progress-label"><span id="dd-progress-current"></span><span id="dd-progress-total"></span></span>
1249
+ <span id="dd-progress-followup">Follow-up</span>
1250
+ </div>
1251
+ <div class="deepdots-progress-track"><div id="dd-progress-bar"></div></div>
1252
+ </div>
1253
+ <div class="deepdots-popup-container-content" id="dd-content">
1039
1254
  <div class="deepdots-popup-main" id="dd-main">
1040
1255
  <div id="dd-form-wrapper">
1041
1256
  <div class="mf-spinner" id="dd-spinner" role="status" aria-label="Loading survey"><div class="mf-spinner-circle"></div></div>
1042
1257
  <div id="mf"></div>
1043
1258
  </div>
1044
1259
  <div class="deepdots-error-hint" id="dd-error" role="alert" aria-live="polite"></div>
1045
- <div class="deepdots-popup-footer" id="dd-footer">
1046
- <button type="button" class="dd-nav-btn" id="dd-submit">Send</button>
1047
- <button type="button" class="dd-nav-btn" id="dd-back">Back</button>
1048
- <button type="button" class="dd-nav-btn" id="dd-complete">Complete survey</button>
1049
- <button type="button" class="dd-nav-btn" id="dd-start">Start survey</button>
1050
- </div>
1260
+ </div>
1261
+ <div class="deepdots-popup-footer" id="dd-footer">
1262
+ <button type="button" class="dd-nav-btn" id="dd-submit">Send</button>
1263
+ <button type="button" class="dd-nav-btn" id="dd-back">Back</button>
1264
+ <button type="button" class="dd-nav-btn" id="dd-complete">Complete survey</button>
1265
+ <button type="button" class="dd-nav-btn" id="dd-start">Start survey</button>
1051
1266
  </div>
1052
1267
  </div>
1053
1268
  </div>
@@ -1056,9 +1271,11 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
1056
1271
  function emit(s){ try{ if(window.ReactNativeWebView){ window.ReactNativeWebView.postMessage(s); } }catch(e){} }
1057
1272
  function emitJSON(n,p){ try{ emit(JSON.stringify({name:n,payload:p||{}})); }catch(e){} }
1058
1273
  window.DeepdotsClose = function(){ emitJSON('popup_close'); };
1274
+ var chromeOn=${chrome ? "true" : "false"};
1059
1275
 
1060
1276
  var popup=document.getElementById('dd-popup');
1061
1277
  var main=document.getElementById('dd-main');
1278
+ var content=document.getElementById('dd-content');
1062
1279
  var footer=document.getElementById('dd-footer');
1063
1280
  var spinner=document.getElementById('dd-spinner');
1064
1281
  var formHost=document.getElementById('mf');
@@ -1067,6 +1284,58 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
1067
1284
  var startBtn=document.getElementById('dd-start');
1068
1285
  var completeBtn=document.getElementById('dd-complete');
1069
1286
  var submitBtn=document.getElementById('dd-submit');
1287
+ var titleEl=document.getElementById('dd-title');
1288
+ var progressEl=document.getElementById('dd-progress');
1289
+ var progressLabel=document.getElementById('dd-progress-label');
1290
+ var progressCurrent=document.getElementById('dd-progress-current');
1291
+ var progressTotal=document.getElementById('dd-progress-total');
1292
+ var progressFollowUp=document.getElementById('dd-progress-followup');
1293
+ var progressBar=document.getElementById('dd-progress-bar');
1294
+
1295
+ function setTitle(t){
1296
+ if(!t) return;
1297
+ titleEl.textContent=t;
1298
+ titleEl.hidden=false;
1299
+ }
1300
+ setTitle(${titleJson});
1301
+
1302
+ // Estado de la barra de progreso. \`progressPref\` null = manda la plataforma (style).
1303
+ var progressPref=${progressPref};
1304
+ var progressEnabled=progressPref===true;
1305
+ var progressShowUnit=true;
1306
+ var progressUnit='fraction';
1307
+ var onStartPage=false;
1308
+
1309
+ function updateProgress(p){
1310
+ var total=p&&typeof p.total==='number'?p.total:0;
1311
+ var progress=p&&typeof p.progress==='number'?p.progress:0;
1312
+ // Solo tiene sentido con m\xE1s de una p\xE1gina, fuera de la pantalla de inicio y sin completar.
1313
+ if(!progressEnabled||onStartPage||p&&p.completed||total<=1){
1314
+ progressEl.style.display='none';
1315
+ // Sin barra, el hueco cabecera\u2192pregunta lo pone el contenido.
1316
+ content.style.paddingTop='16px';
1317
+ return;
1318
+ }
1319
+ progressEl.style.display='flex';
1320
+ // Con barra, el hueco inferior ya lo pone el bloque de progreso: no duplicarlo.
1321
+ content.style.paddingTop='0';
1322
+ // Espejo de LineProgressQuestion (MagicSurvey): la barra usa el valor real (las follow-up
1323
+ // suman +0.5 y avanzan media casilla) y la etiqueta redondea hacia abajo, porque una
1324
+ // follow-up es un paso DENTRO de la misma pregunta, no la siguiente.
1325
+ var current=Math.min(total,Math.max(1,progress+1));
1326
+ var pct=Math.min(100,Math.max(0,(current/total)*100));
1327
+ progressBar.style.width=pct+'%';
1328
+ var label=Math.min(total,Math.max(1,Math.floor(progress)+1));
1329
+ progressLabel.style.display=progressShowUnit?'block':'none';
1330
+ if(progressUnit==='percentage'){
1331
+ progressCurrent.textContent=Math.round(pct)+'%';
1332
+ progressTotal.textContent='';
1333
+ } else {
1334
+ progressCurrent.textContent='Question '+label;
1335
+ progressTotal.textContent=' of '+total;
1336
+ }
1337
+ progressFollowUp.style.display=p&&p.followup?'inline-block':'none';
1338
+ }
1070
1339
 
1071
1340
  backBtn.textContent=${backLabel};
1072
1341
  startBtn.textContent=${startLabel};
@@ -1075,7 +1344,13 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
1075
1344
 
1076
1345
  document.getElementById('dd-close').onclick=function(){ emitJSON('popup_close'); };
1077
1346
  backBtn.onclick=function(){ if(window.DeepdotsForm && window.DeepdotsForm.back){ window.DeepdotsForm.back(); } };
1078
- startBtn.onclick=function(){ if(window.DeepdotsForm && window.DeepdotsForm.startForm){ window.DeepdotsForm.startForm(); } };
1347
+ startBtn.onclick=function(){
1348
+ if(window.DeepdotsForm && window.DeepdotsForm.startForm){
1349
+ window.DeepdotsForm.startForm();
1350
+ onStartPage=false;
1351
+ updateProgress({ progress:window.DeepdotsForm.progress, total:window.DeepdotsForm.total, completed:false, followup:false });
1352
+ }
1353
+ };
1079
1354
  completeBtn.onclick=function(){ emitJSON('popup_close'); };
1080
1355
  var surveyCompletedEmitted=false;
1081
1356
  submitBtn.onclick=function(){
@@ -1083,6 +1358,36 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
1083
1358
  if(window.DeepdotsForm && window.DeepdotsForm.send){ window.DeepdotsForm.send(); }
1084
1359
  };
1085
1360
 
1361
+ // Mensaje final configurado en la plataforma (\`style.successMessage\`). Se guarda al cargar
1362
+ // y se pinta al completar. Va por innerHTML porque es HTML del editor de la plataforma
1363
+ // (imagen + texto), igual que ya hace \`renderStartMessage\` con el mensaje de inicio.
1364
+ var successMessageHtml='';
1365
+ function showSuccessScreen(){
1366
+ progressEl.style.display='none';
1367
+ var wrapper=document.getElementById('dd-form-wrapper');
1368
+ if(wrapper){ wrapper.style.display='none'; }
1369
+ var done=document.getElementById('dd-success');
1370
+ if(!done){
1371
+ done=document.createElement('div');
1372
+ done.id='dd-success';
1373
+ done.className='deepdots-success';
1374
+ main.insertBefore(done, errorHint);
1375
+ }
1376
+ done.innerHTML=successMessageHtml || '<p>Thank you for your feedback!</p>';
1377
+ done.style.display='block';
1378
+ }
1379
+
1380
+ // Profundidad de navegaci\xF3n DENTRO del survey: +1 por p\xE1gina avanzada, -1 al volver.
1381
+ // Sustituye a la condici\xF3n \`total>1 && progress>0 && progress<total\`, que escond\xEDa el
1382
+ // Back siempre que la siguiente pantalla era una follow-up din\xE1mica: las follow-up no
1383
+ // entran en el grafo (suman +0.5 al progress y no tocan el total), as\xED que un survey de
1384
+ // una pregunta con follow-up tiene total=1 y nunca cumpl\xEDa \`total>1\`.
1385
+ var pageDepth=0;
1386
+
1387
+ function updateNavButtons(){
1388
+ updateButtons(pageDepth>0?'in_progress_next':'in_progress_first');
1389
+ }
1390
+
1086
1391
  function updateButtons(state){
1087
1392
  backBtn.style.display='none';
1088
1393
  startBtn.style.display='none';
@@ -1127,11 +1432,21 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
1127
1432
  form.generate('mf', {
1128
1433
  addButton:false,
1129
1434
  getMetaData:true,
1435
+ // La pantalla final la pinta el popup: renderSuccess de @magicfeedback/native usa
1436
+ // textContent, as\xED que el mensaje de la plataforma (HTML con imagen) no se ver\xEDa, y su
1437
+ // fallback es un literal gen\xE9rico que ignora style.successMessage.
1438
+ addSuccessScreen:false,
1130
1439
  onLoadedEvent:function(args){
1131
1440
  var s=args && args.formData ? args.formData.style : null;
1132
1441
  if(s && !stylesInjected){
1133
1442
  stylesInjected=true;
1134
- if(s.boxBackgroundColor){ popup.style.background=s.boxBackgroundColor; }
1443
+ if(s.successMessage){ successMessageHtml=s.successMessage; }
1444
+ // La barra de progreso la decide el host (init) y, si no se pronuncia, la plataforma.
1445
+ if(progressPref===null){ progressEnabled=s.showProgressBar===true; }
1446
+ if(s.showProgressUnit!==undefined){ progressShowUnit=s.showProgressUnit!==false; }
1447
+ if(s.progressUnit){ progressUnit=s.progressUnit; }
1448
+ if(s.loadingBarColor){ progressBar.style.background=s.loadingBarColor; progressFollowUp.style.background=s.loadingBarColor; }
1449
+ if(chromeOn && s.boxBackgroundColor){ popup.style.background=s.boxBackgroundColor; }
1135
1450
  if(s.contentAlign){ main.style.justifyContent = s.contentAlign==='center' ? 'center' : 'flex-start'; }
1136
1451
  if(s.buttonPrimaryColor){
1137
1452
  submitBtn.style.background=s.buttonPrimaryColor; submitBtn.style.border='none'; submitBtn.style.color='#fff';
@@ -1139,7 +1454,8 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
1139
1454
  completeBtn.style.background=s.buttonPrimaryColor; completeBtn.style.border='none'; completeBtn.style.color='#fff';
1140
1455
  }
1141
1456
  if(s.buttonSecondaryColor){
1142
- backBtn.style.background='#fff'; backBtn.style.color=s.buttonSecondaryColor; backBtn.style.border='1px solid '+s.buttonSecondaryColor;
1457
+ // Bot\xF3n de texto: solo ti\xF1e la etiqueta, sin recuperar fondo ni borde.
1458
+ backBtn.style.background='transparent'; backBtn.style.color=s.buttonSecondaryColor; backBtn.style.border='none';
1143
1459
  }
1144
1460
  if(s.logo && !document.getElementById('dd-logo')){
1145
1461
  var logoImg=document.createElement('img');
@@ -1152,11 +1468,13 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
1152
1468
  else if(s.logoPosition==='center'){ logoImg.style.margin='0 auto 20px auto'; logoImg.style.display='block'; }
1153
1469
  main.insertBefore(logoImg, document.getElementById('dd-form-wrapper'));
1154
1470
  }
1155
- if(s.startMessage && s.startMessage!==''){ updateButtons('start'); }
1471
+ if(s.startMessage && s.startMessage!==''){ onStartPage=true; updateButtons('start'); }
1156
1472
  else { updateButtons('in_progress_first'); }
1157
1473
  } else {
1158
1474
  updateButtons('in_progress_first');
1159
1475
  }
1476
+ // El total solo se conoce una vez montado el form; sin \xE9l no hay barra que pintar.
1477
+ updateProgress({ progress:form.progress, total:form.total, completed:false, followup:false });
1160
1478
  emitJSON('loaded');
1161
1479
  setLoading(false);
1162
1480
  },
@@ -1169,9 +1487,10 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
1169
1487
  if(error){
1170
1488
  setLoading(false);
1171
1489
  if(error.toLowerCase().indexOf('no response')!==-1){
1490
+ // La p\xE1gina no ha cambiado: el estado de navegaci\xF3n se queda como estaba.
1172
1491
  errorHint.textContent='Please answer the required question to continue.';
1173
1492
  errorHint.style.display='block';
1174
- updateButtons('in_progress_next');
1493
+ updateNavButtons();
1175
1494
  return;
1176
1495
  }
1177
1496
  errorHint.textContent='An error occurred while submitting. Please try again or close the popup.';
@@ -1182,17 +1501,23 @@ body{display:flex;justify-content:${pos.justifyContent};align-items:${pos.alignI
1182
1501
  setLoading(false);
1183
1502
  if(p && p.completed){
1184
1503
  surveyCompletedEmitted=true;
1504
+ showSuccessScreen();
1185
1505
  updateButtons('completed');
1506
+ updateProgress(p);
1186
1507
  emitJSON('survey_completed', p);
1187
1508
  return;
1188
1509
  }
1189
- if(p && p.total>1 && p.progress>0 && p.progress<p.total){ updateButtons('in_progress_next'); }
1190
- else { updateButtons('in_progress_first'); }
1510
+ pageDepth++;
1511
+ updateNavButtons();
1512
+ updateProgress(p);
1191
1513
  emitJSON('after_submit', p);
1192
1514
  },
1193
1515
  onBackEvent:function(p){
1194
- if(p && p.progress===0){ updateButtons('in_progress_first'); }
1195
- else { updateButtons('in_progress_next'); }
1516
+ // Con error ("No page found") no hubo navegaci\xF3n: la profundidad no se toca.
1517
+ if(!(p&&p.error)){ pageDepth=Math.max(0,pageDepth-1); }
1518
+ updateNavButtons();
1519
+ // onBackEvent no trae \`total\`: se lee del form, que es su due\xF1o.
1520
+ updateProgress({ progress:p&&p.progress, total:form.total, completed:false, followup:p&&p.followup });
1196
1521
  emitJSON('back', p);
1197
1522
  }
1198
1523
  }).catch(function(e){ setLoading(false); emit('error:init'); });
@@ -1221,7 +1546,7 @@ var ReactNativePopupRenderer = class {
1221
1546
  }
1222
1547
  init() {
1223
1548
  }
1224
- show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId) {
1549
+ show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId, renderChrome, options) {
1225
1550
  this.emitFn = emit;
1226
1551
  this.onCloseFn = onClose;
1227
1552
  this.currentSurveyId = surveyId;
@@ -1236,7 +1561,12 @@ var ReactNativePopupRenderer = class {
1236
1561
  font: style?.font,
1237
1562
  theme: style?.theme,
1238
1563
  position: style?.position,
1239
- actions
1564
+ actions,
1565
+ // renderChrome:false (init) → HTML sin tarjeta/overlay: el host lo envuelve en su Modal.
1566
+ chrome: renderChrome,
1567
+ title: options?.title,
1568
+ showProgressBar: options?.showProgressBar,
1569
+ surveyCss: options?.surveyCss
1240
1570
  });
1241
1571
  if (this.options.onShow) {
1242
1572
  this.options.onShow({ surveyId, productId, html });
@@ -1276,7 +1606,6 @@ var ReactNativePopupRenderer = class {
1276
1606
  break;
1277
1607
  case "survey_completed":
1278
1608
  this.emitFn("survey_completed", surveyId);
1279
- this.onCloseFn?.();
1280
1609
  break;
1281
1610
  case "popup_close":
1282
1611
  this.onCloseFn?.();
@@ -1327,14 +1656,14 @@ var BrowserPopupRenderer = class {
1327
1656
  document.body.appendChild(this.container);
1328
1657
  }
1329
1658
  }
1330
- show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId) {
1659
+ show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId, _renderChrome, options) {
1331
1660
  if (this.visible) return;
1332
1661
  if (!this.container || !document.body.contains(this.container)) this.init();
1333
1662
  if (!this.container) return;
1334
1663
  this.visible = true;
1335
1664
  const container = this.container;
1336
1665
  void Promise.resolve().then(() => (init_renderPopup(), renderPopup_exports)).then(({ renderPopup: renderPopup2 }) => {
1337
- renderPopup2(container, surveyId, productId, actions, emit, onClose, env, userId, style, sessionId, miniService, analyticsFeedbackSessionId);
1666
+ renderPopup2(container, surveyId, productId, actions, emit, onClose, env, userId, style, sessionId, miniService, analyticsFeedbackSessionId, options);
1338
1667
  });
1339
1668
  }
1340
1669
  hide() {
@@ -2188,6 +2517,12 @@ var DeepdotsPopups = class {
2188
2517
  this.deferredExitTimers = [];
2189
2518
  this.baseUrl = "";
2190
2519
  this.env = "production";
2520
+ /** Si el SDK pinta el "modal" del popup (RN). Default true; false = el host lo envuelve. */
2521
+ this.renderChrome = true;
2522
+ /** Barra de progreso. undefined = la decide la plataforma (style.showProgressBar). */
2523
+ this.showProgressBar = void 0;
2524
+ /** CSS del host inyectado al final de los estilos del popup. */
2525
+ this.surveyCss = void 0;
2191
2526
  /** Identidad + sesión (Fase 1 tracking). Null hasta init(). */
2192
2527
  this.tracking = null;
2193
2528
  /** Capa de analytics (canal separado del feedback). Null hasta init(). */
@@ -2238,6 +2573,9 @@ var DeepdotsPopups = class {
2238
2573
  const env = resolveEnvironment(config.nodeEnv);
2239
2574
  this.baseUrl = env.apiBaseUrl;
2240
2575
  this.env = config.nodeEnv || "production";
2576
+ this.renderChrome = config.renderChrome ?? true;
2577
+ this.showProgressBar = config.showProgressBar;
2578
+ this.surveyCss = config.surveyCss;
2241
2579
  this.config = {
2242
2580
  apiKey: config.apiKey || void 0,
2243
2581
  debug: config.debug || false,
@@ -2423,6 +2761,22 @@ var DeepdotsPopups = class {
2423
2761
  trackFunnelStep(funnel, step, taskId, params) {
2424
2762
  this.track("deepdots_funnel_step", { funnel, step, task_id: taskId, ...params ?? {} });
2425
2763
  }
2764
+ /**
2765
+ * Product Effectiveness: una interacción significativa del usuario (`interaction_type` es la
2766
+ * dimensión de agrupación, p. ej. `get_help`, `homepage`, `contact_support`).
2767
+ *
2768
+ * Existe como evento RESERVADO para que la convención no la invente cada host: un `track()`
2769
+ * custom acaba como `deepdots_event_…` y no lo cuenta la analítica de effectiveness.
2770
+ * Un `interactionType` vacío se descarta con warning (no aporta dato agrupable).
2771
+ */
2772
+ trackMeaningfulInteraction(interactionType, params) {
2773
+ const type = typeof interactionType === "string" ? interactionType.trim() : "";
2774
+ if (!type) {
2775
+ console.warn("[DeepdotsPopups] trackMeaningfulInteraction discarded: empty interaction_type");
2776
+ return;
2777
+ }
2778
+ this.track("deepdots_meaningful_interaction", { interaction_type: type, ...params ?? {} });
2779
+ }
2426
2780
  /**
2427
2781
  * Messaging (#18–22): registra una etapa del funnel de una notificación (push/in-app).
2428
2782
  * No-op si tracking off. El evento se descarta (con warning) si el `channel` no es válido,
@@ -2667,7 +3021,7 @@ var DeepdotsPopups = class {
2667
3021
  this.log("Showing popup (definition)", def);
2668
3022
  this.surveyToPopupId.set(def.surveyId, def.id);
2669
3023
  this.lastShown.set(def.id, Date.now());
2670
- this.renderPopup(def.surveyId, def.productId, def.actions, def.style);
3024
+ this.renderPopup(def.surveyId, def.productId, def.actions, def.style, def.title);
2671
3025
  this.emitEvent("popup_shown", def.surveyId, { popupId: def.id });
2672
3026
  }
2673
3027
  shouldShow(def, pathUrl, skipPathCheck = false) {
@@ -3005,7 +3359,7 @@ var DeepdotsPopups = class {
3005
3359
  document.body.appendChild(this.popupContainer);
3006
3360
  }
3007
3361
  /** Render the popup UI */
3008
- renderPopup(surveyId, productId, actions, style) {
3362
+ renderPopup(surveyId, productId, actions, style, title) {
3009
3363
  const userId = this.tracking?.getUserId() ?? this.config?.userId;
3010
3364
  const sessionId = this.tracking?.getSessionId() ?? void 0;
3011
3365
  const miniService = this.analytics?.getMiniService() ?? void 0;
@@ -3023,7 +3377,9 @@ var DeepdotsPopups = class {
3023
3377
  style,
3024
3378
  sessionId,
3025
3379
  miniService,
3026
- analyticsFeedbackSessionId
3380
+ analyticsFeedbackSessionId,
3381
+ this.renderChrome,
3382
+ { title, showProgressBar: this.showProgressBar, surveyCss: this.surveyCss }
3027
3383
  );
3028
3384
  return;
3029
3385
  }
@@ -3042,7 +3398,8 @@ var DeepdotsPopups = class {
3042
3398
  style,
3043
3399
  sessionId,
3044
3400
  miniService,
3045
- analyticsFeedbackSessionId
3401
+ analyticsFeedbackSessionId,
3402
+ { title, showProgressBar: this.showProgressBar, surveyCss: this.surveyCss }
3046
3403
  );
3047
3404
  });
3048
3405
  }