Skip to content

feat: add mask() method to input field components for masking library integration#161

Draft
Copilot wants to merge 3 commits intomainfrom
copilot/add-mask-method-to-field-components
Draft

feat: add mask() method to input field components for masking library integration#161
Copilot wants to merge 3 commits intomainfrom
copilot/add-mask-method-to-field-components

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 17, 2026

Summary

Adds a public .mask(callback) method to SmarkForm field components that provides a clean integration scaffold for input-masking libraries (like iMask.js) without adding any hard dependency.

Changes

src/types/input.type.js

mask(callback) method (added to the input class, inherited by number, date, time, datetime-local, color, etc.):

  • Temporarily changes <input type> to "text" for any non-text input, because masking libraries like iMask.js require type="text". The original type is preserved in _originalType.
  • Calls callback(targetFieldNode) with the raw DOM element as the sole argument — this is the integration point where the caller attaches iMask or any other library.
  • Stores the callback's return value as _maskInstance.
  • For singletons, delegates to the inner field component (so _maskInstance lives where export() reads it).
  • Returns this for chaining.

_setTargetFieldValue() updated:

  • Dispatches a synthetic input event on the element when a mask instance is active. This allows masking libraries to re-process the value when import() is called programmatically.

export() updated:

  • When _maskInstance.unmaskedValue is defined, uses it as the raw value instead of nodeFld.value. This ensures that derived types (number, date, time, etc.) receive the raw unmasked string and can still apply their own semantic type conversion (e.g. Number("1234.56")1234.56 rather than Number("1,234.56")NaN).

test/mask.tests.js (new)

13 Playwright test cases covering:

  • Type change for number/date inputs; no-op for text inputs
  • _originalType is stored correctly
  • Callback receives the correct DOM element
  • mask() returns this for chaining
  • export() uses unmaskedValue when provided
  • Number fields still export a JS number after masking
  • Fallback to nodeFld.value when mask has no unmaskedValue (or returns null)
  • Singleton delegation: _maskInstance lands on the inner field
  • import() dispatches input event on masked fields (and does NOT dispatch it on unmasked fields)

Usage example (iMask.js)

const form = new SmarkForm(document.querySelector("body"));
await form.rendered;

const priceField = form.find("/price");
priceField.mask(node => IMask(node, {
    mask: Number,
    scale: 2,
    thousandsSeparator: ',',
    radix: '.',
}));
// form.export() will still return { price: 1234.56 } even though
// the visible value is "1,234.56"

Testing

All 284 existing tests continue to pass. All 13 new mask tests pass.

… integration

- Add mask(callback) method to SmarkField (via input.type.js):
  - Changes <input> type to "text" for non-text inputs (required by iMask.js etc.)
  - Stores original type in _originalType for reference
  - Calls callback(targetFieldNode) and stores result as _maskInstance
  - Delegates to inner field for singletons, returns `me` for chaining
- Update _setTargetFieldValue() to dispatch "input" event when mask is active,
  so masking libraries re-process the new value on programmatic import()
- Update export() to use _maskInstance.unmaskedValue when available,
  so derived types (number, date, etc.) still parse/return the correct semantic type
- Add comprehensive tests in test/mask.tests.js (13 scenarios)

Agent-Logs-Url: https://github.com/bitifet/SmarkForm/sessions/72c9bcc2-72c5-42a0-8d32-9fe27015b3da

Co-authored-by: bitifet <1643647+bitifet@users.noreply.github.com>
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.

2 participants