@operato/input 9.0.10 → 9.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,15 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ### [9.0.13](https://github.com/hatiolab/operato/compare/v9.0.12...v9.0.13) (2025-07-27)
7
+
8
+
9
+ ### :bug: Bug Fix
10
+
11
+ * custom functions for ox-input-formula ([42e36d1](https://github.com/hatiolab/operato/commit/42e36d10a6198ddd0e736cdc1cf2d7863749c68c))
12
+
13
+
14
+
6
15
  ### [9.0.10](https://github.com/hatiolab/operato/compare/v9.0.9...v9.0.10) (2025-07-23)
7
16
 
8
17
 
@@ -8,7 +8,7 @@ import { OxFormField } from '@operato/input';
8
8
  type FormulaVariable = {
9
9
  name: string;
10
10
  description?: string;
11
- type?: 'number' | 'string' | 'date' | 'metric' | 'kpi';
11
+ type?: string;
12
12
  unit?: string;
13
13
  help?: string;
14
14
  example?: string;
@@ -31,16 +31,22 @@ type FormulaFunction = {
31
31
  * <ox-input-formula
32
32
  * .value=${formulaValue}
33
33
  * .availableVariables=${variables}
34
+ * .availableFunctions=${functions}
35
+ * .includeDefaultFunctions=${true}
34
36
  * ></ox-input-formula>
35
37
  */
36
38
  export declare class KpiFormulaEditor extends OxFormField {
37
39
  static styles: import("lit").CSSResult[];
38
40
  value: string;
39
41
  availableVariables: FormulaVariable[];
42
+ availableFunctions: FormulaFunction[];
43
+ includeDefaultFunctions: boolean;
40
44
  private errorMessage;
41
45
  private isValid;
42
46
  editor: HTMLTextAreaElement;
43
47
  private _changingNow;
48
+ private readonly _defaultFunctions;
49
+ get functions(): FormulaFunction[];
44
50
  getValue(): any;
45
51
  setValue(value: any): void;
46
52
  validate(): boolean;
@@ -49,7 +55,6 @@ export declare class KpiFormulaEditor extends OxFormField {
49
55
  blur(): void;
50
56
  reset(): void;
51
57
  private readonly operators;
52
- private readonly functions;
53
58
  firstUpdated(): void;
54
59
  render(): import("lit-html").TemplateResult<1>;
55
60
  updated(changes: any): void;
@@ -16,6 +16,8 @@ import { OxFormField } from '@operato/input';
16
16
  * <ox-input-formula
17
17
  * .value=${formulaValue}
18
18
  * .availableVariables=${variables}
19
+ * .availableFunctions=${functions}
20
+ * .includeDefaultFunctions=${true}
19
21
  * ></ox-input-formula>
20
22
  */
21
23
  let KpiFormulaEditor = class KpiFormulaEditor extends OxFormField {
@@ -23,28 +25,13 @@ let KpiFormulaEditor = class KpiFormulaEditor extends OxFormField {
23
25
  super(...arguments);
24
26
  this.value = '';
25
27
  this.availableVariables = [];
28
+ this.availableFunctions = [];
29
+ this.includeDefaultFunctions = true;
26
30
  this.errorMessage = '';
27
31
  this.isValid = true;
28
32
  this._changingNow = false;
29
- // 기본 연산자들
30
- this.operators = [
31
- { symbol: '+', description: '더하기' },
32
- { symbol: '-', description: '빼기' },
33
- { symbol: '*', description: '곱하기' },
34
- { symbol: '/', description: '나누기' },
35
- { symbol: '(', description: '여는 괄호' },
36
- { symbol: ')', description: '닫는 괄호' },
37
- { symbol: '=', description: '같음' },
38
- { symbol: '>', description: '보다 큼' },
39
- { symbol: '<', description: '보다 작음' },
40
- { symbol: '>=', description: '보다 크거나 같음' },
41
- { symbol: '<=', description: '보다 작거나 같음' },
42
- { symbol: '!=', description: '다름' },
43
- { symbol: '&&', description: 'AND' },
44
- { symbol: '||', description: 'OR' }
45
- ];
46
33
  // 기본 함수들 (도움말 정보 포함)
47
- this.functions = [
34
+ this._defaultFunctions = [
48
35
  {
49
36
  name: 'SUM()',
50
37
  description: '합계',
@@ -152,6 +139,23 @@ let KpiFormulaEditor = class KpiFormulaEditor extends OxFormField {
152
139
  ]
153
140
  }
154
141
  ];
142
+ // 기본 연산자들
143
+ this.operators = [
144
+ { symbol: '+', description: '더하기' },
145
+ { symbol: '-', description: '빼기' },
146
+ { symbol: '*', description: '곱하기' },
147
+ { symbol: '/', description: '나누기' },
148
+ { symbol: '(', description: '여는 괄호' },
149
+ { symbol: ')', description: '닫는 괄호' },
150
+ { symbol: '=', description: '같음' },
151
+ { symbol: '>', description: '보다 큼' },
152
+ { symbol: '<', description: '보다 작음' },
153
+ { symbol: '>=', description: '보다 크거나 같음' },
154
+ { symbol: '<=', description: '보다 작거나 같음' },
155
+ { symbol: '!=', description: '다름' },
156
+ { symbol: '&&', description: 'AND' },
157
+ { symbol: '||', description: 'OR' }
158
+ ];
155
159
  }
156
160
  static { this.styles = [
157
161
  css `
@@ -487,6 +491,29 @@ let KpiFormulaEditor = class KpiFormulaEditor extends OxFormField {
487
491
  }
488
492
  `
489
493
  ]; }
494
+ // 사용 가능한 함수 목록을 가져오는 getter
495
+ get functions() {
496
+ let resultFunctions = [];
497
+ // 기본 함수 포함 여부 확인
498
+ if (this.includeDefaultFunctions) {
499
+ resultFunctions = [...this._defaultFunctions];
500
+ }
501
+ // 사용자 정의 함수들 추가
502
+ if (this.availableFunctions && this.availableFunctions.length > 0) {
503
+ for (const customFunc of this.availableFunctions) {
504
+ const existingIndex = resultFunctions.findIndex(f => f.name === customFunc.name);
505
+ if (existingIndex >= 0) {
506
+ // 기존 함수를 사용자 정의 함수로 교체
507
+ resultFunctions[existingIndex] = customFunc;
508
+ }
509
+ else {
510
+ // 새로운 함수 추가
511
+ resultFunctions.push(customFunc);
512
+ }
513
+ }
514
+ }
515
+ return resultFunctions;
516
+ }
490
517
  getValue() {
491
518
  return this.value;
492
519
  }
@@ -513,8 +540,6 @@ let KpiFormulaEditor = class KpiFormulaEditor extends OxFormField {
513
540
  this.isValid = true;
514
541
  this._updateValue();
515
542
  }
516
- // 변수명 정규화 헬퍼 메서드
517
- // _normalizeVariableName 메서드 완전히 삭제
518
543
  firstUpdated() {
519
544
  this.addEventListener('change', this._onChange.bind(this));
520
545
  }
@@ -588,33 +613,38 @@ let KpiFormulaEditor = class KpiFormulaEditor extends OxFormField {
588
613
  `)}
589
614
  </div>
590
615
 
591
- <div class="functions-container">
592
- <div class="functions-header middle-align">
593
- <md-icon>functions</md-icon>
594
- <ox-i18n msgid="label.functions"></ox-i18n>
595
- </div>
596
-
597
- <div class="functions-grid">
598
- ${this.functions.map(func => html `
599
- <div class="function-button" @click=${() => this._insertFunction(func.template)}>
600
- <div style="font-weight: 500;">${func.name}</div>
601
- <div style="font-size: 10px; color: var(--md-sys-color-on-surface-variant);">${func.description}</div>
602
- ${func.help
616
+ ${this.functions.length > 0
603
617
  ? html `
604
- <md-icon
605
- class="help-icon"
606
- @click=${(e) => this._showFunctionHelp(e, func)}
607
- style="position: absolute; top: 4px; right: 4px; font-size: 12px;"
608
- >
609
- help
610
- </md-icon>
611
- `
612
- : ''}
618
+ <div class="functions-container">
619
+ <div class="functions-header middle-align">
620
+ <md-icon>functions</md-icon>
621
+ <ox-i18n msgid="label.functions"></ox-i18n>
613
622
  </div>
614
- `)}
615
- </div>
616
- </div>
617
623
 
624
+ <div class="functions-grid">
625
+ ${this.functions.map(func => html `
626
+ <div class="function-button" @click=${() => this._insertFunction(func.template)}>
627
+ <div style="font-weight: 500;">${func.name}</div>
628
+ <div style="font-size: 10px; color: var(--md-sys-color-on-surface-variant);">
629
+ ${func.description}
630
+ </div>
631
+ ${func.help
632
+ ? html `
633
+ <md-icon
634
+ class="help-icon"
635
+ @click=${(e) => this._showFunctionHelp(e, func)}
636
+ style="position: absolute; top: 4px; right: 4px; font-size: 12px;"
637
+ >
638
+ help
639
+ </md-icon>
640
+ `
641
+ : ''}
642
+ </div>
643
+ `)}
644
+ </div>
645
+ </div>
646
+ `
647
+ : ''}
618
648
  ${this.value
619
649
  ? html `
620
650
  <div class="preview-container">
@@ -949,6 +979,12 @@ __decorate([
949
979
  __decorate([
950
980
  property({ type: Array })
951
981
  ], KpiFormulaEditor.prototype, "availableVariables", void 0);
982
+ __decorate([
983
+ property({ type: Array })
984
+ ], KpiFormulaEditor.prototype, "availableFunctions", void 0);
985
+ __decorate([
986
+ property({ type: Boolean })
987
+ ], KpiFormulaEditor.prototype, "includeDefaultFunctions", void 0);
952
988
  __decorate([
953
989
  state()
954
990
  ], KpiFormulaEditor.prototype, "errorMessage", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"ox-input-formula.js","sourceRoot":"","sources":["../../src/ox-input-formula.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport '@material/web/icon/icon.js'\nimport '@material/web/button/elevated-button.js'\n\nimport '@operato/i18n/ox-i18n.js'\nimport { css, html } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { OxFormField } from '@operato/input'\n\ntype FormulaVariable = {\n name: string\n description?: string\n type?: 'number' | 'string' | 'date' | 'metric' | 'kpi'\n unit?: string\n help?: string\n example?: string\n}\n\ntype FormulaFunction = {\n name: string\n description: string\n template: string\n syntax: string\n parameters: string[]\n returnType: string\n help?: string\n examples?: string[]\n}\n\n/**\n * Formula editor component for KPI calculations\n *\n * Example:\n *\n * <ox-input-formula\n * .value=${formulaValue}\n * .availableVariables=${variables}\n * ></ox-input-formula>\n */\n@customElement('ox-input-formula')\nexport class KpiFormulaEditor extends OxFormField {\n static styles = [\n css`\n :host {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n margin-bottom: var(--spacing-large);\n gap: var(--spacing-medium);\n }\n\n .formula-container {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-small);\n }\n\n .formula-input-container {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-small);\n }\n\n .formula-textarea {\n min-height: 120px;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 4px;\n padding: var(--spacing-medium);\n font-family: 'Courier New', monospace;\n font-size: 14px;\n line-height: 1.4;\n resize: vertical;\n background-color: #f8f9fa;\n font-size: 1.3rem;\n }\n\n .formula-textarea:focus {\n outline: none;\n border-color: var(--md-sys-color-primary);\n background-color: white;\n }\n\n .variables-container {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-small);\n }\n\n .variables-header {\n display: flex;\n align-items: center;\n gap: var(--spacing-small);\n font-weight: 500;\n color: var(--md-sys-color-on-surface);\n }\n\n .variables-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n gap: var(--spacing-small);\n max-height: 200px;\n overflow-y: auto;\n border: 1px solid rgba(0, 0, 0, 0.1);\n border-radius: 4px;\n padding: var(--spacing-small);\n background-color: #f8f9fa;\n }\n\n .variable-item {\n display: flex;\n flex-direction: column;\n padding: var(--spacing-small);\n border: 1px solid rgba(0, 0, 0, 0.1);\n border-radius: 4px;\n background-color: white;\n cursor: pointer;\n transition: all 0.2s ease;\n position: relative;\n }\n\n .variable-item:hover {\n border-color: var(--md-sys-color-primary);\n background-color: var(--md-sys-color-primary-container);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n }\n\n .variable-name {\n font-weight: 500;\n color: var(--md-sys-color-primary);\n font-size: 12px;\n font-family: 'Courier New', monospace;\n }\n\n .variable-description {\n font-size: 11px;\n color: var(--md-sys-color-on-surface-variant);\n margin-top: 2px;\n }\n\n .variable-type {\n font-size: 10px;\n color: var(--md-sys-color-outline);\n margin-top: 2px;\n text-transform: uppercase;\n }\n\n .help-icon {\n position: absolute;\n top: 4px;\n right: 4px;\n font-size: 14px;\n color: var(--md-sys-color-outline);\n cursor: pointer;\n padding: 2px;\n border-radius: 2px;\n transition: all 0.2s ease;\n }\n\n .help-icon:hover {\n color: var(--md-sys-color-primary);\n background-color: var(--md-sys-color-primary-container);\n }\n\n .operators-container {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-small);\n margin-top: var(--spacing-small);\n }\n\n .operator-button {\n padding: var(--spacing-small) var(--spacing-medium);\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 4px;\n background-color: white;\n cursor: pointer;\n font-family: 'Courier New', monospace;\n font-size: 12px;\n transition: all 0.2s ease;\n }\n\n .operator-button:hover {\n background-color: var(--md-sys-color-primary-container);\n border-color: var(--md-sys-color-primary);\n }\n\n .functions-container {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-small);\n margin-top: var(--spacing-small);\n }\n\n .functions-header {\n font-weight: 500;\n color: var(--md-sys-color-on-surface);\n }\n\n .functions-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));\n gap: var(--spacing-small);\n }\n\n .function-button {\n padding: var(--spacing-small);\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 4px;\n background-color: white;\n cursor: pointer;\n font-family: 'Courier New', monospace;\n font-size: 11px;\n text-align: left;\n transition: all 0.2s ease;\n position: relative;\n }\n\n .function-button:hover {\n background-color: var(--md-sys-color-secondary-container);\n border-color: var(--md-sys-color-secondary);\n }\n\n .preview-container {\n margin-top: var(--spacing-medium);\n padding: var(--spacing-medium);\n background-color: #f8f9fa;\n border-radius: 4px;\n border: 1px solid rgba(0, 0, 0, 0.1);\n }\n\n .preview-title {\n font-weight: 500;\n margin-bottom: var(--spacing-small);\n color: var(--md-sys-color-on-surface);\n }\n\n .preview-formula {\n font-family: 'Courier New', monospace;\n background-color: white;\n padding: var(--spacing-small);\n border-radius: 4px;\n border: 1px solid rgba(0, 0, 0, 0.1);\n white-space: pre-wrap;\n word-break: break-all;\n }\n\n .error-message {\n color: var(--md-sys-color-error);\n font-size: 12px;\n margin-top: var(--spacing-small);\n }\n\n .info-message {\n color: var(--md-sys-color-on-surface-variant);\n font-size: 12px;\n margin-top: var(--spacing-small);\n }\n\n /* 도움말 팝업 스타일 */\n .help-popup {\n max-width: 500px;\n max-height: 400px;\n overflow-y: auto;\n }\n\n .help-title {\n font-size: 16px;\n font-weight: 600;\n margin-bottom: var(--spacing-medium);\n color: var(--md-sys-color-primary);\n }\n\n .help-section {\n margin-bottom: var(--spacing-medium);\n }\n\n .help-section-title {\n font-weight: 500;\n margin-bottom: var(--spacing-small);\n color: var(--md-sys-color-on-surface);\n }\n\n .help-content {\n font-size: 14px;\n line-height: 1.5;\n color: var(--md-sys-color-on-surface);\n }\n\n .help-syntax {\n background-color: #f8f9fa;\n padding: var(--spacing-small);\n border-radius: 4px;\n font-family: 'Courier New', monospace;\n font-size: 12px;\n margin: var(--spacing-small) 0;\n border-left: 3px solid var(--md-sys-color-primary);\n }\n\n .help-example {\n background-color: #f0f8ff;\n padding: var(--spacing-small);\n border-radius: 4px;\n font-family: 'Courier New', monospace;\n font-size: 12px;\n margin: var(--spacing-small) 0;\n border-left: 3px solid var(--md-sys-color-secondary);\n }\n\n .help-parameters {\n margin: var(--spacing-small) 0;\n }\n\n .help-parameter {\n display: flex;\n justify-content: space-between;\n padding: 2px 0;\n border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n }\n\n .help-parameter-name {\n font-weight: 500;\n font-family: 'Courier New', monospace;\n }\n\n .help-parameter-desc {\n color: var(--md-sys-color-on-surface-variant);\n }\n\n /* Dialog specific styles */\n .help-dialog {\n border: none;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);\n padding: 0;\n max-width: 500px;\n max-height: 80vh;\n overflow-y: auto;\n background-color: white;\n }\n\n .help-dialog::backdrop {\n background-color: rgba(0, 0, 0, 0.5);\n }\n\n .dialog-actions {\n display: flex;\n justify-content: flex-end;\n gap: var(--spacing-small);\n margin-top: var(--spacing-medium);\n padding: var(--spacing-medium);\n border-top: 1px solid var(--md-sys-color-outline);\n }\n\n .close-btn {\n padding: var(--spacing-small) var(--spacing-medium);\n border: 1px solid var(--md-sys-color-outline);\n border-radius: 4px;\n background-color: white;\n cursor: pointer;\n font-size: 14px;\n transition: all 0.2s ease;\n }\n\n .close-btn:hover {\n background-color: var(--md-sys-color-secondary-container);\n border-color: var(--md-sys-color-secondary);\n }\n\n .middle-align {\n display: flex;\n align-items: center;\n }\n `\n ]\n\n @property({ type: String }) value: string = ''\n @property({ type: Array }) availableVariables: FormulaVariable[] = []\n\n @state() private errorMessage: string = ''\n @state() private isValid: boolean = true\n\n @query('.formula-textarea') editor!: HTMLTextAreaElement\n\n private _changingNow: boolean = false\n\n getValue(): any {\n return this.value\n }\n\n setValue(value: any): void {\n this.value = value\n this._validateFormula()\n }\n\n validate(): boolean {\n this._validateFormula()\n return this.isValid\n }\n\n getErrorMessage(): string {\n return this.errorMessage\n }\n\n focus(): void {\n this.editor.focus()\n }\n\n blur(): void {\n this.editor.blur()\n }\n\n reset(): void {\n this.value = ''\n this.errorMessage = ''\n this.isValid = true\n this._updateValue()\n }\n\n // 기본 연산자들\n private readonly operators = [\n { symbol: '+', description: '더하기' },\n { symbol: '-', description: '빼기' },\n { symbol: '*', description: '곱하기' },\n { symbol: '/', description: '나누기' },\n { symbol: '(', description: '여는 괄호' },\n { symbol: ')', description: '닫는 괄호' },\n { symbol: '=', description: '같음' },\n { symbol: '>', description: '보다 큼' },\n { symbol: '<', description: '보다 작음' },\n { symbol: '>=', description: '보다 크거나 같음' },\n { symbol: '<=', description: '보다 작거나 같음' },\n { symbol: '!=', description: '다름' },\n { symbol: '&&', description: 'AND' },\n { symbol: '||', description: 'OR' }\n ]\n\n // 기본 함수들 (도움말 정보 포함)\n private readonly functions: FormulaFunction[] = [\n {\n name: 'SUM()',\n description: '합계',\n template: 'SUM({expression})',\n syntax: 'SUM(expression)',\n parameters: ['expression - 합계를 계산할 값 또는 변수'],\n returnType: 'number',\n help: '주어진 값들의 합계를 계산합니다. 숫자 배열이나 변수들을 인자로 받습니다.',\n examples: ['SUM(metric1, metric2, metric3)', 'SUM(production_data)', 'SUM(100, 200, 300)']\n },\n {\n name: 'AVG()',\n description: '평균',\n template: 'AVG({expression})',\n syntax: 'AVG(expression)',\n parameters: ['expression - 평균을 계산할 값 또는 변수'],\n returnType: 'number',\n help: '주어진 값들의 평균을 계산합니다. 숫자 배열이나 변수들을 인자로 받습니다.',\n examples: ['AVG(quality_scores)', 'AVG(metric1, metric2, metric3)', 'AVG(10, 20, 30)']\n },\n {\n name: 'MAX()',\n description: '최대값',\n template: 'MAX({expression})',\n syntax: 'MAX(expression)',\n parameters: ['expression - 최대값을 찾을 값 또는 변수'],\n returnType: 'number',\n help: '주어진 값들 중 최대값을 반환합니다.',\n examples: ['MAX(performance_data)', 'MAX(metric1, metric2, metric3)', 'MAX(100, 200, 300)']\n },\n {\n name: 'MIN()',\n description: '최소값',\n template: 'MIN({expression})',\n syntax: 'MIN(expression)',\n parameters: ['expression - 최소값을 찾을 값 또는 변수'],\n returnType: 'number',\n help: '주어진 값들 중 최소값을 반환합니다.',\n examples: ['MIN(quality_scores)', 'MIN(metric1, metric2, metric3)', 'MIN(10, 20, 30)']\n },\n {\n name: 'COUNT()',\n description: '개수',\n template: 'COUNT({expression})',\n syntax: 'COUNT(expression)',\n parameters: ['expression - 개수를 셀 값 또는 변수'],\n returnType: 'number',\n help: '주어진 값들의 개수를 반환합니다.',\n examples: ['COUNT(active_projects)', 'COUNT(metric1, metric2, metric3)', 'COUNT(1, 2, 3, 4, 5)']\n },\n {\n name: 'ROUND()',\n description: '반올림',\n template: 'ROUND({expression}, 2)',\n syntax: 'ROUND(expression, decimals)',\n parameters: ['expression - 반올림할 값', 'decimals - 소수점 자릿수 (기본값: 0)'],\n returnType: 'number',\n help: '주어진 값을 지정된 소수점 자릿수로 반올림합니다.',\n examples: ['ROUND(3.14159, 2) → 3.14', 'ROUND(metric1, 0)', 'ROUND(AVG(scores), 1)']\n },\n {\n name: 'ABS()',\n description: '절대값',\n template: 'ABS({expression})',\n syntax: 'ABS(expression)',\n parameters: ['expression - 절대값을 구할 값'],\n returnType: 'number',\n help: '주어진 값의 절대값을 반환합니다.',\n examples: ['ABS(-10) → 10', 'ABS(metric1 - target)', 'ABS(deviation)']\n },\n {\n name: 'IF()',\n description: '조건문',\n template: 'IF({condition}, {true_value}, {false_value})',\n syntax: 'IF(condition, true_value, false_value)',\n parameters: [\n 'condition - 조건식 (true/false)',\n 'true_value - 조건이 참일 때 반환할 값',\n 'false_value - 조건이 거짓일 때 반환할 값'\n ],\n returnType: 'any',\n help: '조건에 따라 다른 값을 반환합니다. 조건이 참이면 true_value를, 거짓이면 false_value를 반환합니다.',\n examples: [\n 'IF(score > 80, \"우수\", \"보통\")',\n 'IF(metric1 > target, 100, 0)',\n 'IF(quality_score >= 90, \"A등급\", IF(quality_score >= 80, \"B등급\", \"C등급\"))'\n ]\n },\n {\n name: 'CASE()',\n description: '케이스문',\n template: 'CASE {expression} WHEN {value1} THEN {result1} ELSE {default} END',\n syntax: 'CASE expression WHEN value1 THEN result1 [WHEN value2 THEN result2]... ELSE default END',\n parameters: [\n 'expression - 비교할 값',\n 'value1, value2... - 비교할 값들',\n 'result1, result2... - 해당 값일 때 반환할 결과들',\n 'default - 기본값'\n ],\n returnType: 'any',\n help: '여러 조건에 따라 다른 값을 반환합니다. IF문의 확장된 형태입니다.',\n examples: [\n 'CASE grade WHEN \"A\" THEN 100 WHEN \"B\" THEN 80 WHEN \"C\" THEN 60 ELSE 0 END',\n 'CASE score WHEN 90 THEN \"우수\" WHEN 80 THEN \"양호\" WHEN 70 THEN \"보통\" ELSE \"미흡\" END'\n ]\n }\n ]\n\n // 변수명 정규화 헬퍼 메서드\n // _normalizeVariableName 메서드 완전히 삭제\n\n firstUpdated() {\n this.addEventListener('change', this._onChange.bind(this))\n }\n\n render() {\n return html`\n <div class=\"formula-container\">\n <div class=\"formula-input-container\">\n <label class=\"variables-header\">\n <ox-i18n msgid=\"label.formula\"></ox-i18n>\n </label>\n\n <textarea\n class=\"formula-textarea\"\n .value=${this.value}\n @input=${this._onFormulaInput.bind(this)}\n placeholder=\"수식을 입력하세요. 예: SUM(metric1) + AVG(metric2) * 0.5\"\n ></textarea>\n\n ${this.errorMessage\n ? html`\n <div class=\"error-message middle-align\">\n <md-icon>error</md-icon>\n ${this.errorMessage}\n </div>\n `\n : ''}\n ${!this.errorMessage && this.value\n ? html`\n <div class=\"info-message middle-align\">\n <md-icon>info</md-icon>\n 수식이 유효합니다.\n </div>\n `\n : ''}\n </div>\n\n <div class=\"variables-container\">\n <div class=\"variables-header middle-align\">\n <md-icon>variables</md-icon>\n <ox-i18n msgid=\"label.available-variables\"></ox-i18n>\n </div>\n\n <div class=\"variables-grid\">\n ${this.availableVariables.map(\n variable => html`\n <div class=\"variable-item\" @click=${() => this._insertVariable(variable.name)}>\n <div class=\"variable-name\">[${variable.name}]</div>\n ${variable.description ? html` <div class=\"variable-description\">${variable.description}</div> ` : ''}\n ${variable.type ? html` <div class=\"variable-type\">${variable.type}</div> ` : ''}\n ${variable.help\n ? html`\n <md-icon class=\"help-icon\" @click=${(e: Event) => this._showVariableHelp(e, variable)}>\n help\n </md-icon>\n `\n : ''}\n </div>\n `\n )}\n </div>\n </div>\n\n <div class=\"operators-container\">\n <div class=\"variables-header middle-align\">\n <md-icon>calculate</md-icon>\n <ox-i18n msgid=\"label.operators\"></ox-i18n>\n </div>\n\n ${this.operators.map(\n op => html`\n <button class=\"operator-button\" @click=${() => this._insertOperator(op.symbol)} title=\"${op.description}\">\n ${op.symbol}\n </button>\n `\n )}\n </div>\n\n <div class=\"functions-container\">\n <div class=\"functions-header middle-align\">\n <md-icon>functions</md-icon>\n <ox-i18n msgid=\"label.functions\"></ox-i18n>\n </div>\n\n <div class=\"functions-grid\">\n ${this.functions.map(\n func => html`\n <div class=\"function-button\" @click=${() => this._insertFunction(func.template)}>\n <div style=\"font-weight: 500;\">${func.name}</div>\n <div style=\"font-size: 10px; color: var(--md-sys-color-on-surface-variant);\">${func.description}</div>\n ${func.help\n ? html`\n <md-icon\n class=\"help-icon\"\n @click=${(e: Event) => this._showFunctionHelp(e, func)}\n style=\"position: absolute; top: 4px; right: 4px; font-size: 12px;\"\n >\n help\n </md-icon>\n `\n : ''}\n </div>\n `\n )}\n </div>\n </div>\n\n ${this.value\n ? html`\n <div class=\"preview-container\">\n <div class=\"preview-title middle-align\">\n <md-icon>preview</md-icon>\n <ox-i18n msgid=\"label.formula-preview\"></ox-i18n>\n </div>\n <div class=\"preview-formula\">${this.value}</div>\n </div>\n `\n : ''}\n </div>\n `\n }\n\n updated(changes: any) {\n if (changes.has('value')) {\n this._validateFormula()\n }\n }\n\n _onChange(e: Event) {\n if (this._changingNow) {\n return\n }\n\n this._changingNow = true\n this._updateValue()\n this._changingNow = false\n }\n\n _onFormulaInput(e: Event) {\n const textarea = e.target as HTMLTextAreaElement\n this.value = textarea.value\n this._validateFormula()\n this._updateValue()\n }\n\n _insertVariable(variableName: string) {\n const start = this.editor.selectionStart\n const end = this.editor.selectionEnd\n const currentValue = this.editor.value\n\n // 변수명을 [변수명] 형태로만 감싸서 삽입\n const insertText = `[${variableName}]`\n const newValue = currentValue.substring(0, start) + insertText + currentValue.substring(end)\n this.editor.value = newValue\n this.value = newValue\n\n // 커서 위치 조정\n const newCursorPos = start + insertText.length\n this.editor.setSelectionRange(newCursorPos, newCursorPos)\n this.editor.focus()\n\n this._validateFormula()\n this._updateValue()\n }\n\n _insertOperator(operator: string) {\n const start = this.editor.selectionStart\n const end = this.editor.selectionEnd\n const currentValue = this.editor.value\n\n // 연산자 앞뒤에 공백 추가\n const insertText = ` ${operator} `\n const newValue = currentValue.substring(0, start) + insertText + currentValue.substring(end)\n this.editor.value = newValue\n this.value = newValue\n\n // 커서 위치 조정\n const newCursorPos = start + insertText.length\n this.editor.setSelectionRange(newCursorPos, newCursorPos)\n this.editor.focus()\n\n this._validateFormula()\n this._updateValue()\n }\n\n _insertFunction(template: string) {\n const start = this.editor.selectionStart\n const end = this.editor.selectionEnd\n const currentValue = this.editor.value\n\n // 선택된 텍스트가 있으면 그것을 expression으로 사용\n const selectedText = currentValue.substring(start, end)\n const insertText = template.replace('{expression}', selectedText || 'expression')\n\n const newValue = currentValue.substring(0, start) + insertText + currentValue.substring(end)\n this.editor.value = newValue\n this.value = newValue\n\n // 커서 위치 조정 (expression 부분에 포커스)\n const expressionStart = start + insertText.indexOf('expression')\n const expressionEnd = expressionStart + 'expression'.length\n this.editor.setSelectionRange(expressionStart, expressionEnd)\n this.editor.focus()\n\n this._validateFormula()\n this._updateValue()\n }\n\n _showVariableHelp(e: Event, variable: FormulaVariable) {\n e.stopPropagation()\n\n // 간단한 테스트 버전\n const message = `\n변수: ${variable.name}\n설명: ${variable.description || '없음'}\n타입: ${variable.type || '없음'}\n단위: ${variable.unit || '없음'}\n예시: ${variable.example || '없음'}\n `.trim()\n\n console.log('Variable help:', message)\n\n // dialog 지원 여부 확인\n if (typeof HTMLDialogElement !== 'undefined') {\n const dialog = document.createElement('dialog')\n dialog.className = 'help-dialog'\n\n // HTML 문자열로 직접 작성\n dialog.innerHTML = `\n <div class=\"help-popup\">\n <div class=\"help-title\">${variable.name}</div>\n \n ${\n variable.description\n ? `\n <div class=\"help-section\">\n <div class=\"help-section-title\">설명</div>\n <div class=\"help-content\">${variable.description}</div>\n </div>\n `\n : ''\n }\n \n ${\n variable.type\n ? `\n <div class=\"help-section\">\n <div class=\"help-section-title\">타입</div>\n <div class=\"help-content\">${variable.type}</div>\n </div>\n `\n : ''\n }\n \n ${\n variable.unit\n ? `\n <div class=\"help-section\">\n <div class=\"help-section-title\">단위</div>\n <div class=\"help-content\">${variable.unit}</div>\n </div>\n `\n : ''\n }\n \n ${\n variable.help\n ? `\n <div class=\"help-section\">\n <div class=\"help-section-title\">상세 설명</div>\n <div class=\"help-content\">${variable.help}</div>\n </div>\n `\n : ''\n }\n \n ${\n variable.example\n ? `\n <div class=\"help-section\">\n <div class=\"help-section-title\">사용 예시</div>\n <div class=\"help-example\">${variable.example}</div>\n </div>\n `\n : ''\n }\n </div>\n \n <div class=\"dialog-actions\">\n <button class=\"close-btn\" onclick=\"this.closest('dialog').close()\">닫기</button>\n </div>\n `\n\n document.body.appendChild(dialog)\n dialog.showModal()\n\n // 외부 클릭으로 닫기\n dialog.addEventListener('click', event => {\n const rect = dialog.getBoundingClientRect()\n const isInDialog =\n event.clientX >= rect.left &&\n event.clientX <= rect.right &&\n event.clientY >= rect.top &&\n event.clientY <= rect.bottom\n\n if (!isInDialog) {\n dialog.close()\n }\n })\n\n dialog.addEventListener('close', () => {\n if (document.body.contains(dialog)) {\n document.body.removeChild(dialog)\n }\n })\n\n // ESC 키로 닫기\n const handleEsc = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n dialog.close()\n document.removeEventListener('keydown', handleEsc)\n }\n }\n document.addEventListener('keydown', handleEsc)\n } else {\n // dialog를 지원하지 않는 브라우저에서는 alert 사용\n alert(message)\n }\n }\n\n _showFunctionHelp(e: Event, func: FormulaFunction) {\n e.stopPropagation()\n\n const dialog = document.createElement('dialog')\n dialog.className = 'help-dialog'\n\n // HTML 문자열로 직접 작성\n dialog.innerHTML = `\n <div class=\"help-popup\">\n <div class=\"help-title\">${func.name}</div>\n\n <div class=\"help-section\">\n <div class=\"help-section-title\">설명</div>\n <div class=\"help-content\">${func.description}</div>\n </div>\n\n <div class=\"help-section\">\n <div class=\"help-section-title\">구문</div>\n <div class=\"help-syntax\">${func.syntax}</div>\n </div>\n\n <div class=\"help-section\">\n <div class=\"help-section-title\">매개변수</div>\n <div class=\"help-parameters\">\n ${func.parameters\n .map(\n param => `\n <div class=\"help-parameter\">\n <span class=\"help-parameter-desc\">${param}</span>\n </div>\n `\n )\n .join('')}\n </div>\n </div>\n\n <div class=\"help-section\">\n <div class=\"help-section-title\">반환 타입</div>\n <div class=\"help-content\">${func.returnType}</div>\n </div>\n\n ${\n func.help\n ? `\n <div class=\"help-section\">\n <div class=\"help-section-title\">상세 설명</div>\n <div class=\"help-content\">${func.help}</div>\n </div>\n `\n : ''\n }\n \n ${\n func.examples && func.examples.length > 0\n ? `\n <div class=\"help-section\">\n <div class=\"help-section-title\">사용 예시</div>\n ${func.examples\n .map(\n example => `\n <div class=\"help-example\">${example}</div>\n `\n )\n .join('')}\n </div>\n `\n : ''\n }\n </div>\n \n <div class=\"dialog-actions\">\n <button class=\"close-btn\" onclick=\"this.closest('dialog').close()\">닫기</button>\n </div>\n `\n\n document.body.appendChild(dialog)\n dialog.showModal()\n\n // 외부 클릭으로 닫기\n dialog.addEventListener('click', event => {\n const rect = dialog.getBoundingClientRect()\n const isInDialog =\n event.clientX >= rect.left &&\n event.clientX <= rect.right &&\n event.clientY >= rect.top &&\n event.clientY <= rect.bottom\n\n if (!isInDialog) {\n dialog.close()\n }\n })\n\n dialog.addEventListener('close', () => {\n if (document.body.contains(dialog)) {\n document.body.removeChild(dialog)\n }\n })\n\n // ESC 키로 닫기\n const handleEsc = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n dialog.close()\n document.removeEventListener('keydown', handleEsc)\n }\n }\n document.addEventListener('keydown', handleEsc)\n }\n\n _validateFormula() {\n // 기본적인 수식 유효성 검사\n const formula = this.value.trim()\n\n if (!formula) {\n this.errorMessage = ''\n this.isValid = true\n return\n }\n\n // 괄호 균형 검사\n const openBrackets = (formula.match(/\\(/g) || []).length\n const closeBrackets = (formula.match(/\\)/g) || []).length\n\n if (openBrackets !== closeBrackets) {\n this.errorMessage = '괄호가 균형을 이루지 않습니다.'\n this.isValid = false\n return\n }\n\n // 변수 참조 검증 ([변수명] 형태)\n const variableRefs = formula.match(/\\[([^\\]]+)\\]/g) || []\n for (const ref of variableRefs) {\n const varName = ref.slice(1, -1) // [변수명]에서 변수명 추출\n const availableVarNames = this.availableVariables.map(v => v.name)\n if (!availableVarNames.includes(varName)) {\n this.errorMessage = `알 수 없는 변수: ${varName}`\n this.isValid = false\n return\n }\n }\n\n // 기본 문법 검사\n const invalidPatterns = [\n /[+\\-*/]{2,}/, // 연속된 연산자\n /[+\\-*/]\\s*$/, // 끝에 연산자\n /^\\s*[+\\-*/]/, // 시작에 연산자\n /\\(\\s*\\)/ // 빈 괄호\n ]\n\n for (const pattern of invalidPatterns) {\n if (pattern.test(formula)) {\n this.errorMessage = '수식 문법이 올바르지 않습니다.'\n this.isValid = false\n return\n }\n }\n\n this.errorMessage = ''\n this.isValid = true\n }\n\n _updateValue() {\n this.dispatchEvent(\n new CustomEvent('change', {\n bubbles: true,\n composed: true,\n detail: this.value\n })\n )\n }\n}\n"]}
1
+ {"version":3,"file":"ox-input-formula.js","sourceRoot":"","sources":["../../src/ox-input-formula.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport '@material/web/icon/icon.js'\nimport '@material/web/button/elevated-button.js'\n\nimport '@operato/i18n/ox-i18n.js'\nimport { css, html } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { OxFormField } from '@operato/input'\n\ntype FormulaVariable = {\n name: string\n description?: string\n type?: string\n unit?: string\n help?: string\n example?: string\n}\n\ntype FormulaFunction = {\n name: string\n description: string\n template: string\n syntax: string\n parameters: string[]\n returnType: string\n help?: string\n examples?: string[]\n}\n\n/**\n * Formula editor component for KPI calculations\n *\n * Example:\n *\n * <ox-input-formula\n * .value=${formulaValue}\n * .availableVariables=${variables}\n * .availableFunctions=${functions}\n * .includeDefaultFunctions=${true}\n * ></ox-input-formula>\n */\n@customElement('ox-input-formula')\nexport class KpiFormulaEditor extends OxFormField {\n static styles = [\n css`\n :host {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n margin-bottom: var(--spacing-large);\n gap: var(--spacing-medium);\n }\n\n .formula-container {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-small);\n }\n\n .formula-input-container {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-small);\n }\n\n .formula-textarea {\n min-height: 120px;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 4px;\n padding: var(--spacing-medium);\n font-family: 'Courier New', monospace;\n font-size: 14px;\n line-height: 1.4;\n resize: vertical;\n background-color: #f8f9fa;\n font-size: 1.3rem;\n }\n\n .formula-textarea:focus {\n outline: none;\n border-color: var(--md-sys-color-primary);\n background-color: white;\n }\n\n .variables-container {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-small);\n }\n\n .variables-header {\n display: flex;\n align-items: center;\n gap: var(--spacing-small);\n font-weight: 500;\n color: var(--md-sys-color-on-surface);\n }\n\n .variables-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n gap: var(--spacing-small);\n max-height: 200px;\n overflow-y: auto;\n border: 1px solid rgba(0, 0, 0, 0.1);\n border-radius: 4px;\n padding: var(--spacing-small);\n background-color: #f8f9fa;\n }\n\n .variable-item {\n display: flex;\n flex-direction: column;\n padding: var(--spacing-small);\n border: 1px solid rgba(0, 0, 0, 0.1);\n border-radius: 4px;\n background-color: white;\n cursor: pointer;\n transition: all 0.2s ease;\n position: relative;\n }\n\n .variable-item:hover {\n border-color: var(--md-sys-color-primary);\n background-color: var(--md-sys-color-primary-container);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n }\n\n .variable-name {\n font-weight: 500;\n color: var(--md-sys-color-primary);\n font-size: 12px;\n font-family: 'Courier New', monospace;\n }\n\n .variable-description {\n font-size: 11px;\n color: var(--md-sys-color-on-surface-variant);\n margin-top: 2px;\n }\n\n .variable-type {\n font-size: 10px;\n color: var(--md-sys-color-outline);\n margin-top: 2px;\n text-transform: uppercase;\n }\n\n .help-icon {\n position: absolute;\n top: 4px;\n right: 4px;\n font-size: 14px;\n color: var(--md-sys-color-outline);\n cursor: pointer;\n padding: 2px;\n border-radius: 2px;\n transition: all 0.2s ease;\n }\n\n .help-icon:hover {\n color: var(--md-sys-color-primary);\n background-color: var(--md-sys-color-primary-container);\n }\n\n .operators-container {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-small);\n margin-top: var(--spacing-small);\n }\n\n .operator-button {\n padding: var(--spacing-small) var(--spacing-medium);\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 4px;\n background-color: white;\n cursor: pointer;\n font-family: 'Courier New', monospace;\n font-size: 12px;\n transition: all 0.2s ease;\n }\n\n .operator-button:hover {\n background-color: var(--md-sys-color-primary-container);\n border-color: var(--md-sys-color-primary);\n }\n\n .functions-container {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-small);\n margin-top: var(--spacing-small);\n }\n\n .functions-header {\n font-weight: 500;\n color: var(--md-sys-color-on-surface);\n }\n\n .functions-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));\n gap: var(--spacing-small);\n }\n\n .function-button {\n padding: var(--spacing-small);\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 4px;\n background-color: white;\n cursor: pointer;\n font-family: 'Courier New', monospace;\n font-size: 11px;\n text-align: left;\n transition: all 0.2s ease;\n position: relative;\n }\n\n .function-button:hover {\n background-color: var(--md-sys-color-secondary-container);\n border-color: var(--md-sys-color-secondary);\n }\n\n .preview-container {\n margin-top: var(--spacing-medium);\n padding: var(--spacing-medium);\n background-color: #f8f9fa;\n border-radius: 4px;\n border: 1px solid rgba(0, 0, 0, 0.1);\n }\n\n .preview-title {\n font-weight: 500;\n margin-bottom: var(--spacing-small);\n color: var(--md-sys-color-on-surface);\n }\n\n .preview-formula {\n font-family: 'Courier New', monospace;\n background-color: white;\n padding: var(--spacing-small);\n border-radius: 4px;\n border: 1px solid rgba(0, 0, 0, 0.1);\n white-space: pre-wrap;\n word-break: break-all;\n }\n\n .error-message {\n color: var(--md-sys-color-error);\n font-size: 12px;\n margin-top: var(--spacing-small);\n }\n\n .info-message {\n color: var(--md-sys-color-on-surface-variant);\n font-size: 12px;\n margin-top: var(--spacing-small);\n }\n\n /* 도움말 팝업 스타일 */\n .help-popup {\n max-width: 500px;\n max-height: 400px;\n overflow-y: auto;\n }\n\n .help-title {\n font-size: 16px;\n font-weight: 600;\n margin-bottom: var(--spacing-medium);\n color: var(--md-sys-color-primary);\n }\n\n .help-section {\n margin-bottom: var(--spacing-medium);\n }\n\n .help-section-title {\n font-weight: 500;\n margin-bottom: var(--spacing-small);\n color: var(--md-sys-color-on-surface);\n }\n\n .help-content {\n font-size: 14px;\n line-height: 1.5;\n color: var(--md-sys-color-on-surface);\n }\n\n .help-syntax {\n background-color: #f8f9fa;\n padding: var(--spacing-small);\n border-radius: 4px;\n font-family: 'Courier New', monospace;\n font-size: 12px;\n margin: var(--spacing-small) 0;\n border-left: 3px solid var(--md-sys-color-primary);\n }\n\n .help-example {\n background-color: #f0f8ff;\n padding: var(--spacing-small);\n border-radius: 4px;\n font-family: 'Courier New', monospace;\n font-size: 12px;\n margin: var(--spacing-small) 0;\n border-left: 3px solid var(--md-sys-color-secondary);\n }\n\n .help-parameters {\n margin: var(--spacing-small) 0;\n }\n\n .help-parameter {\n display: flex;\n justify-content: space-between;\n padding: 2px 0;\n border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n }\n\n .help-parameter-name {\n font-weight: 500;\n font-family: 'Courier New', monospace;\n }\n\n .help-parameter-desc {\n color: var(--md-sys-color-on-surface-variant);\n }\n\n /* Dialog specific styles */\n .help-dialog {\n border: none;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);\n padding: 0;\n max-width: 500px;\n max-height: 80vh;\n overflow-y: auto;\n background-color: white;\n }\n\n .help-dialog::backdrop {\n background-color: rgba(0, 0, 0, 0.5);\n }\n\n .dialog-actions {\n display: flex;\n justify-content: flex-end;\n gap: var(--spacing-small);\n margin-top: var(--spacing-medium);\n padding: var(--spacing-medium);\n border-top: 1px solid var(--md-sys-color-outline);\n }\n\n .close-btn {\n padding: var(--spacing-small) var(--spacing-medium);\n border: 1px solid var(--md-sys-color-outline);\n border-radius: 4px;\n background-color: white;\n cursor: pointer;\n font-size: 14px;\n transition: all 0.2s ease;\n }\n\n .close-btn:hover {\n background-color: var(--md-sys-color-secondary-container);\n border-color: var(--md-sys-color-secondary);\n }\n\n .middle-align {\n display: flex;\n align-items: center;\n }\n `\n ]\n\n @property({ type: String }) value: string = ''\n @property({ type: Array }) availableVariables: FormulaVariable[] = []\n @property({ type: Array }) availableFunctions: FormulaFunction[] = []\n @property({ type: Boolean }) includeDefaultFunctions: boolean = true\n\n @state() private errorMessage: string = ''\n @state() private isValid: boolean = true\n\n @query('.formula-textarea') editor!: HTMLTextAreaElement\n\n private _changingNow: boolean = false\n\n // 기본 함수들 (도움말 정보 포함)\n private readonly _defaultFunctions: FormulaFunction[] = [\n {\n name: 'SUM()',\n description: '합계',\n template: 'SUM({expression})',\n syntax: 'SUM(expression)',\n parameters: ['expression - 합계를 계산할 값 또는 변수'],\n returnType: 'number',\n help: '주어진 값들의 합계를 계산합니다. 숫자 배열이나 변수들을 인자로 받습니다.',\n examples: ['SUM(metric1, metric2, metric3)', 'SUM(production_data)', 'SUM(100, 200, 300)']\n },\n {\n name: 'AVG()',\n description: '평균',\n template: 'AVG({expression})',\n syntax: 'AVG(expression)',\n parameters: ['expression - 평균을 계산할 값 또는 변수'],\n returnType: 'number',\n help: '주어진 값들의 평균을 계산합니다. 숫자 배열이나 변수들을 인자로 받습니다.',\n examples: ['AVG(quality_scores)', 'AVG(metric1, metric2, metric3)', 'AVG(10, 20, 30)']\n },\n {\n name: 'MAX()',\n description: '최대값',\n template: 'MAX({expression})',\n syntax: 'MAX(expression)',\n parameters: ['expression - 최대값을 찾을 값 또는 변수'],\n returnType: 'number',\n help: '주어진 값들 중 최대값을 반환합니다.',\n examples: ['MAX(performance_data)', 'MAX(metric1, metric2, metric3)', 'MAX(100, 200, 300)']\n },\n {\n name: 'MIN()',\n description: '최소값',\n template: 'MIN({expression})',\n syntax: 'MIN(expression)',\n parameters: ['expression - 최소값을 찾을 값 또는 변수'],\n returnType: 'number',\n help: '주어진 값들 중 최소값을 반환합니다.',\n examples: ['MIN(quality_scores)', 'MIN(metric1, metric2, metric3)', 'MIN(10, 20, 30)']\n },\n {\n name: 'COUNT()',\n description: '개수',\n template: 'COUNT({expression})',\n syntax: 'COUNT(expression)',\n parameters: ['expression - 개수를 셀 값 또는 변수'],\n returnType: 'number',\n help: '주어진 값들의 개수를 반환합니다.',\n examples: ['COUNT(active_projects)', 'COUNT(metric1, metric2, metric3)', 'COUNT(1, 2, 3, 4, 5)']\n },\n {\n name: 'ROUND()',\n description: '반올림',\n template: 'ROUND({expression}, 2)',\n syntax: 'ROUND(expression, decimals)',\n parameters: ['expression - 반올림할 값', 'decimals - 소수점 자릿수 (기본값: 0)'],\n returnType: 'number',\n help: '주어진 값을 지정된 소수점 자릿수로 반올림합니다.',\n examples: ['ROUND(3.14159, 2) → 3.14', 'ROUND(metric1, 0)', 'ROUND(AVG(scores), 1)']\n },\n {\n name: 'ABS()',\n description: '절대값',\n template: 'ABS({expression})',\n syntax: 'ABS(expression)',\n parameters: ['expression - 절대값을 구할 값'],\n returnType: 'number',\n help: '주어진 값의 절대값을 반환합니다.',\n examples: ['ABS(-10) → 10', 'ABS(metric1 - target)', 'ABS(deviation)']\n },\n {\n name: 'IF()',\n description: '조건문',\n template: 'IF({condition}, {true_value}, {false_value})',\n syntax: 'IF(condition, true_value, false_value)',\n parameters: [\n 'condition - 조건식 (true/false)',\n 'true_value - 조건이 참일 때 반환할 값',\n 'false_value - 조건이 거짓일 때 반환할 값'\n ],\n returnType: 'any',\n help: '조건에 따라 다른 값을 반환합니다. 조건이 참이면 true_value를, 거짓이면 false_value를 반환합니다.',\n examples: [\n 'IF(score > 80, \"우수\", \"보통\")',\n 'IF(metric1 > target, 100, 0)',\n 'IF(quality_score >= 90, \"A등급\", IF(quality_score >= 80, \"B등급\", \"C등급\"))'\n ]\n },\n {\n name: 'CASE()',\n description: '케이스문',\n template: 'CASE {expression} WHEN {value1} THEN {result1} ELSE {default} END',\n syntax: 'CASE expression WHEN value1 THEN result1 [WHEN value2 THEN result2]... ELSE default END',\n parameters: [\n 'expression - 비교할 값',\n 'value1, value2... - 비교할 값들',\n 'result1, result2... - 해당 값일 때 반환할 결과들',\n 'default - 기본값'\n ],\n returnType: 'any',\n help: '여러 조건에 따라 다른 값을 반환합니다. IF문의 확장된 형태입니다.',\n examples: [\n 'CASE grade WHEN \"A\" THEN 100 WHEN \"B\" THEN 80 WHEN \"C\" THEN 60 ELSE 0 END',\n 'CASE score WHEN 90 THEN \"우수\" WHEN 80 THEN \"양호\" WHEN 70 THEN \"보통\" ELSE \"미흡\" END'\n ]\n }\n ]\n\n // 사용 가능한 함수 목록을 가져오는 getter\n get functions(): FormulaFunction[] {\n let resultFunctions: FormulaFunction[] = []\n\n // 기본 함수 포함 여부 확인\n if (this.includeDefaultFunctions) {\n resultFunctions = [...this._defaultFunctions]\n }\n\n // 사용자 정의 함수들 추가\n if (this.availableFunctions && this.availableFunctions.length > 0) {\n for (const customFunc of this.availableFunctions) {\n const existingIndex = resultFunctions.findIndex(f => f.name === customFunc.name)\n if (existingIndex >= 0) {\n // 기존 함수를 사용자 정의 함수로 교체\n resultFunctions[existingIndex] = customFunc\n } else {\n // 새로운 함수 추가\n resultFunctions.push(customFunc)\n }\n }\n }\n\n return resultFunctions\n }\n\n getValue(): any {\n return this.value\n }\n\n setValue(value: any): void {\n this.value = value\n this._validateFormula()\n }\n\n validate(): boolean {\n this._validateFormula()\n return this.isValid\n }\n\n getErrorMessage(): string {\n return this.errorMessage\n }\n\n focus(): void {\n this.editor.focus()\n }\n\n blur(): void {\n this.editor.blur()\n }\n\n reset(): void {\n this.value = ''\n this.errorMessage = ''\n this.isValid = true\n this._updateValue()\n }\n\n // 기본 연산자들\n private readonly operators = [\n { symbol: '+', description: '더하기' },\n { symbol: '-', description: '빼기' },\n { symbol: '*', description: '곱하기' },\n { symbol: '/', description: '나누기' },\n { symbol: '(', description: '여는 괄호' },\n { symbol: ')', description: '닫는 괄호' },\n { symbol: '=', description: '같음' },\n { symbol: '>', description: '보다 큼' },\n { symbol: '<', description: '보다 작음' },\n { symbol: '>=', description: '보다 크거나 같음' },\n { symbol: '<=', description: '보다 작거나 같음' },\n { symbol: '!=', description: '다름' },\n { symbol: '&&', description: 'AND' },\n { symbol: '||', description: 'OR' }\n ]\n\n firstUpdated() {\n this.addEventListener('change', this._onChange.bind(this))\n }\n\n render() {\n return html`\n <div class=\"formula-container\">\n <div class=\"formula-input-container\">\n <label class=\"variables-header\">\n <ox-i18n msgid=\"label.formula\"></ox-i18n>\n </label>\n\n <textarea\n class=\"formula-textarea\"\n .value=${this.value}\n @input=${this._onFormulaInput.bind(this)}\n placeholder=\"수식을 입력하세요. 예: SUM(metric1) + AVG(metric2) * 0.5\"\n ></textarea>\n\n ${this.errorMessage\n ? html`\n <div class=\"error-message middle-align\">\n <md-icon>error</md-icon>\n ${this.errorMessage}\n </div>\n `\n : ''}\n ${!this.errorMessage && this.value\n ? html`\n <div class=\"info-message middle-align\">\n <md-icon>info</md-icon>\n 수식이 유효합니다.\n </div>\n `\n : ''}\n </div>\n\n <div class=\"variables-container\">\n <div class=\"variables-header middle-align\">\n <md-icon>variables</md-icon>\n <ox-i18n msgid=\"label.available-variables\"></ox-i18n>\n </div>\n\n <div class=\"variables-grid\">\n ${this.availableVariables.map(\n variable => html`\n <div class=\"variable-item\" @click=${() => this._insertVariable(variable.name)}>\n <div class=\"variable-name\">[${variable.name}]</div>\n ${variable.description ? html` <div class=\"variable-description\">${variable.description}</div> ` : ''}\n ${variable.type ? html` <div class=\"variable-type\">${variable.type}</div> ` : ''}\n ${variable.help\n ? html`\n <md-icon class=\"help-icon\" @click=${(e: Event) => this._showVariableHelp(e, variable)}>\n help\n </md-icon>\n `\n : ''}\n </div>\n `\n )}\n </div>\n </div>\n\n <div class=\"operators-container\">\n <div class=\"variables-header middle-align\">\n <md-icon>calculate</md-icon>\n <ox-i18n msgid=\"label.operators\"></ox-i18n>\n </div>\n\n ${this.operators.map(\n op => html`\n <button class=\"operator-button\" @click=${() => this._insertOperator(op.symbol)} title=\"${op.description}\">\n ${op.symbol}\n </button>\n `\n )}\n </div>\n\n ${this.functions.length > 0\n ? html`\n <div class=\"functions-container\">\n <div class=\"functions-header middle-align\">\n <md-icon>functions</md-icon>\n <ox-i18n msgid=\"label.functions\"></ox-i18n>\n </div>\n\n <div class=\"functions-grid\">\n ${this.functions.map(\n func => html`\n <div class=\"function-button\" @click=${() => this._insertFunction(func.template)}>\n <div style=\"font-weight: 500;\">${func.name}</div>\n <div style=\"font-size: 10px; color: var(--md-sys-color-on-surface-variant);\">\n ${func.description}\n </div>\n ${func.help\n ? html`\n <md-icon\n class=\"help-icon\"\n @click=${(e: Event) => this._showFunctionHelp(e, func)}\n style=\"position: absolute; top: 4px; right: 4px; font-size: 12px;\"\n >\n help\n </md-icon>\n `\n : ''}\n </div>\n `\n )}\n </div>\n </div>\n `\n : ''}\n ${this.value\n ? html`\n <div class=\"preview-container\">\n <div class=\"preview-title middle-align\">\n <md-icon>preview</md-icon>\n <ox-i18n msgid=\"label.formula-preview\"></ox-i18n>\n </div>\n <div class=\"preview-formula\">${this.value}</div>\n </div>\n `\n : ''}\n </div>\n `\n }\n\n updated(changes: any) {\n if (changes.has('value')) {\n this._validateFormula()\n }\n }\n\n _onChange(e: Event) {\n if (this._changingNow) {\n return\n }\n\n this._changingNow = true\n this._updateValue()\n this._changingNow = false\n }\n\n _onFormulaInput(e: Event) {\n const textarea = e.target as HTMLTextAreaElement\n this.value = textarea.value\n this._validateFormula()\n this._updateValue()\n }\n\n _insertVariable(variableName: string) {\n const start = this.editor.selectionStart\n const end = this.editor.selectionEnd\n const currentValue = this.editor.value\n\n // 변수명을 [변수명] 형태로만 감싸서 삽입\n const insertText = `[${variableName}]`\n const newValue = currentValue.substring(0, start) + insertText + currentValue.substring(end)\n this.editor.value = newValue\n this.value = newValue\n\n // 커서 위치 조정\n const newCursorPos = start + insertText.length\n this.editor.setSelectionRange(newCursorPos, newCursorPos)\n this.editor.focus()\n\n this._validateFormula()\n this._updateValue()\n }\n\n _insertOperator(operator: string) {\n const start = this.editor.selectionStart\n const end = this.editor.selectionEnd\n const currentValue = this.editor.value\n\n // 연산자 앞뒤에 공백 추가\n const insertText = ` ${operator} `\n const newValue = currentValue.substring(0, start) + insertText + currentValue.substring(end)\n this.editor.value = newValue\n this.value = newValue\n\n // 커서 위치 조정\n const newCursorPos = start + insertText.length\n this.editor.setSelectionRange(newCursorPos, newCursorPos)\n this.editor.focus()\n\n this._validateFormula()\n this._updateValue()\n }\n\n _insertFunction(template: string) {\n const start = this.editor.selectionStart\n const end = this.editor.selectionEnd\n const currentValue = this.editor.value\n\n // 선택된 텍스트가 있으면 그것을 expression으로 사용\n const selectedText = currentValue.substring(start, end)\n const insertText = template.replace('{expression}', selectedText || 'expression')\n\n const newValue = currentValue.substring(0, start) + insertText + currentValue.substring(end)\n this.editor.value = newValue\n this.value = newValue\n\n // 커서 위치 조정 (expression 부분에 포커스)\n const expressionStart = start + insertText.indexOf('expression')\n const expressionEnd = expressionStart + 'expression'.length\n this.editor.setSelectionRange(expressionStart, expressionEnd)\n this.editor.focus()\n\n this._validateFormula()\n this._updateValue()\n }\n\n _showVariableHelp(e: Event, variable: FormulaVariable) {\n e.stopPropagation()\n\n // 간단한 테스트 버전\n const message = `\n변수: ${variable.name}\n설명: ${variable.description || '없음'}\n타입: ${variable.type || '없음'}\n단위: ${variable.unit || '없음'}\n예시: ${variable.example || '없음'}\n `.trim()\n\n console.log('Variable help:', message)\n\n // dialog 지원 여부 확인\n if (typeof HTMLDialogElement !== 'undefined') {\n const dialog = document.createElement('dialog')\n dialog.className = 'help-dialog'\n\n // HTML 문자열로 직접 작성\n dialog.innerHTML = `\n <div class=\"help-popup\">\n <div class=\"help-title\">${variable.name}</div>\n \n ${\n variable.description\n ? `\n <div class=\"help-section\">\n <div class=\"help-section-title\">설명</div>\n <div class=\"help-content\">${variable.description}</div>\n </div>\n `\n : ''\n }\n \n ${\n variable.type\n ? `\n <div class=\"help-section\">\n <div class=\"help-section-title\">타입</div>\n <div class=\"help-content\">${variable.type}</div>\n </div>\n `\n : ''\n }\n \n ${\n variable.unit\n ? `\n <div class=\"help-section\">\n <div class=\"help-section-title\">단위</div>\n <div class=\"help-content\">${variable.unit}</div>\n </div>\n `\n : ''\n }\n \n ${\n variable.help\n ? `\n <div class=\"help-section\">\n <div class=\"help-section-title\">상세 설명</div>\n <div class=\"help-content\">${variable.help}</div>\n </div>\n `\n : ''\n }\n \n ${\n variable.example\n ? `\n <div class=\"help-section\">\n <div class=\"help-section-title\">사용 예시</div>\n <div class=\"help-example\">${variable.example}</div>\n </div>\n `\n : ''\n }\n </div>\n \n <div class=\"dialog-actions\">\n <button class=\"close-btn\" onclick=\"this.closest('dialog').close()\">닫기</button>\n </div>\n `\n\n document.body.appendChild(dialog)\n dialog.showModal()\n\n // 외부 클릭으로 닫기\n dialog.addEventListener('click', event => {\n const rect = dialog.getBoundingClientRect()\n const isInDialog =\n event.clientX >= rect.left &&\n event.clientX <= rect.right &&\n event.clientY >= rect.top &&\n event.clientY <= rect.bottom\n\n if (!isInDialog) {\n dialog.close()\n }\n })\n\n dialog.addEventListener('close', () => {\n if (document.body.contains(dialog)) {\n document.body.removeChild(dialog)\n }\n })\n\n // ESC 키로 닫기\n const handleEsc = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n dialog.close()\n document.removeEventListener('keydown', handleEsc)\n }\n }\n document.addEventListener('keydown', handleEsc)\n } else {\n // dialog를 지원하지 않는 브라우저에서는 alert 사용\n alert(message)\n }\n }\n\n _showFunctionHelp(e: Event, func: FormulaFunction) {\n e.stopPropagation()\n\n const dialog = document.createElement('dialog')\n dialog.className = 'help-dialog'\n\n // HTML 문자열로 직접 작성\n dialog.innerHTML = `\n <div class=\"help-popup\">\n <div class=\"help-title\">${func.name}</div>\n\n <div class=\"help-section\">\n <div class=\"help-section-title\">설명</div>\n <div class=\"help-content\">${func.description}</div>\n </div>\n\n <div class=\"help-section\">\n <div class=\"help-section-title\">구문</div>\n <div class=\"help-syntax\">${func.syntax}</div>\n </div>\n\n <div class=\"help-section\">\n <div class=\"help-section-title\">매개변수</div>\n <div class=\"help-parameters\">\n ${func.parameters\n .map(\n param => `\n <div class=\"help-parameter\">\n <span class=\"help-parameter-desc\">${param}</span>\n </div>\n `\n )\n .join('')}\n </div>\n </div>\n\n <div class=\"help-section\">\n <div class=\"help-section-title\">반환 타입</div>\n <div class=\"help-content\">${func.returnType}</div>\n </div>\n\n ${\n func.help\n ? `\n <div class=\"help-section\">\n <div class=\"help-section-title\">상세 설명</div>\n <div class=\"help-content\">${func.help}</div>\n </div>\n `\n : ''\n }\n \n ${\n func.examples && func.examples.length > 0\n ? `\n <div class=\"help-section\">\n <div class=\"help-section-title\">사용 예시</div>\n ${func.examples\n .map(\n example => `\n <div class=\"help-example\">${example}</div>\n `\n )\n .join('')}\n </div>\n `\n : ''\n }\n </div>\n \n <div class=\"dialog-actions\">\n <button class=\"close-btn\" onclick=\"this.closest('dialog').close()\">닫기</button>\n </div>\n `\n\n document.body.appendChild(dialog)\n dialog.showModal()\n\n // 외부 클릭으로 닫기\n dialog.addEventListener('click', event => {\n const rect = dialog.getBoundingClientRect()\n const isInDialog =\n event.clientX >= rect.left &&\n event.clientX <= rect.right &&\n event.clientY >= rect.top &&\n event.clientY <= rect.bottom\n\n if (!isInDialog) {\n dialog.close()\n }\n })\n\n dialog.addEventListener('close', () => {\n if (document.body.contains(dialog)) {\n document.body.removeChild(dialog)\n }\n })\n\n // ESC 키로 닫기\n const handleEsc = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n dialog.close()\n document.removeEventListener('keydown', handleEsc)\n }\n }\n document.addEventListener('keydown', handleEsc)\n }\n\n _validateFormula() {\n // 기본적인 수식 유효성 검사\n const formula = this.value.trim()\n\n if (!formula) {\n this.errorMessage = ''\n this.isValid = true\n return\n }\n\n // 괄호 균형 검사\n const openBrackets = (formula.match(/\\(/g) || []).length\n const closeBrackets = (formula.match(/\\)/g) || []).length\n\n if (openBrackets !== closeBrackets) {\n this.errorMessage = '괄호가 균형을 이루지 않습니다.'\n this.isValid = false\n return\n }\n\n // 변수 참조 검증 ([변수명] 형태)\n const variableRefs = formula.match(/\\[([^\\]]+)\\]/g) || []\n for (const ref of variableRefs) {\n const varName = ref.slice(1, -1) // [변수명]에서 변수명 추출\n const availableVarNames = this.availableVariables.map(v => v.name)\n if (!availableVarNames.includes(varName)) {\n this.errorMessage = `알 수 없는 변수: ${varName}`\n this.isValid = false\n return\n }\n }\n\n // 기본 문법 검사\n const invalidPatterns = [\n /[+\\-*/]{2,}/, // 연속된 연산자\n /[+\\-*/]\\s*$/, // 끝에 연산자\n /^\\s*[+\\-*/]/, // 시작에 연산자\n /\\(\\s*\\)/ // 빈 괄호\n ]\n\n for (const pattern of invalidPatterns) {\n if (pattern.test(formula)) {\n this.errorMessage = '수식 문법이 올바르지 않습니다.'\n this.isValid = false\n return\n }\n }\n\n this.errorMessage = ''\n this.isValid = true\n }\n\n _updateValue() {\n this.dispatchEvent(\n new CustomEvent('change', {\n bubbles: true,\n composed: true,\n detail: this.value\n })\n )\n }\n}\n"]}