Skip to content

[7418] Input controls (link, phone, email)#4818

Merged
sumerjabri merged 7 commits intocraftercms:developfrom
jvega190:feature/7418-input-controls
Mar 17, 2026
Merged

[7418] Input controls (link, phone, email)#4818
sumerjabri merged 7 commits intocraftercms:developfrom
jvega190:feature/7418-input-controls

Conversation

@jvega190
Copy link
Copy Markdown
Member

@jvega190 jvega190 commented Mar 2, 2026

craftercms/craftercms#7418

Summary by CodeRabbit

  • New Features
    • Added email, link/URL, and phone input field types to content types and forms.
    • Each field offers configurable options (maxlength, readonly, tokenization, escape content) and constraints (required, pattern).
    • Built-in validation with tailored messages plus value retrieval and serialization support for these new field types.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 2, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: caa792ec-f4cf-405c-92fb-31dee9928b9f

📥 Commits

Reviewing files that changed from the base of the PR and between 2182ab6 and ddabbce.

📒 Files selected for processing (5)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/index.ts
  • ui/app/src/components/FormsEngine/lib/controlMap.ts
  • ui/app/src/components/FormsEngine/lib/validators.ts
  • ui/app/src/components/FormsEngine/lib/valueRetrievers.ts
  • ui/app/src/components/FormsEngine/lib/valueSerializers.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • ui/app/src/components/FormsEngine/lib/controlMap.ts
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/index.ts
  • ui/app/src/components/FormsEngine/lib/valueSerializers.ts

Walkthrough

Adds three new input field types (email, link, phone): new descriptor files, registration in descriptors index and controlMap, value retrievers/serializers entries, and dedicated validators integrated into the FormsEngine validation pipeline.

Changes

Cohort / File(s) Summary
Input Descriptors
ui/app/src/components/ContentTypeManagement/descriptors/controls/inputEmail.ts, ui/app/src/components/ContentTypeManagement/descriptors/controls/inputLink.ts, ui/app/src/components/ContentTypeManagement/descriptors/controls/linkPhone.ts
New DescriptorContentType files for input-email, input-link, input-phone defining metadata, virtual sections (Options, Constraints), fields (maxlength, readonly, tokenized, escapeContent, required, pattern), defaults, and exported as named + default.
Descriptors Index
ui/app/src/components/ContentTypeManagement/descriptors/controls/index.ts
Imported and added the three new descriptors to the exported controlDescriptors map.
Control Mapping
ui/app/src/components/FormsEngine/lib/controlMap.ts
Extended BuiltInControlType union with 'input-email', 'input-link', 'input-phone' and mapped each to the Text control via lazy import.
Validators
ui/app/src/components/FormsEngine/lib/validators.ts
Extended inputValidator signature to accept optional customValidationMessages; added internal validators inputEmailValidator, inputLinkValidator, inputPhoneValidator that call inputValidator with custom pattern messages; registered these in validatorsMap.
Value Retrievers
ui/app/src/components/FormsEngine/lib/valueRetrievers.ts
Registered 'input-email', 'input-link', 'input-phone' to use textFieldExtractor in valueRetrieverLookup.
Value Serializers
ui/app/src/components/FormsEngine/lib/valueSerializers.ts
Added valueSerializersLookup entries for 'input-email', 'input-link', 'input-phone' (mapped to undefined, matching existing pattern).

Sequence Diagram(s)

sequenceDiagram
  participant UI as ContentType UI
  participant Descriptors as Descriptor Registry
  participant Renderer as FormsEngine (controlMap)
  participant Control as Text Control
  participant Validators as FormsEngine Validators

  UI->>Descriptors: request control descriptors
  Descriptors-->>UI: descriptors for input-email / input-link / input-phone
  UI->>Renderer: build form with control type (e.g., 'input-email')
  Renderer->>Control: lazy-load Text control component
  Control->>Validators: validate input value (uses input-email/link/phone validator)
  Validators-->>Control: return validation result/messages
  Control-->>UI: display field and validation feedback
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • sumerjabri
🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description only provides a link to the related issue without explaining what the PR does or why these changes were made. Expand the description to explain the purpose and implementation details of the new input controls, or at minimum briefly describe what changes are included.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title '[7418] Input controls (link, phone, email)' accurately summarizes the main change—adding three new input control types.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
ui/app/src/components/FormsEngine/lib/validators.ts (1)

396-440: Consider consolidating duplicated wrapper validators.

inputEmailValidator, inputLinkValidator, and inputPhoneValidator share identical structure and only vary the message. A tiny factory/helper would reduce repetition.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/app/src/components/FormsEngine/lib/validators.ts` around lines 396 - 440,
Create a small factory that returns a field validator by accepting the pattern
message and delegating to inputValidator (e.g., make a function like
createInputValidator(patternMessage: string) that calls inputValidator with
defineMessage({ defaultMessage: patternMessage })); then replace
inputEmailValidator, inputLinkValidator, and inputPhoneValidator with calls to
that factory (or simple one-line wrappers) so each just supplies its unique
message while reusing the common logic; reference inputValidator and
defineMessage to build the pattern option and keep the existing function
signatures (field: ContentTypeField, currentValue: string, messages?:
FieldValidityMessage[]).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@ui/app/src/components/ContentTypeManagement/descriptors/controls/inputLink.ts`:
- Line 77: The default regex in the inputLink control is wrong (uses . instead
of literal \. and [^s]* instead of non-whitespace \S*); update the defaultValue
string used in the inputLink control to escape dots and use \S for
non-whitespace so it accepts valid URLs — e.g., change the pattern to something
like '^(https?://)?[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?(/\S*)?$' by
editing the defaultValue value in that file.

In `@ui/app/src/components/FormsEngine/lib/validators.ts`:
- Line 347: Remove the stale JSDoc param entry for customValidationMessages from
the numericInputValidator documentation: locate the JSDoc block above the
numericInputValidator function and delete the line that describes "@param
customValidationMessages" so the doc matches the function signature; ensure the
remaining JSDoc accurately reflects existing parameters for
numericInputValidator.

---

Nitpick comments:
In `@ui/app/src/components/FormsEngine/lib/validators.ts`:
- Around line 396-440: Create a small factory that returns a field validator by
accepting the pattern message and delegating to inputValidator (e.g., make a
function like createInputValidator(patternMessage: string) that calls
inputValidator with defineMessage({ defaultMessage: patternMessage })); then
replace inputEmailValidator, inputLinkValidator, and inputPhoneValidator with
calls to that factory (or simple one-line wrappers) so each just supplies its
unique message while reusing the common logic; reference inputValidator and
defineMessage to build the pattern option and keep the existing function
signatures (field: ContentTypeField, currentValue: string, messages?:
FieldValidityMessage[]).

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7bafec1 and 9e25942.

📒 Files selected for processing (6)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/index.ts
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/inputEmail.ts
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/inputLink.ts
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/linkPhone.ts
  • ui/app/src/components/FormsEngine/lib/controlMap.ts
  • ui/app/src/components/FormsEngine/lib/validators.ts

Comment thread ui/app/src/components/ContentTypeManagement/descriptors/controls/inputLink.ts Outdated
Comment thread ui/app/src/components/FormsEngine/lib/validators.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
ui/app/src/components/FormsEngine/lib/validators.ts (1)

396-440: Consider deduplicating the three pattern-specific wrapper validators.

This is repetitive and can be simplified with a small factory to keep future additions cleaner.

🧹 Optional refactor
+const createPatternValidator = (defaultMessage: string) => {
+	return (field: ContentTypeField, currentValue: string, messages?: FieldValidityMessage[]) =>
+		inputValidator(field, currentValue, messages, {
+			pattern: defineMessage({ defaultMessage })
+		});
+};
+
-const inputEmailValidator = (
-	field: ContentTypeField,
-	currentValue: string,
-	messages?: FieldValidityMessage[]
-): boolean => {
-	return inputValidator(field, currentValue, messages, {
-		pattern: defineMessage({ defaultMessage: 'Please enter a valid email address.' })
-	});
-};
+const inputEmailValidator = createPatternValidator('Please enter a valid email address.');
 
-const inputLinkValidator = (
-	field: ContentTypeField,
-	currentValue: string,
-	messages?: FieldValidityMessage[]
-): boolean => {
-	return inputValidator(field, currentValue, messages, {
-		pattern: defineMessage({ defaultMessage: 'Please enter a valid URL.' })
-	});
-};
+const inputLinkValidator = createPatternValidator('Please enter a valid URL.');
 
-const inputPhoneValidator = (
-	field: ContentTypeField,
-	currentValue: string,
-	messages?: FieldValidityMessage[]
-): boolean => {
-	return inputValidator(field, currentValue, messages, {
-		pattern: defineMessage({ defaultMessage: 'Please enter a valid phone number.' })
-	});
-};
+const inputPhoneValidator = createPatternValidator('Please enter a valid phone number.');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/app/src/components/FormsEngine/lib/validators.ts` around lines 396 - 440,
The three nearly identical wrappers inputEmailValidator, inputLinkValidator, and
inputPhoneValidator should be consolidated with a small factory to avoid
duplication: create a helper (e.g., makePatternValidator) that accepts a pattern
message (defineMessage(...)) and returns a validator function compatible with
inputValidator, then replace inputEmailValidator, inputLinkValidator, and
inputPhoneValidator by calling that factory with their respective messages;
ensure the factory returns the same signature (field, currentValue, messages)
and internally calls inputValidator so existing usage sites need no changes.
ui/app/src/components/FormsEngine/lib/valueSerializers.ts (1)

96-98: Align new input serializers with text-field escaping behavior.

These new text-like controls are currently passthrough. If escapeContent is configured, they won’t follow the same serialization path as other text inputs using prepareString.

♻️ Suggested adjustment
-	'input-email': undefined,
-	'input-link': undefined,
-	'input-phone': undefined
+	'input-email': (field, value) => prepareString(field, value as string),
+	'input-link': (field, value) => prepareString(field, value as string),
+	'input-phone': (field, value) => prepareString(field, value as string)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/app/src/components/FormsEngine/lib/valueSerializers.ts` around lines 96 -
98, The new text-like controls 'input-email', 'input-link', and 'input-phone'
were left as passthrough (undefined) so they bypass the escape-aware path;
update their entries in the serializer map to use the same serializer as
'text-field' (i.e., the prepareString/ text-field serializer) so they honor
escapeContent and follow the same serialization path as other text inputs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@ui/app/src/components/FormsEngine/lib/validators.ts`:
- Around line 396-440: The three nearly identical wrappers inputEmailValidator,
inputLinkValidator, and inputPhoneValidator should be consolidated with a small
factory to avoid duplication: create a helper (e.g., makePatternValidator) that
accepts a pattern message (defineMessage(...)) and returns a validator function
compatible with inputValidator, then replace inputEmailValidator,
inputLinkValidator, and inputPhoneValidator by calling that factory with their
respective messages; ensure the factory returns the same signature (field,
currentValue, messages) and internally calls inputValidator so existing usage
sites need no changes.

In `@ui/app/src/components/FormsEngine/lib/valueSerializers.ts`:
- Around line 96-98: The new text-like controls 'input-email', 'input-link', and
'input-phone' were left as passthrough (undefined) so they bypass the
escape-aware path; update their entries in the serializer map to use the same
serializer as 'text-field' (i.e., the prepareString/ text-field serializer) so
they honor escapeContent and follow the same serialization path as other text
inputs.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9e25942 and 2182ab6.

📒 Files selected for processing (4)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/inputLink.ts
  • ui/app/src/components/FormsEngine/lib/validators.ts
  • ui/app/src/components/FormsEngine/lib/valueRetrievers.ts
  • ui/app/src/components/FormsEngine/lib/valueSerializers.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • ui/app/src/components/ContentTypeManagement/descriptors/controls/inputLink.ts

@jvega190 jvega190 marked this pull request as ready for review March 13, 2026 16:08
@jvega190 jvega190 requested a review from rart as a code owner March 13, 2026 16:08
Copy link
Copy Markdown
Member

@rart rart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@russdanner have we considered having a single input with a type instead of a different control per type? Could help with keeping the control list cleaner

@sumerjabri
Copy link
Copy Markdown
Member

@russdanner please see above

@jvega190 please fix conflicts

@russdanner
Copy link
Copy Markdown
Member

@rart These are pretty thin lightweight wrappers.
IMO this approach makes it easy for people to see/find (rather than complicating the use and testing of the input control.)

…o feature/7418-input-controls

# Conflicts:
#	ui/app/src/components/ContentTypeManagement/descriptors/controls/index.ts
#	ui/app/src/components/FormsEngine/lib/controlMap.ts
#	ui/app/src/components/FormsEngine/lib/validators.ts
@jvega190
Copy link
Copy Markdown
Member Author

@sumerjabri conflicts fixed

@sumerjabri sumerjabri merged commit 2014a45 into craftercms:develop Mar 17, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants