From c018e681d80cd21daf4da9fc277ead42a2481dbd Mon Sep 17 00:00:00 2001
From: Ana Pettirossi <6838-carolpettirossi@users.noreply.drupalcode.org>
Date: Fri, 27 Oct 2023 18:50:24 +0000
Subject: [PATCH] WIP updates

---
 README.md                                     |  73 ++++++
 README.txt                                    |   1 -
 calculation_fields.info.yml                   |   3 +-
 calculation_fields.libraries.yml              |   5 +-
 calculation_fields.module                     |  19 ++
 calculation_fields.routing.yml                |   7 -
 composer.json                                 |  13 +
 css/calculation-fields.css                    |  10 +
 js/calculation-fields.js                      | 107 +++++---
 .../calculation_fields_example.info.yml       |   7 +
 .../calculation_fields_example.module         |  20 ++
 .../calculation_fields_example.routing.yml    |   7 +
 .../src}/Form/ExampleForm.php                 |  34 +--
 modules/webform_calculation_fields/README.md  |  52 ++++
 ...bform.webform_calculation_fields_examp.yml | 230 ++++++++++++++++++
 ...bform_calculation_fields_examples.info.yml |   9 +
 ...ebform_calculation_fields_examples.install |  30 +++
 ...ebformCalculationFieldsElementUiAccess.php |  32 +++
 .../src/Form/WebformCalculationFieldsForm.php |  14 ++
 .../WebformCalculationFieldsFormDelete.php    |  14 ++
 .../WebformElement/WebformFieldCalculator.php |  25 +-
 .../WebformMathMarkupElement.php              |  68 ++++++
 .../WebformCalculationFieldsRouting.php       |  40 +++
 .../webform_calculation_fields.info.yml       |   2 +-
 .../webform_calculation_fields.services.yml   |   5 +
 src/Element/FormMathElement.php               |  81 +++++-
 src/Element/FormMathMarkupElement.php         | 102 ++++++++
 templates/form-math-markup-element.html.twig  |  16 ++
 28 files changed, 953 insertions(+), 73 deletions(-)
 create mode 100644 README.md
 delete mode 100644 README.txt
 delete mode 100644 calculation_fields.routing.yml
 create mode 100644 composer.json
 create mode 100644 css/calculation-fields.css
 create mode 100644 modules/calculation_fields_example/calculation_fields_example.info.yml
 create mode 100644 modules/calculation_fields_example/calculation_fields_example.module
 create mode 100644 modules/calculation_fields_example/calculation_fields_example.routing.yml
 rename {src => modules/calculation_fields_example/src}/Form/ExampleForm.php (62%)
 create mode 100644 modules/webform_calculation_fields/README.md
 create mode 100644 modules/webform_calculation_fields/modules/webform_calculation_fields_examples/config/install/webform.webform.webform_calculation_fields_examp.yml
 create mode 100644 modules/webform_calculation_fields/modules/webform_calculation_fields_examples/webform_calculation_fields_examples.info.yml
 create mode 100644 modules/webform_calculation_fields/modules/webform_calculation_fields_examples/webform_calculation_fields_examples.install
 create mode 100644 modules/webform_calculation_fields/src/Form/WebformCalculationFieldsElementUiAccess.php
 create mode 100644 modules/webform_calculation_fields/src/Form/WebformCalculationFieldsForm.php
 create mode 100644 modules/webform_calculation_fields/src/Form/WebformCalculationFieldsFormDelete.php
 create mode 100644 modules/webform_calculation_fields/src/Plugin/WebformElement/WebformMathMarkupElement.php
 create mode 100644 modules/webform_calculation_fields/src/Routing/WebformCalculationFieldsRouting.php
 create mode 100644 modules/webform_calculation_fields/webform_calculation_fields.services.yml
 create mode 100644 src/Element/FormMathMarkupElement.php
 create mode 100644 templates/form-math-markup-element.html.twig

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9c1e661
--- /dev/null
+++ b/README.md
@@ -0,0 +1,73 @@
+# Calculation Fields
+
+## What the Module Does
+The "form_element_math" module is designed to enhance Drupal forms by introducing a new form element type called "form_element_math." This custom form element allows you to create dynamic and mathematically calculated fields within your forms. It's particularly useful when you need to perform mathematical operations based on the values of other form fields and update the result in real-time.
+
+## How to Use the New Element
+
+### 1. Adding the "form_element_math" to a Form
+To use the "form_element_math" in your Drupal form, you need to define it in the form array. Here's a basic example of how to do this:
+
+```php
+$form['result'] = [
+  '#type' => 'form_element_math',
+  '#title' => $this->t('Result'),
+  '#required' => TRUE,
+  '#evaluation_fields' => '(:first_value + :second_value + :third_value) * :multiple',
+  '#evaluation_round' => 2,
+];
+```
+
+In this example, we create a field named 'result' of type 'form_element_math.' It has the following attributes:
+- `#title`: The title of the field.
+- `#required`: Whether this field is mandatory.
+- `#evaluation_fields`: The expression to be evaluated. In this case, it calculates the result by adding `:first_value`, `:second_value`, and `:third_value`, and then multiplying the result by `:multiple`. You can use field names with `:` to reference the values of other form fields. When any of these fields change, the expression is re-evaluated and updates the 'result' field.
+- `#evaluation_round`: The number of decimal places to round the result to.
+
+### 2. Examples of Usage
+
+**Example 1: Calculate Total Price**
+Suppose you have a form for ordering items, and you want to calculate the total price based on the quantity and unit price. You can use the "form_element_math" as follows:
+
+```php
+$form['quantity'] = [
+  '#type' => 'textfield',
+  '#title' => $this->t('Quantity'),
+];
+$form['unit_price'] = [
+  '#type' => 'textfield',
+  '#title' => $this->t('Unit Price'),
+];
+$form['total_price'] = [
+  '#type' => 'form_element_math',
+  '#title' => $this->t('Total Price'),
+  '#evaluation_fields' => ':quantity * :unit_price',
+  '#evaluation_round' => 2,
+];
+```
+
+Now, when users enter the quantity and unit price, the total price is automatically calculated and displayed.
+
+**Example 2: Calculate BMI (Body Mass Index)**
+Imagine you have a health assessment form, and you want to calculate the Body Mass Index (BMI) based on a person's weight and height. You can achieve this with the "form_element_math" element:
+
+```php
+$form['weight'] = [
+  '#type' => 'textfield',
+  '#title' => $this->t('Weight (kg)'),
+];
+$form['height'] = [
+  '#type' => 'textfield',
+  '#title' => $this->t('Height (m)'),
+];
+$form['bmi'] = [
+  '#type' => 'form_element_math',
+  '#title' => $this->t('BMI'),
+  '#evaluation_fields' => ':weight / (:height * :height)',
+  '#evaluation_round' => 2,
+];
+```
+
+Now, as users input their weight and height, the BMI is calculated and displayed, providing immediate health feedback.
+
+With the "form_element_math" module, you can easily incorporate dynamic calculations into your forms, making them more interactive and informative for users.
diff --git a/README.txt b/README.txt
deleted file mode 100644
index c3d57b0..0000000
--- a/README.txt
+++ /dev/null
@@ -1 +0,0 @@
-Calculation Fields
diff --git a/calculation_fields.info.yml b/calculation_fields.info.yml
index 03b2b08..1c1f6c8 100644
--- a/calculation_fields.info.yml
+++ b/calculation_fields.info.yml
@@ -1,5 +1,6 @@
 name: Calculation Fields
 type: module
-description: Provides additional functionality for the site.
+description: Provides additional form element that can evaluation math expressions.
 package: Fields
 core_version_requirement: ^9 || ^10
+project: 'drupal/calculation_fields'
diff --git a/calculation_fields.libraries.yml b/calculation_fields.libraries.yml
index 447c36a..ed53944 100644
--- a/calculation_fields.libraries.yml
+++ b/calculation_fields.libraries.yml
@@ -1,12 +1,13 @@
-# Custom module library for general purposes.
 calculation_fields:
   js:
     js/calculation-fields.js: {}
+  css:
+    component:
+      css/calculation-fields.css: { }
   dependencies:
     - core/drupal
     - calculation_fields/mathjs
 
-# Third-party library (CDN).
 mathjs:
   remote: https://mathjs.org/
   version: 11.11.1
diff --git a/calculation_fields.module b/calculation_fields.module
index b3d9bbc..79cb510 100644
--- a/calculation_fields.module
+++ b/calculation_fields.module
@@ -1 +1,20 @@
 <?php
+
+/**
+ * Implements hook_theme().
+ */
+function calculation_fields_theme($existing, $type, $theme, $path) {
+  return [
+    'form_math_markup_element' => [
+      'variables' => [
+        'round' => NULL,
+        'formContext' => NULL,
+        'fields' => [],
+        'expression' => '',
+        'previewText' => NULL,
+        'textExpression' => NULL,
+        'name' => [],
+      ],
+    ],
+  ];
+}
diff --git a/calculation_fields.routing.yml b/calculation_fields.routing.yml
deleted file mode 100644
index 193ff55..0000000
--- a/calculation_fields.routing.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-calculation_fields.example:
-  path: '/calculation-fields/example'
-  defaults:
-    _title: 'Example'
-    _form: 'Drupal\calculation_fields\Form\ExampleForm'
-  requirements:
-    _permission: 'access content'
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..561275a
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,13 @@
+{
+    "name": "drupal/calculation_fields",
+    "description": "Extends Drupal form element API adding new form element type to evaluation math expression using math.js and symfony/expression-language",
+    "type": "drupal-module",
+    "autoload": {
+        "psr-4": {
+            "Drupal\\calculation_fields\\": "src/"
+        }
+    },
+    "require": {
+        "symfony/expression-language": "^6.3"
+    }
+}
diff --git a/css/calculation-fields.css b/css/calculation-fields.css
new file mode 100644
index 0000000..fe3d5d4
--- /dev/null
+++ b/css/calculation-fields.css
@@ -0,0 +1,10 @@
+.form-math-markup-element .js-math-result,
+.form-math-markup-element-calculated .js-math-preview,
+.js-math-result-base {
+  display: none;
+}
+
+.form-math-markup-element .js-math-preview,
+.form-math-markup-element-calculated .js-math-result {
+  display: block;
+}
diff --git a/js/calculation-fields.js b/js/calculation-fields.js
index f6db96f..7e04ec3 100644
--- a/js/calculation-fields.js
+++ b/js/calculation-fields.js
@@ -1,36 +1,84 @@
+/**
+ * @file
+ * Behaviors for the form math custom element.
+ */
+
 ((Drupal, math) => {
   Drupal.behaviors.formMathElementCalculator = {
     attach: () => {
+      const previousValue = {};
+
+      const updateResult = (el, value) =>{
+        if (el.tagName === 'INPUT') {
+          el.value = value;
+          el.dispatchEvent(new Event('change'));
+          return;
+        }
+        const markupEl = el.querySelector('.form-math-markup-element');
+        if (markupEl === null) {
+          return;
+        }
+        const expressionEvaluated = markupEl
+          .querySelector('.js-math-result-base')
+          .innerHTML.replace('[RESULT]', value);
+
+        markupEl.querySelector('.js-math-result-input').value = expressionEvaluated;
+        markupEl.querySelector('.js-math-result').innerHTML = expressionEvaluated;
+        if (value !== "") {
+          markupEl.classList.add('form-math-markup-element-calculated');
+        }
+        else {
+          markupEl.classList.remove('form-math-markup-element-calculated');
+        }
+      }
 
-      function calc(fieldElement) {
-        // fieldElement.classList.add('built');
-        const fieldNames = fieldElement.dataset.evaluateFields.split(' ');
+      const calc = (fieldElement) => {
+        const fields = fieldElement.dataset.evaluateFields.split(' ');
         const expression = fieldElement.dataset.evaluateExpression;
         const formContext = fieldElement.dataset.evaluateContext;
-        const deepFields = JSON.parse(fieldElement.dataset.evaluateDeepFields) || {};
-
-        function handleFieldChange (e) {
-          const convertedExpression = fieldNames.reduce((exp, field) => {
-            const currentElement = document.querySelector(`input[name="${field}"], select[name="${field}"]`);
-            let currentFieldValue;
-            if (currentElement === null && deepFields[field] !== undefined) {
-              currentFieldValue = deepFields[field];
-            }
-            else {
-              currentFieldValue = currentElement.value;
-            }
-            if (currentFieldValue !== '') {
-              return exp.replaceAll(`:${field}`, currentFieldValue);
-            }
-            return exp;
-          }, expression);
+        const deepFields = JSON.parse(fieldElement.dataset.evaluateDeepFields || "{}");
+        const fieldEvaluateRound = fieldElement.dataset.evaluateRound || null;
+
+        const buildExpression = (exp, field) => {
+          const currentElement = document.querySelector(`input[name="${field}"], select[name="${field}"]`);
+          let currentFieldValue;
+          if (currentElement === null && deepFields[field] !== undefined) {
+            currentFieldValue = deepFields[field];
+          }
+          else {
+            currentFieldValue = currentElement.value;
+          }
+          if (currentFieldValue !== '') {
+            return exp.replaceAll(`:${field}`, currentFieldValue);
+          }
+          return exp;
+        }
+
+        const handleFieldChange = (e) => {
+          // If the value was clear. Rollback the element to the initial state.
+          if (e.target.value === "" && previousValue[e.target.name] !== undefined && previousValue[e.target.name] !== "") {
+            updateResult(fieldElement, "");
+            return;
+          }
+
+          const convertedExpression = fields.reduce(buildExpression, expression);
           if (convertedExpression.split(':').length === 1) {
-            fieldElement.value = math.evaluate(convertedExpression);
-            fieldElement.dispatchEvent(new Event('change'));
+            let expressionResult = math.evaluate(convertedExpression);
+            if (fieldEvaluateRound !== null) {
+              expressionResult = parseFloat(expressionResult).toFixed(fieldEvaluateRound)
+            }
+            updateResult(fieldElement, expressionResult);
           }
+          previousValue[e.target.name] = e.target.value;
+        }
+
+        let selectorFormContext = '';
+        if (formContext !== '') {
+          selectorFormContext = `form#${formContext} `;
         }
-        fieldNames.forEach(name => {
-          const element = document.querySelector(`form#${formContext} input[name="${name}"], select[name="${name}"]`);
+        fields.forEach(name => {
+          const elementSelector = `${selectorFormContext}input[name="${name}"], select[name="${name}"]`;
+          const element = document.querySelector(elementSelector);
           if (element) {
             element.removeEventListener('change', handleFieldChange);
             element.addEventListener('change', handleFieldChange);
@@ -38,9 +86,12 @@
         });
       }
 
-      document
-        .querySelectorAll('.js-calc-field:not(.built)')
-        .forEach(el => {
+      const formMathElements = document
+        .querySelectorAll('.js-form-math-element:not(.built)');
+      if (formMathElements.length === 0) {
+        return;
+      }
+      formMathElements.forEach(el => {
           if (
             el.dataset.evaluateFields !== undefined &&
             el.dataset.evaluateExpression !== undefined
@@ -52,7 +103,7 @@
               console.error(`Failed to calculate ${e}`);
             }
           }
-        })
+        });
     },
   }
 })(Drupal, math);
diff --git a/modules/calculation_fields_example/calculation_fields_example.info.yml b/modules/calculation_fields_example/calculation_fields_example.info.yml
new file mode 100644
index 0000000..307f658
--- /dev/null
+++ b/modules/calculation_fields_example/calculation_fields_example.info.yml
@@ -0,0 +1,7 @@
+name: Calculation Fields Example
+type: module
+description: Provides examples how to use calculation fields in an normal form or webform.
+package: Fields
+core_version_requirement: ^9 || ^10
+dependencies:
+  - calculation_fields:calculation_fields
diff --git a/modules/calculation_fields_example/calculation_fields_example.module b/modules/calculation_fields_example/calculation_fields_example.module
new file mode 100644
index 0000000..756acc2
--- /dev/null
+++ b/modules/calculation_fields_example/calculation_fields_example.module
@@ -0,0 +1,20 @@
+<?php
+
+/**
+ * @file
+ * Contains custom feature for the module.
+ */
+
+use Drupal\Core\Url;
+
+/**
+ * Implements hook_help().
+ */
+function calculation_fields_example_help($route_name, \Drupal\Core\Routing\RouteMatchInterface $route_match) {
+  switch ($route_name) {
+    case 'help.page.calculation_fields_example':
+      return '<p>' . t('Take a look on the following <a href=":form">form</a> and webforms <a href="/form/webform-calculation-fields-examp">Webform Calculation fields example</a>, <a href="/form/webform-calculation-fields-multi">Webform Calculation fields multistep example</a>.', [
+        ':form' => Url::fromRoute('calculation_fields_example.form_api')->toString()
+      ]) . '</p>';
+  }
+}
diff --git a/modules/calculation_fields_example/calculation_fields_example.routing.yml b/modules/calculation_fields_example/calculation_fields_example.routing.yml
new file mode 100644
index 0000000..b569d1e
--- /dev/null
+++ b/modules/calculation_fields_example/calculation_fields_example.routing.yml
@@ -0,0 +1,7 @@
+calculation_fields_example.form_api:
+  path: '/calculation-fields-example/form'
+  defaults:
+    _title: 'Example'
+    _form: 'Drupal\calculation_fields_example\Form\ExampleForm'
+  requirements:
+    _permission: 'access content'
diff --git a/src/Form/ExampleForm.php b/modules/calculation_fields_example/src/Form/ExampleForm.php
similarity index 62%
rename from src/Form/ExampleForm.php
rename to modules/calculation_fields_example/src/Form/ExampleForm.php
index 0a53c32..d9fcb79 100644
--- a/src/Form/ExampleForm.php
+++ b/modules/calculation_fields_example/src/Form/ExampleForm.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\calculation_fields\Form;
+namespace Drupal\calculation_fields_example\Form;
 
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
@@ -30,7 +30,7 @@ class ExampleForm extends FormBase {
 
     $form['second_value'] = [
       '#type' => 'number',
-      '#title' => $this->t('SEcond value'),
+      '#title' => $this->t('Second value'),
       '#required' => TRUE,
       '#min' => 0,
       '#max' => 2000,
@@ -61,7 +61,21 @@ class ExampleForm extends FormBase {
       '#type' => 'form_element_math',
       '#title' => $this->t('Result'),
       '#required' => TRUE,
-      '#evaluation_fields' => '(:first_value + :second_value + :third_value) * :multiple'
+      '#evaluation_fields' => '(:first_value + :second_value + :third_value) * :multiple',
+      '#evaluation_round' => 2,
+    ];
+
+    $form['result_markup'] = [
+      '#type' => 'form_element_markup_math',
+      '#evaluation_fields' => '<h3>This is my test result divided by 2: R$ <span>{{ ((:first_value + :second_value + :third_value) * :multiple) / 2 }}</span></h3>',
+      '#evaluation_text_preview' => $this->t('With preview markup'),
+      '#evaluation_round' => 2,
+    ];
+
+    $form['result_markup_1'] = [
+      '#type' => 'form_element_markup_math',
+      '#evaluation_fields' => '<h3>This is my test result: R$ <span>{{ (:first_value + :second_value + :third_value) * :multiple }}</span></h3>',
+      '#evaluation_round' => 2,
     ];
 
     $form['actions'] = [
@@ -75,21 +89,13 @@ class ExampleForm extends FormBase {
     return $form;
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function validateForm(array &$form, FormStateInterface $form_state) {
-    if (mb_strlen($form_state->getValue('message')) < 10) {
-      $form_state->setErrorByName('message', $this->t('Message should be at least 10 characters.'));
-    }
-  }
-
   /**
    * {@inheritdoc}
    */
   public function submitForm(array &$form, FormStateInterface $form_state) {
-    $this->messenger()->addStatus($this->t('The message has been sent.'));
-    $form_state->setRedirect('<front>');
+    foreach (['result', 'result_markup', 'result_markup_1'] as $key) {
+      $this->messenger()->addStatus($this->t('The result submitted was: ' . $form_state->getValue($key)));
+    }
   }
 
 }
diff --git a/modules/webform_calculation_fields/README.md b/modules/webform_calculation_fields/README.md
new file mode 100644
index 0000000..1bed30b
--- /dev/null
+++ b/modules/webform_calculation_fields/README.md
@@ -0,0 +1,52 @@
+# Webform Calculation Fields
+
+## What the Module Does
+The "Webform Calculation Fields" module is an extension for Drupal's Webform module, designed to enhance the capabilities of webforms by introducing a custom field type called "Field calculator." This field allows you to perform dynamic calculations within your webforms, similar to the "form_element_math" module, while benefiting from Webform's flexibility and user-friendly interface.
+
+## How to Use the Custom Calculation Field in Webforms
+
+### 1. Installing and Enabling the Module
+Before using the custom "Field calculator" field, make sure you've installed and enabled the "Webform Calculation Fields" module. You can do this via the Drupal admin interface.
+
+### 2. Creating a Webform
+Create a new webform or edit an existing one, depending on your requirements.
+
+### 3. Adding a Calculation Field
+To add a Calculation field to your webform, follow these steps:
+
+1. In your webform, navigate to the "Add Element" section.
+2. Look for the "Field calculator" element type, which is provided by the "Webform Calculation Fields" module.
+3. Click on the "Field calculator" element to add it to your webform.
+
+### 4. Configuring the Calculation Field
+Once you've added the Calculation field to your webform, you'll need to configure it. Here are the essential settings:
+
+- **Title**: Give the field a descriptive title.
+- **Calculation Formula**: In this field, you can specify the mathematical expression you want to use for the calculation. You can use the same format as in the "form_element_math" module, with field names enclosed in colons, such as `:field1 + :field2`. You can reference any other fields in the webform using colons.
+- **Decimal Places**: Choose the number of decimal places to round the result to.
+
+### 5. Permissions
+The "Webform Calculation Fields" module provides permissions to control who can create, edit, and delete elements of the "Calculation" type. Make sure to configure these permissions according to your site's needs.
+
+### 6. Saving and Using the Webform
+After configuring the Calculation field, save your webform, and then it's ready to use. When users fill out the webform, the Calculation field will automatically evaluate the specified formula and display the result.
+
+## Example 1: Simple Calculator
+Suppose you're creating a simple webform where users can input two numbers, and you want to display the sum of those numbers. Here's how you can configure the Calculation field:
+
+- Title: "Result"
+- Calculation Formula: `:number1 + :number2`
+- Decimal Places: 2
+
+In this example, ":number1" and ":number2" should be replaced with the actual field names you've defined in your webform. When users fill in these fields, the "Result" field will automatically calculate and display the sum.
+
+## Example 2: Loan Repayment Calculator
+Imagine you're creating a webform for a loan application, and you want to display the monthly loan repayment amount based on the loan amount, interest rate, and loan term. Here's how you can configure the Calculation field:
+
+- Title: "Monthly Payment"
+- Calculation Formula: `(:loan_amount * :interest_rate * (1 + :interest_rate) ^ :loan_term) / ((1 + :interest_rate) ^ :loan_term - 1)`
+- Decimal Places: 2
+
+In this example, ":loan_amount," ":interest_rate," and ":loan_term" should be replaced with the actual field names you've defined in your webform. The "Monthly Payment" field will automatically calculate and display the monthly repayment amount based on the user's input.
+
+With the "Webform Calculation Fields" module, you can easily incorporate dynamic calculations into your webforms, making them more interactive and user-friendly.
diff --git a/modules/webform_calculation_fields/modules/webform_calculation_fields_examples/config/install/webform.webform.webform_calculation_fields_examp.yml b/modules/webform_calculation_fields/modules/webform_calculation_fields_examples/config/install/webform.webform.webform_calculation_fields_examp.yml
new file mode 100644
index 0000000..9f47dd0
--- /dev/null
+++ b/modules/webform_calculation_fields/modules/webform_calculation_fields_examples/config/install/webform.webform.webform_calculation_fields_examp.yml
@@ -0,0 +1,230 @@
+uuid: ce514239-490a-4df9-b2b1-aa114ffb7714
+langcode: en
+status: open
+dependencies: {  }
+weight: 0
+open: null
+close: null
+uid: 1
+template: false
+archive: false
+id: webform_calculation_fields_examp
+title: 'Webform Calculation fields example'
+description: ''
+categories: {  }
+elements: |-
+  first_value:
+    '#type': number
+    '#title': 'First value'
+  second_value:
+    '#type': number
+    '#title': 'Second Value'
+  first_second:
+    '#type': form_element_math
+    '#title': 'First + Second'
+    '#evaluation_fields': ':first_value + :second_value'
+  multiply:
+    '#type': select
+    '#title': Multiply
+    '#options':
+      10: '10'
+      100: '100'
+      1000: '1000'
+  multiply_result:
+    '#type': form_element_math
+    '#title': 'Multiply - Result'
+    '#evaluation_fields': ':first_second * :multiply'
+  to_divide:
+    '#type': number
+    '#title': 'To Divide'
+    '#min': 1
+  multiply_result_to_divide:
+    '#type': form_element_math
+    '#title': 'Multiply Result / To Divide'
+    '#evaluation_round': 2
+    '#evaluation_fields': ':multiply_result / :to_divide'
+css: ''
+javascript: ''
+settings:
+  ajax: false
+  ajax_scroll_top: form
+  ajax_progress_type: ''
+  ajax_effect: ''
+  ajax_speed: null
+  page: true
+  page_submit_path: ''
+  page_confirm_path: ''
+  page_theme_name: ''
+  form_title: both
+  form_submit_once: false
+  form_open_message: ''
+  form_close_message: ''
+  form_exception_message: ''
+  form_previous_submissions: true
+  form_confidential: false
+  form_confidential_message: ''
+  form_disable_remote_addr: false
+  form_convert_anonymous: false
+  form_prepopulate: false
+  form_prepopulate_source_entity: false
+  form_prepopulate_source_entity_required: false
+  form_prepopulate_source_entity_type: ''
+  form_unsaved: false
+  form_disable_back: false
+  form_submit_back: false
+  form_disable_autocomplete: false
+  form_novalidate: false
+  form_disable_inline_errors: false
+  form_required: false
+  form_autofocus: false
+  form_details_toggle: false
+  form_reset: false
+  form_access_denied: default
+  form_access_denied_title: ''
+  form_access_denied_message: ''
+  form_access_denied_attributes: {  }
+  form_file_limit: ''
+  form_attributes: {  }
+  form_method: ''
+  form_action: ''
+  share: false
+  share_node: false
+  share_theme_name: ''
+  share_title: true
+  share_page_body_attributes: {  }
+  submission_label: ''
+  submission_exception_message: ''
+  submission_locked_message: ''
+  submission_log: false
+  submission_excluded_elements: {  }
+  submission_exclude_empty: false
+  submission_exclude_empty_checkbox: false
+  submission_views: {  }
+  submission_views_replace: {  }
+  submission_user_columns: {  }
+  submission_user_duplicate: false
+  submission_access_denied: default
+  submission_access_denied_title: ''
+  submission_access_denied_message: ''
+  submission_access_denied_attributes: {  }
+  previous_submission_message: ''
+  previous_submissions_message: ''
+  autofill: false
+  autofill_message: ''
+  autofill_excluded_elements: {  }
+  wizard_progress_bar: true
+  wizard_progress_pages: false
+  wizard_progress_percentage: false
+  wizard_progress_link: false
+  wizard_progress_states: false
+  wizard_start_label: ''
+  wizard_preview_link: false
+  wizard_confirmation: true
+  wizard_confirmation_label: ''
+  wizard_auto_forward: true
+  wizard_auto_forward_hide_next_button: false
+  wizard_keyboard: true
+  wizard_track: ''
+  wizard_prev_button_label: ''
+  wizard_next_button_label: ''
+  wizard_toggle: false
+  wizard_toggle_show_label: ''
+  wizard_toggle_hide_label: ''
+  wizard_page_type: container
+  wizard_page_title_tag: h2
+  preview: 0
+  preview_label: ''
+  preview_title: ''
+  preview_message: ''
+  preview_attributes: {  }
+  preview_excluded_elements: {  }
+  preview_exclude_empty: true
+  preview_exclude_empty_checkbox: false
+  draft: none
+  draft_multiple: false
+  draft_auto_save: false
+  draft_saved_message: ''
+  draft_loaded_message: ''
+  draft_pending_single_message: ''
+  draft_pending_multiple_message: ''
+  confirmation_type: page
+  confirmation_url: ''
+  confirmation_title: ''
+  confirmation_message: ''
+  confirmation_attributes: {  }
+  confirmation_back: true
+  confirmation_back_label: ''
+  confirmation_back_attributes: {  }
+  confirmation_exclude_query: false
+  confirmation_exclude_token: false
+  confirmation_update: false
+  limit_total: null
+  limit_total_interval: null
+  limit_total_message: ''
+  limit_total_unique: false
+  limit_user: null
+  limit_user_interval: null
+  limit_user_message: ''
+  limit_user_unique: false
+  entity_limit_total: null
+  entity_limit_total_interval: null
+  entity_limit_user: null
+  entity_limit_user_interval: null
+  purge: none
+  purge_days: null
+  results_disabled: false
+  results_disabled_ignore: false
+  results_customize: false
+  token_view: false
+  token_update: false
+  token_delete: false
+  serial_disabled: false
+access:
+  create:
+    roles:
+      - anonymous
+      - authenticated
+    users: {  }
+    permissions: {  }
+  view_any:
+    roles: {  }
+    users: {  }
+    permissions: {  }
+  update_any:
+    roles: {  }
+    users: {  }
+    permissions: {  }
+  delete_any:
+    roles: {  }
+    users: {  }
+    permissions: {  }
+  purge_any:
+    roles: {  }
+    users: {  }
+    permissions: {  }
+  view_own:
+    roles: {  }
+    users: {  }
+    permissions: {  }
+  update_own:
+    roles: {  }
+    users: {  }
+    permissions: {  }
+  delete_own:
+    roles: {  }
+    users: {  }
+    permissions: {  }
+  administer:
+    roles: {  }
+    users: {  }
+    permissions: {  }
+  test:
+    roles: {  }
+    users: {  }
+    permissions: {  }
+  configuration:
+    roles: {  }
+    users: {  }
+    permissions: {  }
+handlers: {  }
+variants: {  }
\ No newline at end of file
diff --git a/modules/webform_calculation_fields/modules/webform_calculation_fields_examples/webform_calculation_fields_examples.info.yml b/modules/webform_calculation_fields/modules/webform_calculation_fields_examples/webform_calculation_fields_examples.info.yml
new file mode 100644
index 0000000..e984c20
--- /dev/null
+++ b/modules/webform_calculation_fields/modules/webform_calculation_fields_examples/webform_calculation_fields_examples.info.yml
@@ -0,0 +1,9 @@
+name: Webform Calculation Fields Examples
+type: module
+description: Provides webform examples using calculation fiel types.
+package: Webform
+core_version_requirement: ^9 || ^10
+dependencies:
+  - calculation_fields:calculation_fields
+  - webform_calculation_fields:webform_calculation_fields
+  - webform:webform
diff --git a/modules/webform_calculation_fields/modules/webform_calculation_fields_examples/webform_calculation_fields_examples.install b/modules/webform_calculation_fields/modules/webform_calculation_fields_examples/webform_calculation_fields_examples.install
new file mode 100644
index 0000000..5171d87
--- /dev/null
+++ b/modules/webform_calculation_fields/modules/webform_calculation_fields_examples/webform_calculation_fields_examples.install
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * Implements uninstall_hook().
+ */
+function webform_calculation_fields_examples_uninstall() {
+  $webform_machine_names = [
+    'webform_calculation_fields_examp',
+  ];
+
+
+  $query = \Drupal::entityQuery('webform_submission')
+    ->condition('webform_id', $webform_machine_names, 'IN');
+  $submission_ids = $query->execute();
+  if (!empty($submission_ids)) {
+    $submission_storage = \Drupal::entityTypeManager()->getStorage('webform_submission');
+    $submissions = $submission_storage->loadMultiple($submission_ids);
+    $submission_storage->delete($submissions);
+  }
+
+  // Delete webforms.
+  $webform_storage = \Drupal::entityTypeManager()->getStorage('webform');
+  foreach ($webform_machine_names as $webform_machine_name) {
+    $webforms = $webform_storage->loadByProperties(['id' => $webform_machine_name]);
+    if (!empty($webforms)) {
+      $webform_storage->delete($webforms);
+    }
+  }
+
+}
diff --git a/modules/webform_calculation_fields/src/Form/WebformCalculationFieldsElementUiAccess.php b/modules/webform_calculation_fields/src/Form/WebformCalculationFieldsElementUiAccess.php
new file mode 100644
index 0000000..8d62b12
--- /dev/null
+++ b/modules/webform_calculation_fields/src/Form/WebformCalculationFieldsElementUiAccess.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Drupal\webform_calculation_fields\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\user\Entity\User;
+use Drupal\webform\WebformInterface;
+
+/**
+ * Provide access feature for the custom math element.
+ */
+trait WebformCalculationFieldsElementUiAccess {
+
+  /**
+   * {@inheritDoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state, WebformInterface $webform = NULL, $key = NULL, $parent_key = NULL, $type = NULL) {
+    $router_match = $this->getRouteMatch();
+    $field_key = $router_match->getParameter('key');
+    $field_props = $webform->getElement($field_key);
+    $element_type = $field_props['#webform_plugin_id'];
+    $uid = $this->currentUser()->id();
+    if ($element_type === 'form_element_math' && !User::load($uid)->hasPermission('administer calculation_fields configuration')) {
+      return [
+        "#type" => "markup",
+        "#markup" => t('You do not have access to delete this field.'),
+      ];
+    }
+    return parent::buildForm($form, $form_state, $webform, $key, $parent_key, $type);
+  }
+
+}
diff --git a/modules/webform_calculation_fields/src/Form/WebformCalculationFieldsForm.php b/modules/webform_calculation_fields/src/Form/WebformCalculationFieldsForm.php
new file mode 100644
index 0000000..ab86fbc
--- /dev/null
+++ b/modules/webform_calculation_fields/src/Form/WebformCalculationFieldsForm.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace Drupal\webform_calculation_fields\Form;
+
+use Drupal\webform_ui\Form\WebformUiElementEditForm;
+
+/**
+ * Overrides the form element checking the permission before delete the element.
+ */
+class WebformCalculationFieldsForm extends WebformUiElementEditForm {
+
+  use WebformCalculationFieldsElementUiAccess;
+
+}
diff --git a/modules/webform_calculation_fields/src/Form/WebformCalculationFieldsFormDelete.php b/modules/webform_calculation_fields/src/Form/WebformCalculationFieldsFormDelete.php
new file mode 100644
index 0000000..9998558
--- /dev/null
+++ b/modules/webform_calculation_fields/src/Form/WebformCalculationFieldsFormDelete.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace Drupal\webform_calculation_fields\Form;
+
+use Drupal\webform_ui\Form\WebformUiElementDeleteForm;
+
+/**
+ * Overrides the form delete element checking the permission before delete the element.
+ */
+class WebformCalculationFieldsFormDelete extends WebformUiElementDeleteForm {
+
+  use WebformCalculationFieldsElementUiAccess;
+
+}
diff --git a/modules/webform_calculation_fields/src/Plugin/WebformElement/WebformFieldCalculator.php b/modules/webform_calculation_fields/src/Plugin/WebformElement/WebformFieldCalculator.php
index c19c9ec..5dcec7e 100644
--- a/modules/webform_calculation_fields/src/Plugin/WebformElement/WebformFieldCalculator.php
+++ b/modules/webform_calculation_fields/src/Plugin/WebformElement/WebformFieldCalculator.php
@@ -3,28 +3,34 @@
 namespace Drupal\webform_calculation_fields\Plugin\WebformElement;
 
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\user\Entity\User;
 use Drupal\webform\Plugin\WebformElement\Number;
 
 /**
- * Provides a 'Webform Remote Fields Hidden' element.
+ * Provides a Webform Math element.
  *
  * @WebformElement(
  *   id = "form_element_math",
  *   label = @Translation("Field calculator"),
- *   api = "https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Render!Element!Number.php/class/Number",
- *   description = @Translation("Provides a hidden form element with API Integration."),
+ *   description = @Translation("Provides a math element capable to evaluate math expressions."),
  *   category = @Translation("Calculator"),
  * )
  */
 class WebformFieldCalculator extends Number {
 
-
+  /**
+   * {@inheritDoc}
+   */
   public function defineDefaultProperties() {
     return parent::defineDefaultProperties() + [
       'evaluation_fields' => '',
+      'evaluation_round' => NULL,
     ];
   }
 
+  /**
+   * {@inheritDoc}
+   */
   public function form(array $form, FormStateInterface $form_state) {
     $form = parent::form($form, $form_state);
 
@@ -34,13 +40,20 @@ class WebformFieldCalculator extends Number {
       '#weight' => -1,
     ];
 
+    $form['options']['calculator']['evaluation_round'] = [
+      '#type' => 'number',
+      '#min' => 0,
+      '#title' => $this->t('Round result'),
+      '#description' => $this->t('How many decimal cases display'),
+      '#weight' => 1,
+    ];
+
     $form['options']['calculator']['evaluation_fields'] = [
       '#type' => 'textarea',
       '#title' => $this->t('Add here the expression'),
       '#description' => $this->t('Example of expressions: field_1 + field_2 - (field_1 * field_3)'),
-      '#weight' => 1,
+      '#weight' => 2,
     ];
-
     return $form;
   }
 
diff --git a/modules/webform_calculation_fields/src/Plugin/WebformElement/WebformMathMarkupElement.php b/modules/webform_calculation_fields/src/Plugin/WebformElement/WebformMathMarkupElement.php
new file mode 100644
index 0000000..db3f8ea
--- /dev/null
+++ b/modules/webform_calculation_fields/src/Plugin/WebformElement/WebformMathMarkupElement.php
@@ -0,0 +1,68 @@
+<?php
+
+namespace Drupal\webform_calculation_fields\Plugin\WebformElement;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\webform\Plugin\WebformElement\TextField;
+
+/**
+ * Provides a Webform Math element.
+ *
+ * @WebformElement(
+ *   id = "form_element_markup_math",
+ *   label = @Translation("Field calculator markup"),
+ *   description = @Translation("Provided an advance markup that can evaluate expression inside {{ }} tags."),
+ *   category = @Translation("Calculator"),
+ * )
+ */
+class WebformMathMarkupElement extends TextField {
+
+  /**
+   * {@inheritDoc}
+   */
+  public function defineDefaultProperties() {
+    $default = parent::defineDefaultProperties();
+    $custom = [
+      'evaluation_round' => NULL,
+      'evaluation_fields' => '',
+      'evaluation_text_preview' => '',
+    ];
+    return array_merge(
+      $default,
+      $custom
+    );
+  }
+
+  public function form(array $form, FormStateInterface $form_state) {
+    $form = parent::form($form, $form_state);
+    unset($form["summary_attributes"]);
+    unset($form["validation"]);
+    unset($form["element_description"]);
+    unset($form["form"]);
+//    unset($form["element"]);
+
+
+    $form['markup']['evaluation_fields'] = [
+      '#type' => 'webform_html_editor',
+      '#title' => $this->t('HTML markup'),
+      '#description' => $this->t('Enter custom HTML into your webform. Add the expression between {{ }}. Like {{ :field_x + :field_y }}'),
+    ];
+
+    $form['markup']['evaluation_round'] = [
+      '#type' => 'number',
+      '#min' => 0,
+      '#title' => $this->t('Round result'),
+      '#description' => $this->t('How many decimal cases display'),
+      '#weight' => 1,
+    ];
+
+    $form['markup']['evaluation_text_preview'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Add the preview text'),
+      '#description' => $this->t('Text that be displayed until all inputs used by this field be populated. If not provided the element will displayed when the calculate is finished.'),
+      '#weight' => 2,
+    ];
+    return $form;
+  }
+
+}
diff --git a/modules/webform_calculation_fields/src/Routing/WebformCalculationFieldsRouting.php b/modules/webform_calculation_fields/src/Routing/WebformCalculationFieldsRouting.php
new file mode 100644
index 0000000..a3a9a8a
--- /dev/null
+++ b/modules/webform_calculation_fields/src/Routing/WebformCalculationFieldsRouting.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace Drupal\webform_calculation_fields\Routing;
+
+use Drupal\Core\Routing\RouteSubscriberBase;
+use Drupal\webform_calculation_fields\Form\WebformCalculationFieldsForm;
+use Drupal\webform_calculation_fields\Form\WebformCalculationFieldsFormDelete;
+use Symfony\Component\Routing\RouteCollection;
+
+/**
+ * Subscribe alter route event.
+ *
+ * Update the routes defined adding new form that validate if the user can
+ * do anything with the form element.
+ */
+class WebformCalculationFieldsRouting extends RouteSubscriberBase {
+
+  /**
+   * Routes to set the new form behavior.
+   *
+   * @var string[]
+   */
+  protected static $routes = [
+    'entity.webform_ui.element.edit_form' => WebformCalculationFieldsForm::class,
+    'entity.webform_ui.element.delete_form' => WebformCalculationFieldsFormDelete::class,
+  ];
+
+  /**
+   * {@inheritDoc}
+   */
+  protected function alterRoutes(RouteCollection $collection) {
+    foreach (static::$routes as $routeName => $form) {
+      $routeInfo = $collection->get($routeName);
+      if ($routeInfo) {
+        $routeInfo->setDefault('_form', $form);
+      }
+    }
+  }
+
+}
diff --git a/modules/webform_calculation_fields/webform_calculation_fields.info.yml b/modules/webform_calculation_fields/webform_calculation_fields.info.yml
index 942c71f..f36650f 100644
--- a/modules/webform_calculation_fields/webform_calculation_fields.info.yml
+++ b/modules/webform_calculation_fields/webform_calculation_fields.info.yml
@@ -1,6 +1,6 @@
 name: Webform Calculation Fields
 type: module
-description: Provides additional functionality for the site.
+description: Provides additional form math element to realize math expression combining fields.
 package: Webform
 core_version_requirement: ^9 || ^10
 dependencies:
diff --git a/modules/webform_calculation_fields/webform_calculation_fields.services.yml b/modules/webform_calculation_fields/webform_calculation_fields.services.yml
new file mode 100644
index 0000000..96ec1c1
--- /dev/null
+++ b/modules/webform_calculation_fields/webform_calculation_fields.services.yml
@@ -0,0 +1,5 @@
+services:
+  webform_calculation_fields.router_subscriber:
+    class: 'Drupal\webform_calculation_fields\Routing\WebformCalculationFieldsRouting'
+    tags:
+      - { name: event_subscriber }
diff --git a/src/Element/FormMathElement.php b/src/Element/FormMathElement.php
index 9967c08..0e3f1a9 100644
--- a/src/Element/FormMathElement.php
+++ b/src/Element/FormMathElement.php
@@ -10,10 +10,16 @@ use Drupal\webform\Utility\WebformElementHelper;
 use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
 
 /**
+ * Provides a custom element capable to realize some math expression displaying,
+ * the result of the expression.
+ *
  * @FormElement("form_element_math")
  */
 class FormMathElement extends Number {
 
+  /**
+   * {@inheritDoc}
+   */
   public function getInfo() {
     $info = parent::getInfo();
     $info['#evaluation_fields'] = NULL;
@@ -22,8 +28,14 @@ class FormMathElement extends Number {
     return $info;
   }
 
+  /**
+   * Validate form math element callback.
+   *
+   * To avoid disruptive data from the client, every submit evaluate the
+   * expression and set the correct/expected value for the element.
+   */
   public static function validate(&$element, FormStateInterface $form_state, &$complete_form) {
-    $expression = static::mountEvaluation($element["#evaluation_fields"], $form_state);
+    $expression = static::buildFieldEvaluation($element["#evaluation_fields"], $form_state);
     $value = NestedArray::getValue($form_state->getValues(), $element['#parents']);
     if (empty($expression) || empty($value)) {
       return;
@@ -40,18 +52,41 @@ class FormMathElement extends Number {
    */
   public static function preRenderNumber($element) {
     $element['#attributes']['type'] = 'number';
+    $element['#attributes']['readonly'] = 'readonly';
     Element::setAttributes($element, ['id', 'name', 'value', 'step', 'min', 'max', 'placeholder', 'size', 'fields']);
-    static::setAttributes($element, ['form-number', 'js-calc-field']);
+    static::setAttributes($element, ['form-number', 'js-form-math-element']);
     $element['#attributes']['data-evaluate-expression'] = $element["#evaluation_fields"];
     $element['#attributes']['data-evaluate-fields'] = static::evaluateFields($element["#evaluation_fields"]);
     $element['#attached']['library'][] = 'calculation_fields/calculation_fields';
     return $element;
   }
 
-  public static function processFormMathElement($element, \Drupal\Core\Form\FormStateInterface $form_state, $form) {
+  /**
+   * Process each form math element setting custom properties.
+   *
+   * Set two properties:
+   * - data-evaluate-context: used to gurantee that the input will use values,
+   * in the correct form context.
+   * - data-evaluate-deep-fields: deep fields properties is used to store
+   * values of fields that are not being displayed like, like in a multistep
+   * form in a webform for example.
+   *
+   * @param array $element
+   *   The element.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The form state instance.
+   */
+  public static function processFormMathElement(array $element, FormStateInterface $form_state, $form) {
     $element['#attributes']['data-evaluate-context'] = str_replace('_', '-', $form["#form_id"]);
+    if (isset($element['#evaluation_round'])) {
+      $element['#attributes']['data-evaluate-round'] = (int) $element['#evaluation_round'];
+    }
     $dependency_fields = static::evaluateFields($element["#evaluation_fields"]);
 
+    $has_multiple_steps = $form["progress"]["#current_page"] ?? NULL;
+    $completed_form = $form_state->getCompleteForm();
+    $trigerred = $form_state->getTriggeringElement();
+
     $values_dependencies = [];
     foreach ($dependency_fields as $field) {
       if (!empty($form['elements'])) {
@@ -61,7 +96,7 @@ class FormMathElement extends Number {
         $d_element = WebformElementHelper::getElement($form, $field);
       }
 
-      if (!$d_element['#access']) {
+      if ($d_element["#webform_parent_key"] !== $has_multiple_steps || !$d_element['#access']) {
         $values_dependencies[$field] = $form_state->getValue($field);
       }
     }
@@ -69,7 +104,20 @@ class FormMathElement extends Number {
     return $element;
   }
 
-  protected static function mountEvaluation($evaluation, FormStateInterface $form_state) {
+  /**
+   * Build expression field replacing field name for this value.
+   *
+   * Example: (:field_name_1 + :field_name2) became (2 + 2).
+   *
+   * @param string $evaluation
+   *   The field expression.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   Form state.
+   *
+   * @return string
+   *   The expression with values.
+   */
+  public static function buildFieldEvaluation($evaluation, FormStateInterface $form_state) {
     $fields = static::evaluateFields($evaluation);
     $collected_values = [];
     foreach ($fields as $field) {
@@ -88,13 +136,20 @@ class FormMathElement extends Number {
     return $exp;
   }
 
-
-
+  /**
+   * Evaluation fields expression getting the field names.
+   *
+   * @param string $evaluation_fields
+   *   Evaluation field expression.
+   *
+   * @return array
+   *   An array with the field names.
+   */
   public static function evaluateFields($evaluation_fields): array {
-    $fields = explode(':', $evaluation_fields) ?? [];
-    $fields = array_filter($fields);
-    $patterns = [];
-    foreach ($fields as $field) {
+    $expression_fields = explode(':', $evaluation_fields) ?? [];
+    $expression_fields = array_filter($expression_fields);
+    $fields = [];
+    foreach ($expression_fields as $field) {
       $items = explode(' ', $field);
       $items = array_map(function ($item) {
         return preg_replace("/[^a-zA-Z0-9_]/", "", $item);
@@ -102,9 +157,9 @@ class FormMathElement extends Number {
       $filteredItems = array_filter($items, function ($item) {
         return !is_numeric($item) && !empty($item);
       });
-      $patterns = array_merge($patterns, $filteredItems);
+      $fields = array_merge($fields, $filteredItems);
     }
-    return $patterns;
+    return $fields;
   }
 
 
diff --git a/src/Element/FormMathMarkupElement.php b/src/Element/FormMathMarkupElement.php
new file mode 100644
index 0000000..928ed6e
--- /dev/null
+++ b/src/Element/FormMathMarkupElement.php
@@ -0,0 +1,102 @@
+<?php
+
+namespace Drupal\calculation_fields\Element;
+
+use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\Element\Textfield;
+use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
+
+/**
+ * Provides a custom element capable to realize some math expression displaying,
+ * the result of the expression.
+ *
+ * @FormElement("form_element_markup_math")
+ */
+class FormMathMarkupElement extends Textfield {
+
+  /**
+   * {@inheritDoc}
+   */
+  public function getInfo() {
+    $info = parent::getInfo();
+    $info['#process'][] = self::class . '::processFormMathElement';
+    $info['#element_validate'][] = self::class . '::validateExpressionValue';
+    return $info;
+  }
+
+  /**
+   * Validate form math element callback.
+   *
+   * To avoid disruptive data from the client, every submit evaluate the
+   * expression and set the correct/expected value for the element.
+   */
+  public static function validateExpressionValue(&$element, FormStateInterface $form_state, &$complete_form) {
+    $expressionFields = static::extractEvaluation($element);
+    $expressionReplaced = FormMathElement::buildFieldEvaluation($expressionFields, $form_state);
+    $value = NestedArray::getValue($form_state->getValues(), $element['#parents']);
+    if (empty($expressionFields) || empty($value)) {
+      return;
+    }
+    $expressionLanguage = new ExpressionLanguage();
+    $result = $expressionLanguage->evaluate($expressionReplaced);
+    if ($element["#evaluation_round"]) {
+      $result = number_format($result, $element["#evaluation_round"], '.', '');
+    }
+    $expectedResult = str_replace('{{ ' . $expressionFields . ' }}', $result, $element["#evaluation_fields"]);
+    if ($expectedResult !== $value) {
+      $form_state->setValue($element['#name'], $expectedResult);
+    }
+  }
+
+  /**
+   * Process function to get the form context of the element.
+   */
+  public static function processFormMathElement(array &$element, FormStateInterface $form_state, $form) {
+    $element['#attributes']['data-evaluate-context'] = str_replace('_', '-', $form["#form_id"]);
+    return $element;
+  }
+
+  /**
+   * Extract evaluation from the element.
+   */
+  public static function extractEvaluation($element) {
+    $pattern = '/{{(.*?)}}/';
+    preg_match_all($pattern, $element['#evaluation_fields'], $matches);
+    if (empty($matches[1])) {
+      \Drupal::logger('calculation_fields')
+        ->warning(t('Failed to extract expression of the evaluation_fields value @evaluation_fields', [
+          '@name' => $element['name'],
+          '@evaluation_fields' => $element['#evaluation_fields'],
+        ]));
+      return [
+        '#markup' => '',
+      ];
+    }
+    return trim(current($matches[1]));
+  }
+
+  /**
+   * Pre render markup that add the dataset of the evaluation data.
+   */
+  public static function preRenderTextfield($element) {
+    $expression = static::extractEvaluation($element);
+    $formContext = '';
+    if (isset($element["#attributes"]["data-evaluate-context"])) {
+      $formContext = $element["#attributes"]["data-evaluate-context"];
+    }
+    // @todo strip tags.
+    $textExpression = str_replace('{{ ' . $expression . ' }}', '[RESULT]', $element['#evaluation_fields']);
+    return [
+      '#theme' => 'form_math_markup_element',
+      '#round' => $element['#evaluation_round'] ?? NULL,
+      '#formContext' => $formContext,
+      '#fields' => FormMathElement::evaluateFields($expression),
+      '#expression' => $expression,
+      '#previewText' => $element['#evaluation_text_preview'] ?? NULL,
+      '#textExpression' => $textExpression,
+      '#name' => $element["#name"] ?? $element["#webform_key"],
+    ];
+  }
+
+}
diff --git a/templates/form-math-markup-element.html.twig b/templates/form-math-markup-element.html.twig
new file mode 100644
index 0000000..b07b9ad
--- /dev/null
+++ b/templates/form-math-markup-element.html.twig
@@ -0,0 +1,16 @@
+{{ attach_library('calculation_fields/calculation_fields') }}
+<div
+  data-evaluate-round='{{ round }}'
+  data-evaluate-context='{{ formContext }}'
+  data-evaluate-fields='{{ fields|join(' ') }}'
+  data-evaluate-expression="{{ expression }}"
+  class="js-form-math-element">
+  <div class='form-math-markup-element'>
+    {% if previewText %}
+      <p class='js-math-preview'>{{ previewText }}</p>
+    {% endif %}
+    <div class='js-math-result'>{{ textExpression|raw }}</div>
+    <div class='js-math-result-base'>{{ textExpression|raw }}</div>
+    <input class="js-math-result-input" type="hidden" value="" name="{{ name }}">
+  </div>
+</div>
-- 
GitLab