@operato/input 10.10.0 → 10.10.5

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,23 @@
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
+ ### [10.10.5](https://github.com/hatiolab/operato/compare/v10.10.4...v10.10.5) (2026-09-10)
7
+
8
+ **Note:** Version bump only for package @operato/input
9
+
10
+
11
+
12
+
13
+
14
+ ### [10.10.1](https://github.com/hatiolab/operato/compare/v10.10.0...v10.10.1) (2026-09-06)
15
+
16
+
17
+ ### :memo: Documentation
18
+
19
+ * **data-grist, input, attachment:** rewrite today's comments and test names in English ([09983c0](https://github.com/hatiolab/operato/commit/09983c01bd7d47962180e7d5557a20bc5901b174))
20
+
21
+
22
+
6
23
  ## [10.10.0](https://github.com/hatiolab/operato/compare/v10.9.0...v10.10.0) (2026-09-06)
7
24
 
8
25
 
@@ -2,13 +2,13 @@
2
2
  * @license Copyright © HatioLab Inc. All rights reserved.
3
3
  */
4
4
  /**
5
- * 그림 고르는 칸을 맡는다 — 부르는 쪽의 tag 이름을 준다.
5
+ * Claim the image-picking field with a tag name.
6
6
  *
7
- * `@operato/attachment/ox-attachment-selector.js` 를 읽어 들이면 그 module 이 스스로 부른다.
8
- * 앱이 자기 것을 쓰고 싶으면 같은 방식으로 덮어쓸 수 있다.
7
+ * `@operato/attachment/ox-attachment-selector.js` calls this when it loads. An app can override it
8
+ * the same way.
9
9
  */
10
10
  export declare function registerImageSelector(tag: string): void;
11
- /** 지금 등록된 tag 이름. 아무도 등록하지 않았으면 빈 문자열이다. */
11
+ /** The registered tag name, or '' when nothing has claimed the slot. */
12
12
  export declare function imageSelectorTag(): string;
13
- /** 등록이 바뀌면 알려 준다. 돌려받는 함수를 부르면 그만 듣는다. */
13
+ /** Notifies on registration change. Call the returned function to stop listening. */
14
14
  export declare function onImageSelectorChange(listener: () => void): () => void;
@@ -2,58 +2,51 @@
2
2
  * @license Copyright © HatioLab Inc. All rights reserved.
3
3
  */
4
4
  /**
5
- * 그림을 고르는 칸 — **누가 그리는지는 위 layer 가 정한다.**
5
+ * The image-picking field: a slot this package declares, filled in from above.
6
6
  *
7
- * ── 왜 이런 것이 필요한가 (2026-09-06) ────────────────────────────────────
8
- * `ox-input-background-pattern` 은 그림을 하나 고르게 해야 한다. 전에는 그 자리에
9
- * `@operato/attachment` 의 selector 를 직접 import 해서 썼다. 그런데 `@operato/attachment` 는
10
- * 이 package 보다 **위**에 있다.
7
+ * `ox-input-background-pattern` needs to pick an image. It used to import the selector from
8
+ * `@operato/attachment` directly, but that package sits above this one:
11
9
  *
12
10
  * input ──▶ attachment ──▶ data-grist ──▶ input
13
11
  *
14
- * 고리가 생겼다. 그리고 이 고리는 눈에 안 보이는 불편이 아니라 **package 가 아예 빌드되지 않는**
15
- * 상태였다. tsc 가 자기 dist 의 .d.ts 를 다시 읽어 들여 TS5055 로 멈춘다(일곱 파일).
16
- * `@operato/attachment` 는 `input/package.json` 의 dependencies 에 적혀 있지도 않았다.
12
+ * That cycle did not merely offend layering — it stopped `@operato/input` from building at all.
13
+ * tsc pulled this package's own `dist/src/*.d.ts` back into the program and failed with TS5055 on
14
+ * seven files, and `noEmitOnError` meant nothing was written. `@operato/attachment` was not even
15
+ * listed in this package's dependencies.
17
16
  *
18
- * ── 어느 쪽 화살표가 잘못인가 ─────────────────────────────────────────────
19
- * 셋 중 둘은 맞다. attachment 가 목록을 표로 보이니 data-grist 를 쓰고, data-grist 가 filter 와
20
- * editor 에 입력칸을 쓰니 input 을 쓴다. **input 이 attachment 를 부르는 것 하나가 거꾸로다** —
21
- * 가장 아래의 부품이 위의 기능을 안다.
17
+ * Two of the three arrows are right: attachment shows a list as a grid so it uses data-grist, and
18
+ * data-grist puts inputs in filters and editors so it uses input. Only `input ──▶ attachment` runs
19
+ * the wrong way — the bottom layer reaching for a feature above it.
22
20
  *
23
- * ── 그래서 화살표를 뒤집는다 ──────────────────────────────────────────────
24
- * input 은 그림 고르는 칸의 **자리만** 둔다. 그 자리를 채우는 것은 그림을 실제로 가진 쪽
25
- * (@operato/attachment)이 스스로 등록한다. 그러면 화살표가 attachment ─▶ input 하나로 정리되고,
26
- * 그것은 이미 선언되어 있는 방향이다.
21
+ * So the arrow is reversed. `input` declares the slot; whoever actually owns images registers into
22
+ * it. The only remaining edge is `attachment ──▶ input`, which is already declared.
27
23
  *
28
- * ── 등록이 없으면 무엇이 나오나 ───────────────────────────────────────────
29
- * 빈 칸이 아니라 **글자 칸**이다. attachment 의 selector 도 속을 열어 보면 글자 칸 + 찾아보기
30
- * 단추이고, 값은 그냥 문자열(URL 또는 첨부 참조)이다. 그래서 등록이 없을 때도 주소를 직접 적거나
31
- * 붙여 넣는 것은 그대로 된다 — 없어지는 것은 찾아보기 단추 하나다.
32
- *
33
- * 등록하지 않은 앱에서 아무것도 없는 칸이 나오는 것(등록 안 된 custom element 는 소리 없이 빈
34
- * 상자로 그려진다)이 가장 나쁜 결말이라, 그것만은 피한다.
24
+ * With nothing registered the field is a text box, not an empty gap. The attachment selector is
25
+ * itself a text box plus a browse icon, and its value is a plain string (URL or attachment ref), so
26
+ * typing or pasting an address keeps working; only the browse button is missing. An unregistered
27
+ * custom element renders as a silent empty box, which is the worst outcome available here.
35
28
  */
36
29
  let tagName = '';
37
30
  const listeners = new Set();
38
31
  /**
39
- * 그림 고르는 칸을 맡는다 — 부르는 쪽의 tag 이름을 준다.
32
+ * Claim the image-picking field with a tag name.
40
33
  *
41
- * `@operato/attachment/ox-attachment-selector.js` 를 읽어 들이면 그 module 이 스스로 부른다.
42
- * 앱이 자기 것을 쓰고 싶으면 같은 방식으로 덮어쓸 수 있다.
34
+ * `@operato/attachment/ox-attachment-selector.js` calls this when it loads. An app can override it
35
+ * the same way.
43
36
  */
44
37
  export function registerImageSelector(tag) {
45
38
  if (tagName === tag) {
46
39
  return;
47
40
  }
48
41
  tagName = tag;
49
- /* 이미 그려진 것들이 새 칸으로 바뀌어야 한다 — 등록이 늦게 와도 자리가 비어 있지 않게. */
42
+ /* Fields already on screen have to swap — registration can arrive after they rendered. */
50
43
  listeners.forEach(listener => listener());
51
44
  }
52
- /** 지금 등록된 tag 이름. 아무도 등록하지 않았으면 빈 문자열이다. */
45
+ /** The registered tag name, or '' when nothing has claimed the slot. */
53
46
  export function imageSelectorTag() {
54
47
  return tagName;
55
48
  }
56
- /** 등록이 바뀌면 알려 준다. 돌려받는 함수를 부르면 그만 듣는다. */
49
+ /** Notifies on registration change. Call the returned function to stop listening. */
57
50
  export function onImageSelectorChange(listener) {
58
51
  listeners.add(listener);
59
52
  return () => listeners.delete(listener);
@@ -1 +1 @@
1
- {"version":3,"file":"image-selector.js","sourceRoot":"","sources":["../../src/image-selector.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,IAAI,OAAO,GAAG,EAAE,CAAA;AAEhB,MAAM,SAAS,GAAG,IAAI,GAAG,EAAc,CAAA;AAEvC;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,IAAI,OAAO,KAAK,GAAG,EAAE,CAAC;QACpB,OAAM;IACR,CAAC;IAED,OAAO,GAAG,GAAG,CAAA;IAEb,wDAAwD;IACxD,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAA;AAC3C,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,gBAAgB;IAC9B,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,0CAA0C;AAC1C,MAAM,UAAU,qBAAqB,CAAC,QAAoB;IACxD,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAEvB,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;AACzC,CAAC","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\n/**\n * 그림을 고르는 칸 — **누가 그리는지는 위 layer 가 정한다.**\n *\n * ── 왜 이런 것이 필요한가 (2026-09-06) ────────────────────────────────────\n * `ox-input-background-pattern` 은 그림을 하나 고르게 해야 한다. 전에는 그 자리에\n * `@operato/attachment` 의 selector 를 직접 import 해서 썼다. 그런데 `@operato/attachment` 는\n * 이 package 보다 **위**에 있다.\n *\n * input ──▶ attachment ──▶ data-grist ──▶ input\n *\n * 고리가 생겼다. 그리고 이 고리는 눈에 안 보이는 불편이 아니라 **package 가 아예 빌드되지 않는**\n * 상태였다. tsc 가 자기 dist 의 .d.ts 를 다시 읽어 들여 TS5055 로 멈춘다(일곱 파일).\n * `@operato/attachment` 는 `input/package.json` 의 dependencies 에 적혀 있지도 않았다.\n *\n * ── 어느 쪽 화살표가 잘못인가 ─────────────────────────────────────────────\n * 셋 중 둘은 맞다. attachment 가 목록을 표로 보이니 data-grist 를 쓰고, data-grist 가 filter 와\n * editor 에 입력칸을 쓰니 input 을 쓴다. **input 이 attachment 를 부르는 것 하나가 거꾸로다** —\n * 가장 아래의 부품이 위의 기능을 안다.\n *\n * ── 그래서 화살표를 뒤집는다 ──────────────────────────────────────────────\n * input 은 그림 고르는 칸의 **자리만** 둔다. 그 자리를 채우는 것은 그림을 실제로 가진 쪽\n * (@operato/attachment)이 스스로 등록한다. 그러면 화살표가 attachment ─▶ input 하나로 정리되고,\n * 그것은 이미 선언되어 있는 방향이다.\n *\n * ── 등록이 없으면 무엇이 나오나 ───────────────────────────────────────────\n * 빈 칸이 아니라 **글자 칸**이다. attachment 의 selector 도 속을 열어 보면 글자 칸 + 찾아보기\n * 단추이고, 값은 그냥 문자열(URL 또는 첨부 참조)이다. 그래서 등록이 없을 때도 주소를 직접 적거나\n * 붙여 넣는 것은 그대로 된다 — 없어지는 것은 찾아보기 단추 하나다.\n *\n * 등록하지 않은 앱에서 아무것도 없는 칸이 나오는 것(등록 안 된 custom element 는 소리 없이 빈\n * 상자로 그려진다)이 가장 나쁜 결말이라, 그것만은 피한다.\n */\n\nlet tagName = ''\n\nconst listeners = new Set<() => void>()\n\n/**\n * 그림 고르는 칸을 맡는다 — 부르는 쪽의 tag 이름을 준다.\n *\n * `@operato/attachment/ox-attachment-selector.js` 를 읽어 들이면 그 module 이 스스로 부른다.\n * 앱이 자기 것을 쓰고 싶으면 같은 방식으로 덮어쓸 수 있다.\n */\nexport function registerImageSelector(tag: string) {\n if (tagName === tag) {\n return\n }\n\n tagName = tag\n\n /* 이미 그려진 것들이 새 칸으로 바뀌어야 한다 — 등록이 늦게 와도 자리가 비어 있지 않게. */\n listeners.forEach(listener => listener())\n}\n\n/** 지금 등록된 tag 이름. 아무도 등록하지 않았으면 빈 문자열이다. */\nexport function imageSelectorTag(): string {\n return tagName\n}\n\n/** 등록이 바뀌면 알려 준다. 돌려받는 함수를 부르면 그만 듣는다. */\nexport function onImageSelectorChange(listener: () => void): () => void {\n listeners.add(listener)\n\n return () => listeners.delete(listener)\n}\n"]}
1
+ {"version":3,"file":"image-selector.js","sourceRoot":"","sources":["../../src/image-selector.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,IAAI,OAAO,GAAG,EAAE,CAAA;AAEhB,MAAM,SAAS,GAAG,IAAI,GAAG,EAAc,CAAA;AAEvC;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,IAAI,OAAO,KAAK,GAAG,EAAE,CAAC;QACpB,OAAM;IACR,CAAC;IAED,OAAO,GAAG,GAAG,CAAA;IAEb,0FAA0F;IAC1F,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAA;AAC3C,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,gBAAgB;IAC9B,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,qBAAqB,CAAC,QAAoB;IACxD,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAEvB,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;AACzC,CAAC","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\n/**\n * The image-picking field: a slot this package declares, filled in from above.\n *\n * `ox-input-background-pattern` needs to pick an image. It used to import the selector from\n * `@operato/attachment` directly, but that package sits above this one:\n *\n * input ──▶ attachment ──▶ data-grist ──▶ input\n *\n * That cycle did not merely offend layering — it stopped `@operato/input` from building at all.\n * tsc pulled this package's own `dist/src/*.d.ts` back into the program and failed with TS5055 on\n * seven files, and `noEmitOnError` meant nothing was written. `@operato/attachment` was not even\n * listed in this package's dependencies.\n *\n * Two of the three arrows are right: attachment shows a list as a grid so it uses data-grist, and\n * data-grist puts inputs in filters and editors so it uses input. Only `input ──▶ attachment` runs\n * the wrong way — the bottom layer reaching for a feature above it.\n *\n * So the arrow is reversed. `input` declares the slot; whoever actually owns images registers into\n * it. The only remaining edge is `attachment ──▶ input`, which is already declared.\n *\n * With nothing registered the field is a text box, not an empty gap. The attachment selector is\n * itself a text box plus a browse icon, and its value is a plain string (URL or attachment ref), so\n * typing or pasting an address keeps working; only the browse button is missing. An unregistered\n * custom element renders as a silent empty box, which is the worst outcome available here.\n */\n\nlet tagName = ''\n\nconst listeners = new Set<() => void>()\n\n/**\n * Claim the image-picking field with a tag name.\n *\n * `@operato/attachment/ox-attachment-selector.js` calls this when it loads. An app can override it\n * the same way.\n */\nexport function registerImageSelector(tag: string) {\n if (tagName === tag) {\n return\n }\n\n tagName = tag\n\n /* Fields already on screen have to swap — registration can arrive after they rendered. */\n listeners.forEach(listener => listener())\n}\n\n/** The registered tag name, or '' when nothing has claimed the slot. */\nexport function imageSelectorTag(): string {\n return tagName\n}\n\n/** Notifies on registration change. Call the returned function to stop listening. */\nexport function onImageSelectorChange(listener: () => void): () => void {\n listeners.add(listener)\n\n return () => listeners.delete(listener)\n}\n"]}
@@ -31,14 +31,14 @@ export declare class OxInputBackgroundPattern extends OxFormField {
31
31
  value?: BackgroundPatternOption;
32
32
  render(): import("lit-html").TemplateResult;
33
33
  /**
34
- * 그림 고르는 칸.
34
+ * The image-picking field.
35
35
  *
36
- * 그림을 가진 package 가 자기 칸을 등록해 두었으면 그것을 쓴다(image-selector.ts 의 머리말 참조).
37
- * 등록이 없으면 글자 칸으로 둔다 — 주소를 적거나 붙여 넣는 것은 그대로 되고, 없는 것은 찾아보기
38
- * 단추 하나다.
36
+ * If a package that owns images has registered its own field, that is used — see the header of
37
+ * image-selector.ts. Otherwise a text box: typing or pasting an address still works, and the only
38
+ * thing missing is the browse button.
39
39
  *
40
- * 두 갈래 모두 `value-key="image"` 를 달고 `change` 를 올린다. 아래 _onChange 가 그 규칙 하나로
41
- * 모든 칸을 받으므로, 어느 쪽이 그려지든 값이 담기는 길은 같다.
40
+ * Both branches carry `value-key="image"` and raise `change`. _onChange below handles every field
41
+ * by that one rule, so the value takes the same path out either way.
42
42
  */
43
43
  private renderImageField;
44
44
  private unsubscribeImageSelector?;
@@ -82,14 +82,14 @@ let OxInputBackgroundPattern = class OxInputBackgroundPattern extends OxFormFiel
82
82
  `;
83
83
  }
84
84
  /**
85
- * 그림 고르는 칸.
85
+ * The image-picking field.
86
86
  *
87
- * 그림을 가진 package 가 자기 칸을 등록해 두었으면 그것을 쓴다(image-selector.ts 의 머리말 참조).
88
- * 등록이 없으면 글자 칸으로 둔다 — 주소를 적거나 붙여 넣는 것은 그대로 되고, 없는 것은 찾아보기
89
- * 단추 하나다.
87
+ * If a package that owns images has registered its own field, that is used — see the header of
88
+ * image-selector.ts. Otherwise a text box: typing or pasting an address still works, and the only
89
+ * thing missing is the browse button.
90
90
  *
91
- * 두 갈래 모두 `value-key="image"` 를 달고 `change` 를 올린다. 아래 _onChange 가 그 규칙 하나로
92
- * 모든 칸을 받으므로, 어느 쪽이 그려지든 값이 담기는 길은 같다.
91
+ * Both branches carry `value-key="image"` and raise `change`. _onChange below handles every field
92
+ * by that one rule, so the value takes the same path out either way.
93
93
  */
94
94
  renderImageField(value) {
95
95
  const tag = imageSelectorTag();
@@ -116,7 +116,7 @@ let OxInputBackgroundPattern = class OxInputBackgroundPattern extends OxFormFiel
116
116
  }
117
117
  connectedCallback() {
118
118
  super.connectedCallback();
119
- /* 등록이 이 요소보다 늦게 올 수 있다 — 그때 칸이 글자 칸으로 남아 있지 않게 한다. */
119
+ /* Registration can arrive after this element renders; re-render so the field swaps. */
120
120
  this.unsubscribeImageSelector = onImageSelectorChange(() => this.requestUpdate());
121
121
  }
122
122
  disconnectedCallback() {
@@ -1 +1 @@
1
- {"version":3,"file":"ox-input-background-pattern.js","sourceRoot":"","sources":["../../src/ox-input-background-pattern.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 '@operato/i18n/ox-i18n.js'\nimport './ox-input-color.js'\n\nimport { css } from 'lit'\nimport { html, unsafeStatic } from 'lit/static-html.js'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { PropertyGridStyles } from '@operato/styles/property-grid-styles.js'\n\nimport { OxFormField } from './ox-form-field.js'\nimport { imageSelectorTag, onImageSelectorChange } from './image-selector.js'\n\nexport type BackgroundPatternOption = {\n image?: HTMLImageElement | string\n color?: string\n align?: 'left-top' | 'top' | 'right-top' | 'left' | 'center' | 'right' | 'left-bottom' | 'bottom' | 'right-bottom'\n offsetX?: number\n offsetY?: number\n width?: number\n height?: number\n fitPattern?: boolean\n noRepeat?: boolean\n guideOnly?: boolean\n}\n\n/**\n * 컴포넌트의 fill pattern을 편집하는 element\n *\n * Example:\n * <ox-input-background-pattern\n * @change=\"${e => { this.pattern = e.target.value }}\"\n * .value=${this.pattern}\"\n * ></ox-input-background-pattern>\n */\n\n@customElement('ox-input-background-pattern')\nexport class OxInputBackgroundPattern extends OxFormField {\n static styles = [\n PropertyGridStyles,\n css`\n :host {\n display: flex;\n }\n `\n ]\n\n @property({ type: Object }) value?: BackgroundPatternOption = undefined\n\n render() {\n const value = this.value || ({} as BackgroundPatternOption)\n\n return html`\n <div class=\"property-grid\">\n <label> <ox-i18n msgid=\"label.image\">image</ox-i18n> </label>\n\n ${this.renderImageField(value)}\n\n <label> <ox-i18n msgid=\"label.align\">align</ox-i18n> </label>\n\n <select value-key=\"align\" .value=${value.align || 'left-top'}>\n <option value=\"left-top\">Left Top</option>\n <option value=\"top\">Center Top</option>\n <option value=\"right-top\">Right Top</option>\n <option value=\"left\">Left Center</option>\n <option value=\"center\">Center Center</option>\n <option value=\"right\">Right Center</option>\n <option value=\"left-bottom\">Left Bottom</option>\n <option value=\"bottom\">Center Bottom</option>\n <option value=\"right-bottom\">Right Bottom</option>\n </select>\n\n <label> <ox-i18n msgid=\"label.offset-x\">offsetX</ox-i18n> </label>\n <input type=\"number\" value-key=\"offsetX\" .value=${String(value.offsetX || 0)} />\n\n <label> <ox-i18n msgid=\"label.offset-y\">offsetY</ox-i18n> </label>\n <input type=\"number\" value-key=\"offsetY\" .value=${String(value.offsetY || 0)} />\n\n <label> <ox-i18n msgid=\"label.width\">width</ox-i18n> </label>\n <input type=\"number\" value-key=\"width\" .value=${String(value.width || 0)} />\n\n <label> <ox-i18n msgid=\"label.height\">height</ox-i18n> </label>\n <input type=\"number\" value-key=\"height\" .value=${String(value.height || 0)} />\n\n <label><md-icon>format_color_fill</md-icon></label>\n <ox-input-color class=\"custom-editor\" value-key=\"color\" .value=${value.color}> </ox-input-color>\n\n <input id=\"fitPattern\" value-key=\"fitPattern\" type=\"checkbox\" ?checked=${value.fitPattern} required />\n <label for=\"fitPattern\"> <ox-i18n msgid=\"label.fit\">fit</ox-i18n> </label>\n\n <input id=\"noRepeat\" value-key=\"noRepeat\" type=\"checkbox\" ?checked=${value.noRepeat} required />\n <label for=\"noRepeat\"> <ox-i18n msgid=\"label.no-repeat\">no repeat</ox-i18n> </label>\n\n <input id=\"guideOnly\" value-key=\"guideOnly\" type=\"checkbox\" ?checked=${value.guideOnly} required />\n <label for=\"guideOnly\"> <ox-i18n msgid=\"label.guide-only\">guide only</ox-i18n> </label>\n </div>\n `\n }\n\n /**\n * 그림 고르는 칸.\n *\n * 그림을 가진 package 가 자기 칸을 등록해 두었으면 그것을 쓴다(image-selector.ts 의 머리말 참조).\n * 등록이 없으면 글자 칸으로 둔다 — 주소를 적거나 붙여 넣는 것은 그대로 되고, 없는 것은 찾아보기\n * 단추 하나다.\n *\n * 두 갈래 모두 `value-key=\"image\"` 를 달고 `change` 를 올린다. 아래 _onChange 가 그 규칙 하나로\n * 모든 칸을 받으므로, 어느 쪽이 그려지든 값이 담기는 길은 같다.\n */\n private renderImageField(value: BackgroundPatternOption) {\n const tag = imageSelectorTag()\n\n if (!tag) {\n return html`\n <input\n type=\"text\"\n value-key=\"image\"\n class=\"custom-editor\"\n .value=${String(value.image || '')}\n placeholder=\"https://\"\n />\n `\n }\n\n const selector = unsafeStatic(tag)\n\n return html`\n <${selector}\n value-key=\"image\"\n .value=${value.image || ''}\n .properties=${{ category: 'image' }}\n class=\"custom-editor\"\n ></${selector}>\n `\n }\n\n private unsubscribeImageSelector?: () => void\n\n connectedCallback() {\n super.connectedCallback()\n\n /* 등록이 이 요소보다 늦게 올 수 있다 — 그때 칸이 글자 칸으로 남아 있지 않게 한다. */\n this.unsubscribeImageSelector = onImageSelectorChange(() => this.requestUpdate())\n }\n\n disconnectedCallback() {\n this.unsubscribeImageSelector?.()\n this.unsubscribeImageSelector = undefined\n\n super.disconnectedCallback()\n }\n\n firstUpdated() {\n this.renderRoot.addEventListener('change', this._onChange.bind(this))\n }\n\n _onChange(e: Event) {\n var element = e.target as HTMLInputElement\n var key = element.getAttribute('value-key')\n var value: any = element.value\n\n if (key === 'fitPattern' || key === 'noRepeat' || key === 'guideOnly') {\n value = element.checked\n }\n\n this.value = {\n ...this.value,\n [key!]: value\n }\n\n this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }))\n }\n}\n"]}
1
+ {"version":3,"file":"ox-input-background-pattern.js","sourceRoot":"","sources":["../../src/ox-input-background-pattern.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 '@operato/i18n/ox-i18n.js'\nimport './ox-input-color.js'\n\nimport { css } from 'lit'\nimport { html, unsafeStatic } from 'lit/static-html.js'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { PropertyGridStyles } from '@operato/styles/property-grid-styles.js'\n\nimport { OxFormField } from './ox-form-field.js'\nimport { imageSelectorTag, onImageSelectorChange } from './image-selector.js'\n\nexport type BackgroundPatternOption = {\n image?: HTMLImageElement | string\n color?: string\n align?: 'left-top' | 'top' | 'right-top' | 'left' | 'center' | 'right' | 'left-bottom' | 'bottom' | 'right-bottom'\n offsetX?: number\n offsetY?: number\n width?: number\n height?: number\n fitPattern?: boolean\n noRepeat?: boolean\n guideOnly?: boolean\n}\n\n/**\n * 컴포넌트의 fill pattern을 편집하는 element\n *\n * Example:\n * <ox-input-background-pattern\n * @change=\"${e => { this.pattern = e.target.value }}\"\n * .value=${this.pattern}\"\n * ></ox-input-background-pattern>\n */\n\n@customElement('ox-input-background-pattern')\nexport class OxInputBackgroundPattern extends OxFormField {\n static styles = [\n PropertyGridStyles,\n css`\n :host {\n display: flex;\n }\n `\n ]\n\n @property({ type: Object }) value?: BackgroundPatternOption = undefined\n\n render() {\n const value = this.value || ({} as BackgroundPatternOption)\n\n return html`\n <div class=\"property-grid\">\n <label> <ox-i18n msgid=\"label.image\">image</ox-i18n> </label>\n\n ${this.renderImageField(value)}\n\n <label> <ox-i18n msgid=\"label.align\">align</ox-i18n> </label>\n\n <select value-key=\"align\" .value=${value.align || 'left-top'}>\n <option value=\"left-top\">Left Top</option>\n <option value=\"top\">Center Top</option>\n <option value=\"right-top\">Right Top</option>\n <option value=\"left\">Left Center</option>\n <option value=\"center\">Center Center</option>\n <option value=\"right\">Right Center</option>\n <option value=\"left-bottom\">Left Bottom</option>\n <option value=\"bottom\">Center Bottom</option>\n <option value=\"right-bottom\">Right Bottom</option>\n </select>\n\n <label> <ox-i18n msgid=\"label.offset-x\">offsetX</ox-i18n> </label>\n <input type=\"number\" value-key=\"offsetX\" .value=${String(value.offsetX || 0)} />\n\n <label> <ox-i18n msgid=\"label.offset-y\">offsetY</ox-i18n> </label>\n <input type=\"number\" value-key=\"offsetY\" .value=${String(value.offsetY || 0)} />\n\n <label> <ox-i18n msgid=\"label.width\">width</ox-i18n> </label>\n <input type=\"number\" value-key=\"width\" .value=${String(value.width || 0)} />\n\n <label> <ox-i18n msgid=\"label.height\">height</ox-i18n> </label>\n <input type=\"number\" value-key=\"height\" .value=${String(value.height || 0)} />\n\n <label><md-icon>format_color_fill</md-icon></label>\n <ox-input-color class=\"custom-editor\" value-key=\"color\" .value=${value.color}> </ox-input-color>\n\n <input id=\"fitPattern\" value-key=\"fitPattern\" type=\"checkbox\" ?checked=${value.fitPattern} required />\n <label for=\"fitPattern\"> <ox-i18n msgid=\"label.fit\">fit</ox-i18n> </label>\n\n <input id=\"noRepeat\" value-key=\"noRepeat\" type=\"checkbox\" ?checked=${value.noRepeat} required />\n <label for=\"noRepeat\"> <ox-i18n msgid=\"label.no-repeat\">no repeat</ox-i18n> </label>\n\n <input id=\"guideOnly\" value-key=\"guideOnly\" type=\"checkbox\" ?checked=${value.guideOnly} required />\n <label for=\"guideOnly\"> <ox-i18n msgid=\"label.guide-only\">guide only</ox-i18n> </label>\n </div>\n `\n }\n\n /**\n * The image-picking field.\n *\n * If a package that owns images has registered its own field, that is used — see the header of\n * image-selector.ts. Otherwise a text box: typing or pasting an address still works, and the only\n * thing missing is the browse button.\n *\n * Both branches carry `value-key=\"image\"` and raise `change`. _onChange below handles every field\n * by that one rule, so the value takes the same path out either way.\n */\n private renderImageField(value: BackgroundPatternOption) {\n const tag = imageSelectorTag()\n\n if (!tag) {\n return html`\n <input\n type=\"text\"\n value-key=\"image\"\n class=\"custom-editor\"\n .value=${String(value.image || '')}\n placeholder=\"https://\"\n />\n `\n }\n\n const selector = unsafeStatic(tag)\n\n return html`\n <${selector}\n value-key=\"image\"\n .value=${value.image || ''}\n .properties=${{ category: 'image' }}\n class=\"custom-editor\"\n ></${selector}>\n `\n }\n\n private unsubscribeImageSelector?: () => void\n\n connectedCallback() {\n super.connectedCallback()\n\n /* Registration can arrive after this element renders; re-render so the field swaps. */\n this.unsubscribeImageSelector = onImageSelectorChange(() => this.requestUpdate())\n }\n\n disconnectedCallback() {\n this.unsubscribeImageSelector?.()\n this.unsubscribeImageSelector = undefined\n\n super.disconnectedCallback()\n }\n\n firstUpdated() {\n this.renderRoot.addEventListener('change', this._onChange.bind(this))\n }\n\n _onChange(e: Event) {\n var element = e.target as HTMLInputElement\n var key = element.getAttribute('value-key')\n var value: any = element.value\n\n if (key === 'fitPattern' || key === 'noRepeat' || key === 'guideOnly') {\n value = element.checked\n }\n\n this.value = {\n ...this.value,\n [key!]: value\n }\n\n this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }))\n }\n}\n"]}
@@ -9,14 +9,14 @@ import '@operato/i18n/ox-i18n.js';
9
9
  import { css, html } from 'lit';
10
10
  import { customElement, property, query, state } from 'lit/decorators.js';
11
11
  /*
12
- * 이 파일은 @operato/input 안에 있다 — 자기 패키지를 이름으로 부르지 않는다.
12
+ * This file lives inside @operato/input, so it must not import the package by name.
13
13
  *
14
- * 전에는 '@operato/input' 에서 가져왔다. 그러면 package.json 의 exports 를 타고 **자기 dist** 로
15
- * 돌아 들어가서, 이미 만들어 둔 dist/src/*.d.ts 가 컴파일 대상에 섞인다. tsc 는 자기가 읽고 있는
16
- * 파일 위에 다시 쓸 수 없으므로 TS5055 로 멈추고, noEmitOnError 라 **패키지가 아예 빌드되지 않는다**
17
- * (ox-checkbox · ox-form-field · ox-input-search 등 일곱 개).
14
+ * It used to import from '@operato/input'. That follows package.json exports back into this
15
+ * package's own dist, pulling the already-built dist/src/*.d.ts into the compilation. tsc cannot
16
+ * write over a file it is reading, so it stops with TS5055 — and with noEmitOnError the package
17
+ * does not build at all (seven files: ox-checkbox, ox-form-field, ox-input-search and others).
18
18
  *
19
- * 같은 패키지 안에서는 상대 경로로 가져온다.
19
+ * Within the same package, import by relative path.
20
20
  */
21
21
  import { OxFormField } from './ox-form-field.js';
22
22
  import { InputStyles } from './input-styles.js';
@@ -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'\nimport './ox-input-formula-help-popup.js'\n\nimport '@operato/i18n/ox-i18n.js'\nimport { css, html } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\n/*\n * 이 파일은 @operato/input 안에 있다 — 자기 패키지를 이름으로 부르지 않는다.\n *\n * 전에는 '@operato/input' 에서 가져왔다. 그러면 package.json 의 exports 를 타고 **자기 dist** 로\n * 돌아 들어가서, 이미 만들어 둔 dist/src/*.d.ts 가 컴파일 대상에 섞인다. tsc 는 자기가 읽고 있는\n * 파일 위에 다시 쓸 수 없으므로 TS5055 로 멈추고, noEmitOnError 라 **패키지가 아예 빌드되지 않는다**\n * (ox-checkbox · ox-form-field · ox-input-search 등 일곱 개).\n *\n * 같은 패키지 안에서는 상대 경로로 가져온다.\n */\nimport { OxFormField } from './ox-form-field.js'\nimport { InputStyles } from './input-styles.js'\nimport { OxInputFormulaHelpPopup, HelpContent } from './ox-input-formula-help-popup.js'\nimport { ScrollbarStyles } from '@operato/styles'\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 InputStyles,\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n margin-bottom: calc(var(--ox-input-gap) * 3);\n gap: calc(var(--ox-input-gap) * 2);\n }\n\n .formula-container {\n display: flex;\n flex-direction: column;\n gap: var(--ox-input-gap);\n }\n\n .formula-input-container {\n display: flex;\n flex-direction: column;\n gap: var(--ox-input-gap);\n }\n\n .formula-textarea {\n min-height: var(--ox-formula-textarea-min-height, 120px);\n border: var(--ox-input-border);\n border-radius: var(--ox-input-radius);\n padding: var(--ox-input-padding);\n font-family: var(--ox-formula-font-family, 'Courier New', monospace);\n font-size: var(--ox-formula-textarea-font-size, 1.3rem);\n line-height: var(--ox-input-line-height);\n resize: vertical;\n background-color: var(--ox-formula-sunken-background, var(--md-sys-color-surface-container-low, #f8f9fa));\n }\n\n .formula-textarea:focus {\n outline: none;\n border-color: var(--md-sys-color-primary);\n background-color: var(--ox-input-background);\n }\n\n .variables-container {\n display: flex;\n flex-direction: column;\n gap: var(--ox-input-gap);\n }\n\n .variables-header {\n display: flex;\n align-items: center;\n gap: var(--ox-input-gap);\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(--ox-input-gap);\n max-height: var(--ox-formula-grid-max-height, 200px);\n overflow-y: auto;\n border: var(--ox-input-border);\n border-radius: var(--ox-input-radius);\n padding: var(--ox-input-gap);\n background-color: var(--ox-formula-sunken-background, var(--md-sys-color-surface-container-low, #f8f9fa));\n }\n\n .variable-item {\n display: flex;\n flex-direction: column;\n padding: var(--ox-input-gap);\n border: var(--ox-input-border);\n border-radius: var(--ox-input-radius);\n background-color: var(--ox-input-background);\n cursor: pointer;\n transition: var(--ox-input-transition);\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: var(--ox-input-shadow);\n }\n\n .variable-name {\n font-weight: 500;\n color: var(--md-sys-color-primary);\n font-size: var(--ox-formula-font-size-small, 0.75rem);\n font-family: var(--ox-formula-font-family, 'Courier New', monospace);\n }\n\n .variable-description {\n font-size: var(--ox-formula-font-size-tiny, 0.6875rem);\n color: var(--md-sys-color-on-surface-variant);\n margin-top: 2px;\n }\n\n .variable-type {\n font-size: var(--ox-formula-font-size-tiny, 0.6875rem);\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: var(--ox-input-font-size);\n color: var(--md-sys-color-outline);\n cursor: pointer;\n padding: var(--ox-formula-icon-padding, 2px);\n border-radius: var(--ox-input-radius);\n transition: var(--ox-input-transition);\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(--ox-input-gap);\n margin-top: var(--ox-input-gap);\n }\n\n .operator-button {\n padding: var(--ox-input-padding);\n border: var(--ox-input-border);\n border-radius: var(--ox-input-radius);\n background-color: var(--ox-input-background);\n cursor: pointer;\n font-family: var(--ox-formula-font-family, 'Courier New', monospace);\n font-size: var(--ox-formula-font-size-small, 0.75rem);\n transition: var(--ox-input-transition);\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(--ox-input-gap);\n margin-top: var(--ox-input-gap);\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(--ox-input-gap);\n }\n\n .function-button {\n padding: var(--ox-input-gap);\n border: var(--ox-input-border);\n border-radius: var(--ox-input-radius);\n background-color: var(--ox-input-background);\n cursor: pointer;\n font-family: var(--ox-formula-font-family, 'Courier New', monospace);\n font-size: var(--ox-formula-font-size-tiny, 0.6875rem);\n text-align: left;\n transition: var(--ox-input-transition);\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: calc(var(--ox-input-gap) * 2);\n padding: var(--ox-input-padding);\n background-color: var(--ox-formula-sunken-background, var(--md-sys-color-surface-container-low, #f8f9fa));\n border-radius: var(--ox-input-radius);\n border: var(--ox-input-border);\n }\n\n .preview-title {\n font-weight: 500;\n margin-bottom: var(--ox-input-gap);\n color: var(--md-sys-color-on-surface);\n }\n\n .preview-formula {\n font-family: var(--ox-formula-font-family, 'Courier New', monospace);\n background-color: var(--ox-input-background);\n padding: var(--ox-input-gap);\n border-radius: var(--ox-input-radius);\n border: var(--ox-input-border);\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: var(--ox-formula-font-size-small, 0.75rem);\n margin-top: var(--ox-input-gap);\n }\n\n .info-message {\n color: var(--md-sys-color-on-surface-variant);\n font-size: var(--ox-formula-font-size-small, 0.75rem);\n margin-top: var(--ox-input-gap);\n }\n\n /* 도움말 팝업 스타일 */\n .help-popup {\n max-width: 500px;\n max-height: 400px;\n overflow-y: auto;\n background: var(--ox-input-background);\n border-radius: var(--ox-input-popup-radius);\n box-shadow: var(--ox-input-shadow);\n }\n\n .help-title {\n font-size: 20px;\n font-weight: 600;\n margin-bottom: 16px;\n color: var(--md-sys-color-primary);\n padding: 20px 20px 16px 20px;\n background: var(--ox-formula-sunken-background, var(--md-sys-color-surface-container-low, #f8f9fa));\n border-bottom: var(--ox-input-border);\n border-radius: var(--ox-input-popup-radius) var(--ox-input-popup-radius) 0 0;\n }\n\n .help-section {\n margin-bottom: 16px;\n padding: 0 20px;\n }\n\n .help-section-title {\n font-weight: 600;\n margin-bottom: 8px;\n color: var(--ox-input-color);\n font-size: var(--ox-input-font-size);\n border-bottom: var(--ox-input-border);\n padding-bottom: 4px;\n }\n\n .help-content {\n font-size: var(--ox-input-font-size);\n line-height: 1.6;\n color: var(--ox-input-placeholder-color);\n padding: 4px 0;\n }\n\n .help-syntax {\n background: var(--ox-formula-sunken-background, var(--md-sys-color-surface-container-low, #f8f9fa));\n border: var(--ox-input-border);\n border-radius: var(--ox-input-radius);\n padding: 12px;\n font-family: var(--ox-formula-font-family, 'Courier New', monospace);\n font-size: 13px;\n color: var(--ox-input-color);\n margin: 8px 0;\n }\n\n .help-example {\n background: var(--md-sys-color-secondary-container);\n border: 1px solid var(--md-sys-color-tertiary-container);\n border-radius: var(--ox-input-radius);\n padding: 12px;\n font-family: var(--ox-formula-font-family, 'Courier New', monospace);\n font-size: 13px;\n color: var(--md-sys-color-on-tertiary-container);\n margin: 8px 0;\n }\n\n .help-parameters {\n margin: 8px 0;\n }\n\n .help-parameter {\n background: var(--ox-formula-sunken-background, var(--md-sys-color-surface-container-low, #f8f9fa));\n border-left: 3px solid var(--md-sys-color-primary);\n border-radius: var(--ox-input-radius);\n padding: 8px 12px;\n margin-bottom: 4px;\n font-size: 13px;\n }\n\n .help-parameter-desc {\n color: var(--ox-input-placeholder-color);\n }\n\n /* Dialog specific styles */\n .help-dialog {\n border: none;\n border-radius: var(--ox-input-popup-radius);\n box-shadow: var(--ox-input-shadow);\n padding: 0;\n max-width: 500px;\n max-height: 80vh;\n overflow-y: auto;\n background-color: var(--ox-input-background);\n }\n\n .help-dialog::backdrop {\n background-color: var(--ox-input-scrim);\n }\n\n .dialog-actions {\n display: flex;\n justify-content: flex-end;\n padding: 16px 20px;\n border-top: var(--ox-input-border);\n background: var(--ox-formula-sunken-background, var(--md-sys-color-surface-container-low, #f8f9fa));\n border-radius: 0 0 8px 8px;\n }\n\n .close-btn {\n padding: 8px 16px;\n border: 1px solid var(--md-sys-color-primary);\n border-radius: var(--ox-input-radius);\n background-color: var(--md-sys-color-primary);\n color: var(--md-sys-color-on-primary);\n cursor: pointer;\n font-size: var(--ox-input-font-size);\n font-weight: 500;\n transition: var(--ox-input-transition);\n }\n\n .close-btn:hover {\n background-color: var(--ox-input-focus-color);\n border-color: var(--ox-input-focus-color);\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\n style=\"font-size: var(--ox-formula-font-size-tiny, 0.6875rem); color: var(--md-sys-color-on-surface-variant);\"\n >\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: var(--ox-formula-font-size-small, 0.75rem);\"\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 const sections: Array<{\n title: string\n content: string\n type?: 'text' | 'code' | 'parameter' | 'example'\n }> = []\n\n if (variable.description) {\n sections.push({\n title: '설명',\n content: variable.description,\n type: 'text'\n })\n }\n\n if (variable.type) {\n sections.push({\n title: '타입',\n content: variable.type,\n type: 'text'\n })\n }\n\n if (variable.unit) {\n sections.push({\n title: '단위',\n content: variable.unit,\n type: 'text'\n })\n }\n\n if (variable.help) {\n sections.push({\n title: '상세 설명',\n content: variable.help,\n type: 'text'\n })\n }\n\n if (variable.example) {\n sections.push({\n title: '사용 예시',\n content: variable.example,\n type: 'example'\n })\n }\n\n const helpContent: HelpContent = {\n title: variable.name,\n sections\n }\n\n this._showHelpPopup(helpContent)\n }\n\n _showFunctionHelp(e: Event, func: FormulaFunction) {\n e.stopPropagation()\n\n const sections: Array<{\n title: string\n content: string\n type?: 'text' | 'code' | 'parameter' | 'example'\n }> = [\n {\n title: '설명',\n content: func.description,\n type: 'text'\n },\n {\n title: '구문',\n content: func.syntax,\n type: 'code'\n },\n {\n title: '매개변수',\n content: func.parameters.join('\\n'),\n type: 'parameter'\n },\n {\n title: '반환 타입',\n content: func.returnType,\n type: 'text'\n }\n ]\n\n if (func.help) {\n sections.push({\n title: '상세 설명',\n content: func.help,\n type: 'text'\n })\n }\n\n if (func.examples && func.examples.length > 0) {\n sections.push({\n title: '사용 예시',\n content: func.examples.join('\\n'),\n type: 'example'\n })\n }\n\n const helpContent: HelpContent = {\n title: func.name,\n sections\n }\n\n this._showHelpPopup(helpContent)\n }\n\n private _showHelpPopup(content: HelpContent) {\n const dialog = document.createElement('dialog')\n dialog.style.cssText = `\n border: none;\n border-radius: var(--ox-input-popup-radius);\n box-shadow: var(--ox-input-shadow);\n padding: 0;\n max-width: 500px;\n max-height: 80vh;\n overflow-y: auto;\n background-color: var(--ox-input-background);\n `\n\n const helpPopup = document.createElement('ox-input-formula-help-popup') as OxInputFormulaHelpPopup\n helpPopup.content = content\n helpPopup.onClose = () => {\n dialog.close()\n }\n\n dialog.appendChild(helpPopup)\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'\nimport './ox-input-formula-help-popup.js'\n\nimport '@operato/i18n/ox-i18n.js'\nimport { css, html } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\n/*\n * This file lives inside @operato/input, so it must not import the package by name.\n *\n * It used to import from '@operato/input'. That follows package.json exports back into this\n * package's own dist, pulling the already-built dist/src/*.d.ts into the compilation. tsc cannot\n * write over a file it is reading, so it stops with TS5055 — and with noEmitOnError the package\n * does not build at all (seven files: ox-checkbox, ox-form-field, ox-input-search and others).\n *\n * Within the same package, import by relative path.\n */\nimport { OxFormField } from './ox-form-field.js'\nimport { InputStyles } from './input-styles.js'\nimport { OxInputFormulaHelpPopup, HelpContent } from './ox-input-formula-help-popup.js'\nimport { ScrollbarStyles } from '@operato/styles'\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 InputStyles,\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n margin-bottom: calc(var(--ox-input-gap) * 3);\n gap: calc(var(--ox-input-gap) * 2);\n }\n\n .formula-container {\n display: flex;\n flex-direction: column;\n gap: var(--ox-input-gap);\n }\n\n .formula-input-container {\n display: flex;\n flex-direction: column;\n gap: var(--ox-input-gap);\n }\n\n .formula-textarea {\n min-height: var(--ox-formula-textarea-min-height, 120px);\n border: var(--ox-input-border);\n border-radius: var(--ox-input-radius);\n padding: var(--ox-input-padding);\n font-family: var(--ox-formula-font-family, 'Courier New', monospace);\n font-size: var(--ox-formula-textarea-font-size, 1.3rem);\n line-height: var(--ox-input-line-height);\n resize: vertical;\n background-color: var(--ox-formula-sunken-background, var(--md-sys-color-surface-container-low, #f8f9fa));\n }\n\n .formula-textarea:focus {\n outline: none;\n border-color: var(--md-sys-color-primary);\n background-color: var(--ox-input-background);\n }\n\n .variables-container {\n display: flex;\n flex-direction: column;\n gap: var(--ox-input-gap);\n }\n\n .variables-header {\n display: flex;\n align-items: center;\n gap: var(--ox-input-gap);\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(--ox-input-gap);\n max-height: var(--ox-formula-grid-max-height, 200px);\n overflow-y: auto;\n border: var(--ox-input-border);\n border-radius: var(--ox-input-radius);\n padding: var(--ox-input-gap);\n background-color: var(--ox-formula-sunken-background, var(--md-sys-color-surface-container-low, #f8f9fa));\n }\n\n .variable-item {\n display: flex;\n flex-direction: column;\n padding: var(--ox-input-gap);\n border: var(--ox-input-border);\n border-radius: var(--ox-input-radius);\n background-color: var(--ox-input-background);\n cursor: pointer;\n transition: var(--ox-input-transition);\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: var(--ox-input-shadow);\n }\n\n .variable-name {\n font-weight: 500;\n color: var(--md-sys-color-primary);\n font-size: var(--ox-formula-font-size-small, 0.75rem);\n font-family: var(--ox-formula-font-family, 'Courier New', monospace);\n }\n\n .variable-description {\n font-size: var(--ox-formula-font-size-tiny, 0.6875rem);\n color: var(--md-sys-color-on-surface-variant);\n margin-top: 2px;\n }\n\n .variable-type {\n font-size: var(--ox-formula-font-size-tiny, 0.6875rem);\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: var(--ox-input-font-size);\n color: var(--md-sys-color-outline);\n cursor: pointer;\n padding: var(--ox-formula-icon-padding, 2px);\n border-radius: var(--ox-input-radius);\n transition: var(--ox-input-transition);\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(--ox-input-gap);\n margin-top: var(--ox-input-gap);\n }\n\n .operator-button {\n padding: var(--ox-input-padding);\n border: var(--ox-input-border);\n border-radius: var(--ox-input-radius);\n background-color: var(--ox-input-background);\n cursor: pointer;\n font-family: var(--ox-formula-font-family, 'Courier New', monospace);\n font-size: var(--ox-formula-font-size-small, 0.75rem);\n transition: var(--ox-input-transition);\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(--ox-input-gap);\n margin-top: var(--ox-input-gap);\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(--ox-input-gap);\n }\n\n .function-button {\n padding: var(--ox-input-gap);\n border: var(--ox-input-border);\n border-radius: var(--ox-input-radius);\n background-color: var(--ox-input-background);\n cursor: pointer;\n font-family: var(--ox-formula-font-family, 'Courier New', monospace);\n font-size: var(--ox-formula-font-size-tiny, 0.6875rem);\n text-align: left;\n transition: var(--ox-input-transition);\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: calc(var(--ox-input-gap) * 2);\n padding: var(--ox-input-padding);\n background-color: var(--ox-formula-sunken-background, var(--md-sys-color-surface-container-low, #f8f9fa));\n border-radius: var(--ox-input-radius);\n border: var(--ox-input-border);\n }\n\n .preview-title {\n font-weight: 500;\n margin-bottom: var(--ox-input-gap);\n color: var(--md-sys-color-on-surface);\n }\n\n .preview-formula {\n font-family: var(--ox-formula-font-family, 'Courier New', monospace);\n background-color: var(--ox-input-background);\n padding: var(--ox-input-gap);\n border-radius: var(--ox-input-radius);\n border: var(--ox-input-border);\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: var(--ox-formula-font-size-small, 0.75rem);\n margin-top: var(--ox-input-gap);\n }\n\n .info-message {\n color: var(--md-sys-color-on-surface-variant);\n font-size: var(--ox-formula-font-size-small, 0.75rem);\n margin-top: var(--ox-input-gap);\n }\n\n /* 도움말 팝업 스타일 */\n .help-popup {\n max-width: 500px;\n max-height: 400px;\n overflow-y: auto;\n background: var(--ox-input-background);\n border-radius: var(--ox-input-popup-radius);\n box-shadow: var(--ox-input-shadow);\n }\n\n .help-title {\n font-size: 20px;\n font-weight: 600;\n margin-bottom: 16px;\n color: var(--md-sys-color-primary);\n padding: 20px 20px 16px 20px;\n background: var(--ox-formula-sunken-background, var(--md-sys-color-surface-container-low, #f8f9fa));\n border-bottom: var(--ox-input-border);\n border-radius: var(--ox-input-popup-radius) var(--ox-input-popup-radius) 0 0;\n }\n\n .help-section {\n margin-bottom: 16px;\n padding: 0 20px;\n }\n\n .help-section-title {\n font-weight: 600;\n margin-bottom: 8px;\n color: var(--ox-input-color);\n font-size: var(--ox-input-font-size);\n border-bottom: var(--ox-input-border);\n padding-bottom: 4px;\n }\n\n .help-content {\n font-size: var(--ox-input-font-size);\n line-height: 1.6;\n color: var(--ox-input-placeholder-color);\n padding: 4px 0;\n }\n\n .help-syntax {\n background: var(--ox-formula-sunken-background, var(--md-sys-color-surface-container-low, #f8f9fa));\n border: var(--ox-input-border);\n border-radius: var(--ox-input-radius);\n padding: 12px;\n font-family: var(--ox-formula-font-family, 'Courier New', monospace);\n font-size: 13px;\n color: var(--ox-input-color);\n margin: 8px 0;\n }\n\n .help-example {\n background: var(--md-sys-color-secondary-container);\n border: 1px solid var(--md-sys-color-tertiary-container);\n border-radius: var(--ox-input-radius);\n padding: 12px;\n font-family: var(--ox-formula-font-family, 'Courier New', monospace);\n font-size: 13px;\n color: var(--md-sys-color-on-tertiary-container);\n margin: 8px 0;\n }\n\n .help-parameters {\n margin: 8px 0;\n }\n\n .help-parameter {\n background: var(--ox-formula-sunken-background, var(--md-sys-color-surface-container-low, #f8f9fa));\n border-left: 3px solid var(--md-sys-color-primary);\n border-radius: var(--ox-input-radius);\n padding: 8px 12px;\n margin-bottom: 4px;\n font-size: 13px;\n }\n\n .help-parameter-desc {\n color: var(--ox-input-placeholder-color);\n }\n\n /* Dialog specific styles */\n .help-dialog {\n border: none;\n border-radius: var(--ox-input-popup-radius);\n box-shadow: var(--ox-input-shadow);\n padding: 0;\n max-width: 500px;\n max-height: 80vh;\n overflow-y: auto;\n background-color: var(--ox-input-background);\n }\n\n .help-dialog::backdrop {\n background-color: var(--ox-input-scrim);\n }\n\n .dialog-actions {\n display: flex;\n justify-content: flex-end;\n padding: 16px 20px;\n border-top: var(--ox-input-border);\n background: var(--ox-formula-sunken-background, var(--md-sys-color-surface-container-low, #f8f9fa));\n border-radius: 0 0 8px 8px;\n }\n\n .close-btn {\n padding: 8px 16px;\n border: 1px solid var(--md-sys-color-primary);\n border-radius: var(--ox-input-radius);\n background-color: var(--md-sys-color-primary);\n color: var(--md-sys-color-on-primary);\n cursor: pointer;\n font-size: var(--ox-input-font-size);\n font-weight: 500;\n transition: var(--ox-input-transition);\n }\n\n .close-btn:hover {\n background-color: var(--ox-input-focus-color);\n border-color: var(--ox-input-focus-color);\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\n style=\"font-size: var(--ox-formula-font-size-tiny, 0.6875rem); color: var(--md-sys-color-on-surface-variant);\"\n >\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: var(--ox-formula-font-size-small, 0.75rem);\"\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 const sections: Array<{\n title: string\n content: string\n type?: 'text' | 'code' | 'parameter' | 'example'\n }> = []\n\n if (variable.description) {\n sections.push({\n title: '설명',\n content: variable.description,\n type: 'text'\n })\n }\n\n if (variable.type) {\n sections.push({\n title: '타입',\n content: variable.type,\n type: 'text'\n })\n }\n\n if (variable.unit) {\n sections.push({\n title: '단위',\n content: variable.unit,\n type: 'text'\n })\n }\n\n if (variable.help) {\n sections.push({\n title: '상세 설명',\n content: variable.help,\n type: 'text'\n })\n }\n\n if (variable.example) {\n sections.push({\n title: '사용 예시',\n content: variable.example,\n type: 'example'\n })\n }\n\n const helpContent: HelpContent = {\n title: variable.name,\n sections\n }\n\n this._showHelpPopup(helpContent)\n }\n\n _showFunctionHelp(e: Event, func: FormulaFunction) {\n e.stopPropagation()\n\n const sections: Array<{\n title: string\n content: string\n type?: 'text' | 'code' | 'parameter' | 'example'\n }> = [\n {\n title: '설명',\n content: func.description,\n type: 'text'\n },\n {\n title: '구문',\n content: func.syntax,\n type: 'code'\n },\n {\n title: '매개변수',\n content: func.parameters.join('\\n'),\n type: 'parameter'\n },\n {\n title: '반환 타입',\n content: func.returnType,\n type: 'text'\n }\n ]\n\n if (func.help) {\n sections.push({\n title: '상세 설명',\n content: func.help,\n type: 'text'\n })\n }\n\n if (func.examples && func.examples.length > 0) {\n sections.push({\n title: '사용 예시',\n content: func.examples.join('\\n'),\n type: 'example'\n })\n }\n\n const helpContent: HelpContent = {\n title: func.name,\n sections\n }\n\n this._showHelpPopup(helpContent)\n }\n\n private _showHelpPopup(content: HelpContent) {\n const dialog = document.createElement('dialog')\n dialog.style.cssText = `\n border: none;\n border-radius: var(--ox-input-popup-radius);\n box-shadow: var(--ox-input-shadow);\n padding: 0;\n max-width: 500px;\n max-height: 80vh;\n overflow-y: auto;\n background-color: var(--ox-input-background);\n `\n\n const helpPopup = document.createElement('ox-input-formula-help-popup') as OxInputFormulaHelpPopup\n helpPopup.content = content\n helpPopup.onClose = () => {\n dialog.close()\n }\n\n dialog.appendChild(helpPopup)\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"]}
@@ -61,17 +61,17 @@ let OxInputSearch = class OxInputSearch extends OxFormField {
61
61
  render() {
62
62
  return html `
63
63
  <!--
64
- 돋보기 — 누르면 검색을 건다. 그런데 md-icon 은 포커스를 받지 않아서 키보드로는 닿지 않는다.
65
- 같은 일을 입력칸에서 Enter 로 할 수 있으므로 기능이 막힌 것은 아니다. 이름 없는 클릭 대상이
66
- 하나 더 읽히지 않도록 보조기술에서는 지운다 — 감춰도 잃는 동작이 없다.
64
+ The magnifier runs the search on click, but md-icon takes no focus, so the keyboard never
65
+ reaches it. Enter in the input does the same thing, so no function is blocked. Hiding it
66
+ from assistive tech removes one more unnamed click target and costs nothing.
67
67
  -->
68
68
  <md-icon aria-hidden="true" @click=${(e) => !this.disabled && this._onClickSearch(e)}>search</md-icon>
69
69
  <!--
70
- 입력칸에 이름을 붙인다. 전에는 placeholder 만 있었다 — placeholder 는 이름이 아니다.
71
- 글자를 치는 순간 사라지므로 「내가 지금 무엇을 적고 있었나」를 되물을 수 없고, 부르는 쪽이
72
- placeholder 를 안 넘기면 아무것도 남지 않는다(대부분의 화면이 안 넘긴다).
70
+ Name the input. It had only a placeholder, and a placeholder is not a name: it disappears
71
+ the moment you type, so there is no way to ask again what you were entering, and when the
72
+ caller passes none — which most screens do — nothing is left.
73
73
 
74
- 부르는 쪽이 정한 문구가 있으면 그것을 쓰고, 없으면 「검색어」로 물러난다.
74
+ Use whatever the caller set, and fall back to "search".
75
75
  -->
76
76
  <input
77
77
  type="text"