@elliemae/loan-field-renderers 26.2.2
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.
- package/dist/cjs/ARCHITECTURE.md +434 -0
- package/dist/cjs/OVERVIEW.md +229 -0
- package/dist/cjs/bll/constants.js +86 -0
- package/dist/cjs/bll/formatters/booleanFormatter.js +51 -0
- package/dist/cjs/bll/formatters/dateFormatter.js +78 -0
- package/dist/cjs/bll/formatters/dropdownFormatter.js +34 -0
- package/dist/cjs/bll/formatters/factory/index.js +115 -0
- package/dist/cjs/bll/formatters/index.js +24 -0
- package/dist/cjs/bll/formatters/numberFormatter.js +70 -0
- package/dist/cjs/bll/formatters/phoneFormatter.js +57 -0
- package/dist/cjs/bll/formatters/regexFormatter.js +52 -0
- package/dist/cjs/bll/formatters/ssnFormatter.js +50 -0
- package/dist/cjs/bll/formatters/textFormatter.js +43 -0
- package/dist/cjs/bll/formatters/zipFormatter.js +48 -0
- package/dist/cjs/bll/index.js +62 -0
- package/dist/cjs/bll/ssf/index.js +48 -0
- package/dist/cjs/bll/ssf/loan.js +81 -0
- package/dist/cjs/bll/ssf/loconnect.js +70 -0
- package/dist/cjs/bll/ssf/ssfBase.js +97 -0
- package/dist/cjs/bll/ssf/types.js +16 -0
- package/dist/cjs/bll/types.js +16 -0
- package/dist/cjs/bll/validators/dateValidator.js +60 -0
- package/dist/cjs/bll/validators/emailValidator.js +47 -0
- package/dist/cjs/bll/validators/factory/index.js +81 -0
- package/dist/cjs/bll/validators/index.js +24 -0
- package/dist/cjs/bll/validators/maxCharValidator.js +49 -0
- package/dist/cjs/bll/validators/requiredValidator.js +44 -0
- package/dist/cjs/bll/validators/zipValidator.js +53 -0
- package/dist/cjs/core/index.js +52 -0
- package/dist/cjs/demo/config.js +391 -0
- package/dist/cjs/demo/index.js +31 -0
- package/dist/cjs/package.json +7 -0
- package/dist/cjs/renderer/FieldRenderer.js +45 -0
- package/dist/cjs/renderer/base/hooks/fieldDescription.js +39 -0
- package/dist/cjs/renderer/base/hooks/fieldDisabled.js +53 -0
- package/dist/cjs/renderer/base/hooks/fieldGoTo.js +50 -0
- package/dist/cjs/renderer/base/hooks/fieldLocked.js +42 -0
- package/dist/cjs/renderer/base/hooks/fieldMeta.js +150 -0
- package/dist/cjs/renderer/base/hooks/fieldSubscribers.js +66 -0
- package/dist/cjs/renderer/base/hooks/fieldValidation.js +45 -0
- package/dist/cjs/renderer/base/hooks/fieldValue.js +215 -0
- package/dist/cjs/renderer/base/hooks/hookBase.js +29 -0
- package/dist/cjs/renderer/base/hooks/index.js +139 -0
- package/dist/cjs/renderer/base/renderer.js +198 -0
- package/dist/cjs/renderer/base/rendererValidator.js +97 -0
- package/dist/cjs/renderer/factory/index.js +58 -0
- package/dist/cjs/renderer/field-renderers/AddonRenderer.js +75 -0
- package/dist/cjs/renderer/field-renderers/CheckboxRenderer.js +123 -0
- package/dist/cjs/renderer/field-renderers/DateRenderer.js +206 -0
- package/dist/cjs/renderer/field-renderers/DropdownRenderer/hook.js +99 -0
- package/dist/cjs/renderer/field-renderers/DropdownRenderer/index.js +216 -0
- package/dist/cjs/renderer/field-renderers/LargeTextRenderer.js +209 -0
- package/dist/cjs/renderer/field-renderers/NumberRenderer.js +216 -0
- package/dist/cjs/renderer/field-renderers/RadioGroupRenderer.js +128 -0
- package/dist/cjs/renderer/field-renderers/RadioRenderer.js +121 -0
- package/dist/cjs/renderer/field-renderers/TextRenderer.js +223 -0
- package/dist/cjs/renderer/field-renderers/ToggleRenderer.js +121 -0
- package/dist/cjs/renderer/field-renderers/ZipCodeRenderer/helper.js +132 -0
- package/dist/cjs/renderer/field-renderers/ZipCodeRenderer/hook.js +128 -0
- package/dist/cjs/renderer/field-renderers/ZipCodeRenderer/index.js +273 -0
- package/dist/cjs/renderer/index.js +24 -0
- package/dist/cjs/renderer/styles.js +51 -0
- package/dist/cjs/renderer/types.js +16 -0
- package/dist/cjs/tests/base/flowBase.js +125 -0
- package/dist/cjs/tests/base/index.js +52 -0
- package/dist/cjs/tests/flows/checkboxRendererFlows.js +85 -0
- package/dist/cjs/tests/flows/dateRendererFlows.js +870 -0
- package/dist/cjs/tests/flows/dropdownRendererFlows.js +591 -0
- package/dist/cjs/tests/flows/largeTextRendererFlows.js +99 -0
- package/dist/cjs/tests/flows/numberRendererFlows.js +175 -0
- package/dist/cjs/tests/flows/radioRendererFlows.js +115 -0
- package/dist/cjs/tests/flows/textRendererFlows.js +349 -0
- package/dist/cjs/tests/flows/toggleRendererFlows.js +106 -0
- package/dist/cjs/tests/flows/zipCodeRendererFlows.js +1163 -0
- package/dist/cjs/utils/dateHelper.js +65 -0
- package/dist/esm/ARCHITECTURE.md +434 -0
- package/dist/esm/OVERVIEW.md +229 -0
- package/dist/esm/bll/constants.js +66 -0
- package/dist/esm/bll/formatters/booleanFormatter.js +33 -0
- package/dist/esm/bll/formatters/dateFormatter.js +48 -0
- package/dist/esm/bll/formatters/dropdownFormatter.js +14 -0
- package/dist/esm/bll/formatters/factory/index.js +97 -0
- package/dist/esm/bll/formatters/index.js +4 -0
- package/dist/esm/bll/formatters/numberFormatter.js +54 -0
- package/dist/esm/bll/formatters/phoneFormatter.js +41 -0
- package/dist/esm/bll/formatters/regexFormatter.js +34 -0
- package/dist/esm/bll/formatters/ssnFormatter.js +32 -0
- package/dist/esm/bll/formatters/textFormatter.js +25 -0
- package/dist/esm/bll/formatters/zipFormatter.js +30 -0
- package/dist/esm/bll/index.js +44 -0
- package/dist/esm/bll/ssf/index.js +30 -0
- package/dist/esm/bll/ssf/loan.js +63 -0
- package/dist/esm/bll/ssf/loconnect.js +52 -0
- package/dist/esm/bll/ssf/ssfBase.js +67 -0
- package/dist/esm/bll/ssf/types.js +0 -0
- package/dist/esm/bll/types.js +0 -0
- package/dist/esm/bll/validators/dateValidator.js +30 -0
- package/dist/esm/bll/validators/emailValidator.js +29 -0
- package/dist/esm/bll/validators/factory/index.js +63 -0
- package/dist/esm/bll/validators/index.js +4 -0
- package/dist/esm/bll/validators/maxCharValidator.js +31 -0
- package/dist/esm/bll/validators/requiredValidator.js +26 -0
- package/dist/esm/bll/validators/zipValidator.js +35 -0
- package/dist/esm/core/index.js +34 -0
- package/dist/esm/demo/config.js +371 -0
- package/dist/esm/demo/index.js +11 -0
- package/dist/esm/package.json +7 -0
- package/dist/esm/renderer/FieldRenderer.js +15 -0
- package/dist/esm/renderer/base/hooks/fieldDescription.js +19 -0
- package/dist/esm/renderer/base/hooks/fieldDisabled.js +33 -0
- package/dist/esm/renderer/base/hooks/fieldGoTo.js +30 -0
- package/dist/esm/renderer/base/hooks/fieldLocked.js +22 -0
- package/dist/esm/renderer/base/hooks/fieldMeta.js +132 -0
- package/dist/esm/renderer/base/hooks/fieldSubscribers.js +36 -0
- package/dist/esm/renderer/base/hooks/fieldValidation.js +25 -0
- package/dist/esm/renderer/base/hooks/fieldValue.js +195 -0
- package/dist/esm/renderer/base/hooks/hookBase.js +9 -0
- package/dist/esm/renderer/base/hooks/index.js +121 -0
- package/dist/esm/renderer/base/renderer.js +178 -0
- package/dist/esm/renderer/base/rendererValidator.js +77 -0
- package/dist/esm/renderer/factory/index.js +38 -0
- package/dist/esm/renderer/field-renderers/AddonRenderer.js +55 -0
- package/dist/esm/renderer/field-renderers/CheckboxRenderer.js +93 -0
- package/dist/esm/renderer/field-renderers/DateRenderer.js +176 -0
- package/dist/esm/renderer/field-renderers/DropdownRenderer/hook.js +79 -0
- package/dist/esm/renderer/field-renderers/DropdownRenderer/index.js +186 -0
- package/dist/esm/renderer/field-renderers/LargeTextRenderer.js +179 -0
- package/dist/esm/renderer/field-renderers/NumberRenderer.js +188 -0
- package/dist/esm/renderer/field-renderers/RadioGroupRenderer.js +108 -0
- package/dist/esm/renderer/field-renderers/RadioRenderer.js +91 -0
- package/dist/esm/renderer/field-renderers/TextRenderer.js +197 -0
- package/dist/esm/renderer/field-renderers/ToggleRenderer.js +91 -0
- package/dist/esm/renderer/field-renderers/ZipCodeRenderer/helper.js +112 -0
- package/dist/esm/renderer/field-renderers/ZipCodeRenderer/hook.js +108 -0
- package/dist/esm/renderer/field-renderers/ZipCodeRenderer/index.js +247 -0
- package/dist/esm/renderer/index.js +4 -0
- package/dist/esm/renderer/styles.js +21 -0
- package/dist/esm/renderer/types.js +0 -0
- package/dist/esm/tests/base/flowBase.js +105 -0
- package/dist/esm/tests/base/index.js +22 -0
- package/dist/esm/tests/flows/checkboxRendererFlows.js +65 -0
- package/dist/esm/tests/flows/dateRendererFlows.js +850 -0
- package/dist/esm/tests/flows/dropdownRendererFlows.js +571 -0
- package/dist/esm/tests/flows/largeTextRendererFlows.js +79 -0
- package/dist/esm/tests/flows/numberRendererFlows.js +155 -0
- package/dist/esm/tests/flows/radioRendererFlows.js +95 -0
- package/dist/esm/tests/flows/textRendererFlows.js +329 -0
- package/dist/esm/tests/flows/toggleRendererFlows.js +86 -0
- package/dist/esm/tests/flows/zipCodeRendererFlows.js +1143 -0
- package/dist/esm/utils/dateHelper.js +35 -0
- package/dist/types/lib/bll/constants.d.ts +9 -0
- package/dist/types/lib/bll/formatters/booleanFormatter.d.ts +5 -0
- package/dist/types/lib/bll/formatters/dateFormatter.d.ts +28 -0
- package/dist/types/lib/bll/formatters/dropdownFormatter.d.ts +6 -0
- package/dist/types/lib/bll/formatters/factory/index.d.ts +71 -0
- package/dist/types/lib/bll/formatters/index.d.ts +2 -0
- package/dist/types/lib/bll/formatters/numberFormatter.d.ts +6 -0
- package/dist/types/lib/bll/formatters/phoneFormatter.d.ts +7 -0
- package/dist/types/lib/bll/formatters/regexFormatter.d.ts +5 -0
- package/dist/types/lib/bll/formatters/ssnFormatter.d.ts +5 -0
- package/dist/types/lib/bll/formatters/textFormatter.d.ts +6 -0
- package/dist/types/lib/bll/formatters/zipFormatter.d.ts +5 -0
- package/dist/types/lib/bll/index.d.ts +20 -0
- package/dist/types/lib/bll/ssf/index.d.ts +25 -0
- package/dist/types/lib/bll/ssf/loan.d.ts +16 -0
- package/dist/types/lib/bll/ssf/loconnect.d.ts +15 -0
- package/dist/types/lib/bll/ssf/ssfBase.d.ts +23 -0
- package/dist/types/lib/bll/ssf/types.d.ts +99 -0
- package/dist/types/lib/bll/types.d.ts +47 -0
- package/dist/types/lib/bll/validators/dateValidator.d.ts +16 -0
- package/dist/types/lib/bll/validators/emailValidator.d.ts +4 -0
- package/dist/types/lib/bll/validators/factory/index.d.ts +15 -0
- package/dist/types/lib/bll/validators/index.d.ts +2 -0
- package/dist/types/lib/bll/validators/maxCharValidator.d.ts +4 -0
- package/dist/types/lib/bll/validators/requiredValidator.d.ts +4 -0
- package/dist/types/lib/bll/validators/zipValidator.d.ts +5 -0
- package/dist/types/lib/core/index.d.ts +29 -0
- package/dist/types/lib/demo/config.d.ts +11 -0
- package/dist/types/lib/demo/index.d.ts +1 -0
- package/dist/types/lib/renderer/FieldRenderer.d.ts +5 -0
- package/dist/types/lib/renderer/base/hooks/fieldDescription.d.ts +5 -0
- package/dist/types/lib/renderer/base/hooks/fieldDisabled.d.ts +10 -0
- package/dist/types/lib/renderer/base/hooks/fieldGoTo.d.ts +4 -0
- package/dist/types/lib/renderer/base/hooks/fieldLocked.d.ts +4 -0
- package/dist/types/lib/renderer/base/hooks/fieldMeta.d.ts +10 -0
- package/dist/types/lib/renderer/base/hooks/fieldSubscribers.d.ts +6 -0
- package/dist/types/lib/renderer/base/hooks/fieldValidation.d.ts +9 -0
- package/dist/types/lib/renderer/base/hooks/fieldValue.d.ts +31 -0
- package/dist/types/lib/renderer/base/hooks/hookBase.d.ts +9 -0
- package/dist/types/lib/renderer/base/hooks/index.d.ts +19 -0
- package/dist/types/lib/renderer/base/renderer.d.ts +43 -0
- package/dist/types/lib/renderer/base/rendererValidator.d.ts +15 -0
- package/dist/types/lib/renderer/factory/index.d.ts +5 -0
- package/dist/types/lib/renderer/field-renderers/AddonRenderer.d.ts +12 -0
- package/dist/types/lib/renderer/field-renderers/CheckboxRenderer.d.ts +7 -0
- package/dist/types/lib/renderer/field-renderers/DateRenderer.d.ts +13 -0
- package/dist/types/lib/renderer/field-renderers/DropdownRenderer/hook.d.ts +23 -0
- package/dist/types/lib/renderer/field-renderers/DropdownRenderer/index.d.ts +12 -0
- package/dist/types/lib/renderer/field-renderers/LargeTextRenderer.d.ts +17 -0
- package/dist/types/lib/renderer/field-renderers/NumberRenderer.d.ts +12 -0
- package/dist/types/lib/renderer/field-renderers/RadioGroupRenderer.d.ts +8 -0
- package/dist/types/lib/renderer/field-renderers/RadioRenderer.d.ts +8 -0
- package/dist/types/lib/renderer/field-renderers/TextRenderer.d.ts +8 -0
- package/dist/types/lib/renderer/field-renderers/ToggleRenderer.d.ts +24 -0
- package/dist/types/lib/renderer/field-renderers/ZipCodeRenderer/helper.d.ts +48 -0
- package/dist/types/lib/renderer/field-renderers/ZipCodeRenderer/hook.d.ts +17 -0
- package/dist/types/lib/renderer/field-renderers/ZipCodeRenderer/index.d.ts +9 -0
- package/dist/types/lib/renderer/index.d.ts +2 -0
- package/dist/types/lib/renderer/styles.d.ts +7 -0
- package/dist/types/lib/renderer/types.d.ts +325 -0
- package/dist/types/lib/tests/base/flowBase.d.ts +13 -0
- package/dist/types/lib/tests/base/index.d.ts +6 -0
- package/dist/types/lib/tests/flows/checkboxRendererFlows.d.ts +9 -0
- package/dist/types/lib/tests/flows/dateRendererFlows.d.ts +120 -0
- package/dist/types/lib/tests/flows/dropdownRendererFlows.d.ts +92 -0
- package/dist/types/lib/tests/flows/largeTextRendererFlows.d.ts +9 -0
- package/dist/types/lib/tests/flows/numberRendererFlows.d.ts +11 -0
- package/dist/types/lib/tests/flows/radioRendererFlows.d.ts +10 -0
- package/dist/types/lib/tests/flows/textRendererFlows.d.ts +16 -0
- package/dist/types/lib/tests/flows/toggleRendererFlows.d.ts +10 -0
- package/dist/types/lib/tests/flows/zipCodeRendererFlows.d.ts +169 -0
- package/dist/types/lib/tests/loan-field-renderer-flows.test.d.ts +1 -0
- package/dist/types/lib/utils/dateHelper.d.ts +8 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +103 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var dateHelper_exports = {};
|
|
30
|
+
__export(dateHelper_exports, {
|
|
31
|
+
calNextBusinessDay: () => calNextBusinessDay,
|
|
32
|
+
calNextPresumedRecievedDay: () => calNextPresumedRecievedDay,
|
|
33
|
+
convertToLocalDateTime: () => convertToLocalDateTime,
|
|
34
|
+
formatDateForBr: () => formatDateForBr,
|
|
35
|
+
formatISODate: () => formatISODate,
|
|
36
|
+
isHoliday: () => isHoliday,
|
|
37
|
+
isSunday: () => isSunday
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(dateHelper_exports);
|
|
40
|
+
var import_moment = __toESM(require("moment"));
|
|
41
|
+
const isSunday = (momentDateObj) => (0, import_moment.default)(momentDateObj).format("dddd") === "Sunday";
|
|
42
|
+
const isHoliday = (momentDateObj, holidays) => holidays.includes((0, import_moment.default)(momentDateObj).format("YYYY-MM-DD"));
|
|
43
|
+
const calNextBusinessDay = (dayCound, momentDateObj, holidays) => {
|
|
44
|
+
const nextDateObj = momentDateObj.add(dayCound, "d");
|
|
45
|
+
if (isSunday(nextDateObj) || isHoliday(nextDateObj, holidays)) {
|
|
46
|
+
calNextBusinessDay(dayCound, nextDateObj, holidays);
|
|
47
|
+
}
|
|
48
|
+
return nextDateObj;
|
|
49
|
+
};
|
|
50
|
+
const calNextPresumedRecievedDay = (dayCount, momentDateObj, holidays) => {
|
|
51
|
+
const nextPresumedRecievedDay = isSunday(momentDateObj) || isHoliday(momentDateObj, holidays) ? calNextBusinessDay(1, momentDateObj, holidays) : momentDateObj;
|
|
52
|
+
for (let index = 0; index < dayCount; index += 1) {
|
|
53
|
+
calNextBusinessDay(1, nextPresumedRecievedDay, holidays);
|
|
54
|
+
}
|
|
55
|
+
return nextPresumedRecievedDay;
|
|
56
|
+
};
|
|
57
|
+
const formatISODate = (date) => (0, import_moment.default)(date).utc().format("MM/DD/YYYY");
|
|
58
|
+
const formatDateForBr = (date, format) => {
|
|
59
|
+
if (!date) return date;
|
|
60
|
+
if (format === "ISO") {
|
|
61
|
+
return (0, import_moment.default)(date).format("YYYY-MM-DD");
|
|
62
|
+
}
|
|
63
|
+
return (0, import_moment.default)(date).format("MM/DD/YYYY");
|
|
64
|
+
};
|
|
65
|
+
const convertToLocalDateTime = (date) => date ? import_moment.default.utc(date).local().format("MM/DD/YYYY [at] hh:mm A") : date;
|
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
# Loan Field Renderers — Technical Documentation
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## 1. Purpose
|
|
6
|
+
|
|
7
|
+
**Loan Field Renderers** is a metadata-driven smart control system that renders loan form fields as UI components. Instead of every page manually wiring up data fetching, formatting, validation, locking, accessibility, and persistence for each field, this system encapsulates all of that behind a single declarative `<FieldRenderer>` component.
|
|
8
|
+
|
|
9
|
+
A consuming page only needs to specify:
|
|
10
|
+
|
|
11
|
+
- **`fieldId`** — the loan field identifier (e.g., `"FR0104"`)
|
|
12
|
+
- **`rendererType`** — the desired UI control (e.g., `"text"`, `"number"`, `"dropdown"`)
|
|
13
|
+
|
|
14
|
+
The system then automatically:
|
|
15
|
+
|
|
16
|
+
- Fetches field metadata (format, options, read-only, lock, maxLength, description) from SSF
|
|
17
|
+
- Fetches and formats the current field value for display
|
|
18
|
+
- Applies the correct input mask (Phone, SSN, number, date, zip)
|
|
19
|
+
- Validates user input on blur using configurable rules
|
|
20
|
+
- Parses display values back to raw data and persists to the loan object
|
|
21
|
+
- Manages lock/unlock, disabled, and read-only states
|
|
22
|
+
- Provides Go-To-Field navigation highlighting
|
|
23
|
+
- Builds ARIA accessibility attributes from field descriptions
|
|
24
|
+
- Subscribes to loan change events for live refresh
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 2. Architecture & Layers
|
|
29
|
+
|
|
30
|
+
The system follows a **layered architecture** with clear separation of concerns. Each layer has a single responsibility and communicates downward through well-defined interfaces.
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
34
|
+
│ CONSUMER / PAGE LAYER │
|
|
35
|
+
│ <FieldRenderer fieldId="FR0104" rendererType="number" /> │
|
|
36
|
+
└──────────────────────────────────┬───────────────────────────┘
|
|
37
|
+
│
|
|
38
|
+
▼
|
|
39
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
40
|
+
│ ENTRY POINT LAYER │
|
|
41
|
+
│ FieldRenderer.tsx → RendererFactory.create(rendererType) │
|
|
42
|
+
└──────────────────────────────────┬───────────────────────────┘
|
|
43
|
+
│
|
|
44
|
+
▼
|
|
45
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
46
|
+
│ RENDERER LAYER (renderer/) │
|
|
47
|
+
│ │
|
|
48
|
+
│ ┌─────────────────────┐ ┌────────────────────────────────┐ │
|
|
49
|
+
│ │ Specific Renderers │ │ Base Infrastructure │ │
|
|
50
|
+
│ │ ───────────────── │ │ ────────────────── │ │
|
|
51
|
+
│ │ TextRenderer │ │ Renderer<T> (abstract base) │ │
|
|
52
|
+
│ │ NumberRenderer │ │ RendererValidator │ │
|
|
53
|
+
│ │ DateRenderer │ │ Hooks (Mixin-composed) │ │
|
|
54
|
+
│ │ DropdownRenderer │ │ ├ FieldMeta │ │
|
|
55
|
+
│ │ ZipCodeRenderer │ │ ├ FieldValue │ │
|
|
56
|
+
│ │ CheckboxRenderer │ │ ├ FieldValidation │ │
|
|
57
|
+
│ │ ToggleRenderer │ │ ├ FieldDisabled │ │
|
|
58
|
+
│ │ RadioRenderer │ │ ├ FieldLocked │ │
|
|
59
|
+
│ │ RadioGroupRenderer │ │ ├ FieldSubscribers │ │
|
|
60
|
+
│ │ LargeTextRenderer │ │ ├ FieldGoTo │ │
|
|
61
|
+
│ │ AddonRenderer │ │ └ FieldDescription │ │
|
|
62
|
+
│ └─────────────────────┘ └────────────────────────────────┘ │
|
|
63
|
+
└──────────────────────────────────┬───────────────────────────┘
|
|
64
|
+
│
|
|
65
|
+
▼
|
|
66
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
67
|
+
│ BUSINESS LOGIC LAYER (bll/) │
|
|
68
|
+
│ │
|
|
69
|
+
│ BLL (Singleton Façade) │
|
|
70
|
+
│ ├── Formatter Factory → SSN / Phone / Number / Date / Zip │
|
|
71
|
+
│ │ Boolean / Text / Dropdown / Regex │
|
|
72
|
+
│ ├── Validator Factory → Required / Email / Date / Zip / │
|
|
73
|
+
│ │ MaxChar │
|
|
74
|
+
│ ├── SSF Service (Mixin-composed) │
|
|
75
|
+
│ │ ├ Loan → field values, metadata, lock, collections │
|
|
76
|
+
│ │ └ LoConnect → host operations, readonly, GTF, state DD │
|
|
77
|
+
│ └── Core → Logging, Exceptions, Utilities │
|
|
78
|
+
└──────────────────────────────────────────────────────────────┘
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Layer Breakdown
|
|
82
|
+
|
|
83
|
+
| Layer | Location | Responsibility |
|
|
84
|
+
| --------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
85
|
+
| **Entry Point** | `renderer/FieldRenderer.tsx` | Single public component. Delegates to `RendererFactory` based on `rendererType`. |
|
|
86
|
+
| **Renderer** | `renderer/` | UI rendering, event handling, ViewModel initialization. Each renderer extends the abstract `Renderer<T>` base class. |
|
|
87
|
+
| **Hooks** | `renderer/base/hooks/` | Composable state management classes mixed into a single `Hooks` class. Each hook handles one concern (metadata, value, validation, disabled, locked, subscribers, go-to, accessibility). |
|
|
88
|
+
| **BLL** | `bll/` | Business logic. Formatter and Validator factories, SSF data access, Core utilities. Acts as the single gateway between the renderer layer and external services. |
|
|
89
|
+
| **SSF** | `bll/ssf/` | Loan data operations. `Loan` mixin handles field CRUD; `LoConnect` mixin handles host-level operations (readonly status, Go-To-Field, state dropdown). |
|
|
90
|
+
| **Core** | `core/` | Cross-cutting concerns: structured logging and exception utilities. |
|
|
91
|
+
|
|
92
|
+
### Key Design Patterns
|
|
93
|
+
|
|
94
|
+
| Pattern | Where Used | Why |
|
|
95
|
+
| ----------------------- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
96
|
+
| **Factory** | `RendererFactory`, `FormatterFactory`, `ValidatorFactory` | Dynamic creation of renderers, formatters, and validators based on runtime type/acronym. Enables open-closed extensibility. |
|
|
97
|
+
| **Abstract Base Class** | `Renderer<T>` | Shared initialization (`initVM`), formatting/parsing, validation, BR wrapper, and prop sanitization across all renderers. |
|
|
98
|
+
| **Mixin Composition** | `Hooks`, `SSF` | Avoids deep class hierarchies. Each concern is a self-contained class mixed into a combined class using `@decorators.class.Mixins`. |
|
|
99
|
+
| **Singleton** | `BLL`, `SSF`, `FormatterFactory`, `Core` | Shared instances across renderers for consistent state and performance. |
|
|
100
|
+
| **Strategy** | Formatters, Validators | Each formatter/validator encapsulates a specific algorithm (e.g., `NumberFormatter` vs. `PhoneFormatter`). The factory selects the correct strategy at runtime. |
|
|
101
|
+
| **ViewModel** | `ViewModelT` | Encapsulates all reactive state a renderer needs, decoupling UI rendering from state management. |
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 3. High-Level Design
|
|
106
|
+
|
|
107
|
+
### Component Hierarchy
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
FieldRenderer (public API)
|
|
111
|
+
└─ RendererFactory.create(type)
|
|
112
|
+
└─ [SpecificRenderer].render() ← e.g., TextRenderer
|
|
113
|
+
├─ BRWrapper (Business Rules) ← wraps the field for BR integration
|
|
114
|
+
│ └─ subscribes to loan change + loanUpdated events
|
|
115
|
+
├─ AddonRenderer ← lock button + right addon slot
|
|
116
|
+
└─ DS Component ← e.g., DSInputText, DSCombobox
|
|
117
|
+
├─ value ← formatted via Formatter
|
|
118
|
+
├─ onChange → local state update + optional callback
|
|
119
|
+
├─ onBlur → format → validate → parse → persist to SSF
|
|
120
|
+
├─ disabled ← computed from metadata (readonly, locked)
|
|
121
|
+
└─ ARIA props ← built from field description
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### ViewModel (`ViewModelT`)
|
|
125
|
+
|
|
126
|
+
Every renderer initializes a shared ViewModel through `initVM(props)`. The ViewModel contains:
|
|
127
|
+
|
|
128
|
+
| Property | Type | Source |
|
|
129
|
+
| ------------------ | --------------------------- | ---------------------------------------------------------------------------- |
|
|
130
|
+
| `fieldMetadata` | `FieldMetadataT` | Fetched from SSF via `FieldMeta` hook |
|
|
131
|
+
| `fieldValue` | `unknown` | Fetched from SSF, formatted for display |
|
|
132
|
+
| `setFieldValue` | state setter | React `useState` |
|
|
133
|
+
| `isLockedState` | `boolean` | SSF lock status via `FieldLocked` hook |
|
|
134
|
+
| `isFieldDisabled` | `boolean` | Computed: `isReadonlyLoan OR (isLockField AND !isLockedState) OR isReadOnly` |
|
|
135
|
+
| `isSearchedField` | `boolean` | Go-To-Field highlight via `FieldGoTo` hook |
|
|
136
|
+
| `validationResult` | `IValidationResult \| null` | Set on blur after running validators |
|
|
137
|
+
| `ariaDescProps` | `AriaDescT` | Built from label + field description via `FieldDescription` hook |
|
|
138
|
+
|
|
139
|
+
### Initialization Sequence (inside `useFieldInit`)
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
1. Parallel fetch via Promise.all:
|
|
143
|
+
├─ getMetadata(fieldId) → field format, options, readonly, lock, maxLength
|
|
144
|
+
├─ isLoanReadonly() → loan-level readonly status
|
|
145
|
+
├─ getFieldLockStatus(fieldId)→ field-level lock status
|
|
146
|
+
├─ getFieldValue(fieldId) → raw field value from loan object
|
|
147
|
+
└─ isGoToField(fieldId) → whether this is the Go-To-Field target
|
|
148
|
+
|
|
149
|
+
2. Post-fetch processing:
|
|
150
|
+
├─ Format raw value using FormatterFactory → display value
|
|
151
|
+
├─ Resolve lock state from metadata.isLockField + SSF lock status
|
|
152
|
+
├─ Set readonly state
|
|
153
|
+
├─ Set Go-To-Field highlight state
|
|
154
|
+
└─ Build ARIA description props from label + metadata.description
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## 4. Sequence Diagrams
|
|
160
|
+
|
|
161
|
+
### 4.1 Mount Flow — Field Appears on Screen
|
|
162
|
+
|
|
163
|
+
```mermaid
|
|
164
|
+
sequenceDiagram
|
|
165
|
+
participant Page as Page (Consumer)
|
|
166
|
+
participant FR as FieldRenderer
|
|
167
|
+
participant Factory as RendererFactory
|
|
168
|
+
participant TR as TextRenderer
|
|
169
|
+
participant Hooks as Hooks (Mixins)
|
|
170
|
+
participant BLL as BLL
|
|
171
|
+
participant SSF as SSF
|
|
172
|
+
|
|
173
|
+
Page->>FR: <FieldRenderer fieldId="FR0104" rendererType="text" />
|
|
174
|
+
FR->>Factory: create("text")
|
|
175
|
+
Factory-->>FR: TextRenderer.render() → FC
|
|
176
|
+
|
|
177
|
+
FR->>TR: render(props)
|
|
178
|
+
TR->>Hooks: initVM(props)
|
|
179
|
+
|
|
180
|
+
rect rgb(235, 245, 255)
|
|
181
|
+
Note over Hooks,SSF: Parallel fetch via Promise.all
|
|
182
|
+
Hooks->>SSF: getMetadata(fieldId)
|
|
183
|
+
Hooks->>SSF: getFieldValue(fieldId)
|
|
184
|
+
Hooks->>SSF: getLockStatus(fieldId)
|
|
185
|
+
Hooks->>SSF: isLoanReadonly()
|
|
186
|
+
Hooks->>SSF: isGoToField(fieldId)
|
|
187
|
+
SSF-->>Hooks: metadata, value, lock, readonly, goTo
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
Hooks->>BLL: formatValue(rawValue, fieldFormat)
|
|
191
|
+
BLL-->>Hooks: displayValue
|
|
192
|
+
|
|
193
|
+
Hooks->>Hooks: compute isFieldDisabled
|
|
194
|
+
Hooks->>Hooks: build ARIA props
|
|
195
|
+
|
|
196
|
+
Hooks-->>TR: ViewModel (value, metadata, disabled, locked, validation, aria)
|
|
197
|
+
|
|
198
|
+
TR->>TR: render BRWrapper → AddonRenderer → DSInputText
|
|
199
|
+
TR-->>Page: Rendered field on screen
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### 4.2 onChange Flow — User Types
|
|
203
|
+
|
|
204
|
+
```mermaid
|
|
205
|
+
sequenceDiagram
|
|
206
|
+
participant User
|
|
207
|
+
participant TR as TextRenderer
|
|
208
|
+
participant VM as ViewModel (state)
|
|
209
|
+
participant Page as Page (Consumer)
|
|
210
|
+
|
|
211
|
+
User->>TR: keystroke
|
|
212
|
+
TR->>TR: clear GoToField highlight
|
|
213
|
+
TR->>VM: setFieldValue(typedValue)
|
|
214
|
+
VM-->>TR: UI re-renders with new value
|
|
215
|
+
|
|
216
|
+
opt onChange callback provided
|
|
217
|
+
TR->>Page: onChange(fieldId, parsedValue)
|
|
218
|
+
end
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### 4.3 onBlur Flow — User Leaves Field
|
|
222
|
+
|
|
223
|
+
```mermaid
|
|
224
|
+
sequenceDiagram
|
|
225
|
+
participant User
|
|
226
|
+
participant TR as TextRenderer
|
|
227
|
+
participant BLL as BLL
|
|
228
|
+
participant Hooks as Hooks
|
|
229
|
+
participant SSF as SSF
|
|
230
|
+
participant Page as Page (Consumer)
|
|
231
|
+
|
|
232
|
+
User->>TR: blur (leaves field)
|
|
233
|
+
|
|
234
|
+
TR->>BLL: getFormattedValue(rawInput)
|
|
235
|
+
BLL-->>TR: formattedValue
|
|
236
|
+
|
|
237
|
+
TR->>Hooks: runValidationsOnValue(formattedValue, rules)
|
|
238
|
+
|
|
239
|
+
alt Validation fails
|
|
240
|
+
Hooks-->>TR: { isValid: false, message }
|
|
241
|
+
TR->>TR: setValidationResult → show error
|
|
242
|
+
Note over TR: STOP — do not save
|
|
243
|
+
else Validation passes
|
|
244
|
+
Hooks-->>TR: { isValid: true }
|
|
245
|
+
TR->>BLL: getParsedValue(formattedValue)
|
|
246
|
+
BLL-->>TR: parsedValue (raw for storage)
|
|
247
|
+
|
|
248
|
+
opt autoFieldSet = true (default)
|
|
249
|
+
TR->>SSF: setFieldValue(fieldId, parsedValue)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
opt onBlur callback provided
|
|
253
|
+
TR->>Page: onBlur(fieldId, parsedValue)
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### 4.4 External Change Flow — Live Sync
|
|
259
|
+
|
|
260
|
+
```mermaid
|
|
261
|
+
sequenceDiagram
|
|
262
|
+
participant BR as Business Rule / Other Field
|
|
263
|
+
participant SSF as SSF
|
|
264
|
+
participant BRW as BRWrapper
|
|
265
|
+
participant TR as TextRenderer
|
|
266
|
+
participant BLL as BLL
|
|
267
|
+
participant VM as ViewModel (state)
|
|
268
|
+
|
|
269
|
+
BR->>SSF: modifies loan data
|
|
270
|
+
|
|
271
|
+
alt Specific field changed
|
|
272
|
+
SSF-)BRW: loan.change event (fieldId, oldVal, newVal)
|
|
273
|
+
Note over BRW: only reacts if fieldId matches & oldVal ≠ newVal
|
|
274
|
+
else Bulk loan update
|
|
275
|
+
SSF-)BRW: loan.loanUpdated event
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
BRW->>TR: refreshFieldFromLoan()
|
|
279
|
+
TR->>SSF: getFieldValue(fieldId)
|
|
280
|
+
SSF-->>TR: raw value
|
|
281
|
+
TR->>BLL: formatValue(rawValue, fieldFormat)
|
|
282
|
+
BLL-->>TR: displayValue
|
|
283
|
+
TR->>VM: setFieldValue(displayValue)
|
|
284
|
+
VM-->>TR: UI re-renders with updated value
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Key Lifecycle Events
|
|
288
|
+
|
|
289
|
+
| Event | What Happens |
|
|
290
|
+
| ---------------------- | --------------------------------------------------------------------------------------------------------- |
|
|
291
|
+
| **Mount** | `useFieldInit` fires → parallel SSF fetches → ViewModel populated → UI renders |
|
|
292
|
+
| **onChange** | Local state updated immediately → optional `props.onChange` callback fired |
|
|
293
|
+
| **onBlur** | Format → Validate → (if invalid, show error & stop) → Parse → Persist to SSF → `props.onBlur` callback |
|
|
294
|
+
| **Loan Change Event** | BRWrapper detects `change` event for this `fieldId` → re-fetches value from SSF → re-formats → updates UI |
|
|
295
|
+
| **Loan Updated Event** | BRWrapper detects `loanUpdated` → re-fetches and refreshes all field data |
|
|
296
|
+
| **Lock Toggle** | `callCalcForLock()` on SSF → toggle `isLockedState` → recompute `isFieldDisabled` |
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## 5. Smart Control Capabilities via Field Metadata
|
|
301
|
+
|
|
302
|
+
Field metadata (`FieldMetadataT`) is fetched once per field from SSF and drives virtually all behavior. Below is each metadata property and what the smart controls do with it.
|
|
303
|
+
|
|
304
|
+
### 5.1 Format-Driven Rendering (`fieldFormat`)
|
|
305
|
+
|
|
306
|
+
The `fieldFormat` acronym (e.g., `"D2"`, `"SS"`, `"ST"`, `"P"`) determines:
|
|
307
|
+
|
|
308
|
+
| Acronym | Format | Formatter Used | Behavior |
|
|
309
|
+
| ----------------------- | ------------------- | ------------------- | --------------------------------------------- |
|
|
310
|
+
| `SS` | SSN | `SsnFormatter` | Masks as `***-**-1234`, parses to raw digits |
|
|
311
|
+
| `P` | Phone | `PhoneFormatter` | Formats as `(123) 456-7890`, parses to digits |
|
|
312
|
+
| `I` | Integer | `NumberFormatter` | No decimal, thousands separator |
|
|
313
|
+
| `D2`–`D6` | Decimal (2-6) | `NumberFormatter` | Fixed decimal places, thousands separator |
|
|
314
|
+
| `T` | Date | `DateFormatter` | Formats to `MM/DD/YYYY` or custom format |
|
|
315
|
+
| `TD` | DateTime | `DateFormatter` | Date + time formatting |
|
|
316
|
+
| `Y` | Yes/No | `BooleanFormatter` | Converts `"Y"`/`"N"` ↔ `true`/`false` |
|
|
317
|
+
| `S` | String | `TextFormatter` | Pass-through |
|
|
318
|
+
| `ST` | State | `DropdownFormatter` | Auto-fetches state dropdown list from SSF |
|
|
319
|
+
| `Z` | Zip Code | `ZipFormatter` | 5 or 9-digit zip formatting |
|
|
320
|
+
| `RS`, `RI`, `RD2`–`RD6` | Read-Ahead variants | Same as base | Used for collection/RA fields |
|
|
321
|
+
|
|
322
|
+
The `FormatterFactory` maps acronyms to formatter instances. Each formatter implements `IFormatter<T, U>` with `format()` and `parse()` methods, enabling bidirectional conversion between display values and raw loan data.
|
|
323
|
+
|
|
324
|
+
### 5.2 Renderer–Format Compatibility Validation
|
|
325
|
+
|
|
326
|
+
`RendererValidator` ensures the `rendererType` is compatible with the `fieldFormat`:
|
|
327
|
+
|
|
328
|
+
- **number** renderer requires numeric formats (`DECIMAL_*`, `INTEGER`)
|
|
329
|
+
- **checkbox** renderer requires boolean formats (`YN`, `BOOLEAN`)
|
|
330
|
+
- **date** renderer requires date formats (`DATE`, `DATETIME`)
|
|
331
|
+
- **text/email** renderers accept anything except numeric, boolean, and date formats
|
|
332
|
+
|
|
333
|
+
A mismatch throws an error with a diagnostic log, preventing subtle bugs from incorrect configuration.
|
|
334
|
+
|
|
335
|
+
### 5.3 Dropdown Options (`fieldOptions`)
|
|
336
|
+
|
|
337
|
+
- If the metadata includes `fieldOptions`, they are mapped to `{ dsId, type, label, value }` objects for the `DSCombobox` component.
|
|
338
|
+
- **Special case**: When `fieldFormat === "ST"` (State), the system auto-fetches the state dropdown list from SSF via `getStateDropDownList()` and memoizes the result.
|
|
339
|
+
- Consumers can also pass custom `options` via props for non-metadata-driven dropdowns.
|
|
340
|
+
|
|
341
|
+
### 5.4 Lock/Unlock Field (`isLockField`)
|
|
342
|
+
|
|
343
|
+
When `isLockField` is `true` in metadata:
|
|
344
|
+
|
|
345
|
+
- The `AddonRenderer` displays a lock/unlock button next to the field
|
|
346
|
+
- Lock status is fetched from SSF via `getLockStatus(fieldId)`
|
|
347
|
+
- Toggling calls `SSF.callCalcForLock(fieldId, isLockedState)` which triggers a server-side calculation
|
|
348
|
+
- **Locked fields are disabled**: `isFieldDisabled = isLockField && !isLockedState`
|
|
349
|
+
|
|
350
|
+
### 5.5 Read-Only State (`isReadOnly`)
|
|
351
|
+
|
|
352
|
+
Two levels of read-only are checked:
|
|
353
|
+
|
|
354
|
+
- **Field-level**: `metadata.isReadOnly` — this specific field is read-only
|
|
355
|
+
- **Loan-level**: `SSF.isReadOnlyLoan()` — the entire loan is in read-only mode
|
|
356
|
+
|
|
357
|
+
The combined disabled state is: `isReadonlyLoan || (isLockField && !isLockedState) || isReadOnly`
|
|
358
|
+
|
|
359
|
+
### 5.6 Max Length Enforcement (`maxLength`)
|
|
360
|
+
|
|
361
|
+
- For **text** fields: applied directly as the HTML `maxLength` attribute
|
|
362
|
+
- For **number** fields: adjusted to account for prefix, suffix, thousands separators, and decimal points. The system calculates `totalMaxLength = integerPartLength + prefixLength + decimalSeparator + decimalPlaces + suffixLength`
|
|
363
|
+
|
|
364
|
+
### 5.7 Accessibility (`description`)
|
|
365
|
+
|
|
366
|
+
The `description` field from metadata is used to build ARIA attributes:
|
|
367
|
+
|
|
368
|
+
- If the field has a visible `label` → `aria-description` is set to the metadata description
|
|
369
|
+
- If the field has no label → `aria-label` is set to the metadata description
|
|
370
|
+
- This ensures screen readers always have meaningful context for every field
|
|
371
|
+
|
|
372
|
+
### 5.8 Contract Path & Collection Support (`contractPath`)
|
|
373
|
+
|
|
374
|
+
- Each field maps to a canonical loan contract path (e.g., `"Loan.LoanAmount"`)
|
|
375
|
+
- For **collection fields**, the contract path contains a `[%]` placeholder (e.g., `"Loan.Borrowers[%].FirstName"`) which is resolved to the actual row index at runtime via `SSF.getCollectionRowIndex()`
|
|
376
|
+
|
|
377
|
+
### 5.9 Nullable Fields (`isNullable`)
|
|
378
|
+
|
|
379
|
+
The `isNullable` flag from metadata indicates whether a field can hold `null`/empty values. This is used in conjunction with validation rules (e.g., the `required` validator checks this).
|
|
380
|
+
|
|
381
|
+
### 5.10 Validation Rules
|
|
382
|
+
|
|
383
|
+
Validation is consumer-configured via `validationRules` prop but integrates with metadata:
|
|
384
|
+
|
|
385
|
+
| Validator | Trigger | Behavior |
|
|
386
|
+
| ---------- | --------------------------------------------- | ----------------------------------- |
|
|
387
|
+
| `required` | Blur | Fails if value is empty/null |
|
|
388
|
+
| `email` | Blur (auto-added for `rendererType: "email"`) | Regex-based email validation |
|
|
389
|
+
| `date` | Blur | Validates date format and range |
|
|
390
|
+
| `zip` | Blur | Validates 5 or 9-digit zip format |
|
|
391
|
+
| `maxChar` | Blur | Checks against `options.charsLimit` |
|
|
392
|
+
|
|
393
|
+
Validators run sequentially; the first failure stops execution and displays the error message via `validationMessage` and `hasError` props on the BR wrapper.
|
|
394
|
+
|
|
395
|
+
### 5.11 Go-To-Field Highlighting
|
|
396
|
+
|
|
397
|
+
The system integrates with the host application's "Go-To-Field" (GTF) navigation:
|
|
398
|
+
|
|
399
|
+
- On mount, checks if this field is the GTF target via `SSF.getGTFSelectedFormDetails()`
|
|
400
|
+
- If matched, sets `isSearchedField = true` → applies `withHighlight` styling on the BR wrapper
|
|
401
|
+
- On user interaction (`onChange`), the highlight is cleared
|
|
402
|
+
|
|
403
|
+
### 5.12 Prop Sanitization
|
|
404
|
+
|
|
405
|
+
The `sanitize()` method on the base `Renderer` class filters out "controlled props" from the `extra` prop bag. This prevents consumers from accidentally overriding internally-managed props like `onChange`, `onBlur`, `value`, etc. The controlled props per renderer type are defined in `RENDERER_CONTROLLED_PROPS`.
|
|
406
|
+
|
|
407
|
+
### 5.13 Live Loan Synchronization
|
|
408
|
+
|
|
409
|
+
Every rendered field subscribes to two SSF events through the `BRWrapper`:
|
|
410
|
+
|
|
411
|
+
- **`loan.change`** — fired when a specific field changes; if the changed field ID matches, re-fetches and re-formats the value
|
|
412
|
+
- **`loan.loanUpdated`** — fired on bulk loan updates; re-fetches all field data
|
|
413
|
+
|
|
414
|
+
This ensures fields stay in sync when business rules, calculations, or other UI interactions modify loan data externally.
|
|
415
|
+
|
|
416
|
+
### 5.14 Auto Field Set (`autoFieldSet`)
|
|
417
|
+
|
|
418
|
+
The `autoFieldSet` flag (default `true`) controls whether the renderer automatically persists the parsed value to SSF on blur. When set to `false`, the renderer only updates local state and calls the `onBlur` callback, letting the consumer handle persistence manually.
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## Summary
|
|
423
|
+
|
|
424
|
+
| Aspect | Implementation |
|
|
425
|
+
| ---------------------- | ------------------------------------------------------------- |
|
|
426
|
+
| **Entry Point** | `<FieldRenderer fieldId={...} rendererType={...} />` |
|
|
427
|
+
| **Renderer Selection** | Factory pattern → 12 renderer types |
|
|
428
|
+
| **State Management** | ViewModel pattern with React hooks composed via Mixins |
|
|
429
|
+
| **Data Access** | SSF abstraction layer (Loan + LoConnect mixins) |
|
|
430
|
+
| **Formatting** | Bidirectional format/parse via strategy-based formatters |
|
|
431
|
+
| **Validation** | Pluggable validator chain via factory |
|
|
432
|
+
| **Accessibility** | ARIA attributes auto-generated from metadata |
|
|
433
|
+
| **Synchronization** | Event-driven via SSF `change` and `loanUpdated` subscriptions |
|
|
434
|
+
| **Extensibility** | Add new renderer → extend `Renderer<T>`, register in factory |
|