From a39fdb4ada25f9cc97dda63ed8e6da3660eaf3b5 Mon Sep 17 00:00:00 2001
From: Steven Jones <steven.jones@computerminds.co.uk>
Date: Tue, 11 Mar 2025 16:47:20 +0000
Subject: [PATCH 1/2] Issue #3197504 by jrockowitz, steven jones: Initial stab
 at getting something working.

---
 src/WebformSubmissionConditionsValidator.php | 126 +++++++++++++++++++
 1 file changed, 126 insertions(+)

diff --git a/src/WebformSubmissionConditionsValidator.php b/src/WebformSubmissionConditionsValidator.php
index 0ef12abc2..2ded745f8 100644
--- a/src/WebformSubmissionConditionsValidator.php
+++ b/src/WebformSubmissionConditionsValidator.php
@@ -209,6 +209,132 @@ class WebformSubmissionConditionsValidator implements WebformSubmissionCondition
         unset($element['#states']);
       }
     }
+
+    // Loop through visible elements with composite elements with #states.
+    foreach ($visible_elements as &$element) {
+      if (empty($element['#webform_composite'])) {
+        continue;
+      }
+      foreach (array_keys($element['#webform_composite_elements']) as $composite_element_key) {
+        if (isset($element['#' . $composite_element_key . '__states'])) {
+          $states = &$element['#' . $composite_element_key . '__states'];
+        }
+        else {
+          $states = [];
+        }
+        // Store original #states in #_webform_states.
+        $element['#' . $composite_element_key . '__webform_states'] = $states;
+        foreach ($states as $original_state => $conditions) {
+          if (!is_array($conditions)) {
+            continue;
+          }
+
+          // Process state/negate.
+          [$state, $negate] = $this->processState($original_state);
+
+          // If hide/show we need to make sure that validation is not triggered.
+          if (strpos($state, 'visible') === 0) {
+            // @TODO: Is this the correct way to get an after build here?
+            $element[$composite_element_key]['#after_build'][] = [
+              get_class($this),
+              'elementAfterBuild'
+            ];
+          }
+
+          $targets = $this->getConditionTargetsVisibility($conditions, $visible_elements);
+
+          // Determine if targets are visible or cross page.
+          $all_targets_visible = (array_sum($targets) === count($targets));
+          $has_cross_page_targets = (!$all_targets_visible && array_sum($targets));
+
+          // Skip if evaluating conditions when all targets are visible.
+          if ($all_targets_visible) {
+            // Add .js-webform-states-hidden to element's that are not visible when
+            // the form is rendered.
+            if (strpos($state, 'visible') === 0
+              && !$this->validateConditions($conditions, $webform_submission)) {
+              // @TODO: I don't know if/how we can do this.
+              // $this->addStatesHiddenToElement($element);
+            }
+            continue;
+          }
+
+          // Replace hidden cross page targets with hidden inputs.
+          if ($has_cross_page_targets) {
+            $cross_page_targets = array_filter(
+              $targets,
+              function($visible) {
+                return $visible === FALSE;
+              }
+            );
+            $states[$original_state] = $this->replaceCrossPageTargets($conditions, $webform_submission, $cross_page_targets, $form);
+            continue;
+          }
+
+          $result = $this->validateConditions($conditions, $webform_submission);
+
+          // Skip invalid conditions.
+          if ($result === NULL) {
+            continue;
+          }
+
+          // Negate the result.
+          $result = ($negate) ? !$result : $result;
+
+          // Apply result to element state.
+          switch ($state) {
+            case 'required':
+              $element['#' . $composite_element_key . '__required'] = $result;
+              break;
+
+            case 'readonly':
+
+              // Set custom readonly attribute and class.
+              // We can't use the custom #readonly property because it is
+              // processed before cross page targets.
+              // @see \Drupal\webform\Plugin\WebformElementBase::prepare
+              if ($result) {
+                $element['#' . $composite_element_key . '__attributes']['readonly'] = 'readonly';
+                $element['#' . $composite_element_key . '__wrapper_attributes']['class'][] = 'webform-readonly';
+              }
+              break;
+
+            case 'disabled':
+              $element['#' . $composite_element_key . '__disabled'] = $result;
+              break;
+
+            case 'visible':
+            case 'visible-slide':
+              if (!$result) {
+                // Visual hide the element.
+                // @TODO: I don't know if/how we can do this.
+                // $this->addStatesHiddenToElement($element);
+                // Clear the default value.
+                if (!isset($element['#' . $composite_element_key . '__states_clear']) || $element['#' . $composite_element_key . '__states_clear'] === TRUE) {
+                  unset($element['#' . $composite_element_key . '__default_value']);
+                }
+              }
+              break;
+
+            case 'collapsed':
+              $element['#' . $composite_element_key . '__open'] = !$result;
+              break;
+
+            case 'checked':
+              $element['#' . $composite_element_key . '__default_value'] = $result;
+              break;
+          }
+
+          // Remove #states state/conditions.
+          unset($states[$original_state]);
+        }
+
+        // Remove #states if all states have been applied.
+        if (empty($states)) {
+          unset($element['#' . $composite_element_key . '__states']);
+        }
+      }
+    }
   }
 
   /**
-- 
GitLab


From 2e68b5d55379b909d4e1291449f281f1db912b03 Mon Sep 17 00:00:00 2001
From: Steven Jones <steven.jones@computerminds.co.uk>
Date: Wed, 12 Mar 2025 16:12:01 +0000
Subject: [PATCH 2/2] Issue #3197504 by steven jones: [#States API] Address an
 issue with the new code.

---
 src/WebformSubmissionConditionsValidator.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/WebformSubmissionConditionsValidator.php b/src/WebformSubmissionConditionsValidator.php
index 2ded745f8..a35dad3c7 100644
--- a/src/WebformSubmissionConditionsValidator.php
+++ b/src/WebformSubmissionConditionsValidator.php
@@ -212,7 +212,7 @@ class WebformSubmissionConditionsValidator implements WebformSubmissionCondition
 
     // Loop through visible elements with composite elements with #states.
     foreach ($visible_elements as &$element) {
-      if (empty($element['#webform_composite'])) {
+      if (empty($element['#webform_composite']) || empty($element['#webform_composite_elements'])) {
         continue;
       }
       foreach (array_keys($element['#webform_composite_elements']) as $composite_element_key) {
-- 
GitLab