@masterteam/formula-builder 0.0.29 → 0.0.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -561,6 +561,14 @@ class FormulaBuilder {
561
561
  hideToolbar = input(false, ...(ngDevMode ? [{ debugName: "hideToolbar" }] : /* istanbul ignore next */ []));
562
562
  /** Hide the status bar */
563
563
  hideStatusBar = input(false, ...(ngDevMode ? [{ debugName: "hideStatusBar" }] : /* istanbul ignore next */ []));
564
+ /**
565
+ * Treat an empty expression as invalid (a required formula). When true, an
566
+ * empty formula reports `isValid: false` with a localized "required" error so
567
+ * the status bar shows Invalid and `validationChange` emits an invalid state.
568
+ * Default `false` keeps an empty formula valid, so other consumers that allow
569
+ * empty formulas are unaffected.
570
+ */
571
+ invalidWhenEmpty = input(false, ...(ngDevMode ? [{ debugName: "invalidWhenEmpty" }] : /* istanbul ignore next */ []));
564
572
  /** Visible toolbar tabs */
565
573
  toolbarTabs = input(DEFAULT_TOOLBAR_TABS, ...(ngDevMode ? [{ debugName: "toolbarTabs" }] : /* istanbul ignore next */ []));
566
574
  /** Optional host-owned function catalog. Takes precedence over API context. */
@@ -695,8 +703,33 @@ class FormulaBuilder {
695
703
  onTouched = () => { };
696
704
  /** Disabled state */
697
705
  isDisabled = signal(false, ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
698
- /** Validation result from service */
699
- validation = this.validatorService.validation;
706
+ /**
707
+ * Validation result surfaced to the status bar and the `validationChange`
708
+ * output. Normally mirrors the validator service; when `invalidWhenEmpty` is
709
+ * set and the expression is empty it reports an invalid "required" result so
710
+ * the status bar (Invalid + message) and any host-side validity agree that an
711
+ * empty formula is not acceptable here. See `invalidWhenEmpty`.
712
+ */
713
+ validation = computed(() => {
714
+ const base = this.validatorService.validation();
715
+ if (this.invalidWhenEmpty() && this.expressionValue().trim().length === 0) {
716
+ return {
717
+ isValid: false,
718
+ errors: [
719
+ {
720
+ message: this.transloco.translate('formulaBuilder.errors.required'),
721
+ line: 1,
722
+ column: 1,
723
+ severity: 'Error',
724
+ },
725
+ ],
726
+ warnings: [],
727
+ dependencies: [],
728
+ complexity: 0,
729
+ };
730
+ }
731
+ return base;
732
+ }, ...(ngDevMode ? [{ debugName: "validation" }] : /* istanbul ignore next */ []));
700
733
  /** Is validation in progress */
701
734
  isValidating = this.validatorService.isValidating;
702
735
  /** Builder context from API */
@@ -1492,13 +1525,13 @@ class FormulaBuilder {
1492
1525
  return translated && translated !== key ? translated : token;
1493
1526
  }
1494
1527
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FormulaBuilder, deps: [], target: i0.ɵɵFactoryTarget.Component });
1495
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: FormulaBuilder, isStandalone: true, selector: "mt-formula-builder", inputs: { propertiesByPath: { classPropertyName: "propertiesByPath", publicName: "propertiesByPath", isSignal: true, isRequired: false, transformFunction: null }, levelSchemaId: { classPropertyName: "levelSchemaId", publicName: "levelSchemaId", isSignal: true, isRequired: false, transformFunction: null }, moduleId: { classPropertyName: "moduleId", publicName: "moduleId", isSignal: true, isRequired: false, transformFunction: null }, contextKey: { classPropertyName: "contextKey", publicName: "contextKey", isSignal: true, isRequired: false, transformFunction: null }, contextEntityTypeKey: { classPropertyName: "contextEntityTypeKey", publicName: "contextEntityTypeKey", isSignal: true, isRequired: false, transformFunction: null }, templateId: { classPropertyName: "templateId", publicName: "templateId", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, hideToolbar: { classPropertyName: "hideToolbar", publicName: "hideToolbar", isSignal: true, isRequired: false, transformFunction: null }, hideStatusBar: { classPropertyName: "hideStatusBar", publicName: "hideStatusBar", isSignal: true, isRequired: false, transformFunction: null }, toolbarTabs: { classPropertyName: "toolbarTabs", publicName: "toolbarTabs", isSignal: true, isRequired: false, transformFunction: null }, functionCategories: { classPropertyName: "functionCategories", publicName: "functionCategories", isSignal: true, isRequired: false, transformFunction: null }, operators: { classPropertyName: "operators", publicName: "operators", isSignal: true, isRequired: false, transformFunction: null }, codeOnly: { classPropertyName: "codeOnly", publicName: "codeOnly", isSignal: true, isRequired: false, transformFunction: null }, builderOnly: { classPropertyName: "builderOnly", publicName: "builderOnly", isSignal: true, isRequired: false, transformFunction: null }, valueMode: { classPropertyName: "valueMode", publicName: "valueMode", isSignal: true, isRequired: false, transformFunction: null }, isProcessBuilder: { classPropertyName: "isProcessBuilder", publicName: "isProcessBuilder", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { validationChange: "validationChange", tokensChange: "tokensChange" }, host: { classAttribute: "block" }, providers: [
1528
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: FormulaBuilder, isStandalone: true, selector: "mt-formula-builder", inputs: { propertiesByPath: { classPropertyName: "propertiesByPath", publicName: "propertiesByPath", isSignal: true, isRequired: false, transformFunction: null }, levelSchemaId: { classPropertyName: "levelSchemaId", publicName: "levelSchemaId", isSignal: true, isRequired: false, transformFunction: null }, moduleId: { classPropertyName: "moduleId", publicName: "moduleId", isSignal: true, isRequired: false, transformFunction: null }, contextKey: { classPropertyName: "contextKey", publicName: "contextKey", isSignal: true, isRequired: false, transformFunction: null }, contextEntityTypeKey: { classPropertyName: "contextEntityTypeKey", publicName: "contextEntityTypeKey", isSignal: true, isRequired: false, transformFunction: null }, templateId: { classPropertyName: "templateId", publicName: "templateId", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, hideToolbar: { classPropertyName: "hideToolbar", publicName: "hideToolbar", isSignal: true, isRequired: false, transformFunction: null }, hideStatusBar: { classPropertyName: "hideStatusBar", publicName: "hideStatusBar", isSignal: true, isRequired: false, transformFunction: null }, invalidWhenEmpty: { classPropertyName: "invalidWhenEmpty", publicName: "invalidWhenEmpty", isSignal: true, isRequired: false, transformFunction: null }, toolbarTabs: { classPropertyName: "toolbarTabs", publicName: "toolbarTabs", isSignal: true, isRequired: false, transformFunction: null }, functionCategories: { classPropertyName: "functionCategories", publicName: "functionCategories", isSignal: true, isRequired: false, transformFunction: null }, operators: { classPropertyName: "operators", publicName: "operators", isSignal: true, isRequired: false, transformFunction: null }, codeOnly: { classPropertyName: "codeOnly", publicName: "codeOnly", isSignal: true, isRequired: false, transformFunction: null }, builderOnly: { classPropertyName: "builderOnly", publicName: "builderOnly", isSignal: true, isRequired: false, transformFunction: null }, valueMode: { classPropertyName: "valueMode", publicName: "valueMode", isSignal: true, isRequired: false, transformFunction: null }, isProcessBuilder: { classPropertyName: "isProcessBuilder", publicName: "isProcessBuilder", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { validationChange: "validationChange", tokensChange: "tokensChange" }, host: { classAttribute: "block" }, providers: [
1496
1529
  {
1497
1530
  provide: NG_VALUE_ACCESSOR,
1498
1531
  useExisting: forwardRef(() => FormulaBuilder),
1499
1532
  multi: true,
1500
1533
  },
1501
- ], viewQueries: [{ propertyName: "editor", first: true, predicate: ["formulaEditor"], descendants: true, isSignal: true }, { propertyName: "codeEditor", first: true, predicate: ["formulaEditorCode"], descendants: true, isSignal: true }], ngImport: i0, template: "<mt-card\n headless\n [class.ring-2]=\"hasFocus()\"\n [class.ring-primary]=\"hasFocus()\"\n [paddingless]=\"true\"\n>\n <div\n *transloco=\"let t; prefix: 'formulaBuilder'\"\n class=\"flex flex-col overflow-hidden\"\n >\n <!-- Toolbar - Pass data via inputs (pure component) -->\n @if (!hideToolbar()) {\n <mt-formula-toolbar\n [functionCategories]=\"resolvedFunctionCategories()\"\n [operators]=\"operators()\"\n [visibleTabs]=\"resolvedToolbarTabs()\"\n (onBlockInsert)=\"onBlockInsert($event)\"\n >\n <ng-template #properties let-insertBlock=\"insertBlock\">\n @if (isContextLoading()) {\n <div class=\"flex flex-col gap-4 p-4\">\n <div class=\"flex items-center justify-between gap-4\">\n <p-skeleton\n width=\"18rem\"\n height=\"2.5rem\"\n styleClass=\"rounded-md\"\n />\n <p-skeleton\n width=\"7rem\"\n height=\"2.5rem\"\n styleClass=\"rounded-md\"\n />\n </div>\n <div class=\"flex items-center gap-4\">\n <div\n class=\"flex min-h-11 min-w-0 flex-1 flex-col gap-2 rounded-lg bg-slate-50 px-3 py-2 dark:bg-slate-800/50\"\n >\n <div class=\"flex items-center gap-2\">\n <p-skeleton\n width=\"3rem\"\n height=\"1rem\"\n styleClass=\"rounded-md\"\n />\n <div\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\n ></div>\n <p-skeleton\n class=\"flex-1\"\n height=\"2rem\"\n styleClass=\"rounded-md\"\n />\n </div>\n <div\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\n >\n <p-skeleton\n width=\"3rem\"\n height=\"1rem\"\n styleClass=\"rounded-md\"\n />\n <div\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\n ></div>\n <p-skeleton\n class=\"flex-1\"\n height=\"2.5rem\"\n styleClass=\"rounded-md\"\n />\n </div>\n <p-skeleton height=\"2rem\" styleClass=\"rounded-md\" />\n </div>\n </div>\n </div>\n } @else {\n <div class=\"flex flex-col gap-4 p-4\">\n <!-- Scope Selection - Full width, centered -->\n <div class=\"flex items-center justify-between gap-4\">\n <mt-radio-cards\n [options]=\"scopeOptions()\"\n [activeId]=\"propertyScope()\"\n (selectionChange)=\"onScopeChange($event)\"\n size=\"small\"\n />\n </div>\n\n <!-- Path + Field + Preview Row -->\n <div class=\"flex items-center gap-4\">\n <!-- Path Container - Flexible -->\n <div\n class=\"flex min-h-11 min-w-0 flex-1 flex-col gap-2 rounded-lg bg-slate-50 px-3 py-2 dark:bg-slate-800/50\"\n >\n <div class=\"flex items-center gap-2\">\n <span\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\n >{{ t(\"properties.path\") }}</span\n >\n <div\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\n ></div>\n <div class=\"flex min-w-0 flex-1 items-center gap-2\">\n @if (isDirectAccess()) {\n <span\n class=\"rounded-md bg-emerald-100 px-2.5 py-1 text-xs font-medium text-emerald-600 dark:bg-emerald-900/30 dark:text-emerald-400\"\n >\n \u2713 {{ t(\"properties.direct-access\") }}\n </span>\n } @else if (pathSegments().length === 0) {\n <span class=\"text-xs italic text-slate-400\">{{\n t(\"properties.no-path-configured\")\n }}</span>\n } @else {\n <div\n class=\"flex min-w-0 flex-1 items-center gap-1.5 overflow-x-auto\"\n >\n @for (\n segment of pathSegments();\n track $index;\n let segmentIndex = $index\n ) {\n @if (segmentIndex > 0) {\n <span\n class=\"shrink-0 text-slate-300 dark:text-slate-600\"\n >\u203A</span\n >\n }\n <mt-button\n type=\"button\"\n [label]=\"\n segment.value ||\n t('properties.select') +\n ' ' +\n getOperatorDisplayName(segment.operatorToken)\n \"\n icon=\"arrow.chevron-down\"\n [outlined]=\"true\"\n size=\"small\"\n [severity]=\"\n segment.value ? 'primary' : 'secondary'\n \"\n [iconPos]=\"'end'\"\n (onClick)=\"pathPopover.toggle($event)\"\n ></mt-button>\n\n <p-popover\n #pathPopover\n [style]=\"{ width: 'max-content' }\"\n appendTo=\"body\"\n >\n <div class=\"p-2\">\n <div\n class=\"mb-2 text-xs font-semibold uppercase text-slate-400\"\n >\n {{ t(\"properties.select\") }}\n {{\n getOperatorDisplayName(\n segment.operatorToken\n )\n }}\n </div>\n <div\n class=\"flex max-h-[min(24rem,calc(100vh-10rem))] flex-col gap-1 overflow-y-auto pr-1\"\n >\n @for (\n option of segmentOptions(segmentIndex);\n track option.key\n ) {\n <mt-button\n type=\"button\"\n [label]=\"option.name\"\n [icon]=\"\n segment.value === option.key\n ? 'general.check'\n : 'general.minus'\n \"\n [iconPos]=\"'end'\"\n size=\"small\"\n severity=\"secondary\"\n [styleClass]=\"\n 'w-full justify-start rounded-md px-2.5 py-1.5 text-left text-xs font-medium transition-colors ' +\n (segment.value === option.key\n ? 'bg-primary text-white'\n : 'text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-700')\n \"\n (onClick)=\"\n setPathSegmentValue(\n segmentIndex,\n option.key\n );\n pathPopover.hide()\n \"\n ></mt-button>\n }\n </div>\n @if (segment.optional) {\n <mt-button\n type=\"button\"\n [label]=\"t('actions.clear')\"\n [outlined]=\"true\"\n icon=\"general.x-close\"\n [iconPos]=\"'end'\"\n size=\"small\"\n severity=\"danger\"\n styleClass=\"mt-2 w-full rounded-md border border-slate-200 py-1 text-xs text-slate-400 hover:bg-slate-50 dark:border-slate-700\"\n (onClick)=\"\n setPathSegmentValue(segmentIndex, null);\n pathPopover.hide()\n \"\n ></mt-button>\n }\n </div>\n </p-popover>\n\n @if (\n segment.canRemove &&\n segmentIndex === pathSegments().length - 1\n ) {\n <mt-button\n type=\"button\"\n icon=\"general.x-close\"\n size=\"small\"\n severity=\"danger\"\n styleClass=\"flex size-5 shrink-0 items-center justify-center rounded-full bg-red-500 text-white hover:bg-red-600\"\n (onClick)=\"removePathSegment(segmentIndex)\"\n ></mt-button>\n }\n }\n <mt-button\n type=\"button\"\n icon=\"general.plus\"\n size=\"small\"\n severity=\"primary\"\n [disabled]=\"!canAddNextSegment()\"\n [class.hidden]=\"!canAddNextSegment()\"\n styleClass=\"flex size-6 shrink-0 items-center justify-center rounded-md bg-primary text-xs font-bold text-white hover:opacity-90 disabled:opacity-50\"\n (onClick)=\"nextOperatorPopover.toggle($event)\"\n ></mt-button>\n </div>\n }\n <p-popover\n #nextOperatorPopover\n [style]=\"{ width: 'max-content' }\"\n appendTo=\"body\"\n >\n <div class=\"p-2\">\n <div\n class=\"mb-2 text-xs font-semibold uppercase text-slate-400\"\n >\n {{ t(\"properties.add-segment\") }}\n </div>\n <div\n class=\"flex max-h-[min(24rem,calc(100vh-10rem))] flex-col gap-1 overflow-y-auto pr-1\"\n >\n @for (\n option of nextOperatorOptions();\n track option.token\n ) {\n <mt-button\n type=\"button\"\n [label]=\"getOperatorDisplayName(option.token)\"\n icon=\"general.plus\"\n [iconPos]=\"'end'\"\n size=\"small\"\n severity=\"secondary\"\n styleClass=\"w-full justify-start rounded-md px-2.5 py-1.5 text-left text-xs font-medium transition-colors text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-700\"\n (onClick)=\"\n onAddSegmentSelection(\n option.token,\n nextOperatorPopover\n )\n \"\n ></mt-button>\n }\n </div>\n </div>\n </p-popover>\n </div>\n </div>\n\n <!-- Field Selection - Under Path -->\n <div\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\n >\n <span\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\n >{{ t(\"properties.field\") }}</span\n >\n <div\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\n ></div>\n @if (isPropertyLoading()) {\n <p-skeleton\n class=\"flex-1\"\n height=\"2.5rem\"\n styleClass=\"rounded-md\"\n />\n } @else {\n <mt-select-field\n class=\"flex-1\"\n [label]=\"''\"\n [filter]=\"true\"\n [hasPlaceholderPrefix]=\"false\"\n [placeholder]=\"t('properties.select')\"\n [(ngModel)]=\"propertyFieldKey\"\n [options]=\"propertyOptions()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n [size]=\"'small'\"\n />\n }\n </div>\n\n <!-- Value Selection - Only for lookup / status / lookup-matrix fields -->\n @if (isLookupProperty()) {\n <div\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\n >\n <span\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\n >{{ t(\"properties.value\") }}</span\n >\n <div\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\n ></div>\n @if (isLookupItemsLoading()) {\n <p-skeleton\n class=\"flex-1\"\n height=\"2.5rem\"\n styleClass=\"rounded-md\"\n />\n } @else {\n <mt-select-field\n class=\"flex-1\"\n [label]=\"''\"\n [filter]=\"true\"\n [hasPlaceholderPrefix]=\"false\"\n [placeholder]=\"t('properties.select-value')\"\n [(ngModel)]=\"lookupValueKey\"\n [options]=\"lookupItems()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n [size]=\"'small'\"\n />\n }\n </div>\n }\n <div\n class=\"w-full truncate rounded-lg bg-amber-100 px-3 py-2 text-sm font-semibold text-amber-700 shadow-sm hover:bg-amber-200 dark:bg-amber-900/30 dark:text-amber-300 dark:hover:bg-amber-900/50\"\n [mtTooltip]=\"\n '@' +\n propertyTablePath() +\n '::' +\n (selectedProperty()?.key ?? '...')\n \"\n tooltipPosition=\"top\"\n >\n @{{ propertyTablePath() }}::{{\n selectedProperty()?.key ?? \"...\"\n }}\n </div>\n <div class=\"flex justify-end gap-2\">\n @if (isLookupProperty()) {\n <mt-button\n type=\"button\"\n [label]=\"t('actions.insert-value')\"\n icon=\"general.plus\"\n severity=\"secondary\"\n [outlined]=\"true\"\n [disabled]=\"!canInsertLookupValue()\"\n (onClick)=\"insertSelectedLookupValue(insertBlock)\"\n ></mt-button>\n }\n <mt-button\n type=\"button\"\n [label]=\"t('actions.insert')\"\n icon=\"general.plus\"\n severity=\"primary\"\n [disabled]=\"!canInsertProperty()\"\n (onClick)=\"insertSelectedProperty(insertBlock)\"\n ></mt-button>\n </div>\n </div>\n </div>\n </div>\n }\n </ng-template>\n </mt-formula-toolbar>\n }\n\n <!-- Editor Area -->\n <div class=\"p-3\">\n <div\n class=\"overflow-hidden rounded-lg border border-surface-200 bg-white dark:border-surface-700 dark:bg-surface-800\"\n >\n @if (showModeToggle()) {\n <div\n class=\"flex items-center justify-end border-b border-surface-200 px-3 py-2 dark:border-surface-700\"\n >\n <mt-toggle-field\n [label]=\"t('codeMode')\"\n labelPosition=\"end\"\n size=\"small\"\n [ngModel]=\"isCodeMode()\"\n (ngModelChange)=\"onModeToggle($event)\"\n />\n </div>\n }\n <div class=\"p-0\">\n @if (isCodeMode()) {\n <mt-formula-editor-code\n #formulaEditorCode\n [placeholder]=\"placeholder() || t('placeholder')\"\n [initialFormula]=\"expression()\"\n [borderless]=\"true\"\n [autocompleteProvider]=\"autocompleteProvider\"\n (formulaChange)=\"onCodeFormulaChange($event)\"\n (onFocus)=\"onEditorFocus()\"\n (onBlur)=\"onEditorBlur()\"\n />\n } @else {\n <mt-formula-editor\n #formulaEditor\n [placeholder]=\"placeholder() || t('placeholder')\"\n [initialTokens]=\"tokens()\"\n [borderless]=\"true\"\n (formulaChange)=\"onFormulaChange($event)\"\n (tokensChange)=\"onTokensChange($event)\"\n (onFocus)=\"onEditorFocus()\"\n (onBlur)=\"onEditorBlur()\"\n />\n }\n </div>\n </div>\n </div>\n\n <!-- Status Bar - Pass data via inputs (pure component) -->\n @if (!hideStatusBar()) {\n <mt-formula-status-bar [validation]=\"validation()\" />\n }\n </div>\n</mt-card>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "hint", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape", "markCurrentUser"], outputs: ["onChange"] }, { kind: "directive", type: Tooltip, selector: "[mtTooltip]" }, { kind: "component", type: RadioCards, selector: "mt-radio-cards", inputs: ["circle", "color", "size", "columns", "options", "activeId", "itemTemplate"], outputs: ["optionsChange", "activeIdChange", "selectionChange"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i2.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "component", type: Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: FormulaToolbar, selector: "mt-formula-toolbar", inputs: ["knownProperties", "propertiesTemplate", "functionCategories", "operators", "initialTab", "visibleTabs", "searchPlaceholder", "labels"], outputs: ["onBlockInsert", "onTabChange"] }, { kind: "component", type: FormulaStatusBar, selector: "mt-formula-status-bar", inputs: ["validation", "labels"] }, { kind: "component", type: FormulaEditor, selector: "mt-formula-editor", inputs: ["placeholder", "initialTokens", "disabled", "borderless"], outputs: ["formulaChange", "tokensChange", "onBlur", "onFocus"] }, { kind: "component", type: FormulaEditorCode, selector: "mt-formula-editor-code", inputs: ["placeholder", "initialFormula", "disabled", "language", "theme", "borderless", "autocompleteProvider", "autocompleteDebounceMs"], outputs: ["formulaChange", "onBlur", "onFocus"] }] });
1534
+ ], viewQueries: [{ propertyName: "editor", first: true, predicate: ["formulaEditor"], descendants: true, isSignal: true }, { propertyName: "codeEditor", first: true, predicate: ["formulaEditorCode"], descendants: true, isSignal: true }], ngImport: i0, template: "<mt-card\r\n headless\r\n [class.ring-2]=\"hasFocus()\"\r\n [class.ring-primary]=\"hasFocus()\"\r\n [paddingless]=\"true\"\r\n>\r\n <div\r\n *transloco=\"let t; prefix: 'formulaBuilder'\"\r\n class=\"flex flex-col overflow-hidden\"\r\n >\r\n <!-- Toolbar - Pass data via inputs (pure component) -->\r\n @if (!hideToolbar()) {\r\n <mt-formula-toolbar\r\n [functionCategories]=\"resolvedFunctionCategories()\"\r\n [operators]=\"operators()\"\r\n [visibleTabs]=\"resolvedToolbarTabs()\"\r\n (onBlockInsert)=\"onBlockInsert($event)\"\r\n >\r\n <ng-template #properties let-insertBlock=\"insertBlock\">\r\n @if (isContextLoading()) {\r\n <div class=\"flex flex-col gap-4 p-4\">\r\n <div class=\"flex items-center justify-between gap-4\">\r\n <p-skeleton\r\n width=\"18rem\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n <p-skeleton\r\n width=\"7rem\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n </div>\r\n <div class=\"flex items-center gap-4\">\r\n <div\r\n class=\"flex min-h-11 min-w-0 flex-1 flex-col gap-2 rounded-lg bg-slate-50 px-3 py-2 dark:bg-slate-800/50\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <p-skeleton\r\n width=\"3rem\"\r\n height=\"1rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n <p-skeleton\r\n class=\"flex-1\"\r\n height=\"2rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n </div>\r\n <div\r\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\r\n >\r\n <p-skeleton\r\n width=\"3rem\"\r\n height=\"1rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n <p-skeleton\r\n class=\"flex-1\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n </div>\r\n <p-skeleton height=\"2rem\" styleClass=\"rounded-md\" />\r\n </div>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-col gap-4 p-4\">\r\n <!-- Scope Selection - Full width, centered -->\r\n <div class=\"flex items-center justify-between gap-4\">\r\n <mt-radio-cards\r\n [options]=\"scopeOptions()\"\r\n [activeId]=\"propertyScope()\"\r\n (selectionChange)=\"onScopeChange($event)\"\r\n size=\"small\"\r\n />\r\n </div>\r\n\r\n <!-- Path + Field + Preview Row -->\r\n <div class=\"flex items-center gap-4\">\r\n <!-- Path Container - Flexible -->\r\n <div\r\n class=\"flex min-h-11 min-w-0 flex-1 flex-col gap-2 rounded-lg bg-slate-50 px-3 py-2 dark:bg-slate-800/50\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <span\r\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\r\n >{{ t(\"properties.path\") }}</span\r\n >\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n <div class=\"flex min-w-0 flex-1 items-center gap-2\">\r\n @if (isDirectAccess()) {\r\n <span\r\n class=\"rounded-md bg-emerald-100 px-2.5 py-1 text-xs font-medium text-emerald-600 dark:bg-emerald-900/30 dark:text-emerald-400\"\r\n >\r\n \u2713 {{ t(\"properties.direct-access\") }}\r\n </span>\r\n } @else if (pathSegments().length === 0) {\r\n <span class=\"text-xs italic text-slate-400\">{{\r\n t(\"properties.no-path-configured\")\r\n }}</span>\r\n } @else {\r\n <div\r\n class=\"flex min-w-0 flex-1 items-center gap-1.5 overflow-x-auto\"\r\n >\r\n @for (\r\n segment of pathSegments();\r\n track $index;\r\n let segmentIndex = $index\r\n ) {\r\n @if (segmentIndex > 0) {\r\n <span\r\n class=\"shrink-0 text-slate-300 dark:text-slate-600\"\r\n >\u203A</span\r\n >\r\n }\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"\r\n segment.value ||\r\n t('properties.select') +\r\n ' ' +\r\n getOperatorDisplayName(segment.operatorToken)\r\n \"\r\n icon=\"arrow.chevron-down\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n [severity]=\"\r\n segment.value ? 'primary' : 'secondary'\r\n \"\r\n [iconPos]=\"'end'\"\r\n (onClick)=\"pathPopover.toggle($event)\"\r\n ></mt-button>\r\n\r\n <p-popover\r\n #pathPopover\r\n [style]=\"{ width: 'max-content' }\"\r\n appendTo=\"body\"\r\n >\r\n <div class=\"p-2\">\r\n <div\r\n class=\"mb-2 text-xs font-semibold uppercase text-slate-400\"\r\n >\r\n {{ t(\"properties.select\") }}\r\n {{\r\n getOperatorDisplayName(\r\n segment.operatorToken\r\n )\r\n }}\r\n </div>\r\n <div\r\n class=\"flex max-h-[min(24rem,calc(100vh-10rem))] flex-col gap-1 overflow-y-auto pr-1\"\r\n >\r\n @for (\r\n option of segmentOptions(segmentIndex);\r\n track option.key\r\n ) {\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"option.name\"\r\n [icon]=\"\r\n segment.value === option.key\r\n ? 'general.check'\r\n : 'general.minus'\r\n \"\r\n [iconPos]=\"'end'\"\r\n size=\"small\"\r\n severity=\"secondary\"\r\n [styleClass]=\"\r\n 'w-full justify-start rounded-md px-2.5 py-1.5 text-left text-xs font-medium transition-colors ' +\r\n (segment.value === option.key\r\n ? 'bg-primary text-white'\r\n : 'text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-700')\r\n \"\r\n (onClick)=\"\r\n setPathSegmentValue(\r\n segmentIndex,\r\n option.key\r\n );\r\n pathPopover.hide()\r\n \"\r\n ></mt-button>\r\n }\r\n </div>\r\n @if (segment.optional) {\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"t('actions.clear')\"\r\n [outlined]=\"true\"\r\n icon=\"general.x-close\"\r\n [iconPos]=\"'end'\"\r\n size=\"small\"\r\n severity=\"danger\"\r\n styleClass=\"mt-2 w-full rounded-md border border-slate-200 py-1 text-xs text-slate-400 hover:bg-slate-50 dark:border-slate-700\"\r\n (onClick)=\"\r\n setPathSegmentValue(segmentIndex, null);\r\n pathPopover.hide()\r\n \"\r\n ></mt-button>\r\n }\r\n </div>\r\n </p-popover>\r\n\r\n @if (\r\n segment.canRemove &&\r\n segmentIndex === pathSegments().length - 1\r\n ) {\r\n <mt-button\r\n type=\"button\"\r\n icon=\"general.x-close\"\r\n size=\"small\"\r\n severity=\"danger\"\r\n styleClass=\"flex size-5 shrink-0 items-center justify-center rounded-full bg-red-500 text-white hover:bg-red-600\"\r\n (onClick)=\"removePathSegment(segmentIndex)\"\r\n ></mt-button>\r\n }\r\n }\r\n <mt-button\r\n type=\"button\"\r\n icon=\"general.plus\"\r\n size=\"small\"\r\n severity=\"primary\"\r\n [disabled]=\"!canAddNextSegment()\"\r\n [class.hidden]=\"!canAddNextSegment()\"\r\n styleClass=\"flex size-6 shrink-0 items-center justify-center rounded-md bg-primary text-xs font-bold text-white hover:opacity-90 disabled:opacity-50\"\r\n (onClick)=\"nextOperatorPopover.toggle($event)\"\r\n ></mt-button>\r\n </div>\r\n }\r\n <p-popover\r\n #nextOperatorPopover\r\n [style]=\"{ width: 'max-content' }\"\r\n appendTo=\"body\"\r\n >\r\n <div class=\"p-2\">\r\n <div\r\n class=\"mb-2 text-xs font-semibold uppercase text-slate-400\"\r\n >\r\n {{ t(\"properties.add-segment\") }}\r\n </div>\r\n <div\r\n class=\"flex max-h-[min(24rem,calc(100vh-10rem))] flex-col gap-1 overflow-y-auto pr-1\"\r\n >\r\n @for (\r\n option of nextOperatorOptions();\r\n track option.token\r\n ) {\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"getOperatorDisplayName(option.token)\"\r\n icon=\"general.plus\"\r\n [iconPos]=\"'end'\"\r\n size=\"small\"\r\n severity=\"secondary\"\r\n styleClass=\"w-full justify-start rounded-md px-2.5 py-1.5 text-left text-xs font-medium transition-colors text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-700\"\r\n (onClick)=\"\r\n onAddSegmentSelection(\r\n option.token,\r\n nextOperatorPopover\r\n )\r\n \"\r\n ></mt-button>\r\n }\r\n </div>\r\n </div>\r\n </p-popover>\r\n </div>\r\n </div>\r\n\r\n <!-- Field Selection - Under Path -->\r\n <div\r\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\r\n >\r\n <span\r\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\r\n >{{ t(\"properties.field\") }}</span\r\n >\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n @if (isPropertyLoading()) {\r\n <p-skeleton\r\n class=\"flex-1\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n } @else {\r\n <mt-select-field\r\n class=\"flex-1\"\r\n [label]=\"''\"\r\n [filter]=\"true\"\r\n [hasPlaceholderPrefix]=\"false\"\r\n [placeholder]=\"t('properties.select')\"\r\n [(ngModel)]=\"propertyFieldKey\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n [size]=\"'small'\"\r\n />\r\n }\r\n </div>\r\n\r\n <!-- Value Selection - Only for lookup / status / lookup-matrix fields -->\r\n @if (isLookupProperty()) {\r\n <div\r\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\r\n >\r\n <span\r\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\r\n >{{ t(\"properties.value\") }}</span\r\n >\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n @if (isLookupItemsLoading()) {\r\n <p-skeleton\r\n class=\"flex-1\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n } @else {\r\n <mt-select-field\r\n class=\"flex-1\"\r\n [label]=\"''\"\r\n [filter]=\"true\"\r\n [hasPlaceholderPrefix]=\"false\"\r\n [placeholder]=\"t('properties.select-value')\"\r\n [(ngModel)]=\"lookupValueKey\"\r\n [options]=\"lookupItems()\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n [size]=\"'small'\"\r\n />\r\n }\r\n </div>\r\n }\r\n <div\r\n class=\"w-full truncate rounded-lg bg-amber-100 px-3 py-2 text-sm font-semibold text-amber-700 shadow-sm hover:bg-amber-200 dark:bg-amber-900/30 dark:text-amber-300 dark:hover:bg-amber-900/50\"\r\n [mtTooltip]=\"\r\n '@' +\r\n propertyTablePath() +\r\n '::' +\r\n (selectedProperty()?.key ?? '...')\r\n \"\r\n tooltipPosition=\"top\"\r\n >\r\n @{{ propertyTablePath() }}::{{\r\n selectedProperty()?.key ?? \"...\"\r\n }}\r\n </div>\r\n <div class=\"flex justify-end gap-2\">\r\n @if (isLookupProperty()) {\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"t('actions.insert-value')\"\r\n icon=\"general.plus\"\r\n severity=\"secondary\"\r\n [outlined]=\"true\"\r\n [disabled]=\"!canInsertLookupValue()\"\r\n (onClick)=\"insertSelectedLookupValue(insertBlock)\"\r\n ></mt-button>\r\n }\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"t('actions.insert')\"\r\n icon=\"general.plus\"\r\n severity=\"primary\"\r\n [disabled]=\"!canInsertProperty()\"\r\n (onClick)=\"insertSelectedProperty(insertBlock)\"\r\n ></mt-button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </ng-template>\r\n </mt-formula-toolbar>\r\n }\r\n\r\n <!-- Editor Area -->\r\n <div class=\"p-3\">\r\n <div\r\n class=\"overflow-hidden rounded-lg border border-surface-200 bg-white dark:border-surface-700 dark:bg-surface-800\"\r\n >\r\n @if (showModeToggle()) {\r\n <div\r\n class=\"flex items-center justify-end border-b border-surface-200 px-3 py-2 dark:border-surface-700\"\r\n >\r\n <mt-toggle-field\r\n [label]=\"t('codeMode')\"\r\n labelPosition=\"end\"\r\n size=\"small\"\r\n [ngModel]=\"isCodeMode()\"\r\n (ngModelChange)=\"onModeToggle($event)\"\r\n />\r\n </div>\r\n }\r\n <div class=\"p-0\">\r\n @if (isCodeMode()) {\r\n <mt-formula-editor-code\r\n #formulaEditorCode\r\n [placeholder]=\"placeholder() || t('placeholder')\"\r\n [initialFormula]=\"expression()\"\r\n [borderless]=\"true\"\r\n [autocompleteProvider]=\"autocompleteProvider\"\r\n (formulaChange)=\"onCodeFormulaChange($event)\"\r\n (onFocus)=\"onEditorFocus()\"\r\n (onBlur)=\"onEditorBlur()\"\r\n />\r\n } @else {\r\n <mt-formula-editor\r\n #formulaEditor\r\n [placeholder]=\"placeholder() || t('placeholder')\"\r\n [initialTokens]=\"tokens()\"\r\n [borderless]=\"true\"\r\n (formulaChange)=\"onFormulaChange($event)\"\r\n (tokensChange)=\"onTokensChange($event)\"\r\n (onFocus)=\"onEditorFocus()\"\r\n (onBlur)=\"onEditorBlur()\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Status Bar - Pass data via inputs (pure component) -->\r\n @if (!hideStatusBar()) {\r\n <mt-formula-status-bar [validation]=\"validation()\" />\r\n }\r\n </div>\r\n</mt-card>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs", "ariaLabel"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "hint", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape", "markCurrentUser"], outputs: ["onChange"] }, { kind: "directive", type: Tooltip, selector: "[mtTooltip]" }, { kind: "component", type: RadioCards, selector: "mt-radio-cards", inputs: ["circle", "color", "size", "columns", "options", "activeId", "itemTemplate"], outputs: ["optionsChange", "activeIdChange", "selectionChange"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i2.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "component", type: Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: FormulaToolbar, selector: "mt-formula-toolbar", inputs: ["knownProperties", "propertiesTemplate", "functionCategories", "operators", "initialTab", "visibleTabs", "searchPlaceholder", "labels"], outputs: ["onBlockInsert", "onTabChange"] }, { kind: "component", type: FormulaStatusBar, selector: "mt-formula-status-bar", inputs: ["validation", "labels"] }, { kind: "component", type: FormulaEditor, selector: "mt-formula-editor", inputs: ["placeholder", "initialTokens", "disabled", "borderless"], outputs: ["formulaChange", "tokensChange", "onBlur", "onFocus"] }, { kind: "component", type: FormulaEditorCode, selector: "mt-formula-editor-code", inputs: ["placeholder", "initialFormula", "disabled", "language", "theme", "borderless", "autocompleteProvider", "autocompleteDebounceMs"], outputs: ["formulaChange", "onBlur", "onFocus"] }] });
1502
1535
  }
1503
1536
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: FormulaBuilder, decorators: [{
1504
1537
  type: Component,
@@ -1526,8 +1559,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
1526
1559
  useExisting: forwardRef(() => FormulaBuilder),
1527
1560
  multi: true,
1528
1561
  },
1529
- ], template: "<mt-card\n headless\n [class.ring-2]=\"hasFocus()\"\n [class.ring-primary]=\"hasFocus()\"\n [paddingless]=\"true\"\n>\n <div\n *transloco=\"let t; prefix: 'formulaBuilder'\"\n class=\"flex flex-col overflow-hidden\"\n >\n <!-- Toolbar - Pass data via inputs (pure component) -->\n @if (!hideToolbar()) {\n <mt-formula-toolbar\n [functionCategories]=\"resolvedFunctionCategories()\"\n [operators]=\"operators()\"\n [visibleTabs]=\"resolvedToolbarTabs()\"\n (onBlockInsert)=\"onBlockInsert($event)\"\n >\n <ng-template #properties let-insertBlock=\"insertBlock\">\n @if (isContextLoading()) {\n <div class=\"flex flex-col gap-4 p-4\">\n <div class=\"flex items-center justify-between gap-4\">\n <p-skeleton\n width=\"18rem\"\n height=\"2.5rem\"\n styleClass=\"rounded-md\"\n />\n <p-skeleton\n width=\"7rem\"\n height=\"2.5rem\"\n styleClass=\"rounded-md\"\n />\n </div>\n <div class=\"flex items-center gap-4\">\n <div\n class=\"flex min-h-11 min-w-0 flex-1 flex-col gap-2 rounded-lg bg-slate-50 px-3 py-2 dark:bg-slate-800/50\"\n >\n <div class=\"flex items-center gap-2\">\n <p-skeleton\n width=\"3rem\"\n height=\"1rem\"\n styleClass=\"rounded-md\"\n />\n <div\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\n ></div>\n <p-skeleton\n class=\"flex-1\"\n height=\"2rem\"\n styleClass=\"rounded-md\"\n />\n </div>\n <div\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\n >\n <p-skeleton\n width=\"3rem\"\n height=\"1rem\"\n styleClass=\"rounded-md\"\n />\n <div\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\n ></div>\n <p-skeleton\n class=\"flex-1\"\n height=\"2.5rem\"\n styleClass=\"rounded-md\"\n />\n </div>\n <p-skeleton height=\"2rem\" styleClass=\"rounded-md\" />\n </div>\n </div>\n </div>\n } @else {\n <div class=\"flex flex-col gap-4 p-4\">\n <!-- Scope Selection - Full width, centered -->\n <div class=\"flex items-center justify-between gap-4\">\n <mt-radio-cards\n [options]=\"scopeOptions()\"\n [activeId]=\"propertyScope()\"\n (selectionChange)=\"onScopeChange($event)\"\n size=\"small\"\n />\n </div>\n\n <!-- Path + Field + Preview Row -->\n <div class=\"flex items-center gap-4\">\n <!-- Path Container - Flexible -->\n <div\n class=\"flex min-h-11 min-w-0 flex-1 flex-col gap-2 rounded-lg bg-slate-50 px-3 py-2 dark:bg-slate-800/50\"\n >\n <div class=\"flex items-center gap-2\">\n <span\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\n >{{ t(\"properties.path\") }}</span\n >\n <div\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\n ></div>\n <div class=\"flex min-w-0 flex-1 items-center gap-2\">\n @if (isDirectAccess()) {\n <span\n class=\"rounded-md bg-emerald-100 px-2.5 py-1 text-xs font-medium text-emerald-600 dark:bg-emerald-900/30 dark:text-emerald-400\"\n >\n \u2713 {{ t(\"properties.direct-access\") }}\n </span>\n } @else if (pathSegments().length === 0) {\n <span class=\"text-xs italic text-slate-400\">{{\n t(\"properties.no-path-configured\")\n }}</span>\n } @else {\n <div\n class=\"flex min-w-0 flex-1 items-center gap-1.5 overflow-x-auto\"\n >\n @for (\n segment of pathSegments();\n track $index;\n let segmentIndex = $index\n ) {\n @if (segmentIndex > 0) {\n <span\n class=\"shrink-0 text-slate-300 dark:text-slate-600\"\n >\u203A</span\n >\n }\n <mt-button\n type=\"button\"\n [label]=\"\n segment.value ||\n t('properties.select') +\n ' ' +\n getOperatorDisplayName(segment.operatorToken)\n \"\n icon=\"arrow.chevron-down\"\n [outlined]=\"true\"\n size=\"small\"\n [severity]=\"\n segment.value ? 'primary' : 'secondary'\n \"\n [iconPos]=\"'end'\"\n (onClick)=\"pathPopover.toggle($event)\"\n ></mt-button>\n\n <p-popover\n #pathPopover\n [style]=\"{ width: 'max-content' }\"\n appendTo=\"body\"\n >\n <div class=\"p-2\">\n <div\n class=\"mb-2 text-xs font-semibold uppercase text-slate-400\"\n >\n {{ t(\"properties.select\") }}\n {{\n getOperatorDisplayName(\n segment.operatorToken\n )\n }}\n </div>\n <div\n class=\"flex max-h-[min(24rem,calc(100vh-10rem))] flex-col gap-1 overflow-y-auto pr-1\"\n >\n @for (\n option of segmentOptions(segmentIndex);\n track option.key\n ) {\n <mt-button\n type=\"button\"\n [label]=\"option.name\"\n [icon]=\"\n segment.value === option.key\n ? 'general.check'\n : 'general.minus'\n \"\n [iconPos]=\"'end'\"\n size=\"small\"\n severity=\"secondary\"\n [styleClass]=\"\n 'w-full justify-start rounded-md px-2.5 py-1.5 text-left text-xs font-medium transition-colors ' +\n (segment.value === option.key\n ? 'bg-primary text-white'\n : 'text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-700')\n \"\n (onClick)=\"\n setPathSegmentValue(\n segmentIndex,\n option.key\n );\n pathPopover.hide()\n \"\n ></mt-button>\n }\n </div>\n @if (segment.optional) {\n <mt-button\n type=\"button\"\n [label]=\"t('actions.clear')\"\n [outlined]=\"true\"\n icon=\"general.x-close\"\n [iconPos]=\"'end'\"\n size=\"small\"\n severity=\"danger\"\n styleClass=\"mt-2 w-full rounded-md border border-slate-200 py-1 text-xs text-slate-400 hover:bg-slate-50 dark:border-slate-700\"\n (onClick)=\"\n setPathSegmentValue(segmentIndex, null);\n pathPopover.hide()\n \"\n ></mt-button>\n }\n </div>\n </p-popover>\n\n @if (\n segment.canRemove &&\n segmentIndex === pathSegments().length - 1\n ) {\n <mt-button\n type=\"button\"\n icon=\"general.x-close\"\n size=\"small\"\n severity=\"danger\"\n styleClass=\"flex size-5 shrink-0 items-center justify-center rounded-full bg-red-500 text-white hover:bg-red-600\"\n (onClick)=\"removePathSegment(segmentIndex)\"\n ></mt-button>\n }\n }\n <mt-button\n type=\"button\"\n icon=\"general.plus\"\n size=\"small\"\n severity=\"primary\"\n [disabled]=\"!canAddNextSegment()\"\n [class.hidden]=\"!canAddNextSegment()\"\n styleClass=\"flex size-6 shrink-0 items-center justify-center rounded-md bg-primary text-xs font-bold text-white hover:opacity-90 disabled:opacity-50\"\n (onClick)=\"nextOperatorPopover.toggle($event)\"\n ></mt-button>\n </div>\n }\n <p-popover\n #nextOperatorPopover\n [style]=\"{ width: 'max-content' }\"\n appendTo=\"body\"\n >\n <div class=\"p-2\">\n <div\n class=\"mb-2 text-xs font-semibold uppercase text-slate-400\"\n >\n {{ t(\"properties.add-segment\") }}\n </div>\n <div\n class=\"flex max-h-[min(24rem,calc(100vh-10rem))] flex-col gap-1 overflow-y-auto pr-1\"\n >\n @for (\n option of nextOperatorOptions();\n track option.token\n ) {\n <mt-button\n type=\"button\"\n [label]=\"getOperatorDisplayName(option.token)\"\n icon=\"general.plus\"\n [iconPos]=\"'end'\"\n size=\"small\"\n severity=\"secondary\"\n styleClass=\"w-full justify-start rounded-md px-2.5 py-1.5 text-left text-xs font-medium transition-colors text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-700\"\n (onClick)=\"\n onAddSegmentSelection(\n option.token,\n nextOperatorPopover\n )\n \"\n ></mt-button>\n }\n </div>\n </div>\n </p-popover>\n </div>\n </div>\n\n <!-- Field Selection - Under Path -->\n <div\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\n >\n <span\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\n >{{ t(\"properties.field\") }}</span\n >\n <div\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\n ></div>\n @if (isPropertyLoading()) {\n <p-skeleton\n class=\"flex-1\"\n height=\"2.5rem\"\n styleClass=\"rounded-md\"\n />\n } @else {\n <mt-select-field\n class=\"flex-1\"\n [label]=\"''\"\n [filter]=\"true\"\n [hasPlaceholderPrefix]=\"false\"\n [placeholder]=\"t('properties.select')\"\n [(ngModel)]=\"propertyFieldKey\"\n [options]=\"propertyOptions()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n [size]=\"'small'\"\n />\n }\n </div>\n\n <!-- Value Selection - Only for lookup / status / lookup-matrix fields -->\n @if (isLookupProperty()) {\n <div\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\n >\n <span\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\n >{{ t(\"properties.value\") }}</span\n >\n <div\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\n ></div>\n @if (isLookupItemsLoading()) {\n <p-skeleton\n class=\"flex-1\"\n height=\"2.5rem\"\n styleClass=\"rounded-md\"\n />\n } @else {\n <mt-select-field\n class=\"flex-1\"\n [label]=\"''\"\n [filter]=\"true\"\n [hasPlaceholderPrefix]=\"false\"\n [placeholder]=\"t('properties.select-value')\"\n [(ngModel)]=\"lookupValueKey\"\n [options]=\"lookupItems()\"\n optionLabel=\"name\"\n optionValue=\"key\"\n [size]=\"'small'\"\n />\n }\n </div>\n }\n <div\n class=\"w-full truncate rounded-lg bg-amber-100 px-3 py-2 text-sm font-semibold text-amber-700 shadow-sm hover:bg-amber-200 dark:bg-amber-900/30 dark:text-amber-300 dark:hover:bg-amber-900/50\"\n [mtTooltip]=\"\n '@' +\n propertyTablePath() +\n '::' +\n (selectedProperty()?.key ?? '...')\n \"\n tooltipPosition=\"top\"\n >\n @{{ propertyTablePath() }}::{{\n selectedProperty()?.key ?? \"...\"\n }}\n </div>\n <div class=\"flex justify-end gap-2\">\n @if (isLookupProperty()) {\n <mt-button\n type=\"button\"\n [label]=\"t('actions.insert-value')\"\n icon=\"general.plus\"\n severity=\"secondary\"\n [outlined]=\"true\"\n [disabled]=\"!canInsertLookupValue()\"\n (onClick)=\"insertSelectedLookupValue(insertBlock)\"\n ></mt-button>\n }\n <mt-button\n type=\"button\"\n [label]=\"t('actions.insert')\"\n icon=\"general.plus\"\n severity=\"primary\"\n [disabled]=\"!canInsertProperty()\"\n (onClick)=\"insertSelectedProperty(insertBlock)\"\n ></mt-button>\n </div>\n </div>\n </div>\n </div>\n }\n </ng-template>\n </mt-formula-toolbar>\n }\n\n <!-- Editor Area -->\n <div class=\"p-3\">\n <div\n class=\"overflow-hidden rounded-lg border border-surface-200 bg-white dark:border-surface-700 dark:bg-surface-800\"\n >\n @if (showModeToggle()) {\n <div\n class=\"flex items-center justify-end border-b border-surface-200 px-3 py-2 dark:border-surface-700\"\n >\n <mt-toggle-field\n [label]=\"t('codeMode')\"\n labelPosition=\"end\"\n size=\"small\"\n [ngModel]=\"isCodeMode()\"\n (ngModelChange)=\"onModeToggle($event)\"\n />\n </div>\n }\n <div class=\"p-0\">\n @if (isCodeMode()) {\n <mt-formula-editor-code\n #formulaEditorCode\n [placeholder]=\"placeholder() || t('placeholder')\"\n [initialFormula]=\"expression()\"\n [borderless]=\"true\"\n [autocompleteProvider]=\"autocompleteProvider\"\n (formulaChange)=\"onCodeFormulaChange($event)\"\n (onFocus)=\"onEditorFocus()\"\n (onBlur)=\"onEditorBlur()\"\n />\n } @else {\n <mt-formula-editor\n #formulaEditor\n [placeholder]=\"placeholder() || t('placeholder')\"\n [initialTokens]=\"tokens()\"\n [borderless]=\"true\"\n (formulaChange)=\"onFormulaChange($event)\"\n (tokensChange)=\"onTokensChange($event)\"\n (onFocus)=\"onEditorFocus()\"\n (onBlur)=\"onEditorBlur()\"\n />\n }\n </div>\n </div>\n </div>\n\n <!-- Status Bar - Pass data via inputs (pure component) -->\n @if (!hideStatusBar()) {\n <mt-formula-status-bar [validation]=\"validation()\" />\n }\n </div>\n</mt-card>\n" }]
1530
- }], ctorParameters: () => [], propDecorators: { editor: [{ type: i0.ViewChild, args: ['formulaEditor', { isSignal: true }] }], codeEditor: [{ type: i0.ViewChild, args: ['formulaEditorCode', { isSignal: true }] }], propertiesByPath: [{ type: i0.Input, args: [{ isSignal: true, alias: "propertiesByPath", required: false }] }], levelSchemaId: [{ type: i0.Input, args: [{ isSignal: true, alias: "levelSchemaId", required: false }] }], moduleId: [{ type: i0.Input, args: [{ isSignal: true, alias: "moduleId", required: false }] }], contextKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "contextKey", required: false }] }], contextEntityTypeKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "contextEntityTypeKey", required: false }] }], templateId: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateId", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], hideToolbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideToolbar", required: false }] }], hideStatusBar: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideStatusBar", required: false }] }], toolbarTabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolbarTabs", required: false }] }], functionCategories: [{ type: i0.Input, args: [{ isSignal: true, alias: "functionCategories", required: false }] }], operators: [{ type: i0.Input, args: [{ isSignal: true, alias: "operators", required: false }] }], codeOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "codeOnly", required: false }] }], builderOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "builderOnly", required: false }] }], valueMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueMode", required: false }] }], isProcessBuilder: [{ type: i0.Input, args: [{ isSignal: true, alias: "isProcessBuilder", required: false }] }], validationChange: [{ type: i0.Output, args: ["validationChange"] }], tokensChange: [{ type: i0.Output, args: ["tokensChange"] }] } });
1562
+ ], template: "<mt-card\r\n headless\r\n [class.ring-2]=\"hasFocus()\"\r\n [class.ring-primary]=\"hasFocus()\"\r\n [paddingless]=\"true\"\r\n>\r\n <div\r\n *transloco=\"let t; prefix: 'formulaBuilder'\"\r\n class=\"flex flex-col overflow-hidden\"\r\n >\r\n <!-- Toolbar - Pass data via inputs (pure component) -->\r\n @if (!hideToolbar()) {\r\n <mt-formula-toolbar\r\n [functionCategories]=\"resolvedFunctionCategories()\"\r\n [operators]=\"operators()\"\r\n [visibleTabs]=\"resolvedToolbarTabs()\"\r\n (onBlockInsert)=\"onBlockInsert($event)\"\r\n >\r\n <ng-template #properties let-insertBlock=\"insertBlock\">\r\n @if (isContextLoading()) {\r\n <div class=\"flex flex-col gap-4 p-4\">\r\n <div class=\"flex items-center justify-between gap-4\">\r\n <p-skeleton\r\n width=\"18rem\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n <p-skeleton\r\n width=\"7rem\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n </div>\r\n <div class=\"flex items-center gap-4\">\r\n <div\r\n class=\"flex min-h-11 min-w-0 flex-1 flex-col gap-2 rounded-lg bg-slate-50 px-3 py-2 dark:bg-slate-800/50\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <p-skeleton\r\n width=\"3rem\"\r\n height=\"1rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n <p-skeleton\r\n class=\"flex-1\"\r\n height=\"2rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n </div>\r\n <div\r\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\r\n >\r\n <p-skeleton\r\n width=\"3rem\"\r\n height=\"1rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n <p-skeleton\r\n class=\"flex-1\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n </div>\r\n <p-skeleton height=\"2rem\" styleClass=\"rounded-md\" />\r\n </div>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-col gap-4 p-4\">\r\n <!-- Scope Selection - Full width, centered -->\r\n <div class=\"flex items-center justify-between gap-4\">\r\n <mt-radio-cards\r\n [options]=\"scopeOptions()\"\r\n [activeId]=\"propertyScope()\"\r\n (selectionChange)=\"onScopeChange($event)\"\r\n size=\"small\"\r\n />\r\n </div>\r\n\r\n <!-- Path + Field + Preview Row -->\r\n <div class=\"flex items-center gap-4\">\r\n <!-- Path Container - Flexible -->\r\n <div\r\n class=\"flex min-h-11 min-w-0 flex-1 flex-col gap-2 rounded-lg bg-slate-50 px-3 py-2 dark:bg-slate-800/50\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <span\r\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\r\n >{{ t(\"properties.path\") }}</span\r\n >\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n <div class=\"flex min-w-0 flex-1 items-center gap-2\">\r\n @if (isDirectAccess()) {\r\n <span\r\n class=\"rounded-md bg-emerald-100 px-2.5 py-1 text-xs font-medium text-emerald-600 dark:bg-emerald-900/30 dark:text-emerald-400\"\r\n >\r\n \u2713 {{ t(\"properties.direct-access\") }}\r\n </span>\r\n } @else if (pathSegments().length === 0) {\r\n <span class=\"text-xs italic text-slate-400\">{{\r\n t(\"properties.no-path-configured\")\r\n }}</span>\r\n } @else {\r\n <div\r\n class=\"flex min-w-0 flex-1 items-center gap-1.5 overflow-x-auto\"\r\n >\r\n @for (\r\n segment of pathSegments();\r\n track $index;\r\n let segmentIndex = $index\r\n ) {\r\n @if (segmentIndex > 0) {\r\n <span\r\n class=\"shrink-0 text-slate-300 dark:text-slate-600\"\r\n >\u203A</span\r\n >\r\n }\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"\r\n segment.value ||\r\n t('properties.select') +\r\n ' ' +\r\n getOperatorDisplayName(segment.operatorToken)\r\n \"\r\n icon=\"arrow.chevron-down\"\r\n [outlined]=\"true\"\r\n size=\"small\"\r\n [severity]=\"\r\n segment.value ? 'primary' : 'secondary'\r\n \"\r\n [iconPos]=\"'end'\"\r\n (onClick)=\"pathPopover.toggle($event)\"\r\n ></mt-button>\r\n\r\n <p-popover\r\n #pathPopover\r\n [style]=\"{ width: 'max-content' }\"\r\n appendTo=\"body\"\r\n >\r\n <div class=\"p-2\">\r\n <div\r\n class=\"mb-2 text-xs font-semibold uppercase text-slate-400\"\r\n >\r\n {{ t(\"properties.select\") }}\r\n {{\r\n getOperatorDisplayName(\r\n segment.operatorToken\r\n )\r\n }}\r\n </div>\r\n <div\r\n class=\"flex max-h-[min(24rem,calc(100vh-10rem))] flex-col gap-1 overflow-y-auto pr-1\"\r\n >\r\n @for (\r\n option of segmentOptions(segmentIndex);\r\n track option.key\r\n ) {\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"option.name\"\r\n [icon]=\"\r\n segment.value === option.key\r\n ? 'general.check'\r\n : 'general.minus'\r\n \"\r\n [iconPos]=\"'end'\"\r\n size=\"small\"\r\n severity=\"secondary\"\r\n [styleClass]=\"\r\n 'w-full justify-start rounded-md px-2.5 py-1.5 text-left text-xs font-medium transition-colors ' +\r\n (segment.value === option.key\r\n ? 'bg-primary text-white'\r\n : 'text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-700')\r\n \"\r\n (onClick)=\"\r\n setPathSegmentValue(\r\n segmentIndex,\r\n option.key\r\n );\r\n pathPopover.hide()\r\n \"\r\n ></mt-button>\r\n }\r\n </div>\r\n @if (segment.optional) {\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"t('actions.clear')\"\r\n [outlined]=\"true\"\r\n icon=\"general.x-close\"\r\n [iconPos]=\"'end'\"\r\n size=\"small\"\r\n severity=\"danger\"\r\n styleClass=\"mt-2 w-full rounded-md border border-slate-200 py-1 text-xs text-slate-400 hover:bg-slate-50 dark:border-slate-700\"\r\n (onClick)=\"\r\n setPathSegmentValue(segmentIndex, null);\r\n pathPopover.hide()\r\n \"\r\n ></mt-button>\r\n }\r\n </div>\r\n </p-popover>\r\n\r\n @if (\r\n segment.canRemove &&\r\n segmentIndex === pathSegments().length - 1\r\n ) {\r\n <mt-button\r\n type=\"button\"\r\n icon=\"general.x-close\"\r\n size=\"small\"\r\n severity=\"danger\"\r\n styleClass=\"flex size-5 shrink-0 items-center justify-center rounded-full bg-red-500 text-white hover:bg-red-600\"\r\n (onClick)=\"removePathSegment(segmentIndex)\"\r\n ></mt-button>\r\n }\r\n }\r\n <mt-button\r\n type=\"button\"\r\n icon=\"general.plus\"\r\n size=\"small\"\r\n severity=\"primary\"\r\n [disabled]=\"!canAddNextSegment()\"\r\n [class.hidden]=\"!canAddNextSegment()\"\r\n styleClass=\"flex size-6 shrink-0 items-center justify-center rounded-md bg-primary text-xs font-bold text-white hover:opacity-90 disabled:opacity-50\"\r\n (onClick)=\"nextOperatorPopover.toggle($event)\"\r\n ></mt-button>\r\n </div>\r\n }\r\n <p-popover\r\n #nextOperatorPopover\r\n [style]=\"{ width: 'max-content' }\"\r\n appendTo=\"body\"\r\n >\r\n <div class=\"p-2\">\r\n <div\r\n class=\"mb-2 text-xs font-semibold uppercase text-slate-400\"\r\n >\r\n {{ t(\"properties.add-segment\") }}\r\n </div>\r\n <div\r\n class=\"flex max-h-[min(24rem,calc(100vh-10rem))] flex-col gap-1 overflow-y-auto pr-1\"\r\n >\r\n @for (\r\n option of nextOperatorOptions();\r\n track option.token\r\n ) {\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"getOperatorDisplayName(option.token)\"\r\n icon=\"general.plus\"\r\n [iconPos]=\"'end'\"\r\n size=\"small\"\r\n severity=\"secondary\"\r\n styleClass=\"w-full justify-start rounded-md px-2.5 py-1.5 text-left text-xs font-medium transition-colors text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-700\"\r\n (onClick)=\"\r\n onAddSegmentSelection(\r\n option.token,\r\n nextOperatorPopover\r\n )\r\n \"\r\n ></mt-button>\r\n }\r\n </div>\r\n </div>\r\n </p-popover>\r\n </div>\r\n </div>\r\n\r\n <!-- Field Selection - Under Path -->\r\n <div\r\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\r\n >\r\n <span\r\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\r\n >{{ t(\"properties.field\") }}</span\r\n >\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n @if (isPropertyLoading()) {\r\n <p-skeleton\r\n class=\"flex-1\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n } @else {\r\n <mt-select-field\r\n class=\"flex-1\"\r\n [label]=\"''\"\r\n [filter]=\"true\"\r\n [hasPlaceholderPrefix]=\"false\"\r\n [placeholder]=\"t('properties.select')\"\r\n [(ngModel)]=\"propertyFieldKey\"\r\n [options]=\"propertyOptions()\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n [size]=\"'small'\"\r\n />\r\n }\r\n </div>\r\n\r\n <!-- Value Selection - Only for lookup / status / lookup-matrix fields -->\r\n @if (isLookupProperty()) {\r\n <div\r\n class=\"flex items-center gap-2 border-t border-slate-200 pt-2 dark:border-slate-700\"\r\n >\r\n <span\r\n class=\"shrink-0 text-xs font-semibold uppercase tracking-wider text-slate-400\"\r\n >{{ t(\"properties.value\") }}</span\r\n >\r\n <div\r\n class=\"h-4 w-px shrink-0 bg-slate-200 dark:bg-slate-700\"\r\n ></div>\r\n @if (isLookupItemsLoading()) {\r\n <p-skeleton\r\n class=\"flex-1\"\r\n height=\"2.5rem\"\r\n styleClass=\"rounded-md\"\r\n />\r\n } @else {\r\n <mt-select-field\r\n class=\"flex-1\"\r\n [label]=\"''\"\r\n [filter]=\"true\"\r\n [hasPlaceholderPrefix]=\"false\"\r\n [placeholder]=\"t('properties.select-value')\"\r\n [(ngModel)]=\"lookupValueKey\"\r\n [options]=\"lookupItems()\"\r\n optionLabel=\"name\"\r\n optionValue=\"key\"\r\n [size]=\"'small'\"\r\n />\r\n }\r\n </div>\r\n }\r\n <div\r\n class=\"w-full truncate rounded-lg bg-amber-100 px-3 py-2 text-sm font-semibold text-amber-700 shadow-sm hover:bg-amber-200 dark:bg-amber-900/30 dark:text-amber-300 dark:hover:bg-amber-900/50\"\r\n [mtTooltip]=\"\r\n '@' +\r\n propertyTablePath() +\r\n '::' +\r\n (selectedProperty()?.key ?? '...')\r\n \"\r\n tooltipPosition=\"top\"\r\n >\r\n @{{ propertyTablePath() }}::{{\r\n selectedProperty()?.key ?? \"...\"\r\n }}\r\n </div>\r\n <div class=\"flex justify-end gap-2\">\r\n @if (isLookupProperty()) {\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"t('actions.insert-value')\"\r\n icon=\"general.plus\"\r\n severity=\"secondary\"\r\n [outlined]=\"true\"\r\n [disabled]=\"!canInsertLookupValue()\"\r\n (onClick)=\"insertSelectedLookupValue(insertBlock)\"\r\n ></mt-button>\r\n }\r\n <mt-button\r\n type=\"button\"\r\n [label]=\"t('actions.insert')\"\r\n icon=\"general.plus\"\r\n severity=\"primary\"\r\n [disabled]=\"!canInsertProperty()\"\r\n (onClick)=\"insertSelectedProperty(insertBlock)\"\r\n ></mt-button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n </ng-template>\r\n </mt-formula-toolbar>\r\n }\r\n\r\n <!-- Editor Area -->\r\n <div class=\"p-3\">\r\n <div\r\n class=\"overflow-hidden rounded-lg border border-surface-200 bg-white dark:border-surface-700 dark:bg-surface-800\"\r\n >\r\n @if (showModeToggle()) {\r\n <div\r\n class=\"flex items-center justify-end border-b border-surface-200 px-3 py-2 dark:border-surface-700\"\r\n >\r\n <mt-toggle-field\r\n [label]=\"t('codeMode')\"\r\n labelPosition=\"end\"\r\n size=\"small\"\r\n [ngModel]=\"isCodeMode()\"\r\n (ngModelChange)=\"onModeToggle($event)\"\r\n />\r\n </div>\r\n }\r\n <div class=\"p-0\">\r\n @if (isCodeMode()) {\r\n <mt-formula-editor-code\r\n #formulaEditorCode\r\n [placeholder]=\"placeholder() || t('placeholder')\"\r\n [initialFormula]=\"expression()\"\r\n [borderless]=\"true\"\r\n [autocompleteProvider]=\"autocompleteProvider\"\r\n (formulaChange)=\"onCodeFormulaChange($event)\"\r\n (onFocus)=\"onEditorFocus()\"\r\n (onBlur)=\"onEditorBlur()\"\r\n />\r\n } @else {\r\n <mt-formula-editor\r\n #formulaEditor\r\n [placeholder]=\"placeholder() || t('placeholder')\"\r\n [initialTokens]=\"tokens()\"\r\n [borderless]=\"true\"\r\n (formulaChange)=\"onFormulaChange($event)\"\r\n (tokensChange)=\"onTokensChange($event)\"\r\n (onFocus)=\"onEditorFocus()\"\r\n (onBlur)=\"onEditorBlur()\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Status Bar - Pass data via inputs (pure component) -->\r\n @if (!hideStatusBar()) {\r\n <mt-formula-status-bar [validation]=\"validation()\" />\r\n }\r\n </div>\r\n</mt-card>\r\n" }]
1563
+ }], ctorParameters: () => [], propDecorators: { editor: [{ type: i0.ViewChild, args: ['formulaEditor', { isSignal: true }] }], codeEditor: [{ type: i0.ViewChild, args: ['formulaEditorCode', { isSignal: true }] }], propertiesByPath: [{ type: i0.Input, args: [{ isSignal: true, alias: "propertiesByPath", required: false }] }], levelSchemaId: [{ type: i0.Input, args: [{ isSignal: true, alias: "levelSchemaId", required: false }] }], moduleId: [{ type: i0.Input, args: [{ isSignal: true, alias: "moduleId", required: false }] }], contextKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "contextKey", required: false }] }], contextEntityTypeKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "contextEntityTypeKey", required: false }] }], templateId: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateId", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], hideToolbar: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideToolbar", required: false }] }], hideStatusBar: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideStatusBar", required: false }] }], invalidWhenEmpty: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidWhenEmpty", required: false }] }], toolbarTabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolbarTabs", required: false }] }], functionCategories: [{ type: i0.Input, args: [{ isSignal: true, alias: "functionCategories", required: false }] }], operators: [{ type: i0.Input, args: [{ isSignal: true, alias: "operators", required: false }] }], codeOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "codeOnly", required: false }] }], builderOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "builderOnly", required: false }] }], valueMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueMode", required: false }] }], isProcessBuilder: [{ type: i0.Input, args: [{ isSignal: true, alias: "isProcessBuilder", required: false }] }], validationChange: [{ type: i0.Output, args: ["validationChange"] }], tokensChange: [{ type: i0.Output, args: ["tokensChange"] }] } });
1531
1564
 
1532
1565
  /**
1533
1566
  * Services barrel export