@masterteam/components 0.0.134 → 0.0.136

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.
@@ -172,6 +172,21 @@ function createLiteralToken(value, depth = 0, functionId, argIndex) {
172
172
  dragBehavior: 'single',
173
173
  };
174
174
  }
175
+ /**
176
+ * Create a raw text token for identifiers or syntax fragments that are not
177
+ * properties, literals, or operators.
178
+ */
179
+ function createTextToken(value, depth = 0, functionId, argIndex) {
180
+ return {
181
+ id: generateTokenId(),
182
+ type: 'text',
183
+ value,
184
+ depth,
185
+ functionId,
186
+ argIndex,
187
+ dragBehavior: 'single',
188
+ };
189
+ }
175
190
  // ============ TOKEN ARRAY OPERATIONS ============
176
191
  /**
177
192
  * Find the complete range of a function in the token array
@@ -237,20 +252,34 @@ function isValidDropPosition(tokens, dropIndex, draggedTokens) {
237
252
  function serializeTokens(tokens) {
238
253
  const parts = [];
239
254
  let lastType = null;
255
+ let lastValue = '';
240
256
  for (const token of tokens) {
241
- // Add space between tokens (except after fn-open, before fn-close, after separator)
242
- if (lastType &&
243
- lastType !== 'fn-open' &&
244
- token.type !== 'fn-close' &&
245
- token.type !== 'fn-separator' &&
246
- lastType !== 'fn-separator') {
257
+ if (shouldInsertSpace(lastType, lastValue, token)) {
247
258
  parts.push(' ');
248
259
  }
249
260
  parts.push(token.value);
250
261
  lastType = token.type;
262
+ lastValue = token.value;
251
263
  }
252
264
  return parts.join('');
253
265
  }
266
+ function shouldInsertSpace(previousType, previousValue, current) {
267
+ if (!previousType)
268
+ return false;
269
+ if (previousType === 'fn-open')
270
+ return false;
271
+ if (current.type === 'fn-close')
272
+ return false;
273
+ if (current.type === 'fn-separator')
274
+ return false;
275
+ if (previousType === 'fn-separator')
276
+ return true;
277
+ if (current.value === ':')
278
+ return false;
279
+ if (previousValue === ':')
280
+ return true;
281
+ return true;
282
+ }
254
283
  /**
255
284
  * Clone a token with new ID
256
285
  */
@@ -299,6 +328,226 @@ function recalculateDepths(tokens) {
299
328
  }
300
329
  return result;
301
330
  }
331
+ /**
332
+ * Convert a backend template or insertText into builder tokens while
333
+ * preserving the authored syntax as closely as the flat token model allows.
334
+ */
335
+ function tokenizeFormulaTemplate(template) {
336
+ const source = template.trim();
337
+ if (!source)
338
+ return [];
339
+ let index = 0;
340
+ const parseExpression = (context) => {
341
+ const tokens = [];
342
+ while (index < source.length) {
343
+ skipWhitespace();
344
+ if (index >= source.length)
345
+ break;
346
+ const char = source[index];
347
+ if (char === ',' || char === ')') {
348
+ break;
349
+ }
350
+ if (char === '@') {
351
+ tokens.push(createPropertyToken(readPropertyPath(), 'current', context.depth, context.functionId, context.argIndex));
352
+ continue;
353
+ }
354
+ if (char === '"' || char === "'") {
355
+ tokens.push(createLiteralToken(readQuotedString(), context.depth, context.functionId, context.argIndex));
356
+ continue;
357
+ }
358
+ if (isDigit(char)) {
359
+ tokens.push(createLiteralToken(Number(readNumber()), context.depth, context.functionId, context.argIndex));
360
+ continue;
361
+ }
362
+ if (char === '-' &&
363
+ isDigit(source[index + 1] ?? '') &&
364
+ shouldReadNegativeNumber(tokens)) {
365
+ tokens.push(createLiteralToken(Number(readNumber()), context.depth, context.functionId, context.argIndex));
366
+ continue;
367
+ }
368
+ if (isIdentifierStart(char)) {
369
+ const identifier = readIdentifier();
370
+ skipWhitespace();
371
+ if (source[index] === '(') {
372
+ tokens.push(...parseFunction(identifier, context.depth));
373
+ continue;
374
+ }
375
+ if (identifier === 'true' || identifier === 'false') {
376
+ tokens.push(createLiteralToken(identifier === 'true', context.depth, context.functionId, context.argIndex));
377
+ continue;
378
+ }
379
+ if (identifier === 'null') {
380
+ tokens.push(createTextToken(identifier, context.depth, context.functionId, context.argIndex));
381
+ continue;
382
+ }
383
+ tokens.push(createTextToken(identifier, context.depth, context.functionId, context.argIndex));
384
+ continue;
385
+ }
386
+ const operator = readOperator();
387
+ if (operator) {
388
+ tokens.push(createOperatorToken(operator, context.depth, context.functionId, context.argIndex));
389
+ continue;
390
+ }
391
+ tokens.push(createTextToken(char, context.depth, context.functionId, context.argIndex));
392
+ index += 1;
393
+ }
394
+ return tokens;
395
+ };
396
+ const parseFunction = (name, depth) => {
397
+ const functionId = generateFunctionId();
398
+ const tokens = [
399
+ {
400
+ id: generateTokenId(),
401
+ type: 'fn-open',
402
+ value: `${name}(`,
403
+ functionId,
404
+ functionName: name,
405
+ depth,
406
+ dragBehavior: 'function',
407
+ },
408
+ ];
409
+ index += 1; // consume '('
410
+ let argIndex = 0;
411
+ while (index < source.length) {
412
+ skipWhitespace();
413
+ if (source[index] === ')') {
414
+ index += 1;
415
+ break;
416
+ }
417
+ tokens.push(...parseExpression({
418
+ depth: depth + 1,
419
+ functionId,
420
+ argIndex,
421
+ }));
422
+ skipWhitespace();
423
+ if (source[index] === ',') {
424
+ tokens.push({
425
+ id: generateTokenId(),
426
+ type: 'fn-separator',
427
+ value: ',',
428
+ functionId,
429
+ depth,
430
+ argIndex,
431
+ dragBehavior: 'function',
432
+ });
433
+ argIndex += 1;
434
+ index += 1;
435
+ continue;
436
+ }
437
+ if (source[index] === ')') {
438
+ index += 1;
439
+ break;
440
+ }
441
+ }
442
+ tokens.push({
443
+ id: generateTokenId(),
444
+ type: 'fn-close',
445
+ value: ')',
446
+ functionId,
447
+ depth,
448
+ dragBehavior: 'function',
449
+ });
450
+ return tokens;
451
+ };
452
+ const skipWhitespace = () => {
453
+ while (index < source.length && /\s/.test(source[index])) {
454
+ index += 1;
455
+ }
456
+ };
457
+ const readQuotedString = () => {
458
+ const quote = source[index];
459
+ let value = quote;
460
+ index += 1;
461
+ while (index < source.length) {
462
+ const char = source[index];
463
+ value += char;
464
+ index += 1;
465
+ if (char === '\\' && index < source.length) {
466
+ value += source[index];
467
+ index += 1;
468
+ continue;
469
+ }
470
+ if (char === quote) {
471
+ break;
472
+ }
473
+ }
474
+ return value;
475
+ };
476
+ const readNumber = () => {
477
+ const start = index;
478
+ if (source[index] === '-') {
479
+ index += 1;
480
+ }
481
+ while (index < source.length && /[0-9.]/.test(source[index])) {
482
+ index += 1;
483
+ }
484
+ return source.slice(start, index);
485
+ };
486
+ const readIdentifier = () => {
487
+ const start = index;
488
+ index += 1;
489
+ while (index < source.length && /[\w]/.test(source[index])) {
490
+ index += 1;
491
+ }
492
+ return source.slice(start, index);
493
+ };
494
+ const readPropertyPath = () => {
495
+ const start = index;
496
+ index += 1;
497
+ while (index < source.length) {
498
+ const char = source[index];
499
+ const next = source[index + 1] ?? '';
500
+ if (/\s/.test(char) || char === ',' || char === ')' || char === '(') {
501
+ break;
502
+ }
503
+ if (/[+\-*/%<>=!&|?:]/.test(char) && !(char === ':' && next === ':')) {
504
+ break;
505
+ }
506
+ index += 1;
507
+ }
508
+ return source.slice(start, index);
509
+ };
510
+ const readOperator = () => {
511
+ const operators = [
512
+ '==',
513
+ '!=',
514
+ '>=',
515
+ '<=',
516
+ '&&',
517
+ '||',
518
+ ':',
519
+ '+',
520
+ '-',
521
+ '*',
522
+ '/',
523
+ '%',
524
+ '>',
525
+ '<',
526
+ '!',
527
+ '?',
528
+ ];
529
+ for (const operator of operators) {
530
+ if (source.startsWith(operator, index)) {
531
+ index += operator.length;
532
+ return operator;
533
+ }
534
+ }
535
+ return null;
536
+ };
537
+ return recalculateDepths(parseExpression({ depth: 0 }));
538
+ }
539
+ function isDigit(value) {
540
+ return /[0-9]/.test(value);
541
+ }
542
+ function isIdentifierStart(value) {
543
+ return /[A-Za-z_]/.test(value);
544
+ }
545
+ function shouldReadNegativeNumber(tokens) {
546
+ const previous = tokens[tokens.length - 1];
547
+ if (!previous)
548
+ return true;
549
+ return previous.type === 'operator' || previous.type === 'fn-open';
550
+ }
302
551
  /**
303
552
  * Find which argument index a position belongs to within a function
304
553
  */
@@ -325,7 +574,7 @@ function generateSmartBlockId() {
325
574
  return `sb_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
326
575
  }
327
576
  /** Create a function block from signature */
328
- function createFunctionBlock(signature, name) {
577
+ function createFunctionBlock(signature, name, insertText, cursorOffset) {
329
578
  const parsed = parseSignature(signature);
330
579
  return {
331
580
  id: generateSmartBlockId(),
@@ -333,6 +582,8 @@ function createFunctionBlock(signature, name) {
333
582
  value: parsed.name,
334
583
  functionName: name || parsed.name,
335
584
  signature,
585
+ insertText,
586
+ cursorOffset,
336
587
  arguments: parsed.args.map((arg) => ({
337
588
  id: generateSmartBlockId(),
338
589
  name: arg,
@@ -692,6 +943,8 @@ class FormulaEditor {
692
943
  case 'literal':
693
944
  // Literal tokens - emerald colors
694
945
  return `${base} bg-emerald-100 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-300 hover:bg-emerald-200 dark:hover:bg-emerald-900/50`;
946
+ case 'text':
947
+ return `${base} bg-slate-100 dark:bg-slate-800 text-slate-700 dark:text-slate-300 hover:bg-slate-200 dark:hover:bg-slate-700`;
695
948
  default:
696
949
  return base;
697
950
  }
@@ -703,7 +956,7 @@ class FormulaEditor {
703
956
  smartBlockToTokens(block) {
704
957
  switch (block.type) {
705
958
  case 'function':
706
- return createFunctionTokens(block.signature || `${block.functionName}()`, 0);
959
+ return tokenizeFormulaTemplate(block.insertText || block.signature || `${block.functionName}()`);
707
960
  case 'property':
708
961
  return [
709
962
  createPropertyToken(block.propertyKey || block.value, block.propertyType, 0, undefined, undefined, block.display),
@@ -751,6 +1004,49 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
751
1004
  ], template: "<div\r\n [class]=\"containerClasses()\"\r\n [class.opacity-60]=\"disabled()\"\r\n [class.pointer-events-none]=\"disabled()\"\r\n (focus)=\"handleFocus()\"\r\n (blur)=\"handleBlur()\"\r\n tabindex=\"0\"\r\n>\r\n <!-- Line Numbers -->\r\n <div [class]=\"lineNumberClasses()\">\r\n @for (line of lines(); track $index) {\r\n <div class=\"text-surface-400 dark:text-surface-500 text-sm leading-6\">\r\n {{ $index + 1 }}\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Editor Content - Single Drop Zone -->\r\n <div\r\n class=\"flex-1 p-2 flex flex-wrap gap-0.5 items-start content-start min-h-14 cursor-text\"\r\n cdkDropList\r\n cdkDropListOrientation=\"mixed\"\r\n [cdkDropListData]=\"tokens()\"\r\n [cdkDropListDisabled]=\"disabled()\"\r\n (cdkDropListDropped)=\"onDrop($event)\"\r\n >\r\n @if (tokens().length === 0) {\r\n <div class=\"text-surface-400 dark:text-surface-500 text-sm italic\">\r\n {{ placeholder() }}\r\n </div>\r\n } @else {\r\n @for (token of tokens(); track token.id; let i = $index) {\r\n <div\r\n class=\"relative inline-flex items-center group\"\r\n cdkDrag\r\n [cdkDragData]=\"token\"\r\n [cdkDragDisabled]=\"disabled()\"\r\n (cdkDragStarted)=\"onDragStart($event, token, i)\"\r\n (cdkDragEnded)=\"onDragEnd()\"\r\n >\r\n <!-- Drag Placeholder (thin cursor line) -->\r\n <div\r\n *cdkDragPlaceholder\r\n class=\"w-2 min-w-2 h-5 bg-primary rounded-sm opacity-80\"\r\n ></div>\r\n\r\n <!-- Token -->\r\n <span\r\n [class]=\"getTokenClasses(token)\"\r\n [class.border-b-2]=\"!isDragging() && isHighlighted(token)\"\r\n [class.border-primary]=\"!isDragging() && isHighlighted(token)\"\r\n (mouseenter)=\"onTokenHover(token)\"\r\n (mouseleave)=\"onTokenLeave()\"\r\n >\r\n {{ token.display ?? token.value }}\r\n </span>\r\n\r\n <!-- Delete Button (shows on hover, hidden during drag) -->\r\n @if (!isDragging() && !disabled()) {\r\n <button\r\n type=\"button\"\r\n class=\"absolute -top-1.5 -right-1.5 w-3.5 h-3.5 flex items-center justify-center bg-red-500 hover:bg-red-600 text-white rounded-full cursor-pointer scale-75 hover:scale-100 opacity-0 group-hover:opacity-100 pointer-events-none group-hover:pointer-events-auto z-10\"\r\n (click)=\"removeToken(token, i); $event.stopPropagation()\"\r\n [title]=\"\r\n token.dragBehavior === 'function' ? 'Remove function' : 'Remove'\r\n \"\r\n >\r\n <svg\r\n class=\"h-2.5 w-2.5\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"3\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M6 18L18 6M6 6l12 12\"\r\n />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n }\r\n }\r\n </div>\r\n</div>\r\n", styles: [".cdk-drag-preview{width:20px!important;height:20px!important;min-width:20px!important;min-height:20px!important;max-width:20px!important;max-height:20px!important;border-radius:4px;opacity:.9;overflow:hidden!important;cursor:grabbing}.cdk-drag-animating{transition:none!important}.cdk-drag-dragging{opacity:1}\n"] }]
752
1005
  }], ctorParameters: () => [], propDecorators: { placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], initialTokens: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialTokens", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], borderless: [{ type: i0.Input, args: [{ isSignal: true, alias: "borderless", required: false }] }], formulaChange: [{ type: i0.Output, args: ["formulaChange"] }], tokensChange: [{ type: i0.Output, args: ["tokensChange"] }], onBlur: [{ type: i0.Output, args: ["onBlur"] }], onFocus: [{ type: i0.Output, args: ["onFocus"] }] } });
753
1006
 
1007
+ function buildCompletionFilterText(suggestion) {
1008
+ const candidates = [
1009
+ suggestion.displayText,
1010
+ suggestion.insertText,
1011
+ suggestion.text,
1012
+ ]
1013
+ .map((value) => value?.trim() ?? '')
1014
+ .filter((value) => value.length > 0);
1015
+ return Array.from(new Set(candidates)).join(' ');
1016
+ }
1017
+
1018
+ const FORMULA_REFERENCE_CHARACTER = /[@\w.:]/;
1019
+ function resolveCompletionRangeBounds(lineContent, column, wordStartColumn, wordEndColumn, suggestion) {
1020
+ const referenceBounds = getReferenceCompletionBounds(lineContent, column, suggestion);
1021
+ return (referenceBounds ?? {
1022
+ startColumn: wordStartColumn,
1023
+ endColumn: wordEndColumn,
1024
+ });
1025
+ }
1026
+ function getReferenceCompletionBounds(lineContent, column, suggestion) {
1027
+ const insertText = suggestion.insertText ?? suggestion.text;
1028
+ if (suggestion.type !== 'Property' &&
1029
+ suggestion.type !== 'Context' &&
1030
+ !insertText.startsWith('@')) {
1031
+ return null;
1032
+ }
1033
+ const cursorIndex = Math.max(0, Math.min(column - 1, lineContent.length));
1034
+ let startIndex = cursorIndex;
1035
+ while (startIndex > 0 &&
1036
+ FORMULA_REFERENCE_CHARACTER.test(lineContent[startIndex - 1] ?? '')) {
1037
+ startIndex--;
1038
+ }
1039
+ let endIndex = cursorIndex;
1040
+ while (endIndex < lineContent.length &&
1041
+ FORMULA_REFERENCE_CHARACTER.test(lineContent[endIndex] ?? '')) {
1042
+ endIndex++;
1043
+ }
1044
+ return {
1045
+ startColumn: startIndex + 1,
1046
+ endColumn: endIndex + 1,
1047
+ };
1048
+ }
1049
+
754
1050
  class FormulaEditorCode {
755
1051
  placeholder = input('Enter formula...', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
756
1052
  initialFormula = input('', ...(ngDevMode ? [{ debugName: "initialFormula" }] : []));
@@ -986,6 +1282,7 @@ class FormulaEditorCode {
986
1282
  tokenizer: {
987
1283
  root: [
988
1284
  [/@[a-zA-Z_][\w.]*::[\w_]+/, 'type.identifier'],
1285
+ [/@[a-zA-Z_][\w.]*/, 'type.identifier'],
989
1286
  [/\b[A-Z_][A-Z0-9_]*\b/, 'function'],
990
1287
  [
991
1288
  /[a-zA-Z_][\w_]*/,
@@ -1257,8 +1554,6 @@ class FormulaEditorCode {
1257
1554
  if (!response || requestId !== this.currentAutocompleteRequestId) {
1258
1555
  return { suggestions: [] };
1259
1556
  }
1260
- const word = model.getWordUntilPosition(position);
1261
- const range = new this.monaco.Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn);
1262
1557
  return {
1263
1558
  suggestions: (response.suggestions ?? []).map((suggestion, index) => {
1264
1559
  const insertText = suggestion.insertText ?? suggestion.text;
@@ -1269,9 +1564,9 @@ class FormulaEditorCode {
1269
1564
  insertText: text,
1270
1565
  insertTextRules: rule,
1271
1566
  detail: suggestion.description ?? suggestion.category,
1272
- range,
1567
+ range: this.getCompletionRanges(model, position, suggestion),
1273
1568
  sortText: String(index).padStart(4, '0'),
1274
- filterText: suggestion.text,
1569
+ filterText: buildCompletionFilterText(suggestion),
1275
1570
  };
1276
1571
  }),
1277
1572
  };
@@ -1314,6 +1609,14 @@ class FormulaEditorCode {
1314
1609
  rule: this.monaco?.languages.CompletionItemInsertTextRule.InsertAsSnippet,
1315
1610
  };
1316
1611
  }
1612
+ getCompletionRanges(model, position, suggestion) {
1613
+ const word = model.getWordUntilPosition(position);
1614
+ const { startColumn, endColumn } = resolveCompletionRangeBounds(model.getLineContent(position.lineNumber), position.column, word.startColumn, Math.max(word.endColumn, position.column), suggestion);
1615
+ return {
1616
+ insert: new this.monaco.Range(position.lineNumber, startColumn, position.lineNumber, position.column),
1617
+ replace: new this.monaco.Range(position.lineNumber, startColumn, position.lineNumber, endColumn),
1618
+ };
1619
+ }
1317
1620
  mapSuggestionKind(type) {
1318
1621
  if (!this.monaco) {
1319
1622
  return 17;
@@ -1325,6 +1628,8 @@ class FormulaEditorCode {
1325
1628
  return this.monaco.languages.CompletionItemKind.Operator;
1326
1629
  case 'Property':
1327
1630
  return this.monaco.languages.CompletionItemKind.Field;
1631
+ case 'Context':
1632
+ return this.monaco.languages.CompletionItemKind.Module;
1328
1633
  case 'Keyword':
1329
1634
  return this.monaco.languages.CompletionItemKind.Keyword;
1330
1635
  default:
@@ -1343,9 +1648,11 @@ class FormulaEditorCode {
1343
1648
  smartBlockToText(block) {
1344
1649
  switch (block.type) {
1345
1650
  case 'function': {
1346
- const signature = block.signature ?? `${block.functionName ?? block.value}()`;
1347
- const cursorOffset = signature.endsWith(')') ? -1 : 0;
1348
- return { text: signature, cursorOffset };
1651
+ const text = block.insertText ??
1652
+ block.signature ??
1653
+ `${block.functionName ?? block.value}()`;
1654
+ const cursorOffset = block.cursorOffset ?? (text.endsWith(')') ? -1 : 0);
1655
+ return { text, cursorOffset };
1349
1656
  }
1350
1657
  case 'property':
1351
1658
  return { text: block.value ?? '', cursorOffset: 0 };
@@ -1421,29 +1728,84 @@ class FormulaToolbarItem {
1421
1728
  signature = input(...(ngDevMode ? [undefined, { debugName: "signature" }] : []));
1422
1729
  /** Function examples (for functions only) - can be strings or objects with code/description */
1423
1730
  examples = input([], ...(ngDevMode ? [{ debugName: "examples" }] : []));
1731
+ /** Backend template to insert (preferred over signature) */
1732
+ template = input(...(ngDevMode ? [undefined, { debugName: "template" }] : []));
1733
+ /** Cursor offset relative to inserted template */
1734
+ templateCursorOffset = input(...(ngDevMode ? [undefined, { debugName: "templateCursorOffset" }] : []));
1735
+ /** Function hints from backend documentation */
1736
+ hints = input([], ...(ngDevMode ? [{ debugName: "hints" }] : []));
1737
+ /** Function return type */
1738
+ returnType = input(...(ngDevMode ? [undefined, { debugName: "returnType" }] : []));
1739
+ /** Function parameters */
1740
+ parameters = input([], ...(ngDevMode ? [{ debugName: "parameters" }] : []));
1741
+ /** Normalized description */
1742
+ normalizedDescription = computed(() => this.description().trim(), ...(ngDevMode ? [{ debugName: "normalizedDescription" }] : []));
1743
+ /** Normalized signature */
1744
+ normalizedSignature = computed(() => this.signature()?.trim() ?? '', ...(ngDevMode ? [{ debugName: "normalizedSignature" }] : []));
1745
+ /** Normalized template */
1746
+ normalizedTemplate = computed(() => this.template()?.trim() ?? '', ...(ngDevMode ? [{ debugName: "normalizedTemplate" }] : []));
1747
+ /** Normalized return type */
1748
+ normalizedReturnType = computed(() => this.returnType()?.trim() ?? '', ...(ngDevMode ? [{ debugName: "normalizedReturnType" }] : []));
1424
1749
  /** Normalized examples as ExampleItem[] */
1425
1750
  normalizedExamples = computed(() => {
1426
- return this.examples().map((example) => {
1427
- if (typeof example === 'string') {
1428
- return { code: example };
1429
- }
1430
- return example;
1431
- });
1751
+ return this.examples()
1752
+ .map((example) => {
1753
+ const normalized = typeof example === 'string' ? { code: example } : example;
1754
+ return {
1755
+ code: normalized.code.trim(),
1756
+ description: normalized.description?.trim() || undefined,
1757
+ };
1758
+ })
1759
+ .filter((example) => example.code.length > 0);
1432
1760
  }, ...(ngDevMode ? [{ debugName: "normalizedExamples" }] : []));
1761
+ /** Normalized hints */
1762
+ normalizedHints = computed(() => this.hints()
1763
+ .map((hint) => hint.trim())
1764
+ .filter((hint) => hint.length > 0), ...(ngDevMode ? [{ debugName: "normalizedHints" }] : []));
1765
+ /** Normalized parameters */
1766
+ normalizedParameters = computed(() => this.parameters()
1767
+ .map((parameter) => ({
1768
+ ...parameter,
1769
+ name: parameter.name.trim(),
1770
+ type: parameter.type.trim(),
1771
+ description: parameter.description.trim(),
1772
+ }))
1773
+ .filter((parameter) => parameter.name.length > 0 ||
1774
+ parameter.type.length > 0 ||
1775
+ parameter.description.length > 0), ...(ngDevMode ? [{ debugName: "normalizedParameters" }] : []));
1433
1776
  /** Property type for properties */
1434
1777
  propertyType = input('current', ...(ngDevMode ? [{ debugName: "propertyType" }] : []));
1435
1778
  /** Insert event - emits SmartBlock */
1436
1779
  onInsert = output();
1437
1780
  /** Computed display value */
1438
1781
  displayValue = computed(() => this.display() ?? this.value(), ...(ngDevMode ? [{ debugName: "displayValue" }] : []));
1439
- /** Check if has rich tooltip content (signature or examples) */
1782
+ /** Whether function metadata should use the rich tooltip template */
1440
1783
  hasRichTooltip = computed(() => this.type() === 'function' &&
1441
- (this.signature() || this.normalizedExamples().length > 0), ...(ngDevMode ? [{ debugName: "hasRichTooltip" }] : []));
1784
+ Boolean(this.normalizedSignature() ||
1785
+ this.shouldShowTemplate() ||
1786
+ this.normalizedDescription() ||
1787
+ this.normalizedReturnType() ||
1788
+ this.normalizedParameters().length > 0 ||
1789
+ this.normalizedExamples().length > 0 ||
1790
+ this.normalizedHints().length > 0), ...(ngDevMode ? [{ debugName: "hasRichTooltip" }] : []));
1791
+ /** Keep lightweight tooltip behavior only for small descriptions */
1792
+ simpleTooltip = computed(() => this.hasRichTooltip() ? '' : this.normalizedDescription(), ...(ngDevMode ? [{ debugName: "simpleTooltip" }] : []));
1793
+ /** Show insert template when it adds useful information beyond the signature */
1794
+ shouldShowTemplate = computed(() => {
1795
+ const template = this.normalizedTemplate();
1796
+ return template.length > 0 && template !== this.normalizedSignature();
1797
+ }, ...(ngDevMode ? [{ debugName: "shouldShowTemplate" }] : []));
1798
+ /** PrimeNG tooltip class to widen rich tooltip content */
1799
+ tooltipStyleClass = computed(() => this.hasRichTooltip()
1800
+ ? 'mt-formula-toolbar-item-tooltip mt-formula-toolbar-item-tooltip-rich'
1801
+ : 'mt-formula-toolbar-item-tooltip', ...(ngDevMode ? [{ debugName: "tooltipStyleClass" }] : []));
1442
1802
  /** Build SmartBlock from item data */
1443
1803
  smartBlock = computed(() => {
1444
1804
  switch (this.type()) {
1445
1805
  case 'function':
1446
- return createFunctionBlock(this.signature() || `${this.value()}()`, this.value());
1806
+ return createFunctionBlock(this.normalizedSignature() || `${this.value()}()`, this.value(), this.normalizedTemplate() ||
1807
+ this.normalizedSignature() ||
1808
+ `${this.value()}()`, this.templateCursorOffset());
1447
1809
  case 'property':
1448
1810
  return createPropertyBlock(this.value(), this.propertyType(), this.display());
1449
1811
  case 'operator':
@@ -1470,14 +1832,14 @@ class FormulaToolbarItem {
1470
1832
  this.onInsert.emit(this.smartBlock());
1471
1833
  }
1472
1834
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormulaToolbarItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
1473
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: FormulaToolbarItem, isStandalone: true, selector: "mt-formula-toolbar-item", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, display: { classPropertyName: "display", publicName: "display", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, signature: { classPropertyName: "signature", publicName: "signature", isSignal: true, isRequired: false, transformFunction: null }, examples: { classPropertyName: "examples", publicName: "examples", isSignal: true, isRequired: false, transformFunction: null }, propertyType: { classPropertyName: "propertyType", publicName: "propertyType", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onInsert: "onInsert" }, host: { classAttribute: "inline-block" }, ngImport: i0, template: "<button\r\n type=\"button\"\r\n class=\"inline-flex cursor-pointer items-center gap-1 rounded px-2 py-1 text-sm font-medium transition-colors hover:shadow-sm active:scale-95\"\r\n [class]=\"itemClass()\"\r\n [pTooltip]=\"hasRichTooltip() ? richTooltip : description()\"\r\n [tooltipPosition]=\"'bottom'\"\r\n [showDelay]=\"300\"\r\n [hideDelay]=\"100\"\r\n (click)=\"handleClick()\"\r\n>\r\n @if (type() === \"function\") {\r\n <span class=\"text-sm opacity-60\">\u0192</span>\r\n }\r\n {{ displayValue() }}\r\n</button>\r\n\r\n<!-- Rich tooltip template for functions -->\r\n<ng-template #richTooltip>\r\n <div class=\"max-w-xs space-y-2.5 p-1\">\r\n <!-- Signature (first) -->\r\n @if (signature()) {\r\n <div class=\"rounded bg-slate-700 px-2.5 py-1.5\">\r\n <code class=\"font-mono text-sm text-emerald-400\">{{\r\n signature()\r\n }}</code>\r\n </div>\r\n }\r\n\r\n <!-- Description -->\r\n @if (description()) {\r\n <p class=\"text-sm leading-relaxed text-slate-200\">{{ description() }}</p>\r\n }\r\n\r\n <!-- Examples -->\r\n @if (normalizedExamples().length > 0) {\r\n <div class=\"space-y-1.5 border-t border-slate-600 pt-2\">\r\n <span\r\n class=\"text-xs font-semibold uppercase tracking-wider text-slate-400\"\r\n >Examples</span\r\n >\r\n <div class=\"space-y-2\">\r\n @for (example of normalizedExamples(); track $index) {\r\n <div class=\"space-y-0.5\">\r\n <div class=\"rounded bg-slate-800 px-2.5 py-1.5\">\r\n <code class=\"font-mono text-xs text-amber-300\">{{\r\n example.code\r\n }}</code>\r\n </div>\r\n @if (example.description) {\r\n <p class=\"px-1 text-xs text-slate-400\">\r\n {{ example.description }}\r\n </p>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n</ng-template>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1$1.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }] });
1835
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: FormulaToolbarItem, isStandalone: true, selector: "mt-formula-toolbar-item", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, display: { classPropertyName: "display", publicName: "display", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, signature: { classPropertyName: "signature", publicName: "signature", isSignal: true, isRequired: false, transformFunction: null }, examples: { classPropertyName: "examples", publicName: "examples", isSignal: true, isRequired: false, transformFunction: null }, template: { classPropertyName: "template", publicName: "template", isSignal: true, isRequired: false, transformFunction: null }, templateCursorOffset: { classPropertyName: "templateCursorOffset", publicName: "templateCursorOffset", isSignal: true, isRequired: false, transformFunction: null }, hints: { classPropertyName: "hints", publicName: "hints", isSignal: true, isRequired: false, transformFunction: null }, returnType: { classPropertyName: "returnType", publicName: "returnType", isSignal: true, isRequired: false, transformFunction: null }, parameters: { classPropertyName: "parameters", publicName: "parameters", isSignal: true, isRequired: false, transformFunction: null }, propertyType: { classPropertyName: "propertyType", publicName: "propertyType", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onInsert: "onInsert" }, host: { classAttribute: "inline-block max-w-full" }, ngImport: i0, template: "<button\n type=\"button\"\n class=\"inline-flex min-w-0 max-w-full cursor-pointer items-center gap-1 rounded px-2 py-1 text-sm font-medium transition-colors hover:shadow-sm active:scale-95\"\n [class]=\"itemClass()\"\n [pTooltip]=\"hasRichTooltip() ? richTooltip : simpleTooltip()\"\n [tooltipDisabled]=\"!hasRichTooltip() && !simpleTooltip()\"\n [tooltipStyleClass]=\"tooltipStyleClass()\"\n [tooltipPosition]=\"'bottom'\"\n [showDelay]=\"300\"\n [hideDelay]=\"100\"\n [autoHide]=\"!hasRichTooltip()\"\n (click)=\"handleClick()\"\n>\n @if (type() === \"function\") {\n <span class=\"text-sm opacity-60\">f</span>\n }\n <span class=\"truncate\">{{ displayValue() }}</span>\n</button>\n\n<ng-template #richTooltip>\n <div class=\"space-y-3\">\n @if (normalizedSignature()) {\n <div class=\"rounded bg-slate-700 px-3 py-2\">\n <code\n class=\"block whitespace-pre-wrap break-words font-mono text-sm text-emerald-400\"\n >{{ normalizedSignature() }}</code\n >\n </div>\n }\n\n @if (shouldShowTemplate()) {\n <div class=\"space-y-1\">\n <span\n class=\"text-xs font-semibold uppercase tracking-wider text-slate-400\"\n >Insert</span\n >\n <div class=\"rounded bg-slate-800 px-3 py-2\">\n <code\n class=\"block whitespace-pre-wrap break-words font-mono text-xs text-amber-300\"\n >{{ normalizedTemplate() }}</code\n >\n </div>\n </div>\n }\n\n @if (normalizedDescription()) {\n <p class=\"text-sm leading-relaxed text-slate-200\">\n {{ normalizedDescription() }}\n </p>\n }\n\n @if (normalizedReturnType()) {\n <div class=\"flex items-center gap-2 text-xs text-slate-300\">\n <span class=\"font-semibold uppercase tracking-wider text-slate-400\"\n >Returns</span\n >\n <code class=\"rounded bg-slate-800 px-2 py-0.5 text-sky-300\">{{\n normalizedReturnType()\n }}</code>\n </div>\n }\n\n @if (normalizedParameters().length > 0) {\n <div class=\"space-y-2 border-t border-slate-600 pt-3\">\n <span\n class=\"text-xs font-semibold uppercase tracking-wider text-slate-400\"\n >Parameters</span\n >\n <div class=\"space-y-2\">\n @for (\n parameter of normalizedParameters();\n track parameter.name + parameter.type\n ) {\n <div class=\"rounded bg-slate-800/70 px-3 py-2\">\n <div class=\"flex flex-wrap items-center gap-2 text-xs\">\n @if (parameter.name) {\n <code class=\"font-mono text-emerald-300\">{{\n parameter.name\n }}</code>\n }\n @if (parameter.type) {\n <code class=\"text-sky-300\">{{ parameter.type }}</code>\n }\n </div>\n @if (parameter.description) {\n <p class=\"mt-1 text-xs leading-relaxed text-slate-400\">\n {{ parameter.description }}\n </p>\n }\n </div>\n }\n </div>\n </div>\n }\n\n @if (normalizedExamples().length > 0) {\n <div class=\"space-y-2 border-t border-slate-600 pt-3\">\n <span\n class=\"text-xs font-semibold uppercase tracking-wider text-slate-400\"\n >Examples</span\n >\n <div class=\"space-y-2\">\n @for (example of normalizedExamples(); track example.code + $index) {\n <div class=\"space-y-1\">\n <div class=\"rounded bg-slate-800 px-3 py-2\">\n <code\n class=\"block whitespace-pre-wrap break-words font-mono text-xs text-amber-300\"\n >{{ example.code }}</code\n >\n </div>\n @if (example.description) {\n <p class=\"px-1 text-xs leading-relaxed text-slate-400\">\n {{ example.description }}\n </p>\n }\n </div>\n }\n </div>\n </div>\n }\n\n @if (normalizedHints().length > 0) {\n <div class=\"space-y-2 border-t border-slate-600 pt-3\">\n <span\n class=\"text-xs font-semibold uppercase tracking-wider text-slate-400\"\n >Hints</span\n >\n <div class=\"space-y-1.5\">\n @for (hint of normalizedHints(); track hint) {\n <p\n class=\"rounded bg-slate-800/70 px-3 py-2 text-xs leading-relaxed text-slate-300\"\n >\n {{ hint }}\n </p>\n }\n </div>\n </div>\n }\n </div>\n</ng-template>\n", styles: [".mt-formula-toolbar-item-tooltip.p-tooltip,.mt-formula-toolbar-item-tooltip .p-tooltip-text{max-width:min(32rem,92vw)}.mt-formula-toolbar-item-tooltip-rich .p-tooltip-text{width:min(32rem,92vw);max-height:min(70vh,36rem);overflow-y:auto;padding:.75rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1$1.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1474
1836
  }
1475
1837
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormulaToolbarItem, decorators: [{
1476
1838
  type: Component,
1477
- args: [{ selector: 'mt-formula-toolbar-item', standalone: true, imports: [CommonModule, TooltipModule], host: {
1478
- class: 'inline-block',
1479
- }, template: "<button\r\n type=\"button\"\r\n class=\"inline-flex cursor-pointer items-center gap-1 rounded px-2 py-1 text-sm font-medium transition-colors hover:shadow-sm active:scale-95\"\r\n [class]=\"itemClass()\"\r\n [pTooltip]=\"hasRichTooltip() ? richTooltip : description()\"\r\n [tooltipPosition]=\"'bottom'\"\r\n [showDelay]=\"300\"\r\n [hideDelay]=\"100\"\r\n (click)=\"handleClick()\"\r\n>\r\n @if (type() === \"function\") {\r\n <span class=\"text-sm opacity-60\">\u0192</span>\r\n }\r\n {{ displayValue() }}\r\n</button>\r\n\r\n<!-- Rich tooltip template for functions -->\r\n<ng-template #richTooltip>\r\n <div class=\"max-w-xs space-y-2.5 p-1\">\r\n <!-- Signature (first) -->\r\n @if (signature()) {\r\n <div class=\"rounded bg-slate-700 px-2.5 py-1.5\">\r\n <code class=\"font-mono text-sm text-emerald-400\">{{\r\n signature()\r\n }}</code>\r\n </div>\r\n }\r\n\r\n <!-- Description -->\r\n @if (description()) {\r\n <p class=\"text-sm leading-relaxed text-slate-200\">{{ description() }}</p>\r\n }\r\n\r\n <!-- Examples -->\r\n @if (normalizedExamples().length > 0) {\r\n <div class=\"space-y-1.5 border-t border-slate-600 pt-2\">\r\n <span\r\n class=\"text-xs font-semibold uppercase tracking-wider text-slate-400\"\r\n >Examples</span\r\n >\r\n <div class=\"space-y-2\">\r\n @for (example of normalizedExamples(); track $index) {\r\n <div class=\"space-y-0.5\">\r\n <div class=\"rounded bg-slate-800 px-2.5 py-1.5\">\r\n <code class=\"font-mono text-xs text-amber-300\">{{\r\n example.code\r\n }}</code>\r\n </div>\r\n @if (example.description) {\r\n <p class=\"px-1 text-xs text-slate-400\">\r\n {{ example.description }}\r\n </p>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n</ng-template>\r\n" }]
1480
- }], propDecorators: { type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], display: [{ type: i0.Input, args: [{ isSignal: true, alias: "display", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], signature: [{ type: i0.Input, args: [{ isSignal: true, alias: "signature", required: false }] }], examples: [{ type: i0.Input, args: [{ isSignal: true, alias: "examples", required: false }] }], propertyType: [{ type: i0.Input, args: [{ isSignal: true, alias: "propertyType", required: false }] }], onInsert: [{ type: i0.Output, args: ["onInsert"] }] } });
1839
+ args: [{ selector: 'mt-formula-toolbar-item', standalone: true, imports: [CommonModule, TooltipModule], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
1840
+ class: 'inline-block max-w-full',
1841
+ }, template: "<button\n type=\"button\"\n class=\"inline-flex min-w-0 max-w-full cursor-pointer items-center gap-1 rounded px-2 py-1 text-sm font-medium transition-colors hover:shadow-sm active:scale-95\"\n [class]=\"itemClass()\"\n [pTooltip]=\"hasRichTooltip() ? richTooltip : simpleTooltip()\"\n [tooltipDisabled]=\"!hasRichTooltip() && !simpleTooltip()\"\n [tooltipStyleClass]=\"tooltipStyleClass()\"\n [tooltipPosition]=\"'bottom'\"\n [showDelay]=\"300\"\n [hideDelay]=\"100\"\n [autoHide]=\"!hasRichTooltip()\"\n (click)=\"handleClick()\"\n>\n @if (type() === \"function\") {\n <span class=\"text-sm opacity-60\">f</span>\n }\n <span class=\"truncate\">{{ displayValue() }}</span>\n</button>\n\n<ng-template #richTooltip>\n <div class=\"space-y-3\">\n @if (normalizedSignature()) {\n <div class=\"rounded bg-slate-700 px-3 py-2\">\n <code\n class=\"block whitespace-pre-wrap break-words font-mono text-sm text-emerald-400\"\n >{{ normalizedSignature() }}</code\n >\n </div>\n }\n\n @if (shouldShowTemplate()) {\n <div class=\"space-y-1\">\n <span\n class=\"text-xs font-semibold uppercase tracking-wider text-slate-400\"\n >Insert</span\n >\n <div class=\"rounded bg-slate-800 px-3 py-2\">\n <code\n class=\"block whitespace-pre-wrap break-words font-mono text-xs text-amber-300\"\n >{{ normalizedTemplate() }}</code\n >\n </div>\n </div>\n }\n\n @if (normalizedDescription()) {\n <p class=\"text-sm leading-relaxed text-slate-200\">\n {{ normalizedDescription() }}\n </p>\n }\n\n @if (normalizedReturnType()) {\n <div class=\"flex items-center gap-2 text-xs text-slate-300\">\n <span class=\"font-semibold uppercase tracking-wider text-slate-400\"\n >Returns</span\n >\n <code class=\"rounded bg-slate-800 px-2 py-0.5 text-sky-300\">{{\n normalizedReturnType()\n }}</code>\n </div>\n }\n\n @if (normalizedParameters().length > 0) {\n <div class=\"space-y-2 border-t border-slate-600 pt-3\">\n <span\n class=\"text-xs font-semibold uppercase tracking-wider text-slate-400\"\n >Parameters</span\n >\n <div class=\"space-y-2\">\n @for (\n parameter of normalizedParameters();\n track parameter.name + parameter.type\n ) {\n <div class=\"rounded bg-slate-800/70 px-3 py-2\">\n <div class=\"flex flex-wrap items-center gap-2 text-xs\">\n @if (parameter.name) {\n <code class=\"font-mono text-emerald-300\">{{\n parameter.name\n }}</code>\n }\n @if (parameter.type) {\n <code class=\"text-sky-300\">{{ parameter.type }}</code>\n }\n </div>\n @if (parameter.description) {\n <p class=\"mt-1 text-xs leading-relaxed text-slate-400\">\n {{ parameter.description }}\n </p>\n }\n </div>\n }\n </div>\n </div>\n }\n\n @if (normalizedExamples().length > 0) {\n <div class=\"space-y-2 border-t border-slate-600 pt-3\">\n <span\n class=\"text-xs font-semibold uppercase tracking-wider text-slate-400\"\n >Examples</span\n >\n <div class=\"space-y-2\">\n @for (example of normalizedExamples(); track example.code + $index) {\n <div class=\"space-y-1\">\n <div class=\"rounded bg-slate-800 px-3 py-2\">\n <code\n class=\"block whitespace-pre-wrap break-words font-mono text-xs text-amber-300\"\n >{{ example.code }}</code\n >\n </div>\n @if (example.description) {\n <p class=\"px-1 text-xs leading-relaxed text-slate-400\">\n {{ example.description }}\n </p>\n }\n </div>\n }\n </div>\n </div>\n }\n\n @if (normalizedHints().length > 0) {\n <div class=\"space-y-2 border-t border-slate-600 pt-3\">\n <span\n class=\"text-xs font-semibold uppercase tracking-wider text-slate-400\"\n >Hints</span\n >\n <div class=\"space-y-1.5\">\n @for (hint of normalizedHints(); track hint) {\n <p\n class=\"rounded bg-slate-800/70 px-3 py-2 text-xs leading-relaxed text-slate-300\"\n >\n {{ hint }}\n </p>\n }\n </div>\n </div>\n }\n </div>\n</ng-template>\n", styles: [".mt-formula-toolbar-item-tooltip.p-tooltip,.mt-formula-toolbar-item-tooltip .p-tooltip-text{max-width:min(32rem,92vw)}.mt-formula-toolbar-item-tooltip-rich .p-tooltip-text{width:min(32rem,92vw);max-height:min(70vh,36rem);overflow-y:auto;padding:.75rem}\n"] }]
1842
+ }], propDecorators: { type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], display: [{ type: i0.Input, args: [{ isSignal: true, alias: "display", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], signature: [{ type: i0.Input, args: [{ isSignal: true, alias: "signature", required: false }] }], examples: [{ type: i0.Input, args: [{ isSignal: true, alias: "examples", required: false }] }], template: [{ type: i0.Input, args: [{ isSignal: true, alias: "template", required: false }] }], templateCursorOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateCursorOffset", required: false }] }], hints: [{ type: i0.Input, args: [{ isSignal: true, alias: "hints", required: false }] }], returnType: [{ type: i0.Input, args: [{ isSignal: true, alias: "returnType", required: false }] }], parameters: [{ type: i0.Input, args: [{ isSignal: true, alias: "parameters", required: false }] }], propertyType: [{ type: i0.Input, args: [{ isSignal: true, alias: "propertyType", required: false }] }], onInsert: [{ type: i0.Output, args: ["onInsert"] }] } });
1481
1843
 
1482
1844
  const DEFAULT_OPERATORS = [
1483
1845
  // Arithmetic
@@ -1703,15 +2065,21 @@ class FormulaToolbar {
1703
2065
  // ============ COMPUTED ============
1704
2066
  /** Filtered categories based on search */
1705
2067
  filteredCategories = computed(() => {
1706
- const query = this.searchQuery().toLowerCase();
1707
- const categories = this.functionCategories();
1708
- if (!query)
1709
- return categories;
1710
- return categories
2068
+ const query = this.searchQuery().trim().toLowerCase();
2069
+ return this.functionCategories()
1711
2070
  .map((cat) => ({
1712
2071
  ...cat,
1713
- functions: cat.functions.filter((fn) => fn.name.toLowerCase().includes(query) ||
1714
- fn.description.toLowerCase().includes(query)),
2072
+ functions: cat.functions.filter((fn) => {
2073
+ if (!query) {
2074
+ return true;
2075
+ }
2076
+ const functionName = fn.name.toLowerCase();
2077
+ const description = fn.description.toLowerCase();
2078
+ const categoryName = String(cat.displayName ?? cat.name).toLowerCase();
2079
+ return (functionName.includes(query) ||
2080
+ description.includes(query) ||
2081
+ categoryName.includes(query));
2082
+ }),
1715
2083
  }))
1716
2084
  .filter((cat) => cat.functions.length > 0);
1717
2085
  }, ...(ngDevMode ? [{ debugName: "filteredCategories" }] : []));
@@ -1879,11 +2247,11 @@ class FormulaToolbar {
1879
2247
  this.customValue.set('');
1880
2248
  }
1881
2249
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormulaToolbar, deps: [], target: i0.ɵɵFactoryTarget.Component });
1882
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: FormulaToolbar, isStandalone: true, selector: "mt-formula-toolbar", inputs: { knownProperties: { classPropertyName: "knownProperties", publicName: "knownProperties", isSignal: true, isRequired: false, transformFunction: null }, propertiesTemplate: { classPropertyName: "propertiesTemplate", publicName: "propertiesTemplate", 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 }, initialTab: { classPropertyName: "initialTab", publicName: "initialTab", isSignal: true, isRequired: false, transformFunction: null }, visibleTabs: { classPropertyName: "visibleTabs", publicName: "visibleTabs", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onBlockInsert: "onBlockInsert", onTabChange: "onTabChange" }, queries: [{ propertyName: "projectedPropertiesTemplate", first: true, predicate: ["properties"], descendants: true, read: TemplateRef, isSignal: true }], ngImport: i0, template: "<div\r\n *transloco=\"let t; prefix: 'components.formula.toolbar'\"\r\n class=\"flex flex-col border-b border-slate-200 dark:border-slate-700\"\r\n [class.h-52]=\"activeTab() !== 'properties' || !resolvedPropertiesTemplate()\"\r\n>\r\n <!-- Top Bar: Search + Quick Insert -->\r\n <div\r\n class=\"flex items-center gap-2 border-b border-slate-200 px-3 py-2 dark:border-slate-700\"\r\n >\r\n <!-- Search Field -->\r\n <div class=\"relative flex-1\">\r\n <svg\r\n class=\"absolute start-3 top-1/2 h-4 w-4 -translate-y-1/2 text-slate-400\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\"\r\n />\r\n </svg>\r\n <input\r\n type=\"text\"\r\n class=\"w-full rounded-lg border border-slate-300 bg-white py-1.5 ps-9 pe-8 text-sm text-slate-700 placeholder:text-slate-400 focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20 transition-all duration-200 dark:border-slate-600 dark:bg-slate-900 dark:text-slate-200 dark:placeholder:text-slate-500\"\r\n [placeholder]=\"searchPlaceholder() || t('search')\"\r\n [(ngModel)]=\"searchQuery\"\r\n />\r\n @if (searchQuery()) {\r\n <button\r\n type=\"button\"\r\n class=\"absolute end-2 top-1/2 -translate-y-1/2 rounded p-0.5 text-slate-400 hover:bg-slate-200 hover:text-slate-600 transition-all duration-200 dark:hover:bg-slate-700\"\r\n (click)=\"clearSearch()\"\r\n >\r\n <svg\r\n class=\"h-4 w-4\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M6 18L18 6M6 6l12 12\"\r\n />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Separator -->\r\n <div class=\"h-6 w-px bg-slate-200 dark:bg-slate-600\"></div>\r\n\r\n <!-- Quick Insert Input -->\r\n <div class=\"relative flex items-center gap-2\">\r\n <span\r\n class=\"text-sm font-medium text-slate-500 dark:text-slate-400 uppercase tracking-wide\"\r\n >{{ t(\"insertLabel\") }}:</span\r\n >\r\n <div class=\"relative\">\r\n <input\r\n #customValueInput\r\n type=\"text\"\r\n class=\"w-32 rounded-md border border-dashed border-slate-300 bg-slate-50 px-3 py-1.5 text-sm font-mono text-slate-700 placeholder:text-slate-400 focus:border-primary focus:bg-white focus:outline-none focus:ring-2 focus:ring-primary/20 transition-all duration-200 dark:border-slate-600 dark:bg-slate-800 dark:text-slate-200 dark:placeholder:text-slate-500 dark:focus:bg-slate-900\"\r\n [placeholder]=\"t('customValuePlaceholder')\"\r\n [(ngModel)]=\"customValue\"\r\n (keydown.enter)=\"insertCustomValue()\"\r\n (keydown.escape)=\"clearCustomValue()\"\r\n />\r\n </div>\r\n\r\n <!-- Insert Button with Type Preview -->\r\n @if (customValue()) {\r\n <button\r\n type=\"button\"\r\n class=\"inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium transition-all duration-200 hover:shadow-sm active:scale-95\"\r\n [class]=\"customValueTypeClass()\"\r\n (click)=\"insertCustomValue()\"\r\n [title]=\"t('insertType', { type: customValueType() })\"\r\n >\r\n @switch (customValueType()) {\r\n @case (\"number\") {\r\n <svg\r\n class=\"h-3 w-3\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M7 20l4-16m2 16l4-16M6 9h14M4 15h14\"\r\n />\r\n </svg>\r\n }\r\n @case (\"string\") {\r\n <svg\r\n class=\"h-3 w-3\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M7.5 8.25h9m-9 3H12m-9.75 1.51c0 1.6 1.123 2.994 2.707 3.227 1.129.166 2.27.293 3.423.379.35.026.67.21.865.501L12 21l2.755-4.133a1.14 1.14 0 01.865-.501 48.172 48.172 0 003.423-.379c1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0012 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018z\"\r\n />\r\n </svg>\r\n }\r\n @default {\r\n <svg\r\n class=\"h-3 w-3\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M12 4.5v15m7.5-7.5h-15\"\r\n />\r\n </svg>\r\n }\r\n }\r\n <span class=\"max-w-16 truncate\">{{ customValuePreview() }}</span>\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- Main Content Row -->\r\n <div class=\"flex flex-1 overflow-hidden\">\r\n <!-- Vertical Tabs -->\r\n <div\r\n class=\"flex w-44 flex-col border-e border-slate-200 dark:border-slate-700\"\r\n >\r\n @for (tab of resolvedTabOptions(); track tab.value) {\r\n <button\r\n type=\"button\"\r\n class=\"flex cursor-pointer items-center gap-2 px-3 py-2.5 text-start text-sm font-medium transition-all duration-200\"\r\n [class]=\"\r\n activeTab() === tab.value\r\n ? 'bg-white border-e-2 border-primary text-primary dark:bg-slate-900'\r\n : searchQuery() && !tabHasResults(tab.value)\r\n ? 'text-slate-300 dark:text-slate-600'\r\n : 'text-slate-600 hover:bg-slate-100 hover:text-slate-800 dark:text-slate-300 dark:hover:bg-slate-700'\r\n \"\r\n (click)=\"setActiveTab(tab.value)\"\r\n >\r\n <!-- Tab Icons -->\r\n @switch (tab.value) {\r\n @case (\"functions\") {\r\n <svg\r\n class=\"h-5 w-5 shrink-0\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M17.25 6.75L22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3l-4.5 16.5\"\r\n />\r\n </svg>\r\n }\r\n @case (\"properties\") {\r\n <svg\r\n class=\"h-5 w-5 shrink-0\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M9.568 3H5.25A2.25 2.25 0 003 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.095 18.095 0 005.223-5.223c.542-.827.369-1.908-.33-2.607L11.16 3.66A2.25 2.25 0 009.568 3z\"\r\n />\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M6 6h.008v.008H6V6z\"\r\n />\r\n </svg>\r\n }\r\n @case (\"operators\") {\r\n <svg\r\n class=\"h-5 w-5 shrink-0\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M15.75 15.75V18m-7.5-6.75h.008v.008H8.25v-.008zm0 2.25h.008v.008H8.25V13.5zm0 2.25h.008v.008H8.25v-.008zm0 2.25h.008v.008H8.25V18zm2.498-6.75h.007v.008h-.007v-.008zm0 2.25h.007v.008h-.007V13.5zm0 2.25h.007v.008h-.007v-.008zm0 2.25h.007v.008h-.007V18zm2.504-6.75h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V13.5zm0 2.25h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V18zm2.498-6.75h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V13.5zM8.25 6h7.5v2.25h-7.5V6zM12 2.25c-1.892 0-3.758.11-5.593.322C5.307 2.7 4.5 3.65 4.5 4.757V19.5a2.25 2.25 0 002.25 2.25h10.5a2.25 2.25 0 002.25-2.25V4.757c0-1.108-.806-2.057-1.907-2.185A48.507 48.507 0 0012 2.25z\"\r\n />\r\n </svg>\r\n }\r\n }\r\n <!-- Label (always visible) -->\r\n <span class=\"truncate whitespace-nowrap text-sm\">{{\r\n t(tab.value)\r\n }}</span>\r\n <!-- Count Badge -->\r\n @if (tab.value !== \"properties\" || !resolvedPropertiesTemplate()) {\r\n <span\r\n class=\"ms-auto rounded-full px-1.5 py-0.5 text-xs font-semibold\"\r\n [class]=\"\r\n activeTab() === tab.value\r\n ? 'bg-primary/10 text-primary'\r\n : 'bg-slate-200 text-slate-600 dark:bg-slate-600 dark:text-slate-300'\r\n \"\r\n >\r\n {{ getTabCount(tab.value) }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Content Area -->\r\n <div class=\"flex flex-1 flex-col overflow-hidden\">\r\n <!-- Items Grid -->\r\n <div\r\n class=\"flex-1 p-2.5\"\r\n [class.overflow-y-auto]=\"\r\n activeTab() !== 'properties' || !resolvedPropertiesTemplate()\r\n \"\r\n >\r\n @switch (activeTab()) {\r\n @case (\"functions\") {\r\n @if (filteredCategories().length === 0) {\r\n <div\r\n class=\"flex h-full items-center justify-center text-sm text-slate-400 dark:text-slate-500\"\r\n >\r\n {{ labels()?.noFunctionsFound ?? t(\"noFunctionsFound\") }}\r\n </div>\r\n } @else {\r\n <div class=\"space-y-3\">\r\n @for (category of filteredCategories(); track category.name) {\r\n <div>\r\n <div class=\"mb-2 flex items-center gap-2\">\r\n <span\r\n class=\"text-sm font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400\"\r\n >\r\n {{ category.name }}\r\n </span>\r\n <span\r\n class=\"h-px flex-1 bg-slate-200/60 dark:bg-slate-700/60\"\r\n ></span>\r\n <span\r\n class=\"text-sm text-slate-400 dark:text-slate-500\"\r\n >{{ category.functions.length }}</span\r\n >\r\n </div>\r\n <div class=\"flex flex-wrap gap-1.5\">\r\n @for (fn of category.functions; track fn.name) {\r\n <mt-formula-toolbar-item\r\n type=\"function\"\r\n [value]=\"fn.name\"\r\n [description]=\"fn.description\"\r\n [signature]=\"fn.signature\"\r\n [examples]=\"fn.examples ?? []\"\r\n (onInsert)=\"insertBlock($event)\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n @case (\"properties\") {\r\n @if (resolvedPropertiesTemplate(); as template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"template\"\r\n [ngTemplateOutletContext]=\"propertiesTemplateContext\"\r\n />\r\n } @else {\r\n @if (filteredProperties().length === 0) {\r\n <div\r\n class=\"flex h-full items-center justify-center text-sm text-slate-400 dark:text-slate-500\"\r\n >\r\n {{\r\n labels()?.noPropertiesAvailable ??\r\n t(\"noPropertiesAvailable\")\r\n }}\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-wrap gap-1.5\">\r\n @for (prop of filteredProperties(); track prop) {\r\n <mt-formula-toolbar-item\r\n type=\"property\"\r\n [value]=\"prop\"\r\n [description]=\"t('property') + ': ' + prop\"\r\n propertyType=\"current\"\r\n (onInsert)=\"insertBlock($event)\"\r\n />\r\n }\r\n </div>\r\n }\r\n }\r\n }\r\n @case (\"operators\") {\r\n @if (filteredOperators().length === 0) {\r\n <div\r\n class=\"flex h-full items-center justify-center text-sm text-slate-400 dark:text-slate-500\"\r\n >\r\n {{ labels()?.noOperatorsFound ?? t(\"noOperatorsFound\") }}\r\n </div>\r\n } @else {\r\n <div class=\"space-y-3\">\r\n @for (group of operatorGroups(); track group.type) {\r\n <div>\r\n <div class=\"mb-2 flex items-center gap-2\">\r\n <span\r\n class=\"text-sm font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400\"\r\n >\r\n {{ group.type }}\r\n </span>\r\n <span\r\n class=\"h-px flex-1 bg-slate-200/60 dark:bg-slate-700/60\"\r\n ></span>\r\n </div>\r\n <div class=\"flex flex-wrap gap-1.5\">\r\n @for (op of group.operators; track op.symbol) {\r\n <mt-formula-toolbar-item\r\n type=\"operator\"\r\n [value]=\"op.symbol\"\r\n [description]=\"op.description\"\r\n (onInsert)=\"insertBlock($event)\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "directive", type: i3.TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: FormulaToolbarItem, selector: "mt-formula-toolbar-item", inputs: ["type", "value", "display", "description", "signature", "examples", "propertyType"], outputs: ["onInsert"] }] });
2250
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: FormulaToolbar, isStandalone: true, selector: "mt-formula-toolbar", inputs: { knownProperties: { classPropertyName: "knownProperties", publicName: "knownProperties", isSignal: true, isRequired: false, transformFunction: null }, propertiesTemplate: { classPropertyName: "propertiesTemplate", publicName: "propertiesTemplate", 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 }, initialTab: { classPropertyName: "initialTab", publicName: "initialTab", isSignal: true, isRequired: false, transformFunction: null }, visibleTabs: { classPropertyName: "visibleTabs", publicName: "visibleTabs", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onBlockInsert: "onBlockInsert", onTabChange: "onTabChange" }, queries: [{ propertyName: "projectedPropertiesTemplate", first: true, predicate: ["properties"], descendants: true, read: TemplateRef, isSignal: true }], ngImport: i0, template: "<div\r\n *transloco=\"let t; prefix: 'components.formula.toolbar'\"\r\n class=\"flex flex-col border-b border-slate-200 dark:border-slate-700\"\r\n [class.h-52]=\"activeTab() !== 'properties' || !resolvedPropertiesTemplate()\"\r\n>\r\n <!-- Top Bar: Search + Quick Insert -->\r\n <div\r\n class=\"flex items-center gap-2 border-b border-slate-200 px-3 py-2 dark:border-slate-700\"\r\n >\r\n <!-- Search Field -->\r\n <div class=\"relative flex-1\">\r\n <svg\r\n class=\"absolute start-3 top-1/2 h-4 w-4 -translate-y-1/2 text-slate-400\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\"\r\n />\r\n </svg>\r\n <input\r\n type=\"text\"\r\n class=\"w-full rounded-lg border border-slate-300 bg-white py-1.5 ps-9 pe-8 text-sm text-slate-700 placeholder:text-slate-400 focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20 transition-all duration-200 dark:border-slate-600 dark:bg-slate-900 dark:text-slate-200 dark:placeholder:text-slate-500\"\r\n [placeholder]=\"searchPlaceholder() || t('search')\"\r\n [(ngModel)]=\"searchQuery\"\r\n />\r\n @if (searchQuery()) {\r\n <button\r\n type=\"button\"\r\n class=\"absolute end-2 top-1/2 -translate-y-1/2 rounded p-0.5 text-slate-400 hover:bg-slate-200 hover:text-slate-600 transition-all duration-200 dark:hover:bg-slate-700\"\r\n (click)=\"clearSearch()\"\r\n >\r\n <svg\r\n class=\"h-4 w-4\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M6 18L18 6M6 6l12 12\"\r\n />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Separator -->\r\n <div class=\"h-6 w-px bg-slate-200 dark:bg-slate-600\"></div>\r\n\r\n <!-- Quick Insert Input -->\r\n <div class=\"relative flex items-center gap-2\">\r\n <span\r\n class=\"text-sm font-medium text-slate-500 dark:text-slate-400 uppercase tracking-wide\"\r\n >{{ t(\"insertLabel\") }}:</span\r\n >\r\n <div class=\"relative\">\r\n <input\r\n #customValueInput\r\n type=\"text\"\r\n class=\"w-32 rounded-md border border-dashed border-slate-300 bg-slate-50 px-3 py-1.5 text-sm font-mono text-slate-700 placeholder:text-slate-400 focus:border-primary focus:bg-white focus:outline-none focus:ring-2 focus:ring-primary/20 transition-all duration-200 dark:border-slate-600 dark:bg-slate-800 dark:text-slate-200 dark:placeholder:text-slate-500 dark:focus:bg-slate-900\"\r\n [placeholder]=\"t('customValuePlaceholder')\"\r\n [(ngModel)]=\"customValue\"\r\n (keydown.enter)=\"insertCustomValue()\"\r\n (keydown.escape)=\"clearCustomValue()\"\r\n />\r\n </div>\r\n\r\n <!-- Insert Button with Type Preview -->\r\n @if (customValue()) {\r\n <button\r\n type=\"button\"\r\n class=\"inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium transition-all duration-200 hover:shadow-sm active:scale-95\"\r\n [class]=\"customValueTypeClass()\"\r\n (click)=\"insertCustomValue()\"\r\n [title]=\"t('insertType', { type: customValueType() })\"\r\n >\r\n @switch (customValueType()) {\r\n @case (\"number\") {\r\n <svg\r\n class=\"h-3 w-3\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M7 20l4-16m2 16l4-16M6 9h14M4 15h14\"\r\n />\r\n </svg>\r\n }\r\n @case (\"string\") {\r\n <svg\r\n class=\"h-3 w-3\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M7.5 8.25h9m-9 3H12m-9.75 1.51c0 1.6 1.123 2.994 2.707 3.227 1.129.166 2.27.293 3.423.379.35.026.67.21.865.501L12 21l2.755-4.133a1.14 1.14 0 01.865-.501 48.172 48.172 0 003.423-.379c1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0012 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018z\"\r\n />\r\n </svg>\r\n }\r\n @default {\r\n <svg\r\n class=\"h-3 w-3\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M12 4.5v15m7.5-7.5h-15\"\r\n />\r\n </svg>\r\n }\r\n }\r\n <span class=\"max-w-16 truncate\">{{ customValuePreview() }}</span>\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- Main Content Row -->\r\n <div class=\"flex flex-1 overflow-hidden\">\r\n <!-- Vertical Tabs -->\r\n <div\r\n class=\"flex w-44 flex-col border-e border-slate-200 dark:border-slate-700\"\r\n >\r\n @for (tab of resolvedTabOptions(); track tab.value) {\r\n <button\r\n type=\"button\"\r\n class=\"flex cursor-pointer items-center gap-2 px-3 py-2.5 text-start text-sm font-medium transition-all duration-200\"\r\n [class]=\"\r\n activeTab() === tab.value\r\n ? 'bg-white border-e-2 border-primary text-primary dark:bg-slate-900'\r\n : searchQuery() && !tabHasResults(tab.value)\r\n ? 'text-slate-300 dark:text-slate-600'\r\n : 'text-slate-600 hover:bg-slate-100 hover:text-slate-800 dark:text-slate-300 dark:hover:bg-slate-700'\r\n \"\r\n (click)=\"setActiveTab(tab.value)\"\r\n >\r\n <!-- Tab Icons -->\r\n @switch (tab.value) {\r\n @case (\"functions\") {\r\n <svg\r\n class=\"h-5 w-5 shrink-0\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M17.25 6.75L22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3l-4.5 16.5\"\r\n />\r\n </svg>\r\n }\r\n @case (\"properties\") {\r\n <svg\r\n class=\"h-5 w-5 shrink-0\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M9.568 3H5.25A2.25 2.25 0 003 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.095 18.095 0 005.223-5.223c.542-.827.369-1.908-.33-2.607L11.16 3.66A2.25 2.25 0 009.568 3z\"\r\n />\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M6 6h.008v.008H6V6z\"\r\n />\r\n </svg>\r\n }\r\n @case (\"operators\") {\r\n <svg\r\n class=\"h-5 w-5 shrink-0\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M15.75 15.75V18m-7.5-6.75h.008v.008H8.25v-.008zm0 2.25h.008v.008H8.25V13.5zm0 2.25h.008v.008H8.25v-.008zm0 2.25h.008v.008H8.25V18zm2.498-6.75h.007v.008h-.007v-.008zm0 2.25h.007v.008h-.007V13.5zm0 2.25h.007v.008h-.007v-.008zm0 2.25h.007v.008h-.007V18zm2.504-6.75h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V13.5zm0 2.25h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V18zm2.498-6.75h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V13.5zM8.25 6h7.5v2.25h-7.5V6zM12 2.25c-1.892 0-3.758.11-5.593.322C5.307 2.7 4.5 3.65 4.5 4.757V19.5a2.25 2.25 0 002.25 2.25h10.5a2.25 2.25 0 002.25-2.25V4.757c0-1.108-.806-2.057-1.907-2.185A48.507 48.507 0 0012 2.25z\"\r\n />\r\n </svg>\r\n }\r\n }\r\n <!-- Label (always visible) -->\r\n <span class=\"truncate whitespace-nowrap text-sm\">{{\r\n t(tab.value)\r\n }}</span>\r\n <!-- Count Badge -->\r\n @if (tab.value !== \"properties\" || !resolvedPropertiesTemplate()) {\r\n <span\r\n class=\"ms-auto rounded-full px-1.5 py-0.5 text-xs font-semibold\"\r\n [class]=\"\r\n activeTab() === tab.value\r\n ? 'bg-primary/10 text-primary'\r\n : 'bg-slate-200 text-slate-600 dark:bg-slate-600 dark:text-slate-300'\r\n \"\r\n >\r\n {{ getTabCount(tab.value) }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Content Area -->\r\n <div class=\"flex flex-1 flex-col overflow-hidden\">\r\n <!-- Items Grid -->\r\n <div\r\n class=\"flex-1 p-2.5\"\r\n [class.overflow-y-auto]=\"\r\n activeTab() !== 'properties' || !resolvedPropertiesTemplate()\r\n \"\r\n >\r\n @switch (activeTab()) {\r\n @case (\"functions\") {\r\n @if (filteredCategories().length === 0) {\r\n <div\r\n class=\"flex h-full items-center justify-center text-sm text-slate-400 dark:text-slate-500\"\r\n >\r\n {{ labels()?.noFunctionsFound ?? t(\"noFunctionsFound\") }}\r\n </div>\r\n } @else {\r\n <div class=\"space-y-3\">\r\n @for (category of filteredCategories(); track category.name) {\r\n <div>\r\n <div class=\"mb-2 flex items-center gap-2\">\r\n <span\r\n class=\"text-sm font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400\"\r\n >\r\n {{ category.displayName || category.name }}\r\n </span>\r\n <span\r\n class=\"h-px flex-1 bg-slate-200/60 dark:bg-slate-700/60\"\r\n ></span>\r\n <span\r\n class=\"text-sm text-slate-400 dark:text-slate-500\"\r\n >{{ category.functions.length }}</span\r\n >\r\n </div>\r\n <div class=\"flex flex-wrap gap-1.5\">\r\n @for (fn of category.functions; track fn.name) {\r\n <mt-formula-toolbar-item\r\n type=\"function\"\r\n [value]=\"fn.name\"\r\n [description]=\"fn.description\"\r\n [signature]=\"fn.signature\"\r\n [template]=\"fn.template\"\r\n [templateCursorOffset]=\"fn.templateCursorOffset\"\r\n [returnType]=\"fn.returnType\"\r\n [parameters]=\"fn.parameters ?? []\"\r\n [examples]=\"fn.examples ?? []\"\r\n [hints]=\"fn.hints ?? []\"\r\n (onInsert)=\"insertBlock($event)\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n @case (\"properties\") {\r\n @if (resolvedPropertiesTemplate(); as template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"template\"\r\n [ngTemplateOutletContext]=\"propertiesTemplateContext\"\r\n />\r\n } @else {\r\n @if (filteredProperties().length === 0) {\r\n <div\r\n class=\"flex h-full items-center justify-center text-sm text-slate-400 dark:text-slate-500\"\r\n >\r\n {{\r\n labels()?.noPropertiesAvailable ??\r\n t(\"noPropertiesAvailable\")\r\n }}\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-wrap gap-1.5\">\r\n @for (prop of filteredProperties(); track prop) {\r\n <mt-formula-toolbar-item\r\n type=\"property\"\r\n [value]=\"prop\"\r\n [description]=\"t('property') + ': ' + prop\"\r\n propertyType=\"current\"\r\n (onInsert)=\"insertBlock($event)\"\r\n />\r\n }\r\n </div>\r\n }\r\n }\r\n }\r\n @case (\"operators\") {\r\n @if (filteredOperators().length === 0) {\r\n <div\r\n class=\"flex h-full items-center justify-center text-sm text-slate-400 dark:text-slate-500\"\r\n >\r\n {{ labels()?.noOperatorsFound ?? t(\"noOperatorsFound\") }}\r\n </div>\r\n } @else {\r\n <div class=\"space-y-3\">\r\n @for (group of operatorGroups(); track group.type) {\r\n <div>\r\n <div class=\"mb-2 flex items-center gap-2\">\r\n <span\r\n class=\"text-sm font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400\"\r\n >\r\n {{ group.type }}\r\n </span>\r\n <span\r\n class=\"h-px flex-1 bg-slate-200/60 dark:bg-slate-700/60\"\r\n ></span>\r\n </div>\r\n <div class=\"flex flex-wrap gap-1.5\">\r\n @for (op of group.operators; track op.symbol) {\r\n <mt-formula-toolbar-item\r\n type=\"operator\"\r\n [value]=\"op.symbol\"\r\n [description]=\"op.description\"\r\n (onInsert)=\"insertBlock($event)\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "directive", type: i3.TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "component", type: FormulaToolbarItem, selector: "mt-formula-toolbar-item", inputs: ["type", "value", "display", "description", "signature", "examples", "template", "templateCursorOffset", "hints", "returnType", "parameters", "propertyType"], outputs: ["onInsert"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1883
2251
  }
1884
2252
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: FormulaToolbar, decorators: [{
1885
2253
  type: Component,
1886
- args: [{ selector: 'mt-formula-toolbar', standalone: true, imports: [CommonModule, FormsModule, TranslocoModule, FormulaToolbarItem], template: "<div\r\n *transloco=\"let t; prefix: 'components.formula.toolbar'\"\r\n class=\"flex flex-col border-b border-slate-200 dark:border-slate-700\"\r\n [class.h-52]=\"activeTab() !== 'properties' || !resolvedPropertiesTemplate()\"\r\n>\r\n <!-- Top Bar: Search + Quick Insert -->\r\n <div\r\n class=\"flex items-center gap-2 border-b border-slate-200 px-3 py-2 dark:border-slate-700\"\r\n >\r\n <!-- Search Field -->\r\n <div class=\"relative flex-1\">\r\n <svg\r\n class=\"absolute start-3 top-1/2 h-4 w-4 -translate-y-1/2 text-slate-400\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\"\r\n />\r\n </svg>\r\n <input\r\n type=\"text\"\r\n class=\"w-full rounded-lg border border-slate-300 bg-white py-1.5 ps-9 pe-8 text-sm text-slate-700 placeholder:text-slate-400 focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20 transition-all duration-200 dark:border-slate-600 dark:bg-slate-900 dark:text-slate-200 dark:placeholder:text-slate-500\"\r\n [placeholder]=\"searchPlaceholder() || t('search')\"\r\n [(ngModel)]=\"searchQuery\"\r\n />\r\n @if (searchQuery()) {\r\n <button\r\n type=\"button\"\r\n class=\"absolute end-2 top-1/2 -translate-y-1/2 rounded p-0.5 text-slate-400 hover:bg-slate-200 hover:text-slate-600 transition-all duration-200 dark:hover:bg-slate-700\"\r\n (click)=\"clearSearch()\"\r\n >\r\n <svg\r\n class=\"h-4 w-4\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M6 18L18 6M6 6l12 12\"\r\n />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Separator -->\r\n <div class=\"h-6 w-px bg-slate-200 dark:bg-slate-600\"></div>\r\n\r\n <!-- Quick Insert Input -->\r\n <div class=\"relative flex items-center gap-2\">\r\n <span\r\n class=\"text-sm font-medium text-slate-500 dark:text-slate-400 uppercase tracking-wide\"\r\n >{{ t(\"insertLabel\") }}:</span\r\n >\r\n <div class=\"relative\">\r\n <input\r\n #customValueInput\r\n type=\"text\"\r\n class=\"w-32 rounded-md border border-dashed border-slate-300 bg-slate-50 px-3 py-1.5 text-sm font-mono text-slate-700 placeholder:text-slate-400 focus:border-primary focus:bg-white focus:outline-none focus:ring-2 focus:ring-primary/20 transition-all duration-200 dark:border-slate-600 dark:bg-slate-800 dark:text-slate-200 dark:placeholder:text-slate-500 dark:focus:bg-slate-900\"\r\n [placeholder]=\"t('customValuePlaceholder')\"\r\n [(ngModel)]=\"customValue\"\r\n (keydown.enter)=\"insertCustomValue()\"\r\n (keydown.escape)=\"clearCustomValue()\"\r\n />\r\n </div>\r\n\r\n <!-- Insert Button with Type Preview -->\r\n @if (customValue()) {\r\n <button\r\n type=\"button\"\r\n class=\"inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium transition-all duration-200 hover:shadow-sm active:scale-95\"\r\n [class]=\"customValueTypeClass()\"\r\n (click)=\"insertCustomValue()\"\r\n [title]=\"t('insertType', { type: customValueType() })\"\r\n >\r\n @switch (customValueType()) {\r\n @case (\"number\") {\r\n <svg\r\n class=\"h-3 w-3\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M7 20l4-16m2 16l4-16M6 9h14M4 15h14\"\r\n />\r\n </svg>\r\n }\r\n @case (\"string\") {\r\n <svg\r\n class=\"h-3 w-3\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M7.5 8.25h9m-9 3H12m-9.75 1.51c0 1.6 1.123 2.994 2.707 3.227 1.129.166 2.27.293 3.423.379.35.026.67.21.865.501L12 21l2.755-4.133a1.14 1.14 0 01.865-.501 48.172 48.172 0 003.423-.379c1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0012 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018z\"\r\n />\r\n </svg>\r\n }\r\n @default {\r\n <svg\r\n class=\"h-3 w-3\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M12 4.5v15m7.5-7.5h-15\"\r\n />\r\n </svg>\r\n }\r\n }\r\n <span class=\"max-w-16 truncate\">{{ customValuePreview() }}</span>\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- Main Content Row -->\r\n <div class=\"flex flex-1 overflow-hidden\">\r\n <!-- Vertical Tabs -->\r\n <div\r\n class=\"flex w-44 flex-col border-e border-slate-200 dark:border-slate-700\"\r\n >\r\n @for (tab of resolvedTabOptions(); track tab.value) {\r\n <button\r\n type=\"button\"\r\n class=\"flex cursor-pointer items-center gap-2 px-3 py-2.5 text-start text-sm font-medium transition-all duration-200\"\r\n [class]=\"\r\n activeTab() === tab.value\r\n ? 'bg-white border-e-2 border-primary text-primary dark:bg-slate-900'\r\n : searchQuery() && !tabHasResults(tab.value)\r\n ? 'text-slate-300 dark:text-slate-600'\r\n : 'text-slate-600 hover:bg-slate-100 hover:text-slate-800 dark:text-slate-300 dark:hover:bg-slate-700'\r\n \"\r\n (click)=\"setActiveTab(tab.value)\"\r\n >\r\n <!-- Tab Icons -->\r\n @switch (tab.value) {\r\n @case (\"functions\") {\r\n <svg\r\n class=\"h-5 w-5 shrink-0\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M17.25 6.75L22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3l-4.5 16.5\"\r\n />\r\n </svg>\r\n }\r\n @case (\"properties\") {\r\n <svg\r\n class=\"h-5 w-5 shrink-0\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M9.568 3H5.25A2.25 2.25 0 003 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.095 18.095 0 005.223-5.223c.542-.827.369-1.908-.33-2.607L11.16 3.66A2.25 2.25 0 009.568 3z\"\r\n />\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M6 6h.008v.008H6V6z\"\r\n />\r\n </svg>\r\n }\r\n @case (\"operators\") {\r\n <svg\r\n class=\"h-5 w-5 shrink-0\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M15.75 15.75V18m-7.5-6.75h.008v.008H8.25v-.008zm0 2.25h.008v.008H8.25V13.5zm0 2.25h.008v.008H8.25v-.008zm0 2.25h.008v.008H8.25V18zm2.498-6.75h.007v.008h-.007v-.008zm0 2.25h.007v.008h-.007V13.5zm0 2.25h.007v.008h-.007v-.008zm0 2.25h.007v.008h-.007V18zm2.504-6.75h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V13.5zm0 2.25h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V18zm2.498-6.75h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V13.5zM8.25 6h7.5v2.25h-7.5V6zM12 2.25c-1.892 0-3.758.11-5.593.322C5.307 2.7 4.5 3.65 4.5 4.757V19.5a2.25 2.25 0 002.25 2.25h10.5a2.25 2.25 0 002.25-2.25V4.757c0-1.108-.806-2.057-1.907-2.185A48.507 48.507 0 0012 2.25z\"\r\n />\r\n </svg>\r\n }\r\n }\r\n <!-- Label (always visible) -->\r\n <span class=\"truncate whitespace-nowrap text-sm\">{{\r\n t(tab.value)\r\n }}</span>\r\n <!-- Count Badge -->\r\n @if (tab.value !== \"properties\" || !resolvedPropertiesTemplate()) {\r\n <span\r\n class=\"ms-auto rounded-full px-1.5 py-0.5 text-xs font-semibold\"\r\n [class]=\"\r\n activeTab() === tab.value\r\n ? 'bg-primary/10 text-primary'\r\n : 'bg-slate-200 text-slate-600 dark:bg-slate-600 dark:text-slate-300'\r\n \"\r\n >\r\n {{ getTabCount(tab.value) }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Content Area -->\r\n <div class=\"flex flex-1 flex-col overflow-hidden\">\r\n <!-- Items Grid -->\r\n <div\r\n class=\"flex-1 p-2.5\"\r\n [class.overflow-y-auto]=\"\r\n activeTab() !== 'properties' || !resolvedPropertiesTemplate()\r\n \"\r\n >\r\n @switch (activeTab()) {\r\n @case (\"functions\") {\r\n @if (filteredCategories().length === 0) {\r\n <div\r\n class=\"flex h-full items-center justify-center text-sm text-slate-400 dark:text-slate-500\"\r\n >\r\n {{ labels()?.noFunctionsFound ?? t(\"noFunctionsFound\") }}\r\n </div>\r\n } @else {\r\n <div class=\"space-y-3\">\r\n @for (category of filteredCategories(); track category.name) {\r\n <div>\r\n <div class=\"mb-2 flex items-center gap-2\">\r\n <span\r\n class=\"text-sm font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400\"\r\n >\r\n {{ category.name }}\r\n </span>\r\n <span\r\n class=\"h-px flex-1 bg-slate-200/60 dark:bg-slate-700/60\"\r\n ></span>\r\n <span\r\n class=\"text-sm text-slate-400 dark:text-slate-500\"\r\n >{{ category.functions.length }}</span\r\n >\r\n </div>\r\n <div class=\"flex flex-wrap gap-1.5\">\r\n @for (fn of category.functions; track fn.name) {\r\n <mt-formula-toolbar-item\r\n type=\"function\"\r\n [value]=\"fn.name\"\r\n [description]=\"fn.description\"\r\n [signature]=\"fn.signature\"\r\n [examples]=\"fn.examples ?? []\"\r\n (onInsert)=\"insertBlock($event)\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n @case (\"properties\") {\r\n @if (resolvedPropertiesTemplate(); as template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"template\"\r\n [ngTemplateOutletContext]=\"propertiesTemplateContext\"\r\n />\r\n } @else {\r\n @if (filteredProperties().length === 0) {\r\n <div\r\n class=\"flex h-full items-center justify-center text-sm text-slate-400 dark:text-slate-500\"\r\n >\r\n {{\r\n labels()?.noPropertiesAvailable ??\r\n t(\"noPropertiesAvailable\")\r\n }}\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-wrap gap-1.5\">\r\n @for (prop of filteredProperties(); track prop) {\r\n <mt-formula-toolbar-item\r\n type=\"property\"\r\n [value]=\"prop\"\r\n [description]=\"t('property') + ': ' + prop\"\r\n propertyType=\"current\"\r\n (onInsert)=\"insertBlock($event)\"\r\n />\r\n }\r\n </div>\r\n }\r\n }\r\n }\r\n @case (\"operators\") {\r\n @if (filteredOperators().length === 0) {\r\n <div\r\n class=\"flex h-full items-center justify-center text-sm text-slate-400 dark:text-slate-500\"\r\n >\r\n {{ labels()?.noOperatorsFound ?? t(\"noOperatorsFound\") }}\r\n </div>\r\n } @else {\r\n <div class=\"space-y-3\">\r\n @for (group of operatorGroups(); track group.type) {\r\n <div>\r\n <div class=\"mb-2 flex items-center gap-2\">\r\n <span\r\n class=\"text-sm font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400\"\r\n >\r\n {{ group.type }}\r\n </span>\r\n <span\r\n class=\"h-px flex-1 bg-slate-200/60 dark:bg-slate-700/60\"\r\n ></span>\r\n </div>\r\n <div class=\"flex flex-wrap gap-1.5\">\r\n @for (op of group.operators; track op.symbol) {\r\n <mt-formula-toolbar-item\r\n type=\"operator\"\r\n [value]=\"op.symbol\"\r\n [description]=\"op.description\"\r\n (onInsert)=\"insertBlock($event)\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n" }]
2254
+ args: [{ selector: 'mt-formula-toolbar', standalone: true, imports: [CommonModule, FormsModule, TranslocoModule, FormulaToolbarItem], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\r\n *transloco=\"let t; prefix: 'components.formula.toolbar'\"\r\n class=\"flex flex-col border-b border-slate-200 dark:border-slate-700\"\r\n [class.h-52]=\"activeTab() !== 'properties' || !resolvedPropertiesTemplate()\"\r\n>\r\n <!-- Top Bar: Search + Quick Insert -->\r\n <div\r\n class=\"flex items-center gap-2 border-b border-slate-200 px-3 py-2 dark:border-slate-700\"\r\n >\r\n <!-- Search Field -->\r\n <div class=\"relative flex-1\">\r\n <svg\r\n class=\"absolute start-3 top-1/2 h-4 w-4 -translate-y-1/2 text-slate-400\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\"\r\n />\r\n </svg>\r\n <input\r\n type=\"text\"\r\n class=\"w-full rounded-lg border border-slate-300 bg-white py-1.5 ps-9 pe-8 text-sm text-slate-700 placeholder:text-slate-400 focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20 transition-all duration-200 dark:border-slate-600 dark:bg-slate-900 dark:text-slate-200 dark:placeholder:text-slate-500\"\r\n [placeholder]=\"searchPlaceholder() || t('search')\"\r\n [(ngModel)]=\"searchQuery\"\r\n />\r\n @if (searchQuery()) {\r\n <button\r\n type=\"button\"\r\n class=\"absolute end-2 top-1/2 -translate-y-1/2 rounded p-0.5 text-slate-400 hover:bg-slate-200 hover:text-slate-600 transition-all duration-200 dark:hover:bg-slate-700\"\r\n (click)=\"clearSearch()\"\r\n >\r\n <svg\r\n class=\"h-4 w-4\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M6 18L18 6M6 6l12 12\"\r\n />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Separator -->\r\n <div class=\"h-6 w-px bg-slate-200 dark:bg-slate-600\"></div>\r\n\r\n <!-- Quick Insert Input -->\r\n <div class=\"relative flex items-center gap-2\">\r\n <span\r\n class=\"text-sm font-medium text-slate-500 dark:text-slate-400 uppercase tracking-wide\"\r\n >{{ t(\"insertLabel\") }}:</span\r\n >\r\n <div class=\"relative\">\r\n <input\r\n #customValueInput\r\n type=\"text\"\r\n class=\"w-32 rounded-md border border-dashed border-slate-300 bg-slate-50 px-3 py-1.5 text-sm font-mono text-slate-700 placeholder:text-slate-400 focus:border-primary focus:bg-white focus:outline-none focus:ring-2 focus:ring-primary/20 transition-all duration-200 dark:border-slate-600 dark:bg-slate-800 dark:text-slate-200 dark:placeholder:text-slate-500 dark:focus:bg-slate-900\"\r\n [placeholder]=\"t('customValuePlaceholder')\"\r\n [(ngModel)]=\"customValue\"\r\n (keydown.enter)=\"insertCustomValue()\"\r\n (keydown.escape)=\"clearCustomValue()\"\r\n />\r\n </div>\r\n\r\n <!-- Insert Button with Type Preview -->\r\n @if (customValue()) {\r\n <button\r\n type=\"button\"\r\n class=\"inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium transition-all duration-200 hover:shadow-sm active:scale-95\"\r\n [class]=\"customValueTypeClass()\"\r\n (click)=\"insertCustomValue()\"\r\n [title]=\"t('insertType', { type: customValueType() })\"\r\n >\r\n @switch (customValueType()) {\r\n @case (\"number\") {\r\n <svg\r\n class=\"h-3 w-3\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M7 20l4-16m2 16l4-16M6 9h14M4 15h14\"\r\n />\r\n </svg>\r\n }\r\n @case (\"string\") {\r\n <svg\r\n class=\"h-3 w-3\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M7.5 8.25h9m-9 3H12m-9.75 1.51c0 1.6 1.123 2.994 2.707 3.227 1.129.166 2.27.293 3.423.379.35.026.67.21.865.501L12 21l2.755-4.133a1.14 1.14 0 01.865-.501 48.172 48.172 0 003.423-.379c1.584-.233 2.707-1.626 2.707-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0012 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018z\"\r\n />\r\n </svg>\r\n }\r\n @default {\r\n <svg\r\n class=\"h-3 w-3\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M12 4.5v15m7.5-7.5h-15\"\r\n />\r\n </svg>\r\n }\r\n }\r\n <span class=\"max-w-16 truncate\">{{ customValuePreview() }}</span>\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- Main Content Row -->\r\n <div class=\"flex flex-1 overflow-hidden\">\r\n <!-- Vertical Tabs -->\r\n <div\r\n class=\"flex w-44 flex-col border-e border-slate-200 dark:border-slate-700\"\r\n >\r\n @for (tab of resolvedTabOptions(); track tab.value) {\r\n <button\r\n type=\"button\"\r\n class=\"flex cursor-pointer items-center gap-2 px-3 py-2.5 text-start text-sm font-medium transition-all duration-200\"\r\n [class]=\"\r\n activeTab() === tab.value\r\n ? 'bg-white border-e-2 border-primary text-primary dark:bg-slate-900'\r\n : searchQuery() && !tabHasResults(tab.value)\r\n ? 'text-slate-300 dark:text-slate-600'\r\n : 'text-slate-600 hover:bg-slate-100 hover:text-slate-800 dark:text-slate-300 dark:hover:bg-slate-700'\r\n \"\r\n (click)=\"setActiveTab(tab.value)\"\r\n >\r\n <!-- Tab Icons -->\r\n @switch (tab.value) {\r\n @case (\"functions\") {\r\n <svg\r\n class=\"h-5 w-5 shrink-0\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M17.25 6.75L22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3l-4.5 16.5\"\r\n />\r\n </svg>\r\n }\r\n @case (\"properties\") {\r\n <svg\r\n class=\"h-5 w-5 shrink-0\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M9.568 3H5.25A2.25 2.25 0 003 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.095 18.095 0 005.223-5.223c.542-.827.369-1.908-.33-2.607L11.16 3.66A2.25 2.25 0 009.568 3z\"\r\n />\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M6 6h.008v.008H6V6z\"\r\n />\r\n </svg>\r\n }\r\n @case (\"operators\") {\r\n <svg\r\n class=\"h-5 w-5 shrink-0\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M15.75 15.75V18m-7.5-6.75h.008v.008H8.25v-.008zm0 2.25h.008v.008H8.25V13.5zm0 2.25h.008v.008H8.25v-.008zm0 2.25h.008v.008H8.25V18zm2.498-6.75h.007v.008h-.007v-.008zm0 2.25h.007v.008h-.007V13.5zm0 2.25h.007v.008h-.007v-.008zm0 2.25h.007v.008h-.007V18zm2.504-6.75h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V13.5zm0 2.25h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V18zm2.498-6.75h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V13.5zM8.25 6h7.5v2.25h-7.5V6zM12 2.25c-1.892 0-3.758.11-5.593.322C5.307 2.7 4.5 3.65 4.5 4.757V19.5a2.25 2.25 0 002.25 2.25h10.5a2.25 2.25 0 002.25-2.25V4.757c0-1.108-.806-2.057-1.907-2.185A48.507 48.507 0 0012 2.25z\"\r\n />\r\n </svg>\r\n }\r\n }\r\n <!-- Label (always visible) -->\r\n <span class=\"truncate whitespace-nowrap text-sm\">{{\r\n t(tab.value)\r\n }}</span>\r\n <!-- Count Badge -->\r\n @if (tab.value !== \"properties\" || !resolvedPropertiesTemplate()) {\r\n <span\r\n class=\"ms-auto rounded-full px-1.5 py-0.5 text-xs font-semibold\"\r\n [class]=\"\r\n activeTab() === tab.value\r\n ? 'bg-primary/10 text-primary'\r\n : 'bg-slate-200 text-slate-600 dark:bg-slate-600 dark:text-slate-300'\r\n \"\r\n >\r\n {{ getTabCount(tab.value) }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Content Area -->\r\n <div class=\"flex flex-1 flex-col overflow-hidden\">\r\n <!-- Items Grid -->\r\n <div\r\n class=\"flex-1 p-2.5\"\r\n [class.overflow-y-auto]=\"\r\n activeTab() !== 'properties' || !resolvedPropertiesTemplate()\r\n \"\r\n >\r\n @switch (activeTab()) {\r\n @case (\"functions\") {\r\n @if (filteredCategories().length === 0) {\r\n <div\r\n class=\"flex h-full items-center justify-center text-sm text-slate-400 dark:text-slate-500\"\r\n >\r\n {{ labels()?.noFunctionsFound ?? t(\"noFunctionsFound\") }}\r\n </div>\r\n } @else {\r\n <div class=\"space-y-3\">\r\n @for (category of filteredCategories(); track category.name) {\r\n <div>\r\n <div class=\"mb-2 flex items-center gap-2\">\r\n <span\r\n class=\"text-sm font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400\"\r\n >\r\n {{ category.displayName || category.name }}\r\n </span>\r\n <span\r\n class=\"h-px flex-1 bg-slate-200/60 dark:bg-slate-700/60\"\r\n ></span>\r\n <span\r\n class=\"text-sm text-slate-400 dark:text-slate-500\"\r\n >{{ category.functions.length }}</span\r\n >\r\n </div>\r\n <div class=\"flex flex-wrap gap-1.5\">\r\n @for (fn of category.functions; track fn.name) {\r\n <mt-formula-toolbar-item\r\n type=\"function\"\r\n [value]=\"fn.name\"\r\n [description]=\"fn.description\"\r\n [signature]=\"fn.signature\"\r\n [template]=\"fn.template\"\r\n [templateCursorOffset]=\"fn.templateCursorOffset\"\r\n [returnType]=\"fn.returnType\"\r\n [parameters]=\"fn.parameters ?? []\"\r\n [examples]=\"fn.examples ?? []\"\r\n [hints]=\"fn.hints ?? []\"\r\n (onInsert)=\"insertBlock($event)\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n @case (\"properties\") {\r\n @if (resolvedPropertiesTemplate(); as template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"template\"\r\n [ngTemplateOutletContext]=\"propertiesTemplateContext\"\r\n />\r\n } @else {\r\n @if (filteredProperties().length === 0) {\r\n <div\r\n class=\"flex h-full items-center justify-center text-sm text-slate-400 dark:text-slate-500\"\r\n >\r\n {{\r\n labels()?.noPropertiesAvailable ??\r\n t(\"noPropertiesAvailable\")\r\n }}\r\n </div>\r\n } @else {\r\n <div class=\"flex flex-wrap gap-1.5\">\r\n @for (prop of filteredProperties(); track prop) {\r\n <mt-formula-toolbar-item\r\n type=\"property\"\r\n [value]=\"prop\"\r\n [description]=\"t('property') + ': ' + prop\"\r\n propertyType=\"current\"\r\n (onInsert)=\"insertBlock($event)\"\r\n />\r\n }\r\n </div>\r\n }\r\n }\r\n }\r\n @case (\"operators\") {\r\n @if (filteredOperators().length === 0) {\r\n <div\r\n class=\"flex h-full items-center justify-center text-sm text-slate-400 dark:text-slate-500\"\r\n >\r\n {{ labels()?.noOperatorsFound ?? t(\"noOperatorsFound\") }}\r\n </div>\r\n } @else {\r\n <div class=\"space-y-3\">\r\n @for (group of operatorGroups(); track group.type) {\r\n <div>\r\n <div class=\"mb-2 flex items-center gap-2\">\r\n <span\r\n class=\"text-sm font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400\"\r\n >\r\n {{ group.type }}\r\n </span>\r\n <span\r\n class=\"h-px flex-1 bg-slate-200/60 dark:bg-slate-700/60\"\r\n ></span>\r\n </div>\r\n <div class=\"flex flex-wrap gap-1.5\">\r\n @for (op of group.operators; track op.symbol) {\r\n <mt-formula-toolbar-item\r\n type=\"operator\"\r\n [value]=\"op.symbol\"\r\n [description]=\"op.description\"\r\n (onInsert)=\"insertBlock($event)\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n" }]
1887
2255
  }], ctorParameters: () => [], propDecorators: { knownProperties: [{ type: i0.Input, args: [{ isSignal: true, alias: "knownProperties", required: false }] }], propertiesTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "propertiesTemplate", required: false }] }], projectedPropertiesTemplate: [{ type: i0.ContentChild, args: ['properties', { ...{
1888
2256
  read: TemplateRef,
1889
2257
  }, isSignal: true }] }], functionCategories: [{ type: i0.Input, args: [{ isSignal: true, alias: "functionCategories", required: false }] }], operators: [{ type: i0.Input, args: [{ isSignal: true, alias: "operators", required: false }] }], initialTab: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialTab", required: false }] }], visibleTabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "visibleTabs", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], labels: [{ type: i0.Input, args: [{ isSignal: true, alias: "labels", required: false }] }], onBlockInsert: [{ type: i0.Output, args: ["onBlockInsert"] }], onTabChange: [{ type: i0.Output, args: ["onTabChange"] }] } });
@@ -3112,5 +3480,5 @@ function createRuntimeError(code, error) {
3112
3480
  * Generated bundle index. Do not edit.
3113
3481
  */
3114
3482
 
3115
- export { CONDITION_FUNCTION_CATEGORIES, CONDITION_OPERATORS, CONDITION_RUNTIME_CATALOG, DEFAULT_OPERATORS, FormulaEditor, FormulaEditorCode, FormulaRuntimeEngine, FormulaStatusBar, FormulaToolbar, FormulaToolbarItem, VALIDATION_FUNCTION_CATEGORIES, VALIDATION_OPERATORS, VALIDATION_RUNTIME_CATALOG, cloneBlock, cloneToken, cloneTokens, createFunctionBlock, createFunctionTokens, createLiteralBlock, createLiteralToken, createOperatorBlock, createOperatorToken, createPropertyBlock, createPropertyToken, findFunctionRange, generateFunctionId, generateSmartBlockId, generateTokenId, getArgumentIndexAtPosition, getFunctionTokens, isValidDropPosition, parseSignature, recalculateDepths, serializeTokens };
3483
+ export { CONDITION_FUNCTION_CATEGORIES, CONDITION_OPERATORS, CONDITION_RUNTIME_CATALOG, DEFAULT_OPERATORS, FormulaEditor, FormulaEditorCode, FormulaRuntimeEngine, FormulaStatusBar, FormulaToolbar, FormulaToolbarItem, VALIDATION_FUNCTION_CATEGORIES, VALIDATION_OPERATORS, VALIDATION_RUNTIME_CATALOG, cloneBlock, cloneToken, cloneTokens, createFunctionBlock, createFunctionTokens, createLiteralBlock, createLiteralToken, createOperatorBlock, createOperatorToken, createPropertyBlock, createPropertyToken, createTextToken, findFunctionRange, generateFunctionId, generateSmartBlockId, generateTokenId, getArgumentIndexAtPosition, getFunctionTokens, isValidDropPosition, parseSignature, recalculateDepths, serializeTokens, tokenizeFormulaTemplate };
3116
3484
  //# sourceMappingURL=masterteam-components-formula.mjs.map