import * as i0 from '@angular/core';
import { OnChanges, EventEmitter, SimpleChanges, ChangeDetectorRef, OnInit, AfterViewInit, OnDestroy, ElementRef, QueryList, PipeTransform, NgZone } from '@angular/core';
import * as i2 from '@angular/material/snack-bar';
import { MatSnackBar, MatSnackBarRef } from '@angular/material/snack-bar';
import * as i2$1 from '@angular/common';
import * as i3$1 from '@angular/forms';
import { FormGroup, FormArray, FormControl, FormBuilder, ValidatorFn, ControlValueAccessor, AbstractControl, ValidationErrors } from '@angular/forms';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import * as i3$2 from '@angular/router';
import { Router, ActivatedRoute } from '@angular/router';
import { BehaviorSubject, Subject, Observable } from 'rxjs';
import * as i8$1 from '@angular/cdk/overlay';
import { ScrollStrategy, Overlay, ConnectedPosition } from '@angular/cdk/overlay';
import * as i10 from '@angular/material/core';
import { DateAdapter } from '@angular/material/core';
import { DomSanitizer, SafeResourceUrl, SafeHtml } from '@angular/platform-browser';
import * as i1 from '@angular/material/card';
import * as i3 from '@angular/material/checkbox';
import * as i4 from '@angular/material/divider';
import * as i5 from '@angular/material/select';
import * as i6 from '@angular/material/radio';
import * as i7 from '@angular/material/dialog';
import * as i8 from '@angular/material/form-field';
import * as i9 from '@angular/material/datepicker';
import * as i11 from '@angular/material/input';
import * as i12 from '@angular/material/icon';
import * as i13 from '@angular/material/progress-spinner';
import * as i14 from '@angular/material/tabs';
import * as i15 from '@angular/material/button';
import * as i16 from '@angular/material/menu';
import * as i17 from '@angular/material/progress-bar';
import * as i18 from '@angular/material/tooltip';
import { TooltipPosition } from '@angular/material/tooltip';
import * as i19 from '@angular/material/slider';
import * as i20 from '@angular/material/list';
import * as i21 from '@angular/material/chips';
import * as i22 from '@angular/material/sort';
import * as i23 from '@angular/material/autocomplete';
import * as i24 from '@angular/material/slide-toggle';
import * as i25 from '@angular/material/button-toggle';
import * as i26 from '@angular/material/paginator';
import * as i27 from '@angular/material/table';
import * as i28 from '@angular/material/expansion';
import * as i29 from '@angular/cdk/accordion';
import * as i11$2 from 'ngx-quill';
import * as i11$1 from '@angular/cdk/scrolling';
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
import * as i5$1 from '@angular/cdk/drag-drop';
import { CdkDragDrop } from '@angular/cdk/drag-drop';
type ButtonVariant = 'primary' | 'warning' | 'outline' | 'secondary' | 'success' | 'danger' | 'danger-outline' | 'text';
interface ButtonLabels {
iconAltText?: string;
}
interface FormSchema {
entityType: string;
label: string;
formType: 'SECTION' | 'STEPPER';
showTitle?: boolean;
showDescription?: boolean;
description?: string;
metadata?: {
[key: string]: any;
};
/**
* When true, top-level GROUP children of sectionConfig are rendered as
* a horizontal stepper at the top, showing one section at a time.
* Navigate between sections via the Next/Previous buttons in the host app.
*/
sectionStepper?: boolean;
sectionConfig?: SectionConfig;
stepperConfig?: StepperConfig;
submitConfig?: SubmitConfig;
/**
* Configures the action bar shown at the bottom of the form.
* Supports Cancel, Save as Draft, and Submit buttons with flexible layout.
* If omitted, the default Submit (and stepper Prev/Next) behaviour is unchanged.
*/
actionBarConfig?: ActionBarConfig;
showActions?: boolean;
/** Full token string passed to all library API calls (e.g. "Bearer eyJ…") */
token?: string;
/** HTTP header name to use for the token (default: "Authorization") */
tokenHeader?: string;
/** Custom label keys for form actions */
labels?: FormLabels;
/** Config for form editing (GET to load, PATCH/PUT to submit) */
editConfig?: EditConfig;
}
interface FormLabels {
nextLabel?: string;
submitLabel?: string;
previousLabel?: string;
addLabel?: string;
removeLabel?: string;
/** File upload error messages. Supports placeholders: {fileName}, {maxSizeMB}, {maxFiles} */
fileTypeError?: string;
fileSizeError?: string;
maxFilesError?: string;
fileUploadFailed?: string;
fileDeleteFailed?: string;
}
interface SubmitConfig {
apiUrl: string;
method?: 'POST' | 'PUT' | 'PATCH';
successMessage?: string;
errorMessage?: string;
redirectUrl?: string;
extraPayload?: {
[key: string]: any;
};
snackbarConfig?: {
duration?: number;
horizontalPosition?: 'start' | 'center' | 'end' | 'left' | 'right';
verticalPosition?: 'top' | 'bottom';
showCloseButton?: boolean;
};
}
/**
* Describes what happens when an action bar button is clicked.
* One ActionConfig shape works for every button.
*/
interface ActionConfig {
/**
* Action kind.
* 'submit' -> Validates and submits form using submitConfig/editConfig.
* 'draft' -> Saves form data without full validation.
* 'navigate' -> Navigates to redirectUrl.
* 'api' -> Fires an API call then optionally navigates.
* 'emit' -> Emits actionClick event for custom handling.
* 'next' -> Advances to next step (stepper only).
* 'prev' -> Goes back to previous step (stepper only).
*/
kind: 'submit' | 'draft' | 'navigate' | 'api' | 'emit' | 'next' | 'prev';
/** URL for 'navigate' or 'api' callbacks. */
redirectUrl?: string;
/** API endpoint for 'api' actions. */
apiUrl?: string;
/** HTTP method for 'api' actions. @default 'POST' */
method?: 'POST' | 'PUT' | 'PATCH' | 'DELETE';
/** Static extra payload merged into 'api' or 'draft' requests. */
extraPayload?: {
[key: string]: any;
};
/** Snackbar messages for 'api' or 'submit'/'draft' actions. */
successMessage?: string;
errorMessage?: string;
snackbarConfig?: {
duration?: number;
horizontalPosition?: 'start' | 'center' | 'end' | 'left' | 'right';
verticalPosition?: 'top' | 'bottom';
showCloseButton?: boolean;
};
}
/**
* Button configuration focusing on visuals and layout.
* All logic is delegated to the 'action' property.
*/
interface ActionButtonConfig {
/** Unique identifier for the button. */
id: string;
/** Label (i18n key or text). */
label?: string;
/** Button style variant. */
variant?: ButtonVariant | string;
/** Bar alignment. @default 'right' */
alignment?: 'left' | 'right';
/** Display order (lower = first). */
order?: number;
/** Visibility. @default false */
hidden?: boolean;
/** State. @default false */
disabled?: boolean;
/**
* When true and sectionStepper is active, this button is only visible
* on the last step. Use this for Submit buttons that should not appear
* on intermediate steps.
*/
showOnLastStepOnly?: boolean;
/** Action logic. */
action: ActionConfig;
}
/**
* Action bar configuration.
*/
interface ActionBarConfig {
/** Flexibly ordered list of action buttons. */
buttons: ActionButtonConfig[];
}
interface EditConfig {
loadApiUrl: string;
submitApiUrl: string;
submitMethod?: 'PATCH' | 'PUT' | 'POST';
successMessage?: string;
errorMessage?: string;
redirectUrl?: string;
extraPayload?: {
[key: string]: any;
};
snackbarConfig?: {
duration?: number;
horizontalPosition?: 'start' | 'center' | 'end' | 'left' | 'right';
verticalPosition?: 'top' | 'bottom';
showCloseButton?: boolean;
};
}
interface SectionConfig {
children: FieldConfig[];
allowMulti?: boolean;
name?: string;
label?: string;
/** Configuration for the card-based multi-save UI (FAQ style) */
multiSaveConfig?: MultiSaveConfig;
isEnabled?: boolean;
}
interface MultiSaveConfig {
/** If TRUE, enable the Save/Cancel card-based flow for this repeater */
active?: boolean;
/**
* The name of the field to show as the main 'heading' in the collapsed card.
* Typically matches the question or name.
*/
summaryField?: string;
/**
* Optional name of the field to show as the sub-text in the collapsed card.
* Typically matches the answer or description.
*/
descriptionField?: string;
/**
* Custom label key for the 'Add' button. If omitted, defaults to
* '+ Add a [label]'.
*/
addLabel?: string;
}
interface StepperConfig {
children: FieldConfig[];
showStep?: boolean;
isHorizontal?: boolean;
}
/**
* Describes a clickable action icon rendered as a suffix inside a TEXT_INPUT
* or NUMBER_INPUT field. Multiple icons can be shown side-by-side.
* When clicked, the field name and actionId are emitted via the
* SmartFormComponent's `suffixActionClick` output.
*/
interface SuffixActionIcon {
/** Material icon name (e.g. 'edit', 'refresh', 'check', 'lock') */
icon: string;
/** Unique action identifier emitted on click (e.g. 'enable_edit', 'reset_code') */
actionId: string;
/** Optional tooltip shown on hover */
tooltip?: string;
/** Optional custom color override (e.g. '#16A34A' for a green check icon) */
color?: string;
}
interface FieldConfig {
name?: string;
label?: string;
type: string;
subType?: string;
visible?: boolean;
visibilityExpression?: string;
/**
* A boolean expression string (same syntax as visibilityExpression) evaluated
* at runtime to dynamically toggle the `required` validator on this control.
* When omitted, the static `required` boolean governs validation as before —
* fully backwards-compatible.
* Example: "[12,15].indexOf(Number(sessionTypeId)) !== -1"
*/
requiredExpression?: string;
isEnabled?: boolean;
required?: boolean;
disabled?: boolean;
defaultValue?: any;
placeholder?: string;
hint?: string;
/** Dot-notation path for nested payload mapping (e.g., 'status.code') */
payloadPath?: string;
/**
* Column span in a 12-column grid (1–12).
* Use this on any field or ROW to control its width.
* Examples: 3 = 25%, 4 = 33%, 6 = 50%, 12 = 100% (default).
* When a field is inside a ROW, the ROW children share space via colSpan.
* When a field is a direct section child (not inside a ROW), colSpan wraps
* it in the section-level 12-col grid automatically.
*/
colSpan?: number;
/** Custom CSS class for the field container */
className?: string;
/** Unit or symbol shown before the input */
prefix?: string;
/** Unit or symbol shown after the input (e.g. "%", "Students") */
suffix?: string;
/** Whether the field is read-only (shows lock icon) */
readonly?: boolean;
/**
* Used by the Form Field Configuration module (`lib-form-field-configuration`).
* When true, this field's/section's visibility CANNOT be turned off in the
* configurator UI — it is always shown to end users. The visibility toggle is
* rendered as a locked indicator instead of an interactive control.
* Independent of `readonly`, which controls the input's edit state in the
* actual rendered form, not the configurator.
*/
lockVisibility?: boolean;
/**
* Used by the Form Field Configuration module (`lib-form-field-configuration`).
* When true, this field's mandatory (required) state CANNOT be changed in the
* configurator UI. The "Mandatory" control is rendered read-only, preserving
* whatever `required` value the schema shipped with.
*/
lockMandatory?: boolean;
/**
* Clickable action icons rendered as suffixes inside the input.
* Ignored when `readonly` is true (the built-in lock icon takes precedence).
* Each icon emits a `suffixActionClick` event with `{ fieldName, actionId }`.
*/
suffixActionIcons?: SuffixActionIcon[];
sectionConfig?: SectionConfig;
/**
* Cross-field validation config for SUBFIELDS groups.
* Applied as a group-level validator on the nested FormGroup.
*/
onChange?: string;
onValidate?: string;
errorMessage?: string;
textConfig?: TextConfig;
emailConfig?: EmailConfig;
phoneConfig?: PhoneConfig;
numberConfig?: NumberConfig;
dateConfig?: DateConfig;
timeConfig?: TimeConfig;
optionConfig?: OptionConfig$1;
autocompleteConfig?: AutocompleteConfig;
generatedConfig?: GeneratedConfig;
rangeConfig?: RangeConfig;
attachmentConfig?: AttachmentConfig;
locationConfig?: LocationConfig;
ratingConfig?: RatingConfig;
richTextConfig?: RichTextConfig;
linkListConfig?: LinkListConfig;
children?: FieldConfig[];
}
interface TextConfig {
length?: LengthConstraint;
pattern?: string;
patternMessage?: string;
inputType?: string;
/**
* Name of another field in the same FormGroup whose value must equal this
* field's value (e.g. "password" on a confirmPassword field).
* Validation runs bi-directionally: whichever field changes last triggers
* the check on the field that carries matchField config.
*/
matchField?: string;
showCharCount?: boolean;
}
interface LengthConstraint {
min?: number;
max?: number;
}
interface NumberConfig {
min?: number;
max?: number;
precision?: number;
step?: number;
}
interface DateConfig {
allowFuture?: boolean;
/** When false, dates before today are disabled (today is the minimum). When true (default), all past dates are allowed. */
allowPast?: boolean;
minDate?: string;
maxDate?: string;
/** When true, the text input is readonly (picker-only, no keyboard entry). */
inputReadonly?: boolean;
/** Name of a sibling field whose value is used as the dynamic minimum date. */
minDateField?: string;
/**
* Fixes this field's picker to a specific entry granularity — no per-user toggle.
* 'DAY' (default, or omitted) = today's full day+month+year picker, unchanged.
* 'MONTH' = the picker opens straight to the year grid; picking a month commits that
* month with day=1 and closes immediately (the day grid is never shown).
* 'YEAR' = the picker opens to the year grid; picking a year commits Jan 1 of that year
* and closes immediately (neither the month nor day grid is ever shown).
* Opt-in and additive: fields that don't set this keep today's default behavior.
*/
dateGranularity?: 'DAY' | 'MONTH' | 'YEAR';
}
interface TimeConfig {
/** Explicit minimum time in "HH:mm" 24-hour format (e.g. "09:00"). */
minTime?: string;
/** Explicit maximum time in "HH:mm" 24-hour format (e.g. "18:00"). */
maxTime?: string;
/** When true, the input is readonly. */
inputReadonly?: boolean;
/**
* Name of a sibling TIME field whose value is used as the dynamic minimum time.
* When the sibling changes, this field's minimum updates and any now-invalid
* value (earlier than the new minimum) is cleared. Mirrors DateConfig.minDateField.
*/
minTimeField?: string;
/**
* Rendering variant.
* 'default' -> keeps the existing native (no UI change).
* 'wheel' -> activates the drum-roll wheel picker (lib-time-picker).
* Default: 'default' — existing behaviour preserved unless explicitly set to 'wheel'.
*/
variant?: 'default' | 'wheel';
/**
* Hour display mode for the wheel variant only.
* '12' -> 01–12 columns + AM/PM column, outputs "hh:mm AM/PM".
* '24' -> 00–23 columns, outputs "HH:mm".
* Default: '12'.
*/
mode?: '12' | '24';
/**
* Minute increment step for the wheel variant.
* Accepted values: 1, 5, 10, 15, 30.
* Default: 1.
*/
minuteStep?: number;
/** Placeholder text override for the wheel picker trigger field. */
placeholder?: string;
}
/**
* Configuration for enabling search functionality inside DROPDOWN fields.
* Supports both client-side (local) and server-side (remote GET) filtering.
*/
interface DropdownSearchConfig {
/** Whether to display a search input inside the dropdown panel. */
enabled: boolean;
/** Filtering mode. 'local' filters client-side (default). 'server' queries the API on typing via GET. */
mode?: 'local' | 'server';
/** Query parameter key for the search term sent to the API (default: 'search'). Only used in 'server' mode. */
searchKey?: string;
/** Handling mode: 'standard' (e.g. ?search=term) or 'nested_string' (e.g. ?params=...--SEARCH_TEXT=term) */
handling?: 'standard' | 'nested_string';
/** Minimum characters required before triggering a server-side search (default: 3). Only used in 'server' mode. */
minSearchLength?: number;
/** Debounce delay in milliseconds before firing search (default: 300). */
debounceTime?: number;
}
interface NestedStringConfig$1 {
/** Name of the URL query parameter holding the packed string. Default: 'params' */
paramName: string;
/** Static base string prepended before dynamic parameters. E.g. 'MARKET_ID=5' */
baseValue?: string;
/** Delimiter string between key-value pairs. Default: '--' */
separator: string;
/** Key-value assignment operator. Default: '=' */
assignment?: string;
}
interface QueryParamsConfig$1 {
/** Query parameter key for page index. Default: 'page' */
pageKey?: string;
/** Query parameter key for page size. Default: 'size' */
sizeKey?: string;
/** Page index offset adjustment (e.g. -1 or 0 or 1). Default: 0 */
pageIndexOffset?: number;
/** Handling mode: 'standard' or 'nested_string' */
filterHandling?: 'standard' | 'nested_string';
/** Nested string configuration for Dataset APIs */
nestedStringConfig?: NestedStringConfig$1;
}
interface TotalCountConfig {
/** 'same' (count returned in data response) or 'separate' (dedicated count endpoint). Default: 'same' */
source?: 'same' | 'separate';
/** Dedicated Count API URL (required when source === 'separate') */
apiUrl?: string;
/** Dot-notation path to extract count (e.g. '0.totalCount', '[0].totalCount', 'totalElements', 'data.total') */
responsePath?: string;
}
interface DropdownPaginationConfig {
/** Enable server-side pagination. */
enabled: boolean;
/** 'loadMore' button or 'infiniteScroll' on scroll. Default: 'loadMore' */
mode?: 'loadMore' | 'infiniteScroll';
/** Page size per request. Default: 10 */
pageSize?: number;
/** Query param for page index (shorthand when queryParamsConfig is not provided). Default: 'page' */
pageKey?: string;
/** Query param for page size (shorthand when queryParamsConfig is not provided). Default: 'size' */
sizeKey?: string;
/** 0 for 0-indexed APIs, 1 for 1-indexed APIs. Default: 0 */
pageOffset?: number;
/** Configuration for dataset separate count API or same-response count parsing */
totalCountConfig?: TotalCountConfig;
/** Shorthand for totalCountConfig.responsePath */
totalCountPath?: string;
}
interface OptionConfig$1 {
optionClass?: string;
optionUrl?: string;
apiUrl?: string;
apiUrls?: string[];
/** HTTP method for option API requests. Default: 'GET' */
apiMethod?: 'GET' | 'POST' | 'PUT' | 'PATCH';
/** Custom request payload body sent with POST/PUT/PATCH requests. */
apiPayload?: any;
dataPath?: string;
labelPath?: string;
valuePath?: string;
dependencies?: {
[queryParam: string]: string;
};
sortBy?: string;
sortDirection?: 'ASC' | 'DESC';
layout?: 'row' | 'column';
optionList?: OptionItem[];
/** Configuration for enabling search functionality inside the dropdown panel. */
searchConfig?: DropdownSearchConfig;
/** Query parameters configuration matching smart-table (for pagination and dataset APIs). */
queryParamsConfig?: QueryParamsConfig$1;
/** Server-side pagination configuration (loadMore or infiniteScroll). */
pagination?: DropdownPaginationConfig;
/** Nested string config shorthand for Dataset APIs. */
nestedStringConfig?: NestedStringConfig$1;
/** When true, renders a 'Select All' checkbox at the top of a MULTIPLE select dropdown. */
showSelectAll?: boolean;
/** When true, displays a loading spinner during options API requests. */
showLoader?: boolean;
/**
* When true, a plain `optionList`-only SINGLE DROPDOWN (no `searchConfig`/`pagination`) renders
* the same styled overlay/chevron panel used by searchable and paginated dropdowns, instead of
* a native `` — purely for visual consistency with sibling fields. No search box or
* pagination is added.
*/
customUI?: boolean;
/** Edit-mode lookup for resolving primitive initial values (id/code) into full option objects via targeted API call. */
lookupConfig?: LookupConfig;
}
/**
* Configuration for resolving primitive initial values (id/code) into full
* option objects during edit-mode form initialization.
* Only fires when selectedOptionsData is absent and initialValues contains
* a primitive (not a full object).
*/
interface LookupConfig {
/** Endpoint URL. Supports {value} placeholder for single-item GET. */
apiUrl: string;
/** HTTP method. Default: 'GET'. Same convention as OptionConfig.apiMethod. */
apiMethod?: 'GET' | 'POST';
/** Static base payload for POST. Lookup value(s) merged via paramName key. */
apiPayload?: any;
/** Parameter key for the lookup value.
* GET: query param (?id=2415 or ?ids=5,12,18)
* POST: body key ({ "codes": ["MATH_01"] })
* Default: 'id' (single) / 'ids' (multiple). */
paramName?: string;
/** Response path to extract results. Falls back to parent optionConfig.dataPath. */
dataPath?: string;
/** Custom HTTP headers. Same convention as AutocompleteConfig.headers. */
headers?: {
[key: string]: string;
};
}
interface AutocompleteDisplayField {
/** Dot-notation path to the value in the API response item (e.g. 'login', 'contact.phone'). */
path: string;
/**
* How to render the value.
* Built-in: 'text' | 'email' | 'phone' | 'image'.
* Can be any string for custom logic/styling.
*/
type?: 'text' | 'email' | 'phone' | 'image' | string;
/** Optional Material Icon name to show (e.g. 'location_on', 'calendar_today', 'person'). */
icon?: string;
/** Optional label prefix shown before the value (e.g. 'Email: '). */
label?: string;
/** Custom CSS class to apply to this display item. */
className?: string;
}
/**
* Configuration specific to the AUTOCOMPLETE field type.
* For detailed documentation and examples, see documentation/smart-form.md.
*/
interface AutocompleteConfig {
/** HTTP method for the options API. Defaults to 'GET'. */
method?: 'GET' | 'POST' | 'PUT' | 'PATCH';
/** Static request body sent with POST/PUT/PATCH requests. */
body?: any;
/** Static query parameters to append to the API URL on every request. */
queryParams?: {
[key: string]: any;
};
/** Custom HTTP headers to send with the API request (e.g. Authorization, X-TENANT). */
headers?: {
[key: string]: string;
};
/**
* Template string for building a composite label from multiple fields.
* Use {fieldName} placeholders. E.g. '{firstName} {lastName} ({login})'.
* Takes precedence over optionConfig.labelPath if both are set.
*/
labelTemplate?: string;
/**
* One or more extra fields to render below the main label inside each dropdown option.
*
* Accepts:
* - A plain string → treated as a single dot-notation path rendered as 'text'.
* Backward-compatible with the old `displayPath` string.
* - An array of AutocompleteDisplayField objects → full control over icon,
* type (text | email | phone | image), and optional label prefix.
*
* Examples:
* "displayFields": "login"
* "displayFields": [
* { "path": "login", "type": "email" },
* { "path": "phone", "type": "phone" },
* { "path": "photoUrl", "type": "image" }
* ]
*/
displayFields?: string | AutocompleteDisplayField[];
/** Query parameter key appended to the URL when the user types (e.g. 'searchTerm', 'q'). */
searchParam?: string;
/** Alias for 'searchParam'. */
searchKey?: string;
/** Minimum characters to type before a server request fires (default: 1). */
searchMinLength?: number;
/** Debounce delay in ms before firing the search request (default: 300ms server-side, 150ms local). */
searchDebounce?: number;
}
interface EmailConfig {
defaultDomain?: string;
allowedDomains?: string[];
blockedDomains?: string[];
}
interface PhoneConfig {
prefixCountryCode?: boolean;
defaultCountryCode?: string;
supportedCountryCodeLocale?: string[];
}
interface OptionItem {
label: string;
code: any;
value?: any;
hint?: string;
colSpan?: number;
}
interface GeneratedConfig {
formula: string;
variables?: string[];
}
interface RangeConfig {
min?: number;
max?: number;
step?: number;
minDate?: string;
maxDate?: string;
}
/**
* Describes a single query-parameter for a parameterised API URL.
* Supports static values (baked into the JSON config) and dynamic values
* resolved at runtime from a context object via dot-notation `sourcePath`.
*
* Used inside `LibraryUploadConfig.params` to declaratively list all
* query params the library-image sync API needs.
*/
interface ApiQueryParam {
/** The query-param key sent to the backend (e.g. 'entityType', 'completeUrl'). */
key: string;
/**
* A static value baked into the JSON config
* (e.g. 'ENTITY_TYPE.OPPORTUNITY_GALLERY').
* Leave unset when the value must be resolved dynamically at runtime.
*/
staticValue?: string;
/**
* A dot-notation path resolved against a runtime context object
* (e.g. 'libraryItem.url'). Takes precedence over `staticValue`
* when the context provides a non-null value.
*/
sourcePath?: string;
/**
* When true the HTTP request is aborted if this param cannot be resolved
* to a non-empty value.
*/
required?: boolean;
}
/**
* Structured config for the library-image sync POST API.
* Declare each query param as an `ApiQueryParam` so the set can grow
* without any code changes.
*
* Example:
* {
* "baseUrl": "gateway/commons-opportunity-service/api/v1/attachments/upload-url",
* "params": [
* { "key": "entityType", "staticValue": "ENTITY_TYPE.OPPORTUNITY_GALLERY", "required": true },
* { "key": "completeUrl", "sourcePath": "libraryItem.url", "required": true }
* ]
* }
*/
interface LibraryUploadConfig {
/** Base URL without any query string. */
baseUrl: string;
/**
* Declared query params. Static values are embedded in the config;
* dynamic values (e.g. `completeUrl`) are resolved at call time from
* a runtime context object using `sourcePath`.
*/
params?: ApiQueryParam[];
}
/**
* All library-image picker settings grouped under one roof.
* Used as the `libraryConfig` key inside `AttachmentConfig`.
*
* Example:
* {
* "apiUrl": "gateway/.../attachments/bulk/public?entityIds=1&entityType=...",
* "dataPath": "data",
* "urlPath": "completeURL",
* "idPath": "id",
* "uploadConfig": {
* "baseUrl": "gateway/.../attachments/upload-url",
* "params": [
* { "key": "entityType", "staticValue": "ENTITY_TYPE.OPPORTUNITY_GALLERY", "required": true },
* { "key": "completeUrl", "sourcePath": "libraryItem.url", "required": true }
* ]
* }
* }
*/
interface LibraryConfig {
/** API endpoint (GET) to load the library image list. */
apiUrl: string;
/** Dot-notation path to the image array in the API response (e.g. 'data.items'). */
dataPath?: string;
/** Dot-notation path to the image URL within each item (e.g. 'completeURL'). */
urlPath?: string;
/** Dot-notation path to the image ID within each item (e.g. 'id'). */
idPath?: string;
/**
* Structured config for the library-image sync POST API.
* Declare each query param as an `ApiQueryParam` so the set can
* grow without any code changes.
*/
uploadConfig?: LibraryUploadConfig;
}
/**
* Unified attachment / file-upload configuration.
* Used by FILE_UPLOAD fields for any kind of upload — images, documents, PDFs, etc.
*/
interface AttachmentConfig {
/** Allow multiple file selection (default: false) */
multiple?: boolean;
/** Max number of files when multiple=true (default: 10) */
maxFiles?: number;
/** Max file size per file in MB (default: 10) */
maxSizeMB?: number;
/** Accepted MIME types or extensions, e.g. '.pdf,.jpg,image/*' */
accept?: string;
/** Human-readable hint shown in the drop zone, e.g. 'JPG, PNG, PDF (max 5 MB)' */
acceptLabel?: string;
/** Legacy: explicit list of allowed extensions (e.g. ['.pdf', '.jpg']) */
allowedExtensions?: string[];
/**
* API endpoint to upload the file to. When provided, the file is POSTed as
* multipart/form-data and the returned URL is stored as dataUrl instead of
* the base64 data URL produced by FileReader.
*/
uploadUrl?: string;
/**
* Entity type sent along with the upload request (e.g. 'ENTITY_TYPE.SESSION').
* Only relevant when uploadUrl is set.
*/
entityType?: string;
/**
* API endpoint to delete the file. Called when an uploaded file with an ID != 0 is removed.
*/
deleteUrl?: string;
/**
* All library-image picker settings (API, response paths, sync upload).
* Replaces the former flat `libraryApiUrl`, `libraryDataPath`,
* `libraryUrlPath`, `libraryIdPath`, and `libraryUploadConfig` fields.
*/
libraryConfig?: LibraryConfig;
/** Optional description shown in the left info panel for media upload */
description?: string;
/** Optional bullet-point feature lines shown in the left info panel for media upload */
features?: string[];
}
interface LocationConfig {
/** Default active tab (e.g. 'VENUE', 'ONLINE', 'TBA'). Defaults to 'VENUE' when not provided. */
defaultTab?: string;
/** Allow multiple locations. Replaces the need for maxLocations. */
allowMulti?: boolean;
/** Maximum number of venue locations allowed. Defaults to 5 if allowMulti is true. */
maxLocations?: number;
/** Placeholder for the venue search input */
venuePlaceholder?: string;
/** Google Maps API Key – required for map rendering and autocomplete */
googleMapsApiKey?: string;
/** Height of the embedded Google Map. Defaults to '300px'. */
mapHeight?: string;
/** Default map center latitude when no locations are added (e.g., India: 20.5937) */
defaultLat?: number;
/** Default map center longitude when no locations are added (e.g., India: 78.9629) */
defaultLng?: number;
/** Default zoom level when no locations are added (e.g., 4) */
defaultZoom?: number;
/** Placeholder for the online event URL input */
onlinePlaceholder?: string;
/** Show map preview after locations are added (default: true) */
showMap?: boolean;
/** Whether the current location button is enabled inside venue tab */
enableCurrentLocation?: boolean;
/** @deprecated Use showMap instead */
enableMapPicker?: boolean;
}
/** A single venue location picked from Google Places autocomplete. */
interface LocationItem {
uuid?: string;
isActive?: boolean;
id?: number;
locationCode?: string;
latitude?: number;
longitude?: number;
address?: string;
name?: string;
cityLabel?: string;
stateLabel?: string;
countryLabel?: string;
placeId?: string;
type?: string;
/** Legacy field for UI binding */
description?: string;
}
/**
* Value shape stored in the FormControl for a LOCATION field.
* `tab` indicates which mode is active.
*/
interface LocationFieldValue {
/** Active location tab (e.g. 'VENUE', 'ONLINE', 'TBA'). Defaults to 'VENUE'. */
tab: string;
/** Array of venue locations (only valid when tab === 'VENUE') */
venues?: LocationItem[];
/** Event URL (only valid when tab === 'ONLINE') */
onlineUrl?: string;
}
interface RatingConfig {
maxRating?: number;
allowHalf?: boolean;
}
interface RichTextConfig {
height?: string;
placeholder?: string;
maxLength?: number;
showCharCount?: boolean;
/**
* List of toolbar items to show, in order. Supported tokens:
* 'bold' | 'italic' | 'underline' | 'strike' | 'blockquote' | 'code' |
* 'font' | 'size' | 'color' | 'background' | 'align' |
* 'header1' | 'header2' | 'orderedList' | 'bulletList' |
* 'subscript' | 'superscript' | 'indentMinus' | 'indentPlus' |
* 'link' | 'image' | 'video' | 'clean'.
* Defaults to: ['bold', 'italic', 'underline', 'font', 'size', 'color', 'link', 'image', 'video']
*/
headerConfig?: string[];
}
interface ValidationResult {
isValid: boolean;
errorMessage?: string;
fieldErrors?: {
[key: string]: string;
};
}
/**
* A single media item stored in the MEDIA_UPLOAD field value array.
* Can represent an uploaded image (from device or library) or a YouTube video.
*/
interface MediaItem {
/** Server-assigned ID (for pre-filled items) */
id?: number;
/** Media type (e.g. 'image', 'youtube'). Defaults to 'image'. */
mediaType: string;
/** Remote URL of the image returned by the upload API, or the YouTube embed URL */
url: string;
/** Thumbnail URL (for YouTube previews) */
thumbnailUrl?: string;
/** MIME type returned by the upload API (e.g. 'image/png') */
mimeType?: string;
/** File name returned by the upload API */
fileName?: string;
/** True while the file is being uploaded */
isUploading?: boolean;
}
interface LinkListConfig {
listPosition?: 'top' | 'bottom';
editable?: boolean;
deleteable?: boolean;
deletable?: boolean;
valueFormat?: 'string' | 'array' | 'object';
separator?: string;
urlKey?: string;
idField?: string;
deleteApiUrl?: string;
editApiUrl?: string;
pattern?: string;
patternMessage?: string;
colSpan?: number;
}
/**
* Wraps a FieldConfig leaf with selection metadata for the UI tree.
*/
interface SelectionFieldNode {
/** Reference back to the original FieldConfig */
fieldConfig: FieldConfig;
/** Whether this field is selected (checkbox state) */
selected: boolean;
/** If true, the field cannot be deselected by the user */
isLocked: boolean;
}
/**
* Wraps a section (SUBFIELDS / nested sectionConfig) with toggle + tree metadata.
* Sections can recursively contain child sections.
*/
interface SelectionSectionNode {
/** Section label */
label: string;
/** The original sectionConfig reference (if applicable) */
sectionConfig: SectionConfig | null;
/** The parent FieldConfig that owns this sectionConfig (type GROUP/SUBFIELDS) */
parentFieldConfig: FieldConfig | null;
/** Whether the section toggle is ON */
enabled: boolean;
/** Whether the section is visually expanded in the tree */
expanded: boolean;
/** Leaf fields inside this section */
fields: SelectionFieldNode[];
/** Recursive child sections */
subsections: SelectionSectionNode[];
}
/**
* Top-level group node (maps to a GROUP field in stepperConfig.children
* or a top-level sectionConfig in a SECTION form).
*/
interface SelectionGroupNode {
/** Group label */
label: string;
/** The original FieldConfig of type GROUP (stepper forms) or null (section form) */
groupFieldConfig: FieldConfig | null;
/** Whether the entire group toggle is ON */
enabled: boolean;
/** Whether the group is visually expanded */
expanded: boolean;
/** Sections inside this group */
sections: SelectionSectionNode[];
}
/**
* Signal-based service for the field-selection component.
* Manages group/section/field enable/disable toggles.
*/
declare class FieldSelectionService {
private readonly _state;
private readonly treeService;
readonly groups: i0.Signal;
readonly originalSchema: i0.Signal;
readonly totalFieldCount: i0.Signal;
readonly selectedFieldCount: i0.Signal;
/**
* Initialize the store from a FormSchema.
*/
loadSchema(schema: FormSchema): void;
/**
* Load a schema while preserving the expanded/collapsed state of sections and groups.
* Used when the schema structure hasn't changed but field selections have.
* This prevents the UI from unexpectedly collapsing sections when the user toggles a field.
*/
loadSchemaPreservingExpanded(schema: FormSchema): void;
/**
* A freshly-parsed group/section's `enabled` comes straight from its persisted
* FieldConfig.isEnabled — unlike toggleField()/toggleSection(), which always follow a mutation
* with `_recomputeEnabledFromChildren()` to keep the section/group toggle in sync with its
* children's actual selected state. Without this, a schema saved with e.g. Address.isEnabled:
* false but its Country/State/District checkboxes individually selected (a state that toggling
* from within the UI can never itself produce, but stale/pre-fix persisted data can) loads with
* checked child boxes sitting under a section toggle that shows OFF — contradicting what the
* checkboxes say and, worse, matching what the Configurator tree/actual form use to prune the
* whole section. Runs the same reconciliation parse-time gets on every load, so the toggle
* always reflects reality regardless of how the persisted schema got into this state.
*/
private _reconcileGroupsFromChildren;
/**
* Toggle a group's enabled state. Disabling cascades to all sections + fields.
* When enabling, all fields are selected (unless locked).
*/
toggleGroup(groupIndex: number): void;
/**
* Toggle a section's enabled state.
* Disabling cascades to all child fields (and subsections).
*/
toggleSection(groupIndex: number, sectionPath: number[]): void;
/**
* Toggle a section's expanded (collapsed/expanded) state.
*/
toggleSectionExpanded(groupIndex: number, sectionPath: number[]): void;
/**
* Toggle a group's expanded (collapsed/expanded) state.
*/
toggleGroupExpanded(groupIndex: number): void;
/**
* Toggle a field's selected (checkbox) state.
*/
toggleField(groupIndex: number, sectionPath: number[], fieldIndex: number): void;
/**
* Build and return the updated FormSchema with selection changes applied.
*/
buildUpdatedSchema(): FormSchema | null;
private _disableAllSections;
/**
* Enable all sections and their fields (except locked ones).
* Used when toggling a section/group back ON to restore field selections.
*/
private _enableAllSections;
/**
* Re-derives `enabled` bottom-up for every section in the list, from its own current
* fields/subsections — mirroring "Master Toggle Reflects Children" (already true for the
* GROUP toggle vs. its sections) at every level: a section is ON as long as at least one of
* its fields is selected or a subsection is ON. Without this, re-selecting a single field
* after its parent section was switched off left the section's own toggle stuck OFF even
* though a child was visibly selected again.
*/
private _recomputeEnabledFromChildren;
private _toggleSectionAtPath;
private _toggleExpandedAtPath;
private _toggleFieldAtPath;
/**
* Recursively merge expansion state from old sections into new sections.
* Preserves which sections were expanded/collapsed by the user.
*/
private _mergeExpandedSections;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵprov: i0.ɵɵInjectableDeclaration;
}
declare class FieldSelectionComponent implements OnChanges {
schema: FormSchema;
schemaChange: EventEmitter;
/**
* When true, the enable/disable toggle is hidden for option-driven field types
* (DROPDOWN, RADIO, MULTI_SELECT, etc.).
* Useful for business-user-facing form configurators where developers
* pre-fill the option data and these fields should always be included.
* Defaults to false (show toggle for all fields).
*/
hideToggleForOptionTypes: boolean;
protected readonly store: FieldSelectionService;
/**
* Flag to track if the next schema change is from internal toggles.
* When true, we'll use loadSchemaPreservingExpanded() to keep user's expansion state.
*/
private _isInternalChange;
ngOnChanges(changes: SimpleChanges): void;
onToggleGroup(groupIndex: number): void;
onToggleGroupExpanded(groupIndex: number): void;
onToggleSection(groupIndex: number, sectionPath: number[]): void;
onToggleSectionExpanded(groupIndex: number, sectionPath: number[]): void;
onToggleField(groupIndex: number, sectionPath: number[], fieldIndex: number): void;
trackByGroupIndex(index: number): number;
private _emitChange;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
/**
* Metadata about the currently selected field in the configurator.
*/
interface ConfiguratorFieldInfo {
/** Reference to the FieldConfig being edited */
fieldConfig: FieldConfig;
/** Display label of the parent group */
groupLabel: string;
/** Display label of the parent section */
sectionLabel: string;
/** Index path used to locate this field inside the FormSchema tree */
path: number[];
}
/**
* A node in the configurator left-panel tree.
* Represents either a group, section, or field.
*/
type ConfiguratorNodeType = 'group' | 'section' | 'field';
interface ConfiguratorTreeNode {
/** Unique identifier (name or generated index-based key) */
id: string;
/** Node display label */
label: string;
/** Node type */
type: ConfiguratorNodeType;
/** Whether the node is expanded (for groups/sections, and for a 'field' node with children) */
expanded: boolean;
/** Reference to the FieldConfig (only for field nodes) */
fieldConfig: FieldConfig | null;
/** Index path to this node in FormSchema */
path: number[];
/** Child nodes */
children: ConfiguratorTreeNode[];
}
/**
* Signal-based service for the field-configurator component.
* Manages the tree + selected field + config panel state.
*/
declare class FieldConfiguratorService {
private readonly _state;
private readonly treeService;
readonly tree: i0.Signal;
readonly schema: i0.Signal;
readonly selectedFieldPath: i0.Signal;
/** Resolves to the FieldConfig at the selected path. */
readonly selectedField: i0.Signal;
readonly selectedFieldInfo: i0.Signal;
/**
* Returns the builder-compatible field type string for the currently selected field.
* Used to look up the config schema from field-type-schema.map.ts.
*/
readonly selectedFieldBuilderType: i0.Signal;
/**
* Initialize the store from a FormSchema.
*/
loadSchema(schema: FormSchema, preserveSelection?: boolean): void;
/** Select a field by its path. Pass null to deselect. */
selectField(path: number[] | null): void;
/**
* Toggle a tree node's expanded state.
*/
toggleNodeExpanded(nodeId: string): void;
/**
* Apply a config patch to the currently selected field.
* Rebuilds the schema and tree nodes immutably.
*/
patchSelectedField(patch: Partial): void;
/**
* Change the type (and optionally subType) of the currently selected field.
* Mapping goes from builderType keys (e.g. 'richText') → {type, subType?}.
* DROPDOWN fields cannot be changed and are guarded here as well.
*/
changeFieldType(builderType: string): void;
/**
* Get the current schema (with all applied modifications).
*/
getCurrentSchema(): FormSchema | null;
private _toggleExpanded;
private _restoreExpandedStates;
private _getParentLabels;
private _pathsEqual;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵprov: i0.ɵɵInjectableDeclaration;
}
declare class FieldConfiguratorComponent implements OnChanges {
schema: FormSchema;
schemaChange: EventEmitter;
/**
* When false, the optionConfig section (apiUrl, dataPath, etc.) is hidden
* from the configurator panel. Useful for business-user-facing configurators
* where option URLs are pre-filled by the developer.
* Defaults to true (show everything).
*/
showOptionConfig: boolean;
/**
* Field names that must always remain enabled and cannot be toggled off.
* When a locked field is selected, the IS ENABLED / READ ONLY / DISABLED
* controls are hidden so the user cannot accidentally disable the field.
*/
lockedFieldNames: string[];
readonly store: FieldConfiguratorService;
private readonly cdr;
private readonly schemaMapOverride;
/**
* Merged field-type → config-schema map (defaults + optional overrides).
* Memoized to avoid triggering ngOnChanges in children due to new object references.
*/
finalFieldTypeSchemaMap: Record;
private _isInternalChange;
ngOnChanges(changes: SimpleChanges): void;
onFieldSelected(selection: {
path: number[];
}): void;
onNodeToggleExpanded(nodeId: string): void;
onConfigChange(patch: Record): void;
onTypeChange(builderType: string): void;
private _emitChange;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
declare class GroupNodeComponent {
group: SelectionGroupNode;
groupIndex: number;
/** Propagated from FieldSelectionComponent — see SelectionFieldNodeComponent for details. */
hideToggleForOptionTypes: boolean;
toggleEnabled: EventEmitter;
toggleExpanded: EventEmitter;
sectionToggleEnabled: EventEmitter;
sectionToggleExpanded: EventEmitter;
fieldToggle: EventEmitter<{
sectionPath: number[];
fieldIndex: number;
}>;
onSectionToggleEnabled(sectionIndex: number, subPath: number[]): void;
onSectionToggleExpanded(sectionIndex: number, subPath: number[]): void;
onFieldToggle(sectionIndex: number, payload: {
sectionPath: number[];
fieldIndex: number;
}): void;
trackBySectionIndex(index: number): number;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
declare class SelectionSectionNodeComponent {
section: SelectionSectionNode;
sectionIndex: number;
depth: number;
/** Propagated from FieldSelectionComponent — see SelectionFieldNodeComponent for details. */
hideToggleForOptionTypes: boolean;
/** Emits the sub-path from this node downward (empty [] for self) */
toggleEnabled: EventEmitter;
toggleExpanded: EventEmitter;
fieldToggle: EventEmitter<{
sectionPath: number[];
fieldIndex: number;
}>;
onToggleEnabled(): void;
onToggleExpanded(): void;
onSubsectionToggleEnabled(subIndex: number, subPath: number[]): void;
onSubsectionToggleExpanded(subIndex: number, subPath: number[]): void;
onFieldToggle(fieldIndex: number): void;
onSubsectionFieldToggle(subIndex: number, payload: {
sectionPath: number[];
fieldIndex: number;
}): void;
get selectedCount(): number;
get isLocked(): boolean;
trackByFieldIndex(index: number): number;
trackBySubsectionIndex(index: number): number;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
declare class SelectionFieldNodeComponent {
field: SelectionFieldNode;
toggleSelected: EventEmitter;
/**
* When true, the enable/disable toggle is hidden for option-driven field types
* (DROPDOWN, RADIO, MULTI_SELECT, etc.). These types have their options
* pre-configured by the developer and shouldn't be toggled by business users.
*/
hideToggleForOptionTypes: boolean;
/**
* Set when the enclosing section is off. A field can never be meaningfully "selected" while
* its parent section is disabled — the Field Configuration step prunes the whole disabled
* branch regardless of individual field state — so the checkbox is locked out here to make
* that constraint visible instead of letting the user set a checked state that won't survive.
*/
disabled: boolean;
onCheckedChange(): void;
get isOptionDrivenType(): boolean;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
declare class ConfiguratorTreeComponent {
tree: ConfiguratorTreeNode[];
selectedFieldPath: number[] | null;
selectField: EventEmitter<{
path: number[];
}>;
toggleExpanded: EventEmitter;
onNodeClick(node: ConfiguratorTreeNode): void;
onFieldSelect(node: ConfiguratorTreeNode): void;
onToggleExpand(node: ConfiguratorTreeNode, event: Event): void;
isSelected(node: ConfiguratorTreeNode): boolean;
trackByNodeId(_index: number, node: ConfiguratorTreeNode): string;
private pathsEqual;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
type SnackbarVariant = 'success' | 'error' | 'warning' | 'info';
interface SnackbarConfig {
message: string;
variant?: SnackbarVariant;
duration?: number;
horizontalPosition?: 'start' | 'center' | 'end' | 'left' | 'right';
verticalPosition?: 'top' | 'bottom';
showCloseButton?: boolean;
}
declare class SnackbarService {
private snackBar;
constructor(snackBar: MatSnackBar);
show(config: SnackbarConfig): void;
success(message: string, duration?: number): void;
error(message: string, duration?: number): void;
warning(message: string, duration?: number): void;
info(message: string, duration?: number): void;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵprov: i0.ɵɵInjectableDeclaration;
}
declare class ConfiguratorConfigPanelComponent implements OnChanges {
private cdr;
private snackbarService;
constructor(cdr: ChangeDetectorRef, snackbarService: SnackbarService);
selectedField: FieldConfig | null;
selectedFieldInfo: ConfiguratorFieldInfo | null;
builderFieldType: string | null;
fieldTypeSchemaMap: Record;
configChange: EventEmitter>;
typeChange: EventEmitter;
/**
* When false, all `optionConfig.*` fields (apiUrl, dataPath, labelPath, etc.)
* are hidden from the config panel. Business users don't need to configure
* option URLs — these are pre-filled by the developer in the master JSON.
*/
showOptionConfig: boolean;
/**
* Field names that are mandatory and cannot be disabled.
* When the currently selected field is in this list, IS ENABLED / READ ONLY /
* DISABLED controls are hidden from the Field State step.
*/
lockedFieldNames: string[];
/** Exposed to the template for the native type-switcher select */
readonly switchableFieldTypes: {
label: string;
value: string;
}[];
configFormJson: string;
configInitialValues: Record;
showConfigForm: boolean;
/**
* The type currently being PREVIEWED in the config form.
* Starts equal to builderFieldType; changes as user picks a new type.
* Emitted to the parent on Apply.
*/
currentBuilderType: string | null;
/** Identity key of the currently rendered field — used to detect real field switches. */
private _currentFieldKey;
/** True when type switching should be disabled — DROPDOWN-based fields. */
get isDropdownType(): boolean;
ngOnChanges(changes: SimpleChanges): void;
/**
* Called when the user picks a new type from the native select in the header.
* Immediately rebuilds the config form to show fields for the new type.
* The actual field-level type change is only committed when Apply is clicked.
*/
onTypeSelectChange(event: Event): void;
onActionClick(event: {
id: string;
formData: Record;
}): void;
/**
* Rebuild the SmartForm for the given builder type key.
* Uses a destroy/recreate cycle (showConfigForm toggle + setTimeout) to
* guarantee a completely fresh SmartForm instance is mounted.
*/
private _buildConfigFormForType;
/**
* Deep-clones the schema and removes any field whose `name` matches developer-only fields.
* This prevents end users from modifying system-level configurations like:
* - optionConfig.* (API URLs, data paths, etc.)
* - payloadPath (payload mapping)
* - className (CSS styling)
* - name (system identifier)
*
* Also removes entire sections that become empty after filtering.
*/
private _filterSchemaForOptionConfig;
/**
* Remove IS ENABLED, READ ONLY, and DISABLED controls from the config schema
* when the selected field is a mandatory/locked field.
*/
private _filterSchemaForLockedField;
private _extractInitialValuesFromField;
private _buildPatchFromFormData;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
declare class SmartFormController {
private formData;
/** Auth token sourced from the FormSchema configJSON (e.g. "Bearer eyJ…") */
token?: string;
/** HTTP header name for the token (default: "Authorization") */
tokenHeader?: string;
/** Flat map of translated i18n labels passed from SmartFormComponent */
labels: any;
/** Custom label keys for form actions (Next, Submit, Add, etc.) */
actionLabels?: FormLabels;
fieldSubjects: Map>;
fileAdded$: Subject;
fileUploadFinished$: Subject;
fileRemoved$: Subject;
/** Emitted when a suffixActionIcon is clicked inside a form field */
suffixActionClick$: Subject<{
fieldName: string;
actionId: string;
}>;
/** Selected options details passed dynamically from parent component */
selectedOptionsData: {
[fieldName: string]: any;
};
initialize(initialData: {
[key: string]: any;
}): void;
updateField(name: string, value: any): void;
getFieldValue(name: string): any;
getFieldObservable(name: string): Observable;
getAllData(): {
[key: string]: any;
};
reset(): void;
destroy(): void;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵprov: i0.ɵɵInjectableDeclaration;
}
declare class ExpressionService {
private loadedFunctions;
evaluate(expression: string, context: {
[key: string]: any;
}, variables?: string[]): any;
evaluateCondition(expression: string, context: {
[key: string]: any;
}): boolean;
evaluateFormula(formula: string, functionName: string, context: {
[key: string]: any;
}, variables?: string[]): any;
extractVariables(expression: string): string[];
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵprov: i0.ɵɵInjectableDeclaration;
}
interface ConfirmationModalConfig {
title: string;
headerTheme?: 'light' | 'dark';
icon?: string | {
type: 'material' | 'custom';
value: string;
color?: string;
};
width?: string;
size?: 'sm' | 'md' | 'lg' | 'xl';
customClass?: string;
type?: 'modal' | 'side-panel';
panelPosition?: 'left' | 'right' | 'top' | 'bottom';
panelSpacing?: string;
panelWidth?: string;
panelHeight?: string;
backgroundColor?: string;
borderRadius?: string;
borderTopLeftRadius?: string;
borderTopRightRadius?: string;
borderBottomLeftRadius?: string;
borderBottomRightRadius?: string;
padding?: string;
headerBackgroundColor?: string;
headerTextColor?: string;
headerBorderBottom?: string;
bodyTextColor?: string;
footerBackgroundColor?: string;
footerBorderTop?: string;
confirmButton: {
label: string;
type: 'primary' | 'danger' | 'warning';
disabled?: boolean;
loading?: boolean;
};
cancelButton?: {
label?: string;
show?: boolean;
};
customFooter?: boolean;
formMode?: boolean;
closeOnBackdrop?: boolean;
closeOnEsc?: boolean;
showCloseButton?: boolean;
showCodeSnippetButton?: boolean;
ariaLabel?: string;
ariaDescribedBy?: string;
labels?: {
closeAriaLabel?: string;
codeSnippetAriaLabel?: string;
codeSnippetTitle?: string;
iconAltText?: string;
};
}
type TimeMode = '12' | '24';
type TimePickerVariant = 'default' | 'wheel';
interface TimePickerLabels {
label?: string;
placeholder?: string;
hourLabel?: string;
minuteLabel?: string;
periodLabel?: string;
amLabel?: string;
pmLabel?: string;
confirmLabel?: string;
cancelLabel?: string;
selectTimeTitle?: string;
requiredMarker?: string;
clearLabel?: string;
}
interface TimePickerConfig {
label?: string;
placeholder?: string;
variant?: TimePickerVariant;
mode?: TimeMode;
minuteStep?: number;
disabled?: boolean;
required?: boolean;
errorMessage?: string;
width?: string;
height?: string;
borderRadius?: string;
fontSize?: string;
gap?: string;
fontFamily?: string;
labelColor?: string;
labelFontSize?: string;
labelFontWeight?: string;
backgroundColor?: string;
borderColor?: string;
borderWidth?: string;
padding?: string;
fontWeight?: string;
color?: string;
placeholderColor?: string;
focusBorderColor?: string;
errorColor?: string;
disabledBackgroundColor?: string;
disabledColor?: string;
}
declare class FormFieldComponent implements OnInit, AfterViewInit, OnDestroy {
private fb;
private expressionService;
private http;
private hostRef;
private overlay;
private dateAdapter;
private cdr;
config: FieldConfig;
controller: SmartFormController;
/**
* The FormGroup that THIS field's control should be registered in.
* For repeater instances this is the instance's own isolated FormGroup.
* For flat (non-repeater) fields this is the root formGroup.
*/
formGroup: FormGroup;
/**
* Set to TRUE when this field is part of a repeatable group (config.sectionConfig.allowMulti = true).
* When true, the field does NOT sync with the global controller to prevent data collision
* between different instances of the same repeater row.
*/
allowMulti: boolean;
/**
* The repeater's FormArray, set only when this field instance lives inside an
* allowMulti section (see FormSectionComponent). Lets a single-select DROPDOWN
* exclude values already chosen by sibling instances — e.g. picking "English" in
* Language Details #1 removes it from Language Details #2's options — without any
* schema-level config (see displayOptionList/displayLocalOptionList below).
*/
siblingFormArray: FormArray | null;
/** This instance's own index within siblingFormArray — excluded from the "taken values" set. */
siblingIndex: number | null;
value: any;
private _isVisible;
get isVisible(): boolean;
set isVisible(value: boolean);
showPassword: boolean;
dynamicMinDate: string | null;
dynamicMinTime: string | null;
/**
* Effective minimum date for the datepicker.
* Priority: dynamic (sibling field) → explicit minDate → today (when allowPast is false).
* When allowPast is not false, past dates stay allowed unless an explicit min is set.
*/
get effectiveMinDate(): string | null;
/**
* Effective minimum time for the time input.
* Priority: dynamic (sibling field) → explicit minTime.
* Mirrors {@link effectiveMinDate} for TIME fields.
*/
get effectiveMinTime(): string | null;
/** Effective maximum time for the time input (explicit maxTime only). */
get effectiveMaxTime(): string | null;
/** Fixed entry granularity for this DATE field — no per-user toggle, set entirely by
* config (see DateConfig.dateGranularity's doc for what each level means). */
get effectiveDateGranularity(): 'DAY' | 'MONTH' | 'YEAR';
/** Effective start view for the datepicker — jumps straight to the year grid for
* MONTH/YEAR granularity so the day grid (and, for YEAR, the month grid) is skipped. */
get datePickerStartView(): 'month' | 'year' | 'multi-year';
/**
* Material's (yearSelected) output on — fires whenever a year is
* clicked in the multi-year grid, for ANY granularity (it's just how Material's
* datepicker works), so this only acts when granularity is actually 'YEAR': commits
* Jan 1 of that year and closes immediately, skipping the month/day grids entirely.
* For 'DAY'/'MONTH' granularity this is a no-op — Material's own default behavior
* (drill into the month grid next) proceeds untouched.
*/
onDateYearSelected(date: Date, picker: {
close: () => void;
}): void;
/**
* Material's (monthSelected) output — fires when a month is clicked in the month grid.
* Only acts when granularity is 'MONTH': commits day=1 for that month/year and closes
* immediately, skipping the day grid. No-op for 'DAY' (default drill-in continues) and
* 'YEAR' (the picker already closed at year-selection, so this never fires for YEAR).
*/
onDateMonthSelected(date: Date, picker: {
close: () => void;
}): void;
/**
* Fired every time the picker opens (Material's (opened) output). `startView` only sets
* the calendar's view on its very first render — clicking a year (in multi-year view)
* also drives Material's OWN internal auto-drill (MatCalendar's `_goToDateInView`, called
* as a side effect of the exact same click that fires (yearSelected)/(monthSelected)),
* which advances the calendar's `currentView` to 'year' then 'month' regardless of our
* close()-on-select handlers above. There's no public API to suppress that internal
* drill, so for MONTH/YEAR granularity we defensively force the view back to
* 'multi-year' on every open via Material's internal calendar reference — there's no
* supported public way to do this, so it's wrapped in a try/catch and silently no-ops if
* that internal shape ever changes in a future Material version. No-op entirely for
* 'DAY' granularity, leaving default date fields completely untouched.
*/
onDatePickerOpened(picker: any): void;
isMultiDropdownOpen: boolean;
isSingleDropdownOpen: boolean;
dropdownCurrentPage: number;
dropdownTotalCount: number;
hasMoreDropdownPages: boolean;
isDropdownLoadingMore: boolean;
searchText: string;
filteredOptionList: any[];
dropdownSearch$: Subject;
optionsLoading: boolean;
private optionsSubscription;
isDragOver: boolean;
fileUploadError: string;
multiSaveError: string;
private destroy$;
mediaDeviceInput: ElementRef;
/** Host div for the library picker — always in DOM, moved to body to escape parent transforms */
libraryModalRef: ElementRef;
private portalElement;
showMediaMenu: boolean;
showYoutubeInput: boolean;
youtubeUrlInput: string;
youtubeUrlError: string;
mediaCarouselIndex: number;
showLibraryModal: boolean;
libraryImages: any[];
librarySelectedIds: Set;
libraryLoading: boolean;
libraryError: string;
mediaUploadError: string;
/** Active tab: any string, e.g. 'VENUE', 'ONLINE', 'TBA'. Defaults to 'VENUE'. */
locationActiveTab: string;
/** Current text in the venue search box */
locationSearchText: string;
/** Google Places autocomplete suggestions */
locationSuggestions: any[];
/** Show the suggestions dropdown */
locationShowSuggestions: boolean;
/** Cached Google AutocompleteService instance */
private _googleAcService;
/** Whether Google Maps is loaded */
locationMapLoaded: boolean;
/** Map instance */
private _googleMap;
/** Map markers */
private _mapMarkers;
/** FormControl used ONLY for the autocomplete text-input display value */
autocompleteInputCtrl: FormControl;
/** Filtered option list shown in the mat-autocomplete panel */
filteredOptions: {
label: string;
code: any;
}[];
/**
* Component-local option list for DROPDOWN/RADIO/CHECKBOX/CHIP fields.
* Using a local copy prevents shared-config mutation when the same field config
* object is reused across multiple allowMulti repeater instances.
*/
localOptionList: any[];
/** Snapshot of default (unsearched) options and pagination state for DROPDOWN / AUTOCOMPLETE fields */
private defaultStateSnapshot;
/** Tracks whether the current localOptionList is filtered by an active server-side search query */
private _isServerSearchActive;
/** True from the moment "Select All" is turned on until the user deselects a single option,
* toggles it back off, or starts a new search. While active, each newly-arrived paginated
* page (loadMoreDropdownOptions) is auto-merged into the selection — see loadDropdownOptions
* — so the selected count keeps pace with what's been scrolled into view (e.g. 10 -> 20 -> 34)
* instead of freezing at whatever was loaded the moment "Select All" was clicked. */
private _selectAllActive;
/** Dedicated cache of currently selected option objects */
selectedItems: any[];
/** Cache of the latest dependency parameters for server-side autocomplete filtering */
private _latestDependencyValues;
/** True when this field has no optionConfig.dependencies (nothing to satisfy) OR every
* dependency's current value is present — false while waiting on a parent field. Guards every
* opportunistic reload path (dropdown-open, search-reset, search-clear) so a dependent
* dropdown never re-fetches an unfiltered full list just because it was opened/searched before
* its parent was chosen — only setupDependencies()'s own reactive load (which always supplies
* the real dependency params) is allowed to populate it.
* Defaults to true here (fields with no dependencies never get corrected otherwise), but
* ngOnInit flips it to false up front for any field that DOES declare dependencies — closing
* the window between component creation and setupDependencies()'s first (necessarily async,
* via combineLatest) emission, during which a fast dropdown-open would otherwise still see
* this stale `true` default and fire an unfiltered fetch before the parent-unmet state is
* known. */
private _dependenciesSatisfied;
/** For GROUP fields with allowMulti = true */
groupFormArray: FormArray;
/** For GROUP fields with allowMulti = false — single nested FormGroup */
groupFormGroup: FormGroup;
/**
* Tracked list of repeater instances.
* Using a separate array (not FormArray.controls) + trackBy(id) ensures
* Angular creates FRESH child components for every new row, preventing
* cached values from bleeding into new instances.
*
* Enhanced with isEditing and isSaved flags for the 'multiSave' card UI.
* Each instance gets its own rowController so cascading dropdowns work
* independently within each repeater row.
*/
instanceList: {
id: number;
fg: FormGroup;
initialValue?: any;
isEditing?: boolean;
isSaved?: boolean;
isExpanded?: boolean;
rowController: SmartFormController;
}[];
private _nextInstanceId;
/** Tracks open accordion panels for standard (non-multiSave) GROUP repeaters. */
expandedGroupInstances: Set;
newLinkInputValue: string;
editingLinkIndex: number | null;
editingLinkValue: string;
linkValidationError: string;
/**
* Key used to register the GROUP control on the parent formGroup.
* Priority: sectionConfig.name > field.name > camelCase(label) > '__group__'
*/
get groupKey(): string;
readonly dropdownScrollStrategy: ScrollStrategy;
constructor(fb: FormBuilder, expressionService: ExpressionService, http: HttpClient, hostRef: ElementRef, overlay: Overlay, dateAdapter: DateAdapter, cdr: ChangeDetectorRef);
isFieldVisible(field: FieldConfig, rowController?: SmartFormController): boolean;
/** Portal root, resolved from this component's own node rather than the global document. */
private get portalRoot();
private _onGlobalScroll;
ngOnInit(): void;
get addMultiLabel(): string;
/** Getter for Select placeholder label */
get selectPlaceholderLabel(): string;
/** Getter for No options available label */
get noOptionsAvailableLabel(): string;
/** Getter for expand less icon name */
get expandLessLabel(): string;
/** Getter for expand more icon name */
get expandMoreLabel(): string;
/** Getter for dropdown search placeholder label */
get searchPlaceholderLabel(): string;
/** Getter for Select All label */
get selectAllLabel(): string;
/** Getter for No matching options label */
get noMatchingOptionsLabel(): string;
/** Returns the label of the currently selected option for single-select custom dropdowns */
get singleSelectedLabel(): string;
isSingleOptionSelected(code: any): boolean;
/** Whether the dropdown search feature is enabled for this field */
get isSearchableDropdown(): boolean;
/** Whether the custom single-select dropdown overlay is required — for search, pagination, or
* when optionConfig.customUI opts in to the styled overlay purely for visual consistency with
* sibling dropdowns (no search box, no pagination — just the same panel/chevron treatment). */
get isCustomSingleDropdown(): boolean;
private initGroupField;
/**
* Sets up cross-field validation based on the `onValidate` formula.
* Watches all variables mentioned in the formula and updates the field's
* validity whenever any of them change.
*/
private setupFormulaValidation;
addGroupInstance(initialData?: any): void;
saveGroupInstance(index: number): void;
/**
* Re-opens any repeater instance (multiSave card or standard accordion panel)
* whose nested FormGroup is invalid, so errors hidden by a collapsed card/panel
* become visible. Called by the root form when a submit attempt is blocked.
* Returns true if at least one invalid instance was revealed.
*/
revealInvalidInstances(): boolean;
cancelGroupInstance(index: number): void;
editGroupInstance(index: number): void;
toggleExpandGroupInstance(index: number): void;
removeGroupInstance(index: number, force?: boolean): void;
toggleGroupAccordion(index: number): void;
isGroupExpanded(index: number): boolean;
trackByInstanceId(_: number, item: {
id: number;
fg: FormGroup;
}): number;
ngAfterViewInit(): void;
/** Handles click on a suffix action icon and emits via the controller */
onSuffixActionClick(actionId: string): void;
ngOnDestroy(): void;
registerControl(): void;
getValidators(): ValidatorFn[];
/**
* When `textConfig.matchField` is configured, subscribes to value changes on
* BOTH this control and the referenced control so the mismatch error updates
* instantly whichever field the user edits last.
*
* - Values differ → sets `{ passwordMismatch: true }` on THIS control.
* - Values match → clears `passwordMismatch` from THIS control.
*/
setupMatchValidation(): void;
setupVisibility(): void;
/**
* When config.requiredExpression is set, dynamically re-evaluates the required
* validator whenever any referenced variable changes in the controller.
* Fully backwards-compatible: fields without requiredExpression are unaffected.
*/
setupRequiredExpression(): void;
/**
* Returns all validators from getValidators() except Validators.required.
* Used by setupRequiredExpression() to rebuild the validator list without
* duplicating the required validator.
*/
private getValidatorsWithoutRequired;
/**
* trackBy function for field *ngFor loops in ROW containers.
* Keying by field name (or type as fallback for unnamed containers) prevents
* Angular from destroying and recreating FormFieldComponent instances on re-render,
* preserving localOptionList cache and avoiding duplicate API calls.
*/
trackByFieldName(_: number, field: FieldConfig): string;
setupMinDateField(): void;
/**
* Wires up a dynamic minimum for a TIME field from a sibling TIME field
* (config.timeConfig.minTimeField). When the source changes, this field's
* minimum updates and any now-invalid value (earlier than the new minimum)
* is cleared. Mirrors {@link setupMinDateField} for TIME fields.
*/
setupMinTimeField(): void;
setupGeneratedField(): void;
evaluateFormula(context: {
[key: string]: any;
}): any;
extractFunctionName(formula: string): string | null;
setupDependencies(): void;
/** Extracts the total item count from an API response using the configured path or fallbacks. */
private extractTotalCount;
/** Builds HttpParams for dropdown requests supporting both standard and nested_string (dataset) formats. */
private buildDropdownQueryParams;
/**
* Loads options for DROPDOWN / AUTOCOMPLETE fields.
* Supports server-side pagination, separate Dataset count endpoints, and nested_string params.
*/
loadDropdownOptions(dynamicParams?: {
[key: string]: any;
}, pageIndex?: number, isLoadMore?: boolean): void;
/** Triggers loading the next page of dropdown options. */
loadMoreDropdownOptions(): void;
/** Handles scroll event on the dropdown options panel for infiniteScroll mode. */
onDropdownScroll(event: Event): void;
private getValueByPath;
/**
* Replaces `{placeholder}` tokens in a URL with values resolved from the
* current form data (supports dot / array-index paths via getValueByPath).
* Returns the interpolated URL plus whether EVERY token was resolved.
*
* Used by the delete flows: when a required id (e.g. `{entityId}`) is missing
* — as in CREATE mode before the entity exists — `resolved` is false and the
* caller skips the server delete and just removes the item from the form.
*/
private resolveUrlPlaceholders;
/** Builds HttpHeaders using the token stored in the SmartFormController (sourced from configJSON)
* merged with any custom headers declared in optionConfig.headers.
*/
private _fileLabel;
private getHeaders;
updateValue(newValue: any): void;
onCheckboxListChange(code: string, checked: boolean): void;
isChecked(code: string): boolean;
get errorMessage(): string;
get showCharCount(): boolean;
get remainingCharacters(): number | null;
private static readonly RICH_TEXT_TOKEN_MAP;
private static readonly DEFAULT_RICH_TEXT_HEADER;
/**
* Builds the ngx-quill `modules.toolbar` config from `richTextConfig.headerConfig`
* (a flat list of tokens) falling back to a curated default set.
* Consecutive simple (button) tokens are grouped together; dropdown-style
* tokens (font/size/color/...) each get their own group, matching Quill's
* expected toolbar shape.
*/
get richTextModules(): any;
/**
* Preferred positions for the custom dropdown panels, rendered in a CDK
* connected overlay so they escape a scrollable modal body (cc-confirmation-modal)
* instead of being clipped behind its footer. Opens below the trigger, flipping
* above when there isn't room.
*/
readonly dropdownOverlayPositions: ConnectedPosition[];
/**
* Close the dropdown when the CDK overlay reports a click outside the panel.
* Clicks on the trigger itself are ignored here so the trigger's own toggle
* handler can close it (otherwise the two would fight and re-open it).
*/
onDropdownOverlayOutsideClick(event: MouseEvent, triggerEl: HTMLElement): void;
dropdownOverlayWidth: number | string;
toggleMultiDropdown(event: MouseEvent, triggerEl?: HTMLElement): void;
toggleSingleDropdown(event: MouseEvent, triggerEl?: HTMLElement): void;
selectSingleOption(option: any): void;
onDocumentClick(): void;
onWindowResize(): void;
onEscapeKey(): void;
get multiSelectedCount(): number;
/** Cache of values currently chosen for this field name by OTHER repeater instances.
* Only reassigned (a new Set) when siblingFormArray's value actually changes — see
* _setupSiblingExclusion(). Previously this was a getter that rebuilt the Set (and a
* second getter that re-filtered the option list) on every change-detection cycle,
* handing *ngFor a brand-new array reference every digest — that trips
* ExpressionChangedAfterItHasBeenCheckedError in dev builds and made Angular
* re-diff/re-render the option list constantly, very visible in a repeater with
* several dropdown instances. */
private _siblingTaken;
/** True when this is a single-select DROPDOWN living inside an allowMulti repeater. */
private get _excludesSiblingValues();
/** Subscribes to the repeater's FormArray so _siblingTaken is refreshed only when a
* sibling instance's value actually changes, not on every change-detection cycle. */
private _setupSiblingExclusion;
private _refreshSiblingTaken;
/** Memoized per source list: only recomputes (and hands *ngFor a new array reference)
* when the source list, the taken set, or this field's own value actually changed. */
private _displayListMemo;
private _excludeTaken;
/** Options for the custom single-select dropdown, with sibling-taken values hidden. */
get displayOptionList(): any[];
/** Options for the native /radio rendering, with sibling-taken values hidden. */
get displayLocalOptionList(): any[];
/** Initialise the RxJS search stream for dropdown filtering. */
private initDropdownSearch;
/** Execute client-side or server-side dropdown search. */
private executeDropdownSearch;
/** Restores localOptionList and pagination metadata from defaultStateSnapshot, preserving selected item(s) */
private restoreDefaultOptionList;
/** Resets the dropdown search text and filtered list. */
resetDropdownSearch(forceLoad?: boolean, bypassCache?: boolean): void;
/** Merges option(s) from selectedOptionsData into the local dropdown options list */
mergeSelectedOptionsIntoList(): void;
/**
* If the field's initial value is a primitive (not an object) and no
* selectedOptionsData was provided, uses lookupConfig to fire a targeted
* API call to resolve the display label for edit-mode prefilling.
*/
private _resolveLookupIfNeeded;
/**
* Extracts option(s) and their corresponding raw codes from an initial value object or array of objects.
* If the value is a primitive but initialLabelField is configured, it looks up the sibling field value.
*/
private extractInitialOption;
private parseSingleOptionObject;
private addParsedOptions;
private updateSelectedItems;
/** Returns true if every option in the current filtered list is selected. */
isAllSelected(): boolean;
/** Returns true if some (but not all) filtered options are selected — for indeterminate state. */
isSomeSelected(): boolean;
/** Toggles selection of all filtered options. */
toggleSelectAll(checked: boolean): void;
/** Merges every currently-loaded filtered option into the selection — used to keep an
* already-active "Select All" in sync as more paginated pages arrive (see loadDropdownOptions). */
private applySelectAllToLoadedOptions;
get isTextField(): boolean;
get isNumberField(): boolean;
get isDateField(): boolean;
get isTimeField(): boolean;
get isWheelVariant(): boolean;
get timePickerLabels(): TimePickerLabels;
get isDropdown(): boolean;
get isAutocomplete(): boolean;
get isFileUpload(): boolean;
get isMediaUpload(): boolean;
get isRadio(): boolean;
get isCheckbox(): boolean;
get isChip(): boolean;
get isSwitch(): boolean;
get isRating(): boolean;
get isRichText(): boolean;
get isGenerated(): boolean;
get isRow(): boolean;
get isGroup(): boolean;
get isLocation(): boolean;
get isLinkList(): boolean;
/**
* Initialise the separate display-control that drives the mat-autocomplete
* text input. The real form control always stores the *code* value.
*/
private initAutocomplete;
/** Filter options by the user's search text (matches label or code). */
private _filterOptions;
/** Put the human-readable label into the display control based on the stored code. */
private _syncAutocompleteDisplayValue;
/** Called when user picks an option from the mat-autocomplete panel. */
onAutocompleteSelected(option: {
label: string;
code: any;
}): void;
/** Called when the input loses focus — clear display & value if text was manually deleted. */
onAutocompleteClear(): void;
/**
* Returns the effective grid column span for a child inside a ROW.
* If the child declares an explicit colSpan, use it.
* Otherwise divide 12 equally among all children (floor, min 1).
*/
getChildColSpan(child: FieldConfig): number;
getOptionColSpan(option: any): number;
onRatingChange(star: number, event?: MouseEvent): void;
getStarArray(): number[];
isStarHalf(star: number): boolean;
isStarFilled(star: number): boolean;
onDragOver(event: DragEvent): void;
onDragLeave(event: DragEvent): void;
onFileDrop(event: DragEvent): void;
onFileSelected(event: Event): void;
private processFiles;
removeUploadedFile(index: number): void;
getFileIcon(mimeType: string): string;
formatFileSize(bytes: number): string;
get addLabel(): string;
get removeLabel(): string;
get mediaItems(): MediaItem[];
/** Number of active items (used to clamp carousel index) */
get mediaCount(): number;
/** The currently visible carousel item */
get activeMediaItem(): MediaItem | null;
/** Thumbnail strip items */
get mediaThumbnails(): MediaItem[];
mediaCarouselPrev(): void;
mediaCarouselNext(): void;
mediaGoTo(index: number): void;
onMediaMenuVideo(): void;
addYoutubeMedia(): void;
private _extractYoutubeId;
onMediaMenuDevice(): void;
onMediaFileSelected(event: Event): void;
/**
* Resolves the library-image sync POST endpoint from `attachmentConfig.libraryConfig.uploadConfig`.
* Returns `null` when not configured; the caller skips the API call.
*/
private buildLibraryUploadRequest;
/** Config object for the cc-confirmation-modal used as the library picker. */
get libraryModalConfig(): ConfirmationModalConfig;
onMediaMenuLibrary(): void;
private _loadLibraryImages;
getLibraryItemUrl(item: any): string;
getLibraryItemId(item: any): any;
isLibraryItemSelected(item: any): boolean;
toggleLibraryItem(item: any): void;
closeLibraryModal(): void;
confirmLibrarySelection(): void;
removeMediaItem(index: number): void;
private _appendMediaItem;
private showMediaError;
private initLocationField;
private _ensureGoogleMapsScript;
onLocationTabChange(tab: string): void;
get locationValue(): LocationFieldValue;
get locationVenues(): LocationItem[];
get locationOnlineUrl(): string;
get locationMaxReached(): boolean;
handleLocationSearchInput(event: Event): void;
onLocationSuggestionSelect(prediction: any): void;
private _addVenueAndUpdate;
removeLocationVenue(index: number): void;
onLocationUrlChange(url: string): void;
hideLocationSuggestions(): void;
getLocationMapEmbedUrl(): string;
private _renderMap;
get linkListConfig(): LinkListConfig | undefined;
get linkListItems(): any[];
getLinkDisplayUrl(item: any): string;
addLinkItem(event?: Event): void;
deleteLinkItem(index: number): void;
startEditLink(index: number): void;
cancelEditLink(): void;
saveEditLink(index: number): void;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
declare class SmartFormComponent implements OnInit, OnChanges, OnDestroy {
private fb;
controller: SmartFormController;
private expressionService;
private http;
private snackbarService;
private router;
private cdr;
formFieldComponents: QueryList;
private destroy$;
formJson: string;
initialValues?: {
[key: string]: any;
};
enableDraftAutoSave: boolean;
/** Flat i18n labels map passed by the consuming app.
* After JSON parse the schema is walked and every string value that
* matches a key in this map is replaced with the translated value.
* Mirrors the pattern used by ConfigurableFormComponent + translateConfig.
*/
labels: any;
mode: 'CREATE' | 'EDIT';
/** When true, all form fields are disabled and the action bar is hidden (preview/read-only mode). */
readOnly: boolean;
/** Selected options details passed dynamically from parent component to resolve edit-mode dropdown labels */
selectedOptionsData?: {
[key: string]: any;
};
submit: EventEmitter<{
[key: string]: any;
}>;
draftSave: EventEmitter;
/**
* Emitted when a button with a custom `type` (not 'cancel', 'draft', or
* 'submit') is clicked. Payload contains the button `id` and the current
* form data snapshot.
*/
actionClick: EventEmitter<{
id: string;
formData: {
[key: string]: any;
};
}>;
valueChange: EventEmitter<{
[key: string]: any;
}>;
fileAdded: EventEmitter;
fileUploadFinished: EventEmitter;
fileRemoved: EventEmitter;
/** Emitted when a suffixActionIcon is clicked. Payload: { fieldName, actionId } */
suffixActionClick: EventEmitter<{
fieldName: string;
actionId: string;
}>;
/** Emitted whenever the active section step changes. Carries current state so the
* host can show/hide Previous/Next/Submit buttons in its own footer. */
stepChange: EventEmitter<{
currentStep: number;
totalSteps: number;
isFirst: boolean;
isLast: boolean;
stepLabel: string;
}>;
formSchema: FormSchema;
formGroup: FormGroup;
fieldList: FieldConfig[];
isStepper: boolean;
currentStep: number;
isLoading: boolean;
isDraftLoading: boolean;
/** True when sectionStepper mode is active (SECTION form with top-level GROUPs as steps). */
isSectionStepper: boolean;
/** Index of the currently visible section step. */
currentSectionStep: number;
/** Flat list of top-level GROUP FieldConfigs that become the stepper steps. */
sectionSteps: FieldConfig[];
/** Validation state per section step — drives badge colour/icon. */
stepValidationStates: ('untouched' | 'valid' | 'warning')[];
/** Flat field-name lists per step used for targeted validation. */
private stepFieldNames;
/** Controls skeleton visibility. Stays false until schema is parsed AND
* any EDIT-mode data fetch completes, but always shows for at least
* SKELETON_MIN_MS so the animation is visible even on fast loads. */
isFormReady: boolean;
private readonly SKELETON_MIN_MS;
private _skeletonStart;
constructor(fb: FormBuilder, controller: SmartFormController, expressionService: ExpressionService, http: HttpClient, snackbarService: SnackbarService, router: Router, cdr: ChangeDetectorRef);
ngOnInit(): void;
loadEditData(): void;
/** Flips isFormReady=true after the skeleton has been visible for at least SKELETON_MIN_MS. */
private _markReady;
ngOnChanges(changes: SimpleChanges): void;
ngOnDestroy(): void;
/** Public backward-compatible entry point — delegates to _startForm. */
parseFormJson(): void;
private _startForm;
private _applySchema;
initializeForm(): void;
collectFields(fields: FieldConfig[]): void;
handleSubmit(): void;
/**
* Universal action handler for any button click.
* One handler decides how to process based on action.kind.
*/
handleButtonClick(btn: ActionButtonConfig): void;
private fireActionApiCall;
/**
* Constructs nested payload by checking field properties on form controls.
*/
collectFormData(): {
[key: string]: any;
};
/**
* Deep merges the source object (e.g. extraPayload) into the target object (e.g. form payload).
*/
private deepMerge;
private buildNestedPayload;
private setNestedValue;
private extractGroupValue;
validate(): boolean;
scrollToFirstInvalidControl(): void;
submitToApi(formData: any, actionType?: 'submit' | 'draft', btn?: ActionButtonConfig): void;
showAlert(type: 'success' | 'error' | 'warning' | 'info', message: string, customConfig?: any): void;
/** Builds HttpHeaders from the token stored in the controller (sourced from configJSON). */
getHeaders(): HttpHeaders;
nextStep(): void;
previousStep(): void;
get canGoNext(): boolean;
get canGoPrevious(): boolean;
get currentStepConfig(): FieldConfig | undefined;
/** Advance to the next section step. Called by the host footer "Next" button.
* Validates the current step first — marks it valid (green) or warning (orange). */
navigateToNext(): void;
/** Go back to the previous section step. Called by the host footer "Previous" button. */
navigateToPrevious(): void;
/** Jump directly to a specific section step by index.
* Validates the step being left so the badge state updates correctly. */
goToSectionStep(index: number): void;
get isSectionStepFirst(): boolean;
get isSectionStepLast(): boolean;
/** Returns the SectionConfig for a given step — passed to lib-form-section.
* The outer label is intentionally omitted because the stepper nav already
* displays it; showing it again inside the content would be redundant. */
getSectionStepConfig(step: FieldConfig): any;
private _emitStepChange;
/** Marks all controls in the given step as touched, records valid/warning state,
* and returns whether the step had any invalid control. */
private _validateStep;
/** Public hard-validation check for the host app: does the CURRENT step have any
* invalid required field? navigateToNext()/goToSectionStep() only mark a step's badge
* as a soft "warning" and still advance regardless — hosts that need to actually BLOCK
* navigation until required fields are filled (e.g. the beneficiary add/edit wizard)
* should call this before invoking navigateToNext(). Also marks the step's controls as
* touched so the field-level error states render immediately. */
isCurrentStepValid(): boolean;
/** Recursively collects all leaf field names from a set of FieldConfigs. */
private _collectFieldNames;
get nextLabel(): string;
get submitLabel(): string;
get previousLabel(): string;
get actionBarConfig(): ActionBarConfig | undefined;
/**
* Returns buttons for a given alignment, sorted by `order` (stable).
*/
getButtonsForAlignment(alignment: 'left' | 'right'): ActionButtonConfig[];
getButtonLabel(btn: ActionButtonConfig): string;
isButtonDisabled(btn: ActionButtonConfig): boolean;
private getButtonByActionKind;
private navigateTo;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
declare class FormSectionComponent implements OnInit, OnDestroy {
private fb;
private expressionService;
config: SectionConfig;
controller: SmartFormController;
formGroup: FormGroup;
/**
* For allowMulti sections: the FormArray registered on the root formGroup.
* Each element is a FormGroup representing one repeater instance.
*/
repeaterFormArray: FormArray;
/** Tracks which accordion panels are open (by index). New instances start expanded. */
expandedInstances: Set;
/**
* The key under which the FormArray is registered in the root formGroup.
* Falls back to config.name or a generated key.
*/
get arrayKey(): string;
constructor(fb: FormBuilder, expressionService: ExpressionService);
isFieldVisible(field: FieldConfig): boolean;
ngOnInit(): void;
ngOnDestroy(): void;
/** Creates a fresh FormGroup for one repeater instance */
private createInstanceGroup;
addInstance(): void;
removeInstance(index: number): void;
toggleInstance(index: number): void;
isExpanded(index: number): boolean;
getInstanceGroup(index: number): FormGroup;
get instanceGroups(): FormGroup[];
/** For non-allowMulti sections we simply pass the root formGroup down */
get flatFormGroup(): FormGroup;
/** Flatten a field tree to get all leaf fields (for ROW children etc.) */
getFlatFields(fields: FieldConfig[]): FieldConfig[];
/**
* trackBy function for field *ngFor loops.
* Keying by field name (or type as fallback for unnamed containers) prevents
* Angular from destroying and recreating FormFieldComponent instances when the
* parent re-renders — preserving localOptionList cache and avoiding duplicate
* API calls.
*/
trackByFieldName(_: number, field: FieldConfig): string;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
/**
* Bypasses Angular's DomSanitizer for resource URLs (e.g. YouTube embed iframes).
* Used only for trusted URLs such as YouTube embed links derived from user-provided video IDs.
*/
declare class TrustedUrlPipe implements PipeTransform {
private sanitizer;
constructor(sanitizer: DomSanitizer);
transform(url: string): SafeResourceUrl | null;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵpipe: i0.ɵɵPipeDeclaration;
}
declare class MaterialModule {
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵmod: i0.ɵɵNgModuleDeclaration;
static ɵinj: i0.ɵɵInjectorDeclaration;
}
declare class ButtonComponent implements OnInit {
variant: ButtonVariant;
type: 'button' | 'submit' | 'reset';
disabled: boolean;
get pointerEvents(): string;
width?: string;
height?: string;
borderRadius?: string;
fontSize?: string;
fontWeight?: string;
backgroundColor?: string;
color?: string;
border?: string;
icon: boolean | string | {
type: 'material' | 'fontawesome' | 'img';
value: string;
};
labels?: ButtonLabels;
constructor();
ngOnInit(): void;
get isDefaultIcon(): boolean;
get isStringIcon(): boolean;
get isImgIcon(): boolean;
get isObjectIcon(): boolean;
get iconString(): string;
get iconObject(): {
type: string;
value: string;
};
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
declare class ButtonModule {
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵmod: i0.ɵɵNgModuleDeclaration;
static ɵinj: i0.ɵɵInjectorDeclaration;
}
type AlertVariant = 'info' | 'warning' | 'warning-shadow' | 'success' | 'error';
type IconInput = boolean | string | {
type: 'material' | 'fontawesome' | 'img';
value: string;
};
interface AlertLabels {
iconAltText?: string;
}
declare class AlertComponent implements OnInit {
variant: AlertVariant;
title: string;
message: string;
icon: IconInput;
customIcon: string;
labels?: AlertLabels;
width?: string;
height?: string;
borderRadius?: string;
padding?: string;
gap?: string;
backgroundColor?: string;
color?: string;
borderColor?: string;
fontSize?: string;
fontWeight?: string;
boxShadow?: string;
borderTopLeftRadius?: string;
borderTopRightRadius?: string;
borderBottomLeftRadius?: string;
borderBottomRightRadius?: string;
constructor();
ngOnInit(): void;
get isDefaultIcon(): boolean;
get isStringIcon(): boolean;
get isObjectIcon(): boolean;
get iconString(): string;
get isImgIcon(): boolean;
get iconObject(): {
type: string;
value: string;
};
get defaultIconClass(): string;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
declare class AlertModule {
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵmod: i0.ɵɵNgModuleDeclaration;
static ɵinj: i0.ɵɵInjectorDeclaration;
}
declare class TimePickerComponent implements ControlValueAccessor, OnInit, OnChanges {
config?: TimePickerConfig;
labels?: TimePickerLabels;
label: string;
placeholder: string;
variant: TimePickerVariant;
mode: TimeMode;
minuteStep: number;
disabled: boolean;
required: boolean;
errorMessage: string;
minTime?: string;
maxTime?: string;
width?: string;
height?: string;
borderRadius?: string;
fontSize?: string;
gap?: string;
fontFamily?: string;
labelColor?: string;
labelFontSize?: string;
labelFontWeight?: string;
backgroundColor?: string;
borderColor?: string;
borderWidth?: string;
padding?: string;
fontWeight?: string;
color?: string;
placeholderColor?: string;
focusBorderColor?: string;
errorColor?: string;
disabledBackgroundColor?: string;
disabledColor?: string;
timeChange: EventEmitter;
displayValue: string;
isOpen: boolean;
onChange: (value: string) => void;
onTouched: () => void;
ngOnInit(): void;
ngOnChanges(changes: SimpleChanges): void;
private updateFromConfig;
writeValue(value: string): void;
registerOnChange(fn: any): void;
registerOnTouched(fn: any): void;
setDisabledState(isDisabled: boolean): void;
togglePanel(): void;
closePanel(): void;
onConfirmed(timeString: string): void;
onCancelled(): void;
get wrapperStyles(): {
[key: string]: string | undefined;
};
get labelStyles(): {
[key: string]: string | undefined;
};
get fieldStyles(): {
[key: string]: string | undefined;
};
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
type WheelType = 'hour' | 'minute' | 'period';
declare class TimeWheelPanelComponent implements OnInit, AfterViewInit, OnDestroy, OnChanges {
private zone;
mode: TimeMode;
value: string;
labels?: TimePickerLabels;
minuteStep: number;
minTime?: string;
maxTime?: string;
confirmed: EventEmitter;
cancelled: EventEmitter;
hourWheel: ElementRef;
minuteWheel: ElementRef;
periodWheel?: ElementRef;
static readonly ITEM_HEIGHT = 36;
static readonly VISIBLE_ROWS = 3;
readonly ITEM_HEIGHT = 36;
readonly SPACERS: number;
readonly spacerRows: number[];
private get containerHeight();
hours: string[];
minutes: string[];
periods: string[];
hourRepeats: number[];
minuteRepeats: number[];
selectedHour: string;
selectedMinute: string;
selectedPeriod: string;
disabledHours: Set;
disabledMinutes: Set;
disabledPeriods: Set;
private isInitialScrollDone;
private scrollListeners;
private idleTimers;
private rafIds;
private static readonly IDLE_MS;
constructor(zone: NgZone);
ngOnInit(): void;
ngOnChanges(changes: SimpleChanges): void;
ngAfterViewInit(): void;
ngOnDestroy(): void;
private attachScroll;
private generateHours;
private generateMinutes;
private buildRepeats;
private centralBandStart;
private parseInitialValue;
private findClosestMinute;
private setDefaultTime;
private toMinutes;
private parseLimit;
private to24hrHour;
computeConstraints(): void;
updateWheelEffects(element: HTMLElement): void;
private listFor;
private repeatsFor;
private isDisabled;
private onScrollIdle;
private nearestEnabled;
private adjustSelectionOnConstraintChange;
selectValue(type: WheelType, val: string): void;
scrollToValue(type: WheelType, val: string, smooth: boolean): void;
onCancel(): void;
onConfirm(): void;
getFormattedTime(): string;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
type InputType = 'text' | 'number' | 'email' | 'password' | 'tel' | 'url' | 'textarea';
interface InputLabels {
label?: string;
placeholder?: string;
errorMessage?: string;
helperText?: string;
requiredMarker?: string;
passwordToggleAriaLabel?: string;
prefixAltText?: string;
suffixAltText?: string;
}
interface InputConfig {
type?: InputType;
label?: string;
placeholder?: string;
value?: any;
disabled?: boolean;
required?: boolean;
readonly?: boolean;
maxLength?: number;
minLength?: number;
min?: number;
max?: number;
pattern?: string;
errorMessage?: string;
helperText?: string;
rows?: number;
prefixIcon?: string | {
type: 'material' | 'fontawesome' | 'img';
value: string;
};
suffixIcon?: string | {
type: 'material' | 'fontawesome' | 'img';
value: string;
};
width?: string;
height?: string;
borderRadius?: string;
fontSize?: string;
gap?: string;
fontFamily?: string;
labelColor?: string;
labelFontSize?: string;
labelFontWeight?: string;
backgroundColor?: string;
borderColor?: string;
borderWidth?: string;
padding?: string;
fontWeight?: string;
color?: string;
placeholderColor?: string;
focusBorderColor?: string;
errorColor?: string;
disabledBackgroundColor?: string;
disabledColor?: string;
boxShadow?: string;
}
declare class InputComponent implements ControlValueAccessor, OnInit, OnChanges {
config?: InputConfig;
labels?: InputLabels;
type: InputType;
label: string;
placeholder: string;
disabled: boolean;
required: boolean;
readonly: boolean;
clearable: boolean;
maxLength?: number;
minLength?: number;
min?: number | string;
max?: number | string;
pattern?: string;
errorMessage: string;
helperText: string;
rows: number;
prefixIcon?: any;
suffixIcon?: any;
value: any;
width?: string;
height?: string;
borderRadius?: string;
fontSize?: string;
gap?: string;
fontFamily?: string;
labelColor?: string;
labelFontSize?: string;
labelFontWeight?: string;
backgroundColor?: string;
borderColor?: string;
borderWidth?: string;
padding?: string;
fontWeight?: string;
color?: string;
placeholderColor?: string;
focusBorderColor?: string;
errorColor?: string;
disabledBackgroundColor?: string;
disabledColor?: string;
boxShadow?: string;
valueChange: EventEmitter;
inputBlur: EventEmitter;
inputFocus: EventEmitter;
showPassword: boolean;
focused: boolean;
onChange: (value: any) => void;
onTouched: () => void;
ngOnInit(): void;
ngOnChanges(changes: SimpleChanges): void;
private updateFromConfig;
private updateFromLabels;
get requiredMarker(): string;
writeValue(value: any): void;
registerOnChange(fn: any): void;
registerOnTouched(fn: any): void;
setDisabledState(isDisabled: boolean): void;
onInputChange(event: any): void;
onBlur(): void;
onFocus(): void;
togglePasswordVisibility(): void;
getIconType(icon: any): 'material' | 'fontawesome' | 'img' | 'none';
getIconValue(icon: any): string;
get inputType(): string;
private getStyleValue;
get wrapperStyles(): {
[key: string]: string | undefined;
};
get labelStyles(): {
[key: string]: string | undefined;
};
get fieldStyles(): {
[key: string]: string | undefined;
};
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
interface DropdownOption {
value: any;
label: string;
disabled?: boolean;
icon?: string | {
type: 'material' | 'fontawesome' | 'img';
value: string;
};
}
interface DropdownLabels {
label?: string;
placeholder?: string;
searchPlaceholder?: string;
errorMessage?: string;
selectedSuffix?: string;
clearAriaLabel?: string;
noResultsFound?: string;
requiredMarker?: string;
}
interface DropdownConfig {
options: DropdownOption[];
placeholder?: string;
label?: string;
multiple?: boolean;
searchable?: boolean;
clearable?: boolean;
disabled?: boolean;
required?: boolean;
errorMessage?: string;
serverSearch?: boolean;
searchDebounceMs?: number;
lazyLoad?: boolean;
width?: string;
height?: string;
borderRadius?: string;
fontSize?: string;
gap?: string;
fontFamily?: string;
labelColor?: string;
labelFontSize?: string;
labelFontWeight?: string;
backgroundColor?: string;
borderColor?: string;
borderWidth?: string;
padding?: string;
fontWeight?: string;
color?: string;
placeholderColor?: string;
focusBorderColor?: string;
errorColor?: string;
disabledBackgroundColor?: string;
disabledColor?: string;
boxShadow?: string;
}
declare class DropdownComponent implements ControlValueAccessor, OnInit, OnChanges, OnDestroy {
private el;
config?: DropdownConfig;
labels?: DropdownLabels;
options: DropdownOption[];
selectedValue?: any;
placeholder: string;
label: string;
multiple: boolean;
searchable: boolean;
clearable: boolean;
disabled: boolean;
required: boolean;
errorMessage: string;
serverSearch: boolean;
searchDebounceMs: number;
lazyLoad: boolean;
loading: boolean;
loadingMore: boolean;
hasMore: boolean;
width?: string;
height?: string;
borderRadius?: string;
fontSize?: string;
gap?: string;
fontFamily?: string;
labelColor?: string;
labelFontSize?: string;
labelFontWeight?: string;
backgroundColor?: string;
borderColor?: string;
borderWidth?: string;
padding?: string;
fontWeight?: string;
color?: string;
placeholderColor?: string;
focusBorderColor?: string;
errorColor?: string;
disabledBackgroundColor?: string;
disabledColor?: string;
boxShadow?: string;
selectionChange: EventEmitter;
searchTermChange: EventEmitter;
loadMore: EventEmitter;
opened: EventEmitter;
viewport?: CdkVirtualScrollViewport;
searchInput?: ElementRef;
triggerEl?: ElementRef;
filteredOptions: DropdownOption[];
searchTerm: string;
value: any;
isOpen: boolean;
focusedIndex: number;
menuPosition: {
top: number;
left: number;
width: number;
};
onChange: (value: any) => void;
onTouched: () => void;
private selectAllActive;
private search$;
constructor(el: ElementRef);
ngOnInit(): void;
ngOnDestroy(): void;
ngOnChanges(changes: SimpleChanges): void;
private get validOptions();
private updateFromConfig;
private updateFromLabels;
get resolvedLabels(): {
requiredMarker: string;
searchPlaceholder: string;
selectedSuffix: string;
clearAriaLabel: string;
noResultsFound: string;
};
writeValue(value: any): void;
registerOnChange(fn: any): void;
registerOnTouched(fn: any): void;
setDisabledState(isDisabled: boolean): void;
toggle(): void;
close(): void;
get isAllFilteredSelected(): boolean;
toggleSelectAll(): void;
/** Merges every currently-loaded selectable option into the selection — used to keep a
* "Select All" that's already active in sync as more lazy-loaded pages arrive. */
private applySelectAllToLoadedOptions;
selectOption(option: DropdownOption): void;
isSelected(option: DropdownOption): boolean;
onSearch(term: string): void;
onOptionsScroll(event: Event): void;
clearSelection(event?: Event): void;
getIconType(icon: any): 'material' | 'fontawesome' | 'img' | 'none';
getIconValue(icon: any): string;
getSelectedLabel(): string;
hasValue(): boolean;
handleKeyboardEvent(event: KeyboardEvent): void;
scrollToIndex(index: number): void;
private getStyleValue;
get wrapperStyles(): {
[key: string]: string | undefined;
};
get labelStyles(): {
[key: string]: string | undefined;
};
get fieldStyles(): {
[key: string]: string | undefined;
};
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
interface CheckboxOption {
value: any;
label: string;
disabled?: boolean;
checked?: boolean;
}
interface CheckboxLabels {
label?: string;
requiredMarker?: string;
}
interface CheckboxConfig {
label?: string;
checked?: boolean;
disabled?: boolean;
required?: boolean;
indeterminate?: boolean;
options?: CheckboxOption[];
labelPosition?: 'before' | 'after';
color?: 'primary' | 'accent' | 'warn';
borderRadius?: string;
size?: string;
checkedColor?: string;
uncheckedColor?: string;
groupLabelColor?: string;
groupLabelFontSize?: string;
groupLabelFontWeight?: string;
labelFontSize?: string;
labelFontWeight?: string;
labelColor?: string;
gap?: string;
fontFamily?: string;
}
declare class CheckboxComponent implements ControlValueAccessor, OnInit, OnChanges {
config: CheckboxConfig;
labels?: CheckboxLabels;
label: string;
checked: boolean;
disabled: boolean;
required: boolean;
indeterminate: boolean;
options: CheckboxOption[];
labelPosition: 'before' | 'after';
color: string;
borderRadius: string;
value: any;
errorMessage: string;
width?: string;
height?: string;
fontSize?: string;
fontWeight?: string;
labelColor?: string;
labelFontSize?: string;
labelFontWeight?: string;
gap?: string;
fontFamily?: string;
backgroundColor?: string;
borderColor?: string;
borderWidth?: string;
padding?: string;
placeholderColor?: string;
focusBorderColor?: string;
errorColor?: string;
disabledBackgroundColor?: string;
disabledColor?: string;
boxShadow?: string;
size?: string;
checkedColor?: string;
uncheckedColor?: string;
groupLabelColor?: string;
groupLabelFontSize?: string;
groupLabelFontWeight?: string;
checkedChange: EventEmitter;
onChange: (value: any) => void;
onTouched: () => void;
ngOnInit(): void;
ngOnChanges(changes: SimpleChanges): void;
private updateFromConfig;
private updateFromLabels;
get isGroup(): boolean;
get visibleOptions(): CheckboxOption[];
get requiredMarker(): string;
writeValue(value: any): void;
registerOnChange(fn: any): void;
registerOnTouched(fn: any): void;
setDisabledState(isDisabled: boolean): void;
onCheckboxChange(event: any): void;
onGroupCheckboxChange(option: CheckboxOption, event: any): void;
private getStyleValue;
get wrapperStyles(): {
[key: string]: string | undefined;
};
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
interface RadioOption {
value: any;
label: string;
disabled?: boolean;
}
interface RadioLabels {
label?: string;
requiredMarker?: string;
}
interface RadioConfig {
label?: string;
options: RadioOption[];
value?: any;
disabled?: boolean;
required?: boolean;
labelPosition?: 'before' | 'after';
color?: 'primary' | 'warning' | 'danger' | 'success' | 'accent' | 'warn' | string;
layout?: 'vertical' | 'horizontal';
gap?: string;
labelColor?: string;
checkedColor?: string;
uncheckedColor?: string;
fontSize?: string;
fontWeight?: string;
fontFamily?: string;
groupLabelColor?: string;
groupLabelFontSize?: string;
groupLabelFontWeight?: string;
disabledColor?: string;
errorColor?: string;
size?: string;
borderRadius?: string;
labelFontSize?: string;
labelFontWeight?: string;
}
declare class RadioComponent implements ControlValueAccessor, OnInit {
config?: RadioConfig;
label: string;
options: RadioOption[];
disabled: boolean;
required: boolean;
labelPosition: 'before' | 'after';
color: 'primary' | 'warning' | 'danger' | 'success' | 'accent' | 'warn' | string;
layout: 'vertical' | 'horizontal';
labels: RadioLabels;
gap?: string;
labelColor?: string;
checkedColor?: string;
uncheckedColor?: string;
fontSize?: string;
fontWeight?: string;
fontFamily?: string;
groupLabelColor?: string;
groupLabelFontSize?: string;
groupLabelFontWeight?: string;
disabledColor?: string;
errorColor?: string;
size?: string;
borderRadius?: string;
labelFontSize?: string;
labelFontWeight?: string;
selectionChange: EventEmitter;
value: any;
uuid: string;
private onChange;
private onTouched;
ngOnInit(): void;
ngOnChanges(changes: any): void;
private updateFromConfig;
get requiredMarker(): string;
get visibleOptions(): RadioOption[];
writeValue(value: any): void;
registerOnChange(fn: any): void;
registerOnTouched(fn: any): void;
setDisabledState(isDisabled: boolean): void;
onRadioChange(option: RadioOption): void;
private getStyleValue;
private getThemeColor;
get wrapperStyles(): {
[key: string]: string | undefined;
};
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
interface ToggleLabels {
label?: string;
}
interface ToggleConfig {
label?: string;
checked?: boolean;
disabled?: boolean;
required?: boolean;
labelPosition?: 'before' | 'after';
color?: 'primary' | 'warning' | 'danger' | 'success' | string;
uncheckedColor?: string;
checkedColor?: string;
thumbColor?: string;
checkedThumbColor?: string;
fontSize?: string;
fontWeight?: string;
toggleWidth?: string;
toggleHeight?: string;
gap?: string;
fontFamily?: string;
labelColor?: string;
labelFontSize?: string;
labelFontWeight?: string;
}
declare class ToggleComponent implements ControlValueAccessor, OnInit, OnChanges {
config?: ToggleConfig;
labels?: ToggleLabels;
label: string;
checked: boolean;
disabled: boolean;
required: boolean;
labelPosition: 'before' | 'after';
color: string;
labelColor?: string;
uncheckedColor?: string;
checkedColor?: string;
thumbColor?: string;
checkedThumbColor?: string;
fontSize?: string;
fontWeight?: string;
fontFamily?: string;
toggleWidth?: string;
toggleHeight?: string;
gap?: string;
sliderColor?: string;
labelFontSize?: string;
labelFontWeight?: string;
disabledColor?: string;
toggleChange: EventEmitter;
value: boolean;
private onChange;
private onTouched;
ngOnInit(): void;
ngOnChanges(changes: SimpleChanges): void;
private updateFromConfig;
private updateFromLabels;
writeValue(value: any): void;
registerOnChange(fn: any): void;
registerOnTouched(fn: any): void;
setDisabledState(isDisabled: boolean): void;
onToggleChange(event: any): void;
private getStyleValue;
private getThemeColor;
get wrapperStyles(): {
[key: string]: string | undefined;
};
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
interface DatepickerLabels {
label?: string;
placeholder?: string;
startDateLabel?: string;
endDateLabel?: string;
requiredMarker?: string;
}
interface DatePickerConfig {
label?: string;
placeholder?: string;
value?: Date;
disabled?: boolean;
required?: boolean;
minDate?: Date;
maxDate?: Date;
startView?: 'month' | 'year' | 'multi-year';
isRange?: boolean;
startDate?: Date;
endDate?: Date;
width?: string;
borderRadius?: string;
fontSize?: string;
errorMessage?: string;
gap?: string;
fontFamily?: string;
labelColor?: string;
labelFontSize?: string;
labelFontWeight?: string;
backgroundColor?: string;
borderColor?: string;
borderWidth?: string;
padding?: string;
fontWeight?: string;
color?: string;
placeholderColor?: string;
focusBorderColor?: string;
errorColor?: string;
disabledBackgroundColor?: string;
disabledColor?: string;
boxShadow?: string;
height?: string;
}
declare class DatepickerComponent implements ControlValueAccessor, OnInit, OnChanges {
config?: DatePickerConfig;
labels?: DatepickerLabels;
label: string;
placeholder: string;
disabled: boolean;
required: boolean;
minDate?: string | Date;
maxDate?: string | Date;
isRange: boolean;
startView: 'month' | 'year' | 'multi-year';
value: any;
startDate?: string | Date;
endDate?: string | Date;
errorMessage: string;
width?: string;
height?: string;
borderRadius?: string;
fontSize?: string;
gap?: string;
fontFamily?: string;
labelColor?: string;
labelFontSize?: string;
labelFontWeight?: string;
backgroundColor?: string;
borderColor?: string;
borderWidth?: string;
padding?: string;
fontWeight?: string;
color?: string;
placeholderColor?: string;
focusBorderColor?: string;
errorColor?: string;
disabledBackgroundColor?: string;
disabledColor?: string;
boxShadow?: string;
dateChange: EventEmitter;
onChange: (value: any) => void;
onTouched: () => void;
focused: boolean;
ngOnInit(): void;
ngOnChanges(changes: SimpleChanges): void;
private updateFromConfig;
private updateFromLabels;
get requiredMarker(): string;
get startDateLabel(): string;
get endDateLabel(): string;
private formatDate;
get formattedValue(): string;
get formattedStartDate(): string;
get formattedEndDate(): string;
get formattedMin(): string;
get formattedMax(): string;
writeValue(value: any): void;
registerOnChange(fn: any): void;
registerOnTouched(fn: any): void;
setDisabledState(isDisabled: boolean): void;
onDateInput(event: any): void;
onBlur(): void;
onFocus(): void;
onRangeStartInput(event: any): void;
onRangeEndInput(event: any): void;
private updateRangeValue;
private getStyleValue;
get wrapperStyles(): {
[key: string]: string | undefined;
};
get labelStyles(): {
[key: string]: string | undefined;
};
get fieldStyles(): {
[key: string]: string | undefined;
};
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
interface SearchLabels {
label?: string;
placeholder?: string;
clearAriaLabel?: string;
}
interface FilterSearchConfig {
placeholder?: string;
label?: string;
value?: string;
disabled?: boolean;
debounceTime?: number;
clearable?: boolean;
width?: string;
height?: string;
borderRadius?: string;
fontSize?: string;
gap?: string;
fontFamily?: string;
labelColor?: string;
labelFontSize?: string;
labelFontWeight?: string;
backgroundColor?: string;
borderColor?: string;
borderWidth?: string;
border?: string;
padding?: string;
fontWeight?: string;
color?: string;
textColor?: string;
iconColor?: string;
placeholderColor?: string;
focusBorderColor?: string;
errorColor?: string;
disabledBackgroundColor?: string;
disabledColor?: string;
boxShadow?: string;
}
declare class SearchComponent implements ControlValueAccessor, OnInit, OnDestroy, OnChanges {
config?: FilterSearchConfig;
labels?: SearchLabels;
placeholder: string;
label: string;
disabled: boolean;
debounceMs: number;
clearable: boolean;
value: any;
width?: string;
height?: string;
borderRadius?: string;
fontSize?: string;
gap?: string;
fontFamily?: string;
labelColor?: string;
labelFontSize?: string;
labelFontWeight?: string;
backgroundColor?: string;
borderColor?: string;
borderWidth?: string;
border?: string;
padding?: string;
fontWeight?: string;
color?: string;
textColor?: string;
iconColor?: string;
placeholderColor?: string;
focusBorderColor?: string;
disabledBackgroundColor?: string;
disabledColor?: string;
boxShadow?: string;
search: EventEmitter;
clear: EventEmitter;
private searchSubject;
focused: boolean;
onChange: (value: any) => void;
onTouched: () => void;
ngOnInit(): void;
ngOnChanges(changes: SimpleChanges): void;
private updateFromConfig;
private updateFromLabels;
ngOnDestroy(): void;
get clearAriaLabel(): string;
writeValue(value: any): void;
registerOnChange(fn: any): void;
registerOnTouched(fn: any): void;
setDisabledState(isDisabled: boolean): void;
onInputChange(event: any): void;
onClear(): void;
onBlur(): void;
onFocus(): void;
private getStyleValue;
get wrapperStyles(): {
[key: string]: string | undefined;
};
get labelStyles(): {
[key: string]: string | undefined;
};
get fieldStyles(): {
[key: string]: string | undefined;
};
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
declare class ClickOutsideDirective {
private elementRef;
libClickOutside: EventEmitter;
constructor(elementRef: ElementRef);
onClick(target: any): void;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵdir: i0.ɵɵDirectiveDeclaration;
}
declare class FormComponentsModule {
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵmod: i0.ɵɵNgModuleDeclaration;
static ɵinj: i0.ɵɵInjectorDeclaration;
}
declare class TimePickerModule {
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵmod: i0.ɵɵNgModuleDeclaration;
static ɵinj: i0.ɵɵInjectorDeclaration;
}
declare class SmartFormModule {
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵmod: i0.ɵɵNgModuleDeclaration;
static ɵinj: i0.ɵɵInjectorDeclaration;
}
declare class FormBuilderModule {
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵmod: i0.ɵɵNgModuleDeclaration;
static ɵinj: i0.ɵɵInjectorDeclaration;
}
/**
* A single editable field row in the configurator.
* Wraps a leaf FieldConfig with visibility + mandatory state.
*
* `fieldConfig` is a live reference into the module's working (cloned) schema,
* so writing the node state back onto it is all that's needed to produce the
* updated schema — no fragile index re-matching required.
*/
interface ConfigFieldNode {
/** Live reference to the FieldConfig inside the working schema clone. */
fieldConfig: FieldConfig;
/** Display label (resolved through the optional translate fn at render time uses fieldConfig directly). */
label: string;
/** Raw field type (e.g. 'TEXT_INPUT', 'DROPDOWN'). */
type: string;
/** Whether the field is shown to end users. */
visible: boolean;
/** Whether the field is mandatory (required). Only meaningful when `visible` is true. */
mandatory: boolean;
/** Column span in the section's 12-column grid (1-12). Freely editable. */
colSpan: number;
/** When true, the visibility toggle is locked ON (cannot be hidden). */
lockVisibility: boolean;
/** When true, the mandatory control is locked (cannot be changed). */
lockMandatory: boolean;
/**
* Name of the field this one depends on, read from
* `optionConfig.dependencies.parentDataCode` (e.g. a `state` dropdown depends
* on `country`). When the parent is hidden, this field must be hidden too.
*/
parentName?: string;
/**
* Derived: true when this field's dependency parent is currently hidden.
* While true the field is force-hidden and its visibility toggle is disabled —
* the user must show the parent field before this one can be shown.
*/
visibilityLockedByParent: boolean;
}
/**
* A section / group in the configurator tree. Sections can nest recursively.
* A section with `fieldConfig === null` is a synthetic bundle of stray
* top-level leaf fields and has no visibility toggle of its own.
*/
interface ConfigSectionNode {
/** Section label. */
label: string;
/** Live reference to the GROUP/SUBFIELDS FieldConfig, or null for a synthetic bundle / root. */
fieldConfig: FieldConfig | null;
/** Live reference to the backing SectionConfig, when present. */
sectionConfig: SectionConfig | null;
/** Whether the whole section is shown to end users. */
visible: boolean;
/** When true, the section visibility toggle is locked ON. */
lockVisibility: boolean;
/** Whether the section is expanded in the UI tree. */
expanded: boolean;
/** Leaf fields directly inside this section. */
fields: ConfigFieldNode[];
/** Recursively nested child sections. */
subsections: ConfigSectionNode[];
/**
* Live reference to the schema array `fields` was parsed from (e.g. a section's
* `sectionConfig.children`, or the top-level `sectionConfig.children` for a
* synthetic bundle). Reordering writes directly into this array so the schema's
* own field order — not a separate `sequence` property — drives render order.
* Null when there is nothing to reorder into (e.g. an empty section).
*/
fieldsSource: FieldConfig[] | null;
/**
* False when this section's own children include a `ROW` wrapper. Reordering is
* disabled in that case — flattening a ROW's grouped children into plain
* siblings would silently break the row layout, so dragging is turned off
* instead of risking a corrupted schema.
*/
reorderable: boolean;
}
/**
* Signal-based store for the form-field-configuration component.
* Owns the section/field tree and the visibility + mandatory toggle logic.
* Provided at the component level (one store instance per configurator).
*/
declare class FieldConfigurationService {
private readonly tree;
private readonly _state;
readonly sections: i0.Signal;
/**
* Initialise from an input schema. The schema is deep-cloned so the caller's
* object is never mutated; the tree references the clone.
*/
loadSchema(schema: FormSchema): void;
/** Expand/collapse a section. Purely visual — does not change the schema. */
toggleSectionExpanded(path: number[]): void;
/**
* Toggle a section's visibility. Locked sections are ignored.
* Cascades: hiding disables every descendant field/subsection; showing
* re-enables all non-locked descendants.
*/
toggleSectionVisible(path: number[]): void;
/**
* Toggle a field's visibility. Ignored for locked fields and for fields whose
* dependency parent is currently hidden (their toggle is disabled in the UI).
* Hiding a field also hides every field that depends on it (transitively).
*/
toggleFieldVisible(path: number[], fieldIndex: number): void;
/** Toggle a field's mandatory flag. Ignored when locked or hidden. */
toggleFieldMandatory(path: number[], fieldIndex: number): void;
/** Set a field's column span, clamped to the 1-12 grid range. */
setFieldColSpan(path: number[], fieldIndex: number, colSpan: number): void;
/**
* Reorder a field within its own section (drag-and-drop). Reordering is scoped to
* one section's direct fields — dragging never moves a field across sections.
* Rejected (no-op) if the move would place a field above the field it depends on
* via `optionConfig.dependencies` (e.g. a "state" field can never sort above the
* "country" field it depends on).
*/
reorderField(path: number[], previousIndex: number, currentIndex: number): void;
/**
* Produce the updated schema. Writes the current tree state onto the working
* clone and returns a fresh deep clone (safe to hand to the host / submit).
* Returns null if no schema has been loaded.
*/
buildUpdatedSchema(): FormSchema | null;
private _updateSectionAtPath;
private _updateFieldAtPath;
private _mapSectionAtPath;
/** Re-apply field dependency rules to the current tree and commit the result. */
private _normalizeDependencies;
/**
* Enforce field dependencies expressed via `optionConfig.dependencies.parentDataCode`.
* A field can only be visible when its dependency parent is visible; hiding a
* parent cascades (transitively) to every dependent field. Locked-visible fields
* are never force-hidden.
*
* Returns a new tree with each field's `visible` / `mandatory` adjusted and its
* derived `visibilityLockedByParent` flag set (drives the disabled toggle in the UI).
*/
private _applyDependencyRules;
/**
* True when every field with a dependency parent (`parentName`) sorts after that
* parent within the given list. Fields whose parent isn't a sibling in this same
* list (cross-section dependency, or no such field) are unconstrained here.
*/
private _isValidFieldOrder;
/** Recursively set visibility on a section and all its descendants (respecting locks). */
private _cascadeVisibility;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵprov: i0.ɵɵInjectableDeclaration;
}
/** Payload for field-level events, carrying the sub-path from this section down. */
interface FieldEventPayload {
sectionPath: number[];
fieldIndex: number;
}
/** Payload for a field colSpan change, carrying the sub-path from this section down. */
interface FieldColSpanPayload extends FieldEventPayload {
colSpan: number;
}
/** Payload for a field drag-reorder, carrying the sub-path from this section down. */
interface FieldReorderPayload {
sectionPath: number[];
previousIndex: number;
currentIndex: number;
}
/**
* A recursive section/group node in the form-field-configuration tree.
* Emits path-relative events that parents prefix with their own index before
* bubbling up to the store.
*/
declare class ConfigSectionNodeComponent {
section: ConfigSectionNode;
depth: number;
translate?: (key: string) => string;
/** Emits the sub-path from this node downward (empty [] for self). */
toggleVisible: EventEmitter;
toggleExpanded: EventEmitter;
fieldToggleVisible: EventEmitter;
fieldToggleMandatory: EventEmitter;
fieldColSpanChange: EventEmitter;
fieldReorder: EventEmitter;
get displayLabel(): string;
get visibleFieldCount(): number;
get hasToggle(): boolean;
onToggleVisible(): void;
onToggleExpanded(): void;
onFieldToggleVisible(fieldIndex: number): void;
onFieldToggleMandatory(fieldIndex: number): void;
onFieldColSpanChange(fieldIndex: number, colSpan: number): void;
onFieldDrop(event: CdkDragDrop): void;
onSubToggleVisible(subIndex: number, subPath: number[]): void;
onSubToggleExpanded(subIndex: number, subPath: number[]): void;
onSubFieldToggleVisible(subIndex: number, payload: FieldEventPayload): void;
onSubFieldToggleMandatory(subIndex: number, payload: FieldEventPayload): void;
onSubFieldColSpanChange(subIndex: number, payload: FieldColSpanPayload): void;
onSubFieldReorder(subIndex: number, payload: FieldReorderPayload): void;
trackByIndex(index: number): number;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
/**
* Form Field Configuration
* ------------------------
* Renders a compact tree of a form schema's sections and fields, each with a
* **visibility** toggle, a **mandatory** control, an editable **column span**,
* and a drag handle to **reorder** fields within their own section. Intended to
* be embedded inside a `cc-confirmation-modal` on a host page ("Configure fields").
*
* Pass a `FormSchema` via `[schema]`. The input is deep-cloned, so it is never
* mutated. When the user confirms, call `getUpdatedSchema()` to read back the
* modified schema (visible/isEnabled/disabled, required, and colSpan flags
* updated, and each section's own children reordered to match the tree).
*
* Fields/sections carrying `lockVisibility: true` cannot be hidden, and
* `lockMandatory: true` freezes their required state.
*
* Reordering is scoped to one section's direct fields — a field can never be
* dragged into another section, and a field can never be dragged above a field
* it depends on via `optionConfig.dependencies` (e.g. "state" can't sort above
* "country"). Sections whose children include a `ROW` wrapper can't be
* reordered at all (dragging is disabled) to avoid flattening the row layout.
*
* @example
* ```html
*
*
*
* ```
* ```ts
* @ViewChild('cfg') cfg!: FormFieldConfigurationComponent;
* save() { this.updatedSchema = this.cfg.getUpdatedSchema(); }
* ```
*/
declare class FormFieldConfigurationComponent implements OnChanges {
/** The form schema to configure. Deep-cloned internally; never mutated. */
schema: FormSchema;
/** Optional label translator, e.g. an ngx-translate `instant` function. */
translate?: (key: string) => string;
/** Show the "Visible / Mandatory (only if visible)" legend row. Default true. */
showLegend: boolean;
protected readonly store: FieldConfigurationService;
ngOnChanges(changes: SimpleChanges): void;
/**
* Returns a fresh, modified copy of the schema with the current
* visibility/mandatory selections applied. Returns null if no schema loaded.
*/
getUpdatedSchema(): FormSchema | null;
onToggleVisible(sectionIndex: number, subPath: number[]): void;
onToggleExpanded(sectionIndex: number, subPath: number[]): void;
onFieldToggleVisible(sectionIndex: number, payload: FieldEventPayload): void;
onFieldToggleMandatory(sectionIndex: number, payload: FieldEventPayload): void;
onFieldColSpanChange(sectionIndex: number, payload: FieldColSpanPayload): void;
onFieldReorder(sectionIndex: number, payload: FieldReorderPayload): void;
trackByIndex(index: number): number;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
/**
* A single field row inside the form-field-configuration tree.
* Shows a visibility indicator + label on the left, and a "Mandatory"
* control + visibility toggle on the right.
*/
declare class ConfigFieldNodeComponent {
field: ConfigFieldNode;
/** Optional label translator (e.g. an ngx-translate instant fn). */
translate?: (key: string) => string;
toggleVisible: EventEmitter;
toggleMandatory: EventEmitter;
colSpanChange: EventEmitter;
get displayLabel(): string;
onColSpanInput(value: string): void;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
declare class FormFieldConfigurationModule {
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵmod: i0.ɵɵNgModuleDeclaration;
static ɵinj: i0.ɵɵInjectorDeclaration;
}
/**
* Parses a FormSchema into a configurator tree (sections + fields, each carrying
* visibility/mandatory state) and writes that tree back onto a schema.
*
* Nodes hold LIVE references to the FieldConfig objects inside the working schema
* clone, so `applyTreeToSchema` simply walks the tree and assigns the node state
* onto those references — there is no positional re-matching, which keeps it robust
* against ROWs, nested groups, and mixed leaf/section children.
*
* Field order is a plain property of the schema — there is no separate `sequence`
* field. Reordering rewrites the schema's own children array in place, so render
* order (which simply follows array order, as it always has) reflects the
* configurator's choices with no extra sorting logic anywhere else.
*/
declare class ConfigSchemaTreeService {
/**
* Build the configurator section tree from a schema.
* The passed schema is treated as the working copy — nodes reference its objects.
*/
parseSchema(schema: FormSchema): ConfigSectionNode[];
/**
* Write the current tree state back onto the schema the nodes reference.
* Sets isEnabled/visible/disabled for visibility, required for mandatory, and
* colSpan; and physically reorders each section's own children array to match
* the tree's current field order.
*/
applyTreeToSchema(sections: ConfigSectionNode[]): void;
private _buildSections;
private _buildSection;
private _createBundleSection;
private _buildField;
private _isSection;
private _applySection;
/**
* Rewrites `slots` in place so its leaf-field entries follow `fields`' current
* order. Section entries (GROUP/SUBFIELDS) keep their original array position —
* only the leaf fields move. Safe to call whenever `slots` contains no ROW
* (guaranteed by the `reorderable` flag the caller checks).
*/
private _reorderChildren;
private _applyField;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵprov: i0.ɵɵInjectableDeclaration;
}
interface TableOption {
label: string;
value: any;
}
interface TableColumnSubField {
key: string;
label?: string;
dataType: 'text' | 'number' | 'email' | 'select' | 'date';
placeholder?: string;
editable?: boolean;
options?: TableOption[];
editConfig?: {
disabled?: boolean;
defaultValue?: any;
};
}
/**
* Resolves raw codes returned by the row API into human-readable labels by
* calling a secondary "lookup" API (roles, MDM master data, statuses, ...).
*
* Works for BOTH shapes of row value:
* - a single code -> `gender: "GENDER.FEMALE"` => "Female"
* - an array of codes -> `roleCodes: ["role.a", "role.b"]` => "Role A, Role B"
* An object value (e.g. `{ code: 'X' }`) is normalized to its `code`/`value`/`id`
* before matching, so the same config works regardless of the API shape.
*
* The lookup API is called ONCE per distinct endpoint (not per row, not per cell)
* and the resulting code -> label map is cached for the life of the component.
* Columns pointing at the same endpoint share the same cache entry.
*
* Any HTTP verb is supported (`apiMethod`), with free-form `queryParams`,
* `apiPayload` and `headers` — this is not limited to plain GET endpoints.
*/
interface ColumnLookupConfig {
/**
* Name of a shared lookup declared in `TableConfig.lookups`. Any property set
* here overrides the shared definition, so `{ "ref": "roles" }` alone is enough
* to reuse one lookup across several columns.
*/
ref?: string;
/** Lookup endpoint. Supports a `{codes}` / `{value}` placeholder (see `paramName`). */
apiUrl?: string;
/** HTTP verb. Default: 'GET'. */
apiMethod?: 'GET' | 'POST' | 'PUT' | 'PATCH';
/** Static request body for non-GET verbs. Merged with `paramName` in targeted mode. */
apiPayload?: any;
/** Static query params, e.g. `{ classCode: 'CLASS.GENDER', size: 200 }`. Array values are repeated. */
queryParams?: {
[key: string]: any;
};
/** Extra headers, merged on top of the table's auth header. */
headers?: {
[key: string]: string;
};
/** Path to the array inside the response. Omit (or '') when the response IS the array. e.g. 'elements'. */
dataPath?: string;
/** Path inside each lookup item holding the code matched against the row value. Default: 'code'. */
valueKey?: string;
/** Path inside each lookup item holding the label. Supports array indexes, e.g. 'name[0].text'. Default: 'name'. */
labelKey?: string;
/**
* TARGETED MODE. When set, the full list is NOT downloaded: only the distinct
* codes present on the current page are requested, under this key.
* GET -> query param (`?codes=A,B`); non-GET -> body key (`{ "codes": ["A","B"] }`).
* Leave unset to fetch the whole list once and resolve everything client-side.
*/
paramName?: string;
/** How multiple codes are sent in targeted mode. Default: 'csv' for GET, 'array' otherwise. */
paramFormat?: 'csv' | 'repeat' | 'array';
/** Separator used when codes are joined into a CSV param / the `{codes}` placeholder. Default: ','. */
paramSeparator?: string;
/** Joins the labels when the row value is an array. Default: ', '. */
separator?: string;
/** Match codes case-insensitively. Default: true. */
caseInsensitive?: boolean;
/** What to show for a code with no match: 'code' shows the raw code (default), 'empty' drops it. */
fallback?: 'code' | 'empty';
/** Explicit cache bucket. Defaults to `ref`, else derived from method + url + params + payload. */
cacheKey?: string;
}
interface TableColumn {
key: string;
label: string;
type: 'text' | 'number' | 'date' | 'custom' | 'html' | 'badge';
sortable?: boolean;
editable?: boolean;
dataType?: 'text' | 'number' | 'date' | 'email' | 'select';
options?: TableOption[];
badgeConfig?: {
[key: string]: 'success' | 'warning' | 'danger' | 'info' | 'neutral';
};
width?: string;
cellClass?: string;
headerClass?: string;
sticky?: boolean;
labelPath?: string;
emptyValue?: string;
dateFormat?: string;
clickAction?: 'route' | 'callback';
clickRoute?: string;
subFields?: TableColumnSubField[];
/**
* Resolves the code(s) held in this column into display labels via a secondary API.
* Handles both a single code and an array of codes. See {@link ColumnLookupConfig}.
*/
lookupConfig?: ColumnLookupConfig;
editConfig?: {
disabled?: boolean;
defaultValue?: any;
};
/** Set to false to hide this column. Default: true. Driven by the column configurator. */
isEnabled?: boolean;
/** Backward-compatible visibility alias, kept in sync with isEnabled by the column configurator. */
visible?: boolean;
/** Configurator-only flag: when true the column can never be hidden (toggle is replaced by a lock). */
lockVisibility?: boolean;
/**
* Explicit display order (lower renders first). Columns without a sequence keep their
* original relative order, placed after any columns that do have one. Set automatically
* by the column configurator when the user reorders columns.
*/
sequence?: number;
}
interface TableFilter {
key: string;
label: string;
type: 'select' | 'text' | 'date';
options?: TableOption[];
apiUrl?: string;
apiMethod?: 'GET' | 'POST';
apiPayload?: any;
labelKey?: string;
valueKey?: string;
labelPath?: string;
valuePath?: string;
requestKey?: string;
dataPath?: string;
handling?: 'standard' | 'nested_string';
nestedStringConfig?: NestedStringConfig;
}
/**
* A single condition evaluated against a row to decide action visibility.
*
* `field` is a path into the row (supports nesting + array index, e.g.
* 'status.code', 'subStatus.code', 'name[0].text'). When the resolved value is
* an object (e.g. `{ code, name, value }`), it is normalized to its `code`
* (then `name`, then `value`) so the SAME rule works whether the API returns
* `status: { code: 'ACTIVE' }` or `status: 'ACTIVE'`.
*
* String comparisons are case-insensitive.
*/
interface VisibilityRule {
/** Path into the row, e.g. 'status.code' or just 'status'. */
field: string;
/** Comparison operator. Default: 'eq'. */
operator?: 'eq' | 'neq' | 'in' | 'nin' | 'truthy' | 'falsy';
/** Comparison value for 'eq' / 'neq'. */
value?: any;
/** Comparison list for 'in' / 'nin'. */
values?: any[];
}
/**
* Row-aware visibility config shared by actions and action items.
* - `visibleWhen`: ALL rules must pass (AND) for the action to show.
* - `hiddenWhen`: if ANY rule passes (OR), the action is hidden.
* `hiddenWhen` takes precedence over `visibleWhen`. Either may be a single
* rule or an array of rules.
*/
interface ActionVisibility {
visibleWhen?: VisibilityRule | VisibilityRule[];
hiddenWhen?: VisibilityRule | VisibilityRule[];
}
interface TableActionItem extends ActionVisibility {
label: string;
type: 'api' | 'callback' | 'route' | 'delete';
icon?: string;
apiUrl?: string;
apiMethod?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
route?: string;
confirmationNeeded?: boolean;
confirmationMessage?: string;
callback?: (row: any) => void;
/** Set to false to hide this action item. Default: true */
isEnabled?: boolean;
/** Config for native 'delete' action type — drives the built-in confirmation modal */
deleteConfig?: {
apiUrl: string;
idField?: string;
modalTitle?: string;
modalMessage?: string;
confirmLabel?: string;
cancelLabel?: string;
};
}
interface TableAction extends ActionVisibility {
label: string;
type: 'api' | 'callback' | 'route' | 'edit' | 'dropdown';
icon?: string;
btnVariant?: 'primary' | 'secondary' | 'outline' | 'danger' | 'warning' | 'success' | 'danger-outline';
apiUrl?: string;
apiMethod?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
route?: string;
confirmationNeeded?: boolean;
confirmationMessage?: string;
callback?: (row: any) => void;
items?: TableActionItem[];
/** Set to false to hide this action. Default: true */
isEnabled?: boolean;
}
interface PaginationConfig {
enabled: boolean;
pageSize: number;
pageSizeOptions: number[];
totalCountConfig?: {
source: 'same' | 'separate';
apiUrl?: string;
responsePath?: string;
};
}
interface TableTheme {
primaryColor?: string;
headerBg?: string;
headerColor?: string;
rowHoverBg?: string;
borderColor?: string;
}
interface NestedStringConfig {
paramName: string;
baseValue?: string;
separator: string;
assignment: string;
}
interface QueryParamsConfig {
pageKey?: string;
sizeKey?: string;
sortKey?: string;
orderKey?: string;
pageIndexOffset?: number;
filterHandling?: 'standard' | 'nested_string';
nestedStringConfig?: NestedStringConfig;
}
interface TableConfig {
columns: TableColumn[];
apiUrl?: string;
apiMethod?: 'GET' | 'POST';
apiPayload?: any;
dataResponsePath?: string;
filters?: TableFilter[];
filterData?: {
[key: string]: any[];
};
/**
* Reusable lookup definitions, referenced from a column via
* `lookupConfig: { "ref": "" }`. Columns may override any property inline.
*/
lookups?: {
[key: string]: ColumnLookupConfig;
};
pagination?: PaginationConfig;
actions?: TableAction[];
topBarButtons?: TableAction[];
sortBy?: string;
orderBy?: 'ASC' | 'DESC';
theme?: TableTheme;
requestParams?: Function;
selectable?: boolean;
/**
* When `selectable` is true: `true`/omitted renders a checkbox per row (multiple rows
* selectable, plus a "select all" header checkbox). `false` renders a radio button per
* row instead — only one row selectable at a time, and the header checkbox is hidden.
*/
multiSelect?: boolean;
queryParamsConfig?: QueryParamsConfig;
labels?: TableLabels;
searchConfig?: SearchConfig;
maxHeight?: string;
stickyHeader?: boolean;
stickyColumnCount?: number;
token?: string;
tokenHeader?: string;
editingRowClass?: string;
/** Fallback text for any cell whose value is null, undefined, or empty string.
* Overridden per-column via TableColumn.emptyValue. Library default: '-' */
emptyValue?: string;
}
interface SearchConfig {
enabled: boolean;
searchKey?: string;
debounceTime?: number;
handling?: 'standard' | 'nested_string';
minimumCharacter?: number;
}
interface TableLabels {
searchPlaceholder?: string;
actionColumnHeader?: string;
noDataMessage?: string;
itemsPerPageLabel?: string;
defaultConfirmationMessage?: string;
saveLabel?: string;
cancelLabel?: string;
addLabel?: string;
/** Variant for the Add button (new row). Defaults to 'danger'. */
addButtonVariant?: 'primary' | 'secondary' | 'outline' | 'danger' | 'warning' | 'success' | 'danger-outline';
/** Variant for the Save button (edit row). Defaults to 'primary'. */
saveButtonVariant?: 'primary' | 'secondary' | 'outline' | 'danger' | 'warning' | 'success' | 'danger-outline';
}
/**
* Emitted by the SmartTableComponent when operating in external-data mode
* (i.e. when [tableData] input is provided by the parent).
* The parent is responsible for fetching updated data based on this event
* and providing it back via [tableData] and [totalItemsCount].
*/
interface TableDataChangeEvent {
page: number;
pageSize: number;
sortBy?: string;
orderBy?: 'ASC' | 'DESC';
searchTerm?: string;
filters?: {
[key: string]: any;
};
}
interface TableRowSaveEvent {
row: any;
isNew: boolean;
}
/**
* A single editable column row in the column configurator.
* Wraps a TableColumn with its visibility + lock state.
*
* `column` is a live reference into the module's working (cloned) config, so
* writing the node state back onto it is all that's needed to produce the
* updated config — no fragile index re-matching required.
*/
interface ConfigColumnNode {
/** Live reference to the TableColumn inside the working config clone. */
column: TableColumn;
/** Raw label (i18n key or text); resolved through the optional translate fn at render time. */
label: string;
/** Whether the column is shown in the table. */
visible: boolean;
/** When true, the visibility toggle is locked ON (column can never be hidden). */
lockVisibility: boolean;
}
/**
* Signal-based store for the table-column-configuration component.
* Owns the column list and the visibility toggle logic.
* Provided at the component level (one store instance per configurator).
*/
declare class TableColumnConfigurationService {
private readonly _state;
readonly columns: i0.Signal;
/**
* Initialise from an input table config. The config is deep-cloned so the
* caller's object is never mutated; the nodes reference the clone.
*/
loadConfig(config: TableConfig): void;
/** Toggle a column's visibility. Locked columns are ignored. */
toggleColumnVisible(index: number): void;
/** Move a column from `previousIndex` to `currentIndex` (drag-and-drop reorder). */
reorderColumn(previousIndex: number, currentIndex: number): void;
/**
* Produce the updated config. Writes the current node state onto the working
* clone and returns a fresh deep clone (safe to hand to the host / persist).
* Returns null if no config has been loaded.
*/
buildUpdatedConfig(): TableConfig | null;
private _buildColumn;
/**
* Orders columns by `sequence` (ascending). Columns without a `sequence` keep their
* original relative order, placed after any columns that do have one — so configs that
* never set `sequence` come back untouched (stable sort).
*/
private _sortBySequence;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵprov: i0.ɵɵInjectableDeclaration;
}
/**
* Table Column Configuration
* --------------------------
* Renders a compact list of a table config's columns, each with a **visibility**
* toggle and a drag handle for **reordering**. Intended to be embedded inside a
* `cc-confirmation-modal` on a host page ("Configure columns").
*
* Pass a `TableConfig` via `[config]`. The input is deep-cloned, so it is never
* mutated. Columns load pre-sorted by `sequence` (if set); columns without a
* `sequence` keep their original relative order. When the user confirms, call
* `getUpdatedConfig()` to read back the modified config (isEnabled/visible flags
* and `sequence` updated per column, in the new order).
*
* Columns carrying `lockVisibility: true` cannot be hidden — their toggle is
* replaced by a lock icon. They can still be dragged to reorder.
*
* @example
* ```html
*
*
*
* ```
* ```ts
* @ViewChild('cfg') cfg!: TableColumnConfigurationComponent;
* save() { this.updatedConfig = this.cfg.getUpdatedConfig(); }
* ```
*/
declare class TableColumnConfigurationComponent implements OnChanges {
/** The table config to configure. Deep-cloned internally; never mutated. */
config: TableConfig;
/** Optional label translator, e.g. an ngx-translate `instant` function. */
translate?: (key: string) => string;
/** Show the "Visible" legend row. Default true. */
showLegend: boolean;
protected readonly store: TableColumnConfigurationService;
ngOnChanges(changes: SimpleChanges): void;
/**
* Returns a fresh, modified copy of the config with the current visibility
* selections applied. Returns null if no config has been loaded.
*/
getUpdatedConfig(): TableConfig | null;
onToggleVisible(index: number): void;
/** Drag-and-drop reorder. Written back as `sequence` on each column by `getUpdatedConfig()`. */
onDrop(event: CdkDragDrop): void;
trackByIndex(index: number): number;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
/**
* A single column row inside the table-column-configuration list.
* Shows a visibility indicator + column name on the left and a visibility
* toggle (or a lock, when the column is locked visible) on the right.
*/
declare class ConfigColumnNodeComponent {
column: ConfigColumnNode;
/** Optional label translator (e.g. an ngx-translate instant fn). */
translate?: (key: string) => string;
toggleVisible: EventEmitter;
get displayLabel(): string;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
declare class TableColumnConfigurationModule {
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵmod: i0.ɵɵNgModuleDeclaration;
static ɵinj: i0.ɵɵInjectorDeclaration;
}
interface DropdownAction {
label: string;
type: 'api' | 'route' | 'callback';
icon?: string;
color?: string;
variant?: ButtonVariant;
route?: string;
apiUrl?: string;
apiMethod?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
apiPayload?: any;
callback?: (data: any) => void;
disabled?: boolean;
confirmationNeeded?: boolean;
confirmationMessage?: string;
confirmationTitle?: string;
}
declare class ButtonDropdownComponent {
private elementRef;
private router;
private http;
label: string;
variant: ButtonVariant;
menuTheme: 'light' | 'dark';
icon: string;
actions: DropdownAction[];
data: any;
disabled: boolean;
apiActionStart: EventEmitter;
apiActionSuccess: EventEmitter<{
action: DropdownAction;
response: any;
}>;
apiActionError: EventEmitter<{
action: DropdownAction;
error: any;
}>;
actionClick: EventEmitter<{
action: DropdownAction;
data: any;
}>;
isOpen: boolean;
isConfirmModalOpen: boolean;
pendingAction: DropdownAction | null;
confirmConfig: ConfirmationModalConfig | null;
confirmMessage: string;
constructor(elementRef: ElementRef, router: Router, http: HttpClient);
onClickOutside(event: Event): void;
toggleDropdown(event: Event): void;
onActionItemClick(action: DropdownAction, event: Event): void;
private executeAction;
private navigateToRoute;
private executeApiCall;
invokePendingAction(): void;
closeConfirmModal(): void;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
declare class ConfirmationModalComponent implements OnInit, OnDestroy {
config: ConfirmationModalConfig;
isOpen: boolean;
confirmDisabled: boolean;
confirmLoading: boolean;
confirm: EventEmitter;
cancel: EventEmitter;
close: EventEmitter;
showCodeSnippet: EventEmitter;
private defaultConfig;
mergedConfig: ConfirmationModalConfig;
private previousActiveElement;
private isSubmitting;
private _resetSubmittingTimer?;
ngOnInit(): void;
ngOnChanges(): void;
private updateConfig;
ngOnDestroy(): void;
private toggleBodyScroll;
handleEscape(event: KeyboardEvent): void;
onBackdropClick(event: MouseEvent): void;
onConfirm(): void;
onCancel(): void;
onClose(): void;
onShowCodeSnippet(): void;
getModalWidth(): string;
getModalStyles(): any;
getConfirmButtonClass(): string;
getHeaderClass(): string;
resolveIconType(icon: any): 'material' | 'custom' | 'img';
getIconValue(icon: any): string;
getIconColor(icon: any): string | undefined;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
declare class ConfirmationModalModule {
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵmod: i0.ɵɵNgModuleDeclaration;
static ɵinj: i0.ɵɵInjectorDeclaration;
}
declare class ButtonDropdownModule {
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵmod: i0.ɵɵNgModuleDeclaration;
static ɵinj: i0.ɵɵInjectorDeclaration;
}
type FilterItemType = 'input' | 'dropdown' | 'checkbox' | 'radio' | 'toggle' | 'datepicker' | 'active-search' | 'group' | 'custom' | 'divider';
interface FilterItem {
key?: string;
type: FilterItemType;
label?: string;
visible?: boolean;
inputConfig?: InputConfig;
dropdownConfig?: DropdownConfig;
checkboxConfig?: CheckboxConfig;
radioConfig?: RadioConfig;
toggleConfig?: ToggleConfig;
datepickerConfig?: DatePickerConfig;
searchConfig?: FilterSearchConfig;
children?: FilterItem[];
expanded?: boolean;
styles?: {
[key: string]: string;
};
}
interface FilterSidebarConfig {
items: FilterItem[];
styles?: {
width?: string;
padding?: string;
gap?: string;
backgroundColor?: string;
headerHeight?: string;
borderRadius?: string;
};
header?: {
title?: string;
icon?: string;
visible?: boolean;
showClose?: boolean;
};
footer?: {
visible?: boolean;
applyButton?: {
label?: string;
visible?: boolean;
disabled?: boolean;
};
clearButton?: {
label?: string;
visible?: boolean;
};
};
settings?: {
collapsible?: boolean;
persistent?: boolean;
showCodeSnippet?: boolean;
};
labels?: {
collapseAriaLabel?: string;
expandAriaLabel?: string;
closeAriaLabel?: string;
codeSnippetAriaLabel?: string;
};
}
interface FilterSidebarOutput {
[key: string]: any;
}
interface FilterSidebarChangeEvent {
key: string;
value: any;
allFilters: FilterSidebarOutput;
}
type FilterConfig = FilterSidebarConfig;
type FilterChangeEvent = FilterSidebarChangeEvent;
type FilterOutput = FilterSidebarOutput;
declare class FilterSidebarComponent implements OnInit, ControlValueAccessor {
private router;
private route;
config: FilterSidebarConfig;
initialFilters: FilterSidebarOutput;
filterChange: EventEmitter;
filterApply: EventEmitter;
filterClear: EventEmitter;
showCodeSnippet: EventEmitter;
close: EventEmitter;
filters: FilterSidebarOutput;
onChange: any;
onTouched: any;
isCollapsed: boolean;
toggleCollapse(): void;
constructor(router: Router, route: ActivatedRoute);
ngOnInit(): void;
writeValue(value: any): void;
registerOnChange(fn: any): void;
registerOnTouched(fn: any): void;
onValueChange(key: string | undefined, value: any): void;
private notifyChanges;
private updateUrl;
applyFilters(): void;
clearFilters(): void;
onClose(): void;
onShowCodeSnippet(): void;
get sidebarStyles(): {
[key: string]: string;
};
trackByFn(index: number, item: FilterItem): any;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
declare class FilterSidebarModule {
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵmod: i0.ɵɵNgModuleDeclaration;
static ɵinj: i0.ɵɵInjectorDeclaration;
}
interface TableFilterItem {
key?: string;
type: FilterItemType;
label?: string;
visible?: boolean;
inputConfig?: InputConfig;
dropdownConfig?: DropdownConfig;
checkboxConfig?: CheckboxConfig;
radioConfig?: RadioConfig;
toggleConfig?: ToggleConfig;
datepickerConfig?: DatePickerConfig;
searchConfig?: FilterSearchConfig;
children?: TableFilterItem[];
expanded?: boolean;
styles?: {
[key: string]: string;
};
}
interface TableFilterConfig {
items: TableFilterItem[];
styles?: {
width?: string;
padding?: string;
gap?: string;
backgroundColor?: string;
borderRadius?: string;
headerHeight?: string;
};
columns?: TableFilterColumn[];
settings?: {
persistent?: boolean;
collapsible?: boolean;
};
actions?: {
clear?: {
visible?: boolean;
label?: string;
};
apply?: {
visible?: boolean;
label?: string;
};
};
}
interface TableFilterColumn {
id: string;
label: string;
visible: boolean;
filterable?: boolean;
filterOptions?: any[];
}
interface TableFilterLabels {
filterBtn: string;
clear: string;
apply: string;
search: string;
columns: string;
showAll: string;
hideAll: string;
items?: string;
}
interface TableFilterOutput {
[key: string]: any;
}
interface TableFilterChangeEvent {
key: string;
value: any;
allFilters: TableFilterOutput;
}
declare class FilterComponent implements OnInit {
private elementRef;
private router;
private route;
config: TableFilterConfig;
activeFilters: TableFilterOutput;
columns: TableFilterColumn[];
labels: TableFilterLabels;
theme: string;
filterChange: EventEmitter;
columnChange: EventEmitter;
toggle: EventEmitter;
isOpen: boolean;
activeTab: 'filters' | 'columns';
tempFilters: TableFilterOutput;
tempColumns: TableFilterColumn[];
constructor(elementRef: ElementRef, router: Router, route: ActivatedRoute);
ngOnInit(): void;
private initFromUrl;
onClickOutside(event: Event): void;
togglePanel(): void;
setActiveTab(tab: 'filters' | 'columns'): void;
onFilterChange(key: string | undefined, value: any): void;
toggleColumn(columnId: string): void;
toggleAllColumns(visible: boolean): void;
clearAll(): void;
apply(): void;
private updateUrl;
activeFilterCountValue(): number;
get activeFilterCount(): number;
private syncTempState;
get containerStyles(): {
[key: string]: string;
};
trackByFn(index: number, item: any): any;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
declare class FilterModule {
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵmod: i0.ɵɵNgModuleDeclaration;
static ɵinj: i0.ɵɵInjectorDeclaration;
}
interface SummaryCardConfig {
header: string;
value: string;
description?: string;
icon?: string;
iconImage?: string;
descriptionPosition?: 'bottom' | 'inline';
valueSubtext?: string;
metaData?: SummaryCardMeta[];
valueColor?: string;
headerColor?: string;
descriptionColor?: string;
iconColor?: string;
iconBackgroundColor?: string;
iconClass?: string;
valueClass?: string;
headerClass?: string;
descriptionClass?: string;
isDisabled?: boolean;
isClickable?: boolean;
}
interface SummaryCardMeta {
text: string;
type?: 'text' | 'pill';
color?: string;
backgroundColor?: string;
cssClass?: string;
}
interface SummaryCardLabels {
iconAlt: string;
}
declare class SummaryCardComponent {
config: SummaryCardConfig;
theme?: 'theme-1' | 'theme-2';
labels: any;
cardClick: EventEmitter;
constructor();
onCardClick(): void;
get cardClasses(): {
[key: string]: boolean;
};
get iconStyles(): {
[key: string]: string;
};
get headerStyles(): {
[key: string]: string;
};
get valueStyles(): {
[key: string]: string;
};
get descriptionStyles(): {
[key: string]: string;
};
get isDescriptionInline(): boolean;
getMetaStyles(meta: SummaryCardMeta): {
[key: string]: string;
};
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
declare class SummaryCardModule {
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵmod: i0.ɵɵNgModuleDeclaration;
static ɵinj: i0.ɵɵInjectorDeclaration;
}
type FieldType = 'text' | 'number' | 'email' | 'tel' | 'password' | 'select' | 'radio' | 'textarea' | 'date' | 'composite' | 'file' | 'dropdown' | 'url';
type KeyType = 'KEY_TYPE.UI_INPUT' | 'KEY_TYPE.NESTED_REF_JSON' | 'KEY_TYPE.REF_JSON';
type UIType = 'UI_TYPE.TEXT' | 'UI_TYPE.DROP_DOWN' | 'UI_TYPE.RADIO' | 'UI_TYPE.DATE' | 'UI_TYPE.FILE' | 'UI_TYPE.TEXTAREA';
type UISubType = 'UI_SUBTYPE.SHORT_TEXT' | 'UI_SUBTYPE.LONG_TEXT' | 'UI_SUBTYPE.NUMBER' | 'UI_SUBTYPE.EMAIL' | 'UI_SUBTYPE.PHONE' | 'UI_SUBTYPE.URL';
type OptionDTO = 'OPTION_DTO.REF_DATA' | 'OPTION_DTO.STATIC';
interface FormOption {
label: string;
value: any;
code?: string;
name?: string;
}
interface OptionConfig {
optionDTO: OptionDTO;
class?: string;
url?: string;
labelKey?: string;
requestKey?: string;
valueKey?: string;
staticOptions?: FormOption[];
}
interface UIConfig {
type: UIType;
subType?: UISubType;
dependent?: string[];
optionConfigs?: OptionConfig;
minCharacters?: number;
maxCharacters?: number;
}
interface ValidationRules {
isMandatory?: boolean;
isRequired?: boolean;
minLength?: number;
maxLength?: number;
pattern?: string;
min?: number;
max?: number;
}
interface UploadedFile {
name: string;
size: number;
type: string;
url?: string;
file?: File;
}
interface FormField {
type?: FieldType;
name: string;
label?: string;
jsonKey?: string;
sequence?: number;
keyType?: KeyType;
uiConfig?: UIConfig;
validationRules?: ValidationRules;
placeholder?: string;
hint?: string;
helpText?: string;
options?: FormOption[];
required?: boolean;
mandatory?: boolean;
disabled?: boolean;
visible?: boolean;
class?: string;
value?: any;
icon?: string;
suffixIcon?: string;
prefixIcon?: string;
suffixText?: string;
readonly?: boolean;
subFields?: FormField[];
separator?: string;
dependsOn?: string;
dependent?: string[];
accept?: string;
multiple?: boolean;
uploadedFiles?: UploadedFile[];
optionConfigs?: OptionConfig;
loadedOptions?: FormOption[];
compositeValidationRule?: 'minTotal' | 'percentageTotal' | 'minMax';
}
interface FormSection {
sectionTitle?: string;
fields: FormField[];
isRepeater?: boolean;
addLabel?: string;
removeLabel?: string;
repeaterItemLabel?: string;
formArrayName?: string;
noCardLayout?: boolean;
collapsible?: boolean;
collapsed?: boolean;
minItems?: number;
maxItems?: number;
class?: string;
}
interface FormConfig {
sections: FormSection[];
entityType?: string;
}
interface JsonFieldConfig {
jsonKey: string;
sequence: number;
label: string;
keyType: KeyType;
validationRules?: ValidationRules;
uiConfig: UIConfig;
}
interface JsonFormConfig {
entityType: string;
label: string;
jsonConfig: JsonFieldConfig[];
}
declare class ConfigurableFormComponent implements OnInit, OnChanges {
private fb;
private snackBar;
private http;
config: FormConfig;
jsonConfig: JsonFormConfig;
data: any;
baseApiUrl: string;
labels: any;
optionsLoad: EventEmitter;
form: FormGroup;
processedConfig: FormConfig;
fieldVisibilityMap: Map;
passwordFieldState: Map;
constructor(fb: FormBuilder, snackBar: MatSnackBar, http: HttpClient);
ngOnInit(): void;
ngOnChanges(changes: SimpleChanges): void;
initializeForm(): void;
transformJsonConfig(jsonConfig: JsonFormConfig): FormConfig;
transformJsonField(jsonField: JsonFieldConfig): FormField;
mapUISubTypeToFieldType(subType?: string): FieldType;
normalizeFields(): void;
initializeFieldVisibility(): void;
buildForm(): void;
createCompositeValidator(field: FormField): (control: AbstractControl) => {
[x: string]: boolean;
};
createControl(field: FormField): FormControl;
createGroup(fields: FormField[]): FormGroup;
getFormArray(name: string): FormArray;
addRepeaterItem(section: FormSection): void;
removeRepeaterItem(sectionName: string, index: number): void;
validate(): boolean;
scrollToFirstInvalidControl(): void;
setupDependencies(): void;
onFieldValueChange(field: FormField, value: any): void;
loadFieldOptions(field: FormField, parentValues?: any): void;
extractOptions(data: any[], config: any): FormOption[];
getFieldOptions(field: FormField): FormOption[];
isFieldVisible(field: FormField): boolean;
toggleFieldVisibility(field: FormField, visible: boolean): void;
updateControlValidators(control: AbstractControl, field: FormField): void;
onFileChange(event: any, field: FormField): void;
removeFile(field: FormField, index: number): void;
updateFileControlValue(field: FormField): void;
getCharacterCount(fieldName: string): number;
toggleSection(section: FormSection): void;
private findFieldByName;
get sections(): FormSection[];
togglePassword(fieldName: string): void;
isPasswordVisible(fieldName: string): boolean;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
declare class ConfigurableFormModule {
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵmod: i0.ɵɵNgModuleDeclaration;
static ɵinj: i0.ɵɵInjectorDeclaration;
}
interface SideNavItem {
id: string;
label: string;
icon?: string;
route?: string;
roles?: string[];
disabled?: boolean;
showArrow?: boolean;
tooltip?: string;
}
interface SideNavStyleConfig {
bg?: string;
width?: string;
collapsedWidth?: string;
fontFamily?: string;
headingColor?: string;
itemColor?: string;
itemHoverBg?: string;
activeBg?: string;
activeColor?: string;
activeHoverBg?: string;
toggleBg?: string;
toggleBorderColor?: string;
tooltipBg?: string;
tooltipColor?: string;
tooltipFontWeight?: string;
tooltipLetterSpacing?: string;
tooltipOffset?: string;
tooltipShadow?: string;
}
interface SideNavSection {
heading?: string;
items: SideNavItem[];
}
declare class SideNavComponent implements OnChanges {
sections: SideNavSection[];
userRoles?: string[];
activeId?: string;
styleConfig?: SideNavStyleConfig;
/** Control whether the nav is collapsed externally (two-way bindable) */
collapsed: boolean;
/** Width of the nav when expanded. Overrides the CSS variable default. */
width?: string;
/** Width of the nav when collapsed (icons only). Overrides the CSS variable default. */
collapsedWidth?: string;
/** Whether to show the collapse toggle button */
showCollapseToggle: boolean;
/** Whether to hide icons when the side nav is expanded */
hideIconsWhenExpanded: boolean;
/** Whether to show tooltips on nav items */
showTooltips: boolean;
/** Position of the tooltip */
tooltipPosition: TooltipPosition;
/** Optional dictionary for label translation */
labels?: {
[key: string]: string;
};
itemClicked: EventEmitter;
/** Emits whenever the collapsed state changes (supports two-way binding via [(collapsed)]) */
collapsedChange: EventEmitter;
/** Applies collapsed class to :host for the width CSS transition */
get isHostCollapsed(): boolean;
filteredSections: SideNavSection[];
ngOnChanges(changes: SimpleChanges): void;
private filterAndMapSections;
onItemClick(item: SideNavItem, event: Event): void;
toggleCollapse(): void;
get customStyles(): {
[key: string]: string;
};
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
declare class SideNavModule {
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵmod: i0.ɵɵNgModuleDeclaration;
static ɵinj: i0.ɵɵInjectorDeclaration;
}
/**
* Maps a SmartForm field name to its corresponding API query-param key.
*/
interface FilterParamMap {
/** Field name as declared in sectionConfig.children (e.g. "country") */
formFieldName: string;
/** Actual query-param key sent to the table API (e.g. "currentCountryCode") */
apiParamKey: string;
}
/**
* Configuration for the left-hand filter panel (powered by SmartForm).
*/
interface FilterPanelConfig {
/** Full SmartForm JSON schema (entityType, sectionConfig, actionBarConfig, etc.) */
smartFormConfig: FormSchema;
/** Maps each form field to the API query-param that the table expects */
filterParamMapping: FilterParamMap[];
/**
* Controls whether filter parameters are appended as URL query parameters ('queryParams')
* or merged into tableConfig.apiPayload ('apiPayload').
* Default: 'queryParams' for GET, 'apiPayload' for POST.
*/
filterTarget?: 'queryParams' | 'apiPayload';
/**
* Optional default values pre-filled when the component opens AND restored on Clear Filter.
* Key = formFieldName, Value = the field value.
* When provided, the initial table load will include these params.
*/
defaultValues?: Record;
/**
* List of field names that should be rendered as disabled/read-only.
* The values are still used when building API params, but users cannot change them.
* Their values are preserved when Clear Filter is triggered.
*/
disabledFields?: string[];
/**
* i18n key or literal text for the "Clear Filter" button.
* Defaults to 'COMMON.FILTER_TABLE.CLEAR_FILTER'.
*/
clearFilterLabel?: string;
/**
* i18n key or literal text for the "Apply Filter" button.
* Defaults to 'COMMON.FILTER_TABLE.APPLY_FILTER'.
*/
applyFilterLabel?: string;
}
/**
* Controls selection behaviour and bottom action bar labels.
*/
interface SelectionConfig {
/** Allow selecting multiple rows (true = checkbox per row, false = radio). */
multiSelect: boolean;
/**
* i18n token for the "X of Y users Selected" counter.
* Use placeholders {selected} and {total}.
* Example: "COMMON.FILTER_TABLE.SELECTION_COUNT"
*/
selectionCountLabel: string;
/** i18n token (or literal text) for the primary submit button. */
submitButtonLabel: string;
/** i18n token (or literal text) for the secondary cancel/back button. */
cancelButtonLabel: string;
}
/**
* Top-level configuration object for FilterTableSelectorComponent.
*/
interface FilterTableSelectorConfig {
/** Dialog / modal heading. */
title?: string;
/** Left-panel filter form configuration. */
filterConfig: FilterPanelConfig;
/**
* Right-panel table configuration.
* Extends the standard SmartTable config; `selectable` should be true.
* `multiSelect` is controlled via selectionConfig.multiSelect.
*/
tableConfig: FilterTableConfig;
/** Selection behaviour and bottom action bar labels. */
selectionConfig: SelectionConfig;
}
/**
* Extended TableConfig for FilterTableSelector.
* `multiSelect` (checkbox vs. radio row selection) is inherited from `TableConfig`.
*/
interface FilterTableConfig extends TableConfig {
}
declare class FilterTableSelectorComponent implements OnInit, OnChanges, OnDestroy {
private cdr;
private ngZone;
/** Full config object driven by consuming MFE JSON. */
config: FilterTableSelectorConfig;
/**
* Flat i18n labels map from the consuming MFE.
* Mirrors the pattern used by SmartFormComponent.
*/
labels: Record;
/**
* Pre-selected row identifiers.
* When provided, matching rows are pre-checked on first load and
* re-checked after each page navigation.
* Must be an array of row objects (the same shape returned by the API).
*/
preSelectedRows: any[];
/** Emits the array of currently selected row objects on "Add / Submit". */
onSubmit: EventEmitter;
/** Emits void on "Back / Cancel". */
onCancel: EventEmitter;
/** A deep-copy of tableConfig with the current filter params baked-in. */
resolvedTableConfig: FilterTableConfig;
/** Current active filter params (merged from form submission). Array values become repeated
* query-param keys (e.g. roleCodes=1&roleCodes=2), not comma-joined. */
activeFilterParams: Record;
/** The base API URL without any filter query params. */
private baseApiUrl;
/** All rows selected so far, tracked across pagination pages. */
selectedRows: any[];
/** Total rows currently loaded in the table (reported by SmartTable rowSelect). */
totalTableItems: number;
/** Serialised SmartForm JSON (with labels translated + disabled fields applied). */
resolvedFormJson: string;
/**
* Default values to prefill the SmartForm.
* Updated on each initialize() call and reset to config defaults on Clear Filter.
*/
resolvedInitialValues: Record;
/**
* Version counter — bumping this forces *ngIf to re-create the SmartForm
* component with fresh initial values (used by Clear Filter).
*/
formVersion: number;
/** Whether the filter panel is visible (toggled on mobile, always visible on desktop). */
filterPanelVisible: boolean;
/**
* Tracks the live form values as the user changes fields.
* Updated via SmartForm's (valueChange) output.
* Used when the user clicks the "Apply Filter" button in the component.
*/
currentFormValues: Record;
private destroy$;
constructor(cdr: ChangeDetectorRef, ngZone: NgZone);
ngOnInit(): void;
ngOnChanges(changes: SimpleChanges): void;
ngOnDestroy(): void;
private initialize;
/**
* Serialises the SmartForm config JSON.
* Applies disabledFields from filterPanelConfig.
*/
private buildFormJson;
/**
* Rebuilds resolvedTableConfig.
* If filterTarget is 'apiPayload' (or tableConfig.apiMethod is 'POST'), filter parameters are merged into apiPayload.
* Otherwise, filter parameters are appended to apiUrl as query string parameters.
*/
private applyFilterParamsToTable;
/**
* Converts a flat form-value map to API param key/value pairs using the configured
* filterParamMapping, PLUS an identity fallback (formFieldName used as-is for apiParamKey)
* for any form field that mapping doesn't explicitly cover. Without that fallback, a field a
* consuming MFE adds to its smartFormConfig — e.g. an address dropdown chain injected from the
* app's own TS — could never be forwarded to the API unless someone went back and hand-added a
* filterParamMapping entry for it. An explicit mapping entry still wins whenever both exist (e.g.
* remapping "country" to "currentCountryCode"), so nothing already relying on a renamed key
* changes behavior.
*/
private buildFilterParams;
/**
* Called every time a form field value changes (SmartForm valueChange output).
* We track the current values so the component-level "Apply Filter" button
* can read them without relying on a form submit button inside the JSON config.
*/
onFormValueChange(values: Record): void;
/**
* Called when the user clicks the "Apply Filter" button rendered by the component.
* Builds API params from the tracked form values and reloads the table.
*/
applyCurrentFilter(): void;
/**
* Clear Filter: resets form to default values (preserving disabled-field values),
* reloads the table with default params.
* The form is re-created via formVersion bump so SmartForm gets fresh initialValues.
*/
onClearFilter(): void;
/**
* Called by SmartTable's (rowSelect) output.
* Merges page-level selection with the cross-page tracking set.
*/
onRowSelect(globalSelection: any[]): void;
/**
* Syncs preSelectedRows into the local selectedRows (called when input changes).
*/
private syncPreselection;
handleSubmit(): void;
handleCancel(): void;
translate(key: string): string;
get titleLabel(): string;
get submitButtonLabel(): string;
get cancelButtonLabel(): string;
get clearFilterButtonLabel(): string;
get applyFilterButtonLabel(): string;
get selectionCountText(): string;
get hasActiveFilters(): boolean;
static ɵfac: i0.ɵɵFactoryDeclaration;
static ɵcmp: i0.ɵɵComponentDeclaration;
}
declare class SmartTableComponent implements OnInit, OnChanges, AfterViewInit, OnDestroy {
private http;
private router;
private cdr;
private ngZone;
private static instanceCounter;
/** Unique per-instance name for the row-selection radio group (see `isMultiSelect`). */
readonly radioGroupName: string;
config: TableConfig;
/**
* External data mode: pass table rows directly from the parent.
* When this input is provided, the component will NOT make any internal API calls.
* Instead, it emits sortChange / pageChange / searchChange / filterChange events
* so the parent can fetch and supply updated data.
*/
tableData?: any[];
/**
* Total number of items — used by the pagination component when operating in
* external-data mode. Must be kept in sync by the parent.
*/
totalItemsCount?: number;
/**
* External loading state: when the table operates in external-data mode
* (i.e. [tableData] is provided), the parent controls the loading spinner
* via this input. Ignored in internal-data mode where loading is self-managed.
*/
externalLoading: boolean;
action: EventEmitter<{
action: TableAction;
row: any;
}>;
topAction: EventEmitter;
filterChange: EventEmitter<{
key: string;
value: any;
}>;
rowSelect: EventEmitter;
columnClick: EventEmitter<{
row: any;
column: string;
}>;
/**
* Pre-selected row objects. These are tracked across pages.
* Matching incoming data rows (via rowIdField) will be checked automatically.
*/
selectedRows: any[];
/** Emitted in external-data mode when the user changes the sort column/direction. */
sortChange: EventEmitter;
/** Emitted in external-data mode when the user changes the page or page size. */
pageChange: EventEmitter