@operato/app 10.9.0 → 10.10.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ox-selector-resource-object-legacy.js","sourceRoot":"","sources":["../../../src/selector/ox-selector-resource-object-legacy.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@operato/data-grist'\nimport '@operato/form/ox-search-form.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\n\nimport {\n ColumnConfig,\n DataGrist,\n FetchHandler,\n FetchOption,\n GristData,\n GristEventHandler,\n GristRecord,\n InheritedValueType,\n ZERO_DATA\n} from '@operato/data-grist'\nimport { MultiColumnFormStyles, OxSearchForm } from '@operato/form'\nimport { client } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\nimport { closePopup } from '@operato/popup'\nimport { isMobileDevice } from '@operato/utils'\nimport { CommonHeaderStyles } from '@operato/styles'\n\n@customElement('ox-selector-resource-object-legacy')\nexport class OxSelectorResourceObjectLegacy extends LitElement {\n static styles = [\n CommonHeaderStyles,\n MultiColumnFormStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n\n background-color: var(--md-sys-color-surface);\n }\n\n ox-grist {\n flex: 1;\n }\n\n form {\n position: relative;\n }\n\n [search] {\n position: absolute;\n right: 0;\n }\n `\n ]\n\n @property({ type: String }) value?: string\n @property({ type: Object }) config: any\n @property({ type: Object }) data: GristData = ZERO_DATA\n @property({ type: String }) queryName!: string\n @property({ type: Object }) basicArgs: any\n @property({ type: String }) inherited?: InheritedValueType = InheritedValueType.Include\n @property({ type: Object }) confirmCallback?: (record?: GristRecord | null) => void\n @property({ type: Array }) selectedRecords: GristRecord[] = []\n\n @property({ type: Array }) searchFields: any\n @property({ type: Array }) select: {\n type: string\n name: string\n header: string\n subFields?: string[]\n hidden: boolean\n ignoreCondition: boolean\n queryName: string\n width: number\n }[] = []\n @property({ type: Object }) list: any\n @property({ type: String }) valueField: string | ((item: any) => any) = 'id'\n\n @query('ox-grist') grist!: DataGrist\n @query('ox-search-form') searchForm!: OxSearchForm\n\n render() {\n return html`\n <ox-search-form\n id=\"search-form\"\n @keypress=${(e: KeyboardEvent) => {\n if (e.key === 'Enter') {\n this.grist.fetch()\n }\n }}\n @submit=${(e: SubmitEvent) => this.grist.fetch()}\n .fields=${this.searchFields}\n autofocus\n ></ox-search-form>\n\n <!--\n .data 를 넘기지 않는다 — 목록은 fetchHandler 가 채운다.\n\n 그 값은 늘 ZERO_DATA(빈 것)였다. 이 부품에 data 를 주는 부르는 쪽이 없다. 그리스트는\n data 가 설정되면 reset() 하므로(data-grist 의 updated), 이 부품이 **다시 그려지는 순간\n 목록이 통째로 사라진다.**\n\n 오늘은 안 터진다 — 이 부품에 다시 그릴 상태가 없다. 그러나 새 부품(ox-selector-resource-object)\n 에 바닥 단추를 고른 상태에 묶자마자 바로 터졌다. 넘길 값이 없으면서 넘기고 있던 것이므로\n 여기서도 걷는다. 남겨 두면 다음 사람이 같은 곳에 빠진다.\n\n [재봤음] 2026-09-05 · 새 부품에서 라디오 클릭 → reset() 1회 → 20건 → 0건\n -->\n <ox-grist\n .mode=${isMobileDevice() ? 'LIST' : 'GRID'}\n .config=${this.config}\n .fetchHandler=${this.fetchHandler.bind(this)}\n .selectedRecords=${this.selectedRecords}\n >\n <div slot=\"headroom\" id=\"headroom\">\n <div id=\"filters\">\n <ox-filters-form></ox-filters-form>\n </div>\n </div>\n </ox-grist>\n\n <div class=\"footer\">\n <button @click=${this.onEmpty.bind(this)}>\n <md-icon>check_box_outline_blank</md-icon>${i18next.t('button.empty')}\n </button>\n <div filler></div>\n <button @click=${this.onCancel.bind(this)}><md-icon>cancel</md-icon>${i18next.t('button.cancel')}</button>\n <button @click=${this.onConfirm.bind(this)}><md-icon>done</md-icon>${i18next.t('button.confirm')}</button>\n </div>\n `\n }\n\n onEmpty() {\n this.confirmCallback && this.confirmCallback()\n closePopup(this)\n }\n\n onCancel() {\n closePopup(this)\n }\n\n onConfirm() {\n this.confirmCallback && this.confirmCallback(this.selected)\n closePopup(this)\n }\n\n fetchHandler: FetchHandler = async ({ filters, page, limit, sorters = [], inherited }) => {\n const response = await client.query({\n query: gql`\n query($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!], $inherited: InheritedValueType) {\n fetch: ${\n this.queryName\n } (filters: $filters, pagination: $pagination, sortings: $sortings, inherited: $inherited)\n {\n ${this.getSelectFields()}\n }\n }\n `,\n variables: await this._buildConditions({ filters, page, limit, sorters, inherited: inherited || this.inherited })\n })\n\n if (!response.errors) {\n const records = response.data.fetch.items.map((item: any) => {\n let rowValue\n\n if (this.valueField && typeof this.valueField === 'function') {\n rowValue = this.valueField(item)\n } else if (this.valueField) {\n rowValue = item[this.valueField]\n } else {\n rowValue = item.id\n }\n\n if (this.value && this.value === rowValue) {\n this.selectedRecords = [item]\n item['__selected__'] = true\n }\n\n return item\n })\n const total = response.data.fetch.total\n\n return {\n records,\n total,\n limit,\n page\n }\n }\n }\n\n async firstUpdated() {\n this.config = {\n columns: [\n {\n type: 'gutter',\n gutterName: 'sequence'\n },\n {\n type: 'gutter',\n gutterName: 'row-selector',\n multiple: false\n }\n ],\n rows: {\n selectable: {\n multiple: false\n },\n handlers: {\n click: 'select-row',\n dblclick: ((columns, data, column, record, rowIndex, field) => {\n this.onConfirm()\n }) as GristEventHandler\n },\n appendable: false\n }\n }\n\n if (this.select && this.select.length > 0) {\n let _searchFields = this.select.filter(selectField => !selectField.hidden && !selectField.ignoreCondition)\n if (this.list && this.list.fields && this.list.fields.length > 0) {\n _searchFields = _searchFields.filter(searchField => this.list.fields.indexOf(searchField.name) >= 0)\n } else {\n _searchFields = _searchFields.slice(0, 4)\n }\n\n this.searchFields = _searchFields.map(selectField => {\n const fieldType = (selectField.type && selectField.type.toLowerCase()) || 'string'\n const numberTypes = ['integer', 'float']\n return {\n label: selectField.header || i18next.t(`field.${selectField.name}`),\n name: selectField.name,\n type:\n fieldType === 'string'\n ? 'text'\n : numberTypes.indexOf(fieldType) >= 0\n ? 'number'\n : fieldType === 'boolean'\n ? 'checkbox'\n : fieldType,\n queryName: selectField.queryName,\n props:\n fieldType === 'string'\n ? { searchOper: 'i_like' }\n : fieldType === 'object'\n ? { searchOper: 'in' }\n : { searchOper: 'eq' },\n attrs: fieldType === 'boolean' ? ['indeterminated'] : []\n }\n })\n this.config = {\n ...this.config,\n columns: [\n ...this.config.columns,\n ...this.select.map(selectField => {\n return {\n ...selectField,\n type: selectField.type || 'string',\n width: selectField.width || 160,\n header: selectField.header || i18next.t(`field.${selectField.name}`)\n }\n })\n ]\n }\n } else {\n this.searchFields = [\n {\n label: i18next.t('field.name'),\n name: 'name',\n type: 'text',\n props: { searchOper: 'i_like' }\n },\n {\n label: i18next.t('field.description'),\n name: 'description',\n type: 'text',\n props: { searchOper: 'i_like' }\n }\n ]\n\n this.config = {\n ...this.config,\n columns: [\n ...this.config.columns,\n {\n type: 'string',\n name: 'id',\n header: i18next.t('field.id'),\n hidden: true\n },\n {\n type: 'string',\n name: 'name',\n header: i18next.t('field.name'),\n record: {\n align: 'left'\n },\n sortable: true,\n width: 160\n },\n {\n type: 'string',\n name: 'description',\n header: i18next.t('field.description'),\n record: {\n align: 'left'\n },\n sortable: true,\n width: 300\n }\n ]\n }\n }\n\n this.config = {\n ...this.config,\n list: {\n ...this.list,\n fields:\n this.list && this.list.fields && this.list.fields.length > 0\n ? this.list.fields\n : (this.config.columns as ColumnConfig[])\n .filter(column => column.type !== 'gutter')\n .slice(0, 3)\n .map(column => column.name)\n }\n }\n\n await this.updateComplete\n this.grist && this.grist.focus()\n }\n\n getSelectFields() {\n if (this.select && this.select.length > 0) {\n return `items {\n ${this.select.map(selectField => {\n return selectField.type === 'object'\n ? `${selectField.name} { ${\n selectField.subFields && selectField.subFields.length > 0\n ? selectField.subFields.join(' ')\n : `id name description`\n } }`\n : `${selectField.name}`\n })}\n }\n total`\n } else {\n return `\n items {\n id\n name\n description\n }\n total\n `\n }\n }\n\n async _buildConditions({ filters, page, limit, sorters, inherited }: FetchOption) {\n const queryConditions = {\n filters: [],\n ...this.basicArgs\n }\n\n queryConditions.filters = [...queryConditions.filters, ...(await this.searchForm.getQueryFilters())]\n queryConditions.pagination = { page, limit }\n queryConditions.sortings = sorters\n queryConditions.inherited = inherited\n\n return queryConditions\n }\n\n get selected() {\n var grist = this.renderRoot.querySelector('ox-grist') as DataGrist\n\n var selected = grist.selected\n\n return selected && selected.length > 0 ? selected[0] : undefined\n }\n}\n"]}
1
+ {"version":3,"file":"ox-selector-resource-object-legacy.js","sourceRoot":"","sources":["../../../src/selector/ox-selector-resource-object-legacy.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@operato/data-grist'\nimport '@operato/form/ox-search-form.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\n\nimport {\n ColumnConfig,\n DataGrist,\n FetchHandler,\n FetchOption,\n GristData,\n GristEventHandler,\n GristRecord,\n InheritedValueType,\n ZERO_DATA\n} from '@operato/data-grist'\nimport { MultiColumnFormStyles, OxSearchForm } from '@operato/form'\nimport { client } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\nimport { closePopup } from '@operato/popup'\nimport { isMobileDevice } from '@operato/utils'\nimport { CommonHeaderStyles } from '@operato/styles'\n\n@customElement('ox-selector-resource-object-legacy')\nexport class OxSelectorResourceObjectLegacy extends LitElement {\n static styles = [\n CommonHeaderStyles,\n MultiColumnFormStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n\n background-color: var(--md-sys-color-surface);\n }\n\n ox-grist {\n flex: 1;\n }\n\n form {\n position: relative;\n }\n\n [search] {\n position: absolute;\n right: 0;\n }\n `\n ]\n\n @property({ type: String }) value?: string\n @property({ type: Object }) config: any\n @property({ type: Object }) data: GristData = ZERO_DATA\n @property({ type: String }) queryName!: string\n @property({ type: Object }) basicArgs: any\n @property({ type: String }) inherited?: InheritedValueType = InheritedValueType.Include\n @property({ type: Object }) confirmCallback?: (record?: GristRecord | null) => void\n @property({ type: Array }) selectedRecords: GristRecord[] = []\n\n @property({ type: Array }) searchFields: any\n @property({ type: Array }) select: {\n type: string\n name: string\n header: string\n subFields?: string[]\n hidden: boolean\n ignoreCondition: boolean\n queryName: string\n width: number\n }[] = []\n @property({ type: Object }) list: any\n @property({ type: String }) valueField: string | ((item: any) => any) = 'id'\n\n @query('ox-grist') grist!: DataGrist\n @query('ox-search-form') searchForm!: OxSearchForm\n\n render() {\n return html`\n <ox-search-form\n id=\"search-form\"\n @keypress=${(e: KeyboardEvent) => {\n if (e.key === 'Enter') {\n this.grist.fetch()\n }\n }}\n @submit=${(e: SubmitEvent) => this.grist.fetch()}\n .fields=${this.searchFields}\n autofocus\n ></ox-search-form>\n\n <!--\n .data 를 넘기지 않는다 — 목록은 fetchHandler 가 채운다.\n\n 그 값은 늘 ZERO_DATA(빈 것)였다. 이 부품에 data 를 주는 부르는 쪽이 없다. 그리스트는\n data 가 설정되면 reset() 하므로(data-grist 의 updated), 이 부품이 **다시 그려지는 순간\n 목록이 통째로 사라진다.**\n\n 오늘은 안 터진다 — 이 부품에 다시 그릴 상태가 없다. 그러나 새 부품(ox-selector-resource-object)\n 에 바닥 단추를 고른 상태에 묶자마자 바로 터졌다. 넘길 값이 없으면서 넘기고 있던 것이므로\n 여기서도 걷는다. 남겨 두면 다음 사람이 같은 곳에 빠진다.\n\n [확인함] 2026-09-05 · 새 부품에서 라디오 클릭 → reset() 1회 → 20건 → 0건\n -->\n <ox-grist\n .mode=${isMobileDevice() ? 'LIST' : 'GRID'}\n .config=${this.config}\n .fetchHandler=${this.fetchHandler.bind(this)}\n .selectedRecords=${this.selectedRecords}\n >\n <div slot=\"headroom\" id=\"headroom\">\n <div id=\"filters\">\n <ox-filters-form></ox-filters-form>\n </div>\n </div>\n </ox-grist>\n\n <div class=\"footer\">\n <button @click=${this.onEmpty.bind(this)}>\n <md-icon>check_box_outline_blank</md-icon>${i18next.t('button.empty')}\n </button>\n <div filler></div>\n <button @click=${this.onCancel.bind(this)}><md-icon>cancel</md-icon>${i18next.t('button.cancel')}</button>\n <button @click=${this.onConfirm.bind(this)}><md-icon>done</md-icon>${i18next.t('button.confirm')}</button>\n </div>\n `\n }\n\n onEmpty() {\n this.confirmCallback && this.confirmCallback()\n closePopup(this)\n }\n\n onCancel() {\n closePopup(this)\n }\n\n onConfirm() {\n this.confirmCallback && this.confirmCallback(this.selected)\n closePopup(this)\n }\n\n fetchHandler: FetchHandler = async ({ filters, page, limit, sorters = [], inherited }) => {\n const response = await client.query({\n query: gql`\n query($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!], $inherited: InheritedValueType) {\n fetch: ${\n this.queryName\n } (filters: $filters, pagination: $pagination, sortings: $sortings, inherited: $inherited)\n {\n ${this.getSelectFields()}\n }\n }\n `,\n variables: await this._buildConditions({ filters, page, limit, sorters, inherited: inherited || this.inherited })\n })\n\n if (!response.errors) {\n const records = response.data.fetch.items.map((item: any) => {\n let rowValue\n\n if (this.valueField && typeof this.valueField === 'function') {\n rowValue = this.valueField(item)\n } else if (this.valueField) {\n rowValue = item[this.valueField]\n } else {\n rowValue = item.id\n }\n\n if (this.value && this.value === rowValue) {\n this.selectedRecords = [item]\n item['__selected__'] = true\n }\n\n return item\n })\n const total = response.data.fetch.total\n\n return {\n records,\n total,\n limit,\n page\n }\n }\n }\n\n async firstUpdated() {\n this.config = {\n columns: [\n {\n type: 'gutter',\n gutterName: 'sequence'\n },\n {\n type: 'gutter',\n gutterName: 'row-selector',\n multiple: false\n }\n ],\n rows: {\n selectable: {\n multiple: false\n },\n handlers: {\n click: 'select-row',\n dblclick: ((columns, data, column, record, rowIndex, field) => {\n this.onConfirm()\n }) as GristEventHandler\n },\n appendable: false\n }\n }\n\n if (this.select && this.select.length > 0) {\n let _searchFields = this.select.filter(selectField => !selectField.hidden && !selectField.ignoreCondition)\n if (this.list && this.list.fields && this.list.fields.length > 0) {\n _searchFields = _searchFields.filter(searchField => this.list.fields.indexOf(searchField.name) >= 0)\n } else {\n _searchFields = _searchFields.slice(0, 4)\n }\n\n this.searchFields = _searchFields.map(selectField => {\n const fieldType = (selectField.type && selectField.type.toLowerCase()) || 'string'\n const numberTypes = ['integer', 'float']\n return {\n label: selectField.header || i18next.t(`field.${selectField.name}`),\n name: selectField.name,\n type:\n fieldType === 'string'\n ? 'text'\n : numberTypes.indexOf(fieldType) >= 0\n ? 'number'\n : fieldType === 'boolean'\n ? 'checkbox'\n : fieldType,\n queryName: selectField.queryName,\n props:\n fieldType === 'string'\n ? { searchOper: 'i_like' }\n : fieldType === 'object'\n ? { searchOper: 'in' }\n : { searchOper: 'eq' },\n attrs: fieldType === 'boolean' ? ['indeterminated'] : []\n }\n })\n this.config = {\n ...this.config,\n columns: [\n ...this.config.columns,\n ...this.select.map(selectField => {\n return {\n ...selectField,\n type: selectField.type || 'string',\n width: selectField.width || 160,\n header: selectField.header || i18next.t(`field.${selectField.name}`)\n }\n })\n ]\n }\n } else {\n this.searchFields = [\n {\n label: i18next.t('field.name'),\n name: 'name',\n type: 'text',\n props: { searchOper: 'i_like' }\n },\n {\n label: i18next.t('field.description'),\n name: 'description',\n type: 'text',\n props: { searchOper: 'i_like' }\n }\n ]\n\n this.config = {\n ...this.config,\n columns: [\n ...this.config.columns,\n {\n type: 'string',\n name: 'id',\n header: i18next.t('field.id'),\n hidden: true\n },\n {\n type: 'string',\n name: 'name',\n header: i18next.t('field.name'),\n record: {\n align: 'left'\n },\n sortable: true,\n width: 160\n },\n {\n type: 'string',\n name: 'description',\n header: i18next.t('field.description'),\n record: {\n align: 'left'\n },\n sortable: true,\n width: 300\n }\n ]\n }\n }\n\n this.config = {\n ...this.config,\n list: {\n ...this.list,\n fields:\n this.list && this.list.fields && this.list.fields.length > 0\n ? this.list.fields\n : (this.config.columns as ColumnConfig[])\n .filter(column => column.type !== 'gutter')\n .slice(0, 3)\n .map(column => column.name)\n }\n }\n\n await this.updateComplete\n this.grist && this.grist.focus()\n }\n\n getSelectFields() {\n if (this.select && this.select.length > 0) {\n return `items {\n ${this.select.map(selectField => {\n return selectField.type === 'object'\n ? `${selectField.name} { ${\n selectField.subFields && selectField.subFields.length > 0\n ? selectField.subFields.join(' ')\n : `id name description`\n } }`\n : `${selectField.name}`\n })}\n }\n total`\n } else {\n return `\n items {\n id\n name\n description\n }\n total\n `\n }\n }\n\n async _buildConditions({ filters, page, limit, sorters, inherited }: FetchOption) {\n const queryConditions = {\n filters: [],\n ...this.basicArgs\n }\n\n queryConditions.filters = [...queryConditions.filters, ...(await this.searchForm.getQueryFilters())]\n queryConditions.pagination = { page, limit }\n queryConditions.sortings = sorters\n queryConditions.inherited = inherited\n\n return queryConditions\n }\n\n get selected() {\n var grist = this.renderRoot.querySelector('ox-grist') as DataGrist\n\n var selected = grist.selected\n\n return selected && selected.length > 0 ? selected[0] : undefined\n }\n}\n"]}
@@ -125,7 +125,7 @@ let OxSelectorResourceObject = class OxSelectorResourceObject extends LitElement
125
125
  단추를 고른 상태에 묶으면서(hasSelection) 비로소 다시 그려지게 되었고, 그때 줄을
126
126
  누르면 목록이 비었다.
127
127
 
128
- [재봤음] 2026-09-05 · 라디오 클릭 → reset() 1회(DataGrist.updated) → 20건 → 0건
128
+ [확인함] 2026-09-05 · 라디오 클릭 → reset() 1회(DataGrist.updated) → 20건 → 0건
129
129
 
130
130
  고른 상태를 되돌리는 것이 아니라 **이 바인딩을 걷는다.** 넘길 값이 없으면서 넘기고
131
131
  있던 것이고, 남겨 두면 다음 사람이 같은 곳에 빠진다.
@@ -237,7 +237,7 @@ let OxSelectorResourceObject = class OxSelectorResourceObject extends LitElement
237
237
  * 이것이 조용한 데이터 손실로 이어졌다. 고른 표시는 목록을 받아올 때 **그 쪽에서 값을 찾으면**
238
238
  * 켜지므로(아래 fetchHandler), 값이 2쪽에 있으면 1쪽만 받은 상태에서는 빈 채다.
239
239
  *
240
- * [재봤음] 2026-09-05 · 제조법 · 만드는 품목 · 총 106건
240
+ * [확인함] 2026-09-05 · 제조법 · 만드는 품목 · 총 106건
241
241
  * value=MT10097283 은 1쪽에 없다 → selectedRecords = []
242
242
  * 팝업을 열고 아무것도 만지지 않고 확인 → 칸이 빈 값이 되었다
243
243
  *
@@ -474,7 +474,7 @@ OxSelectorResourceObject.styles = [
474
474
  * 강조가 되지 않았다. 강조 잉크는 --ui-accent 이고, 그 색은 **작은 글자를 담을 수 있도록
475
475
  * 톤을 낮춰 둔** 것이다.
476
476
  *
477
- * [재봤음] 2026-09-05 · --ui-accent #0c7a4c · 팝업 면 #f0f2f4 · 대비 4.79
477
+ * [확인함] 2026-09-05 · --ui-accent #0c7a4c · 팝업 면 #f0f2f4 · 대비 4.79
478
478
  * 작은 글자 기준 4.5 를 넘는다
479
479
  *
480
480
  * accent 가 없는 앱에서는 primary 로 떨어진다.
@@ -1 +1 @@
1
- {"version":3,"file":"ox-selector-resource-object.js","sourceRoot":"","sources":["../../../src/selector/ox-selector-resource-object.ts"],"names":[],"mappings":";AAAA,OAAO,4BAA4B,CAAA;AACnC,OAAO,qBAAqB,CAAA;AAE5B,OAAO,GAAG,MAAM,aAAa,CAAA;AAC7B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAkB,MAAM,KAAK,CAAA;AAC3D,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAEzE,OAAO,EAML,SAAS,EACT,kBAAkB,EACnB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC9D,OAAO,EAAyB,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAGpE,IAAM,wBAAwB,GAA9B,MAAM,wBAAyB,SAAQ,UAAU;IAAjD;;QA8DL;;;;;;;;;;;;;;;;;WAiBG;QAC0B,aAAQ,GAAY,KAAK,CAAA;QAE1B,SAAI,GAAc,SAAS,CAAA;QAG3B,cAAS,GAAwB,kBAAkB,CAAC,OAAO,CAAA;QAE5D,oBAAe,GAAkB,EAAE,CAAA;QAGnC,YAAO,GAQ5B,EAAE,CAAA;QAMoB,eAAU,GAAkC,IAAI,CAAA;QAE5E,wCAAwC;QAChC,gBAAW,GAAG,KAAK,CAAA;QAE3B;;;;;;WAMG;QACc,iBAAY,GAAG,KAAK,CAAA;QAwJrC,iBAAY,GAAiB,KAAK,EAAE,EAAE,OAAO,GAAG,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,GAAG,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE;;YAC7F,IAAI,MAAA,IAAI,CAAC,SAAS,0CAAE,OAAO,EAAE,CAAC;gBAC5B,OAAO,GAAG,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;YAC1D,CAAC;YACD,mCAAmC;YACnC,IAAI,CAAA,MAAA,IAAI,CAAC,SAAS,0CAAE,OAAO,KAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACrD,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;YACxC,CAAC;YACD,MAAM,UAAU,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAA;YAElC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;gBAClC,KAAK,EAAE,GAAG,CAAA;;mBAGJ,IAAI,CAAC,SACP;cACI,IAAI,CAAC,cAAc,EAAE;;;OAG5B;gBACD,SAAS,EAAE;oBACT,OAAO;oBACP,UAAU;oBACV,QAAQ;oBACR,SAAS,EAAE,SAAS,IAAI,IAAI,CAAC,SAAS;iBACvC;gBACD,OAAO,EAAE,UAAU,EAAE;aACtB,CAAC,CAAA;YAEF,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;gBACrB,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAS,EAAE,EAAE;oBAC1D,IAAI,QAAQ,CAAA;oBAEZ,IAAI,IAAI,CAAC,UAAU,IAAI,OAAO,IAAI,CAAC,UAAU,KAAK,UAAU,EAAE,CAAC;wBAC7D,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;oBAClC,CAAC;yBAAM,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;wBAC3B,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;oBAClC,CAAC;yBAAM,CAAC;wBACN,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAA;oBACpB,CAAC;oBAED;;;;;uBAKG;oBACH,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;oBAEtF,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;wBAC/C,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;wBAC/E,IAAI,CAAC,cAAc,CAAC,GAAG,IAAI,CAAA;wBAC3B,yCAAyC;wBACzC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAA;oBAC1B,CAAC;oBAED,OAAO,IAAI,CAAA;gBACb,CAAC,CAAC,CAAA;gBACF,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAA;gBAEvC,OAAO;oBACL,OAAO;oBACP,KAAK;oBACL,KAAK;oBACL,IAAI;iBACL,CAAA;YACH,CAAC;QACH,CAAC,CAAA;IAsMH,CAAC;IA7ZC,MAAM;QACJ,OAAO,IAAI,CAAA;;;;;;;;;;;;;;;;;;;;gBAoBC,cAAc,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;kBAChC,IAAI,CAAC,MAAM;wBACL,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;2BACzB,IAAI,CAAC,eAAe;gCACf,GAAG,EAAE;;YAC3B,IAAI,CAAC,YAAY,GAAG,CAAC,CAAA,MAAA,IAAI,CAAC,KAAK,0CAAE,QAAQ,KAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAA;QAC7D,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yBAqCgB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC;;;;;;;;UAQzE,CAAC,IAAI,CAAC,YAAY;YAClB,CAAC,CAAC,IAAI,CAAA;iBACC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,6BAA6B,CAAC;cACvF;YACJ,CAAC,CAAC,EAAE;yBACW,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;;;;;;;;;;;;;;mBAc5D,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;sBACtB,CAAC,IAAI,CAAC,YAAY;kBACtB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC,CAAC,EAAE;;;YAGxE,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC;;;KAGlC,CAAA;IACH,CAAC;IAED,UAAU,CAAC,KAAa;QACtB,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,KAAK,CAAA;IAC/B,CAAC;IAED,YAAY;QACV,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,CAAA;IAC7B,CAAC;IAED,OAAO;QACL,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,eAAe,EAAE,CAAA;QAC9C,UAAU,CAAC,IAAI,CAAC,CAAA;IAClB,CAAC;IAED,QAAQ;QACN,UAAU,CAAC,IAAI,CAAC,CAAA;IAClB,CAAC;IAED,SAAS;QACP,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAA;QAE9B;;;;;;;;;;;;;;;;WAgBG;QACH,IAAI,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;YACpE,UAAU,CAAC,IAAI,CAAC,CAAA;YAChB,OAAM;QACR,CAAC;QAED,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAA;QACtD,UAAU,CAAC,IAAI,CAAC,CAAA;IAClB,CAAC;IAuED;;;;;;;;;;OAUG;IACH,UAAU,CAAC,OAA6B;QACtC,0CAA0C;QAC1C,kDAAkD;QAClD,IACE,IAAI,CAAC,WAAW;YAChB,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;YACvB,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;YACzB,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;YACpB,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EACxB,CAAC;YACD,OAAM;QACR,CAAC;QAED,IAAI,CAAC,WAAW,GAAG,IAAI,CAAA;QAEvB,MAAM,MAAM,GAAG;YACb,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE,UAAU;iBACvB;gBACD;oBACE,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE,cAAc;oBAC1B,QAAQ,EAAE,IAAI,CAAC,QAAQ;iBACxB;aACF;YACD,IAAI,EAAE;gBACJ,UAAU,EAAE;oBACV,QAAQ,EAAE,IAAI,CAAC,QAAQ;iBACxB;gBACD,QAAQ,EAAE;oBACR;;;uBAGG;oBACH,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,YAAY;oBACzD;;;uBAGG;oBACH,GAAG,CAAC,IAAI,CAAC,QAAQ;wBACf,CAAC,CAAC,EAAE;wBACJ,CAAC,CAAC;4BACE,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;gCAC5D,IAAI,CAAC,SAAS,EAAE,CAAA;4BAClB,CAAC,CAAsB;yBACxB,CAAC;iBACP;gBACD,UAAU,EAAE,KAAK;aAClB;YACD,UAAU,EAAE,IAAI,CAAC,UAAU;SAC5B,CAAA;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI;YAC9B;gBACE,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,IAAI;gBACV,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;gBAC7B,MAAM,EAAE,IAAI;aACb;YACD;gBACE,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,MAAM;gBACZ,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC;gBAC/B,MAAM,EAAE;oBACN,KAAK,EAAE,MAAM;iBACd;gBACD,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,QAAQ;gBAChB,KAAK,EAAE,GAAG;aACX;YACD;gBACE,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,aAAa;gBACnB,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC;gBACtC,MAAM,EAAE;oBACN,KAAK,EAAE,MAAM;iBACd;gBACD,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,QAAQ;gBAChB;;;;;;mBAMG;gBACH,KAAK,EAAE,oBAAoB;aAC5B;SACF,CAAA;QAED;;;;;;;;;WASG;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAA;QAE/B,IAAI,CAAC,MAAM,GAAG;YACZ,GAAG,MAAM;YACT,GAAG,KAAK;YACR,OAAO,EAAE;gBACP,GAAG,MAAM,CAAC,OAAO;gBACjB,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE;oBAC3B,OAAO;wBACL,GAAG,WAAW;wBACd,IAAI,EAAE,WAAW,CAAC,IAAI,IAAI,QAAQ;wBAClC,KAAK,EAAE,WAAW,CAAC,KAAK,IAAI,GAAG;wBAC/B,MAAM,EAAE,WAAW,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,SAAS,WAAW,CAAC,IAAI,EAAE,CAAC;qBACrE,CAAA;gBACH,CAAC,CAAC;aACH;SACF,CAAA;QAED;;;;;WAKG;QACH,qBAAqB,CAAC,GAAG,EAAE;;YACzB;;;eAGG;YACH,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAW,EAAE,EAAE;gBAC1D,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAA;gBAC5B,OAAO,MAAM,IAAI,MAAM,KAAK,QAAQ,IAAI,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,QAAQ,MAAK,QAAQ,CAAA;YACvE,CAAC,CAAC,CAAA;YAEF,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAA,IAAI,CAAC,KAAK,0CAAE,YAAY,EAAE,CAAA;YAC5B,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,cAAc;QACZ,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5C,OAAO;UACH,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE;gBAC/B,OAAO,WAAW,CAAC,IAAI,KAAK,QAAQ;oBAClC,CAAC,CAAC,GAAG,WAAW,CAAC,IAAI,MACjB,WAAW,CAAC,SAAS,IAAI,WAAW,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC;wBACvD,CAAC,CAAC,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;wBACjC,CAAC,CAAC,qBACN,IAAI;oBACN,CAAC,CAAC,GAAG,WAAW,CAAC,IAAI,EAAE,CAAA;YAC3B,CAAC,CAAC;;YAEE,CAAA;QACR,CAAC;aAAM,CAAC;YACN,OAAO;;;;;;;OAON,CAAA;QACH,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,IAAI,QAAQ;QACV,IAAI,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,UAAU,CAAc,CAAA;QAElE,IAAI,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAA;QAEnC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,OAAO,QAAQ,CAAA;QACjB,CAAC;QAED,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACtD,CAAC;;AAnhBM,+BAAM,GAAG;IACd,kBAAkB;IAClB,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAgDF;CACF,AAnDY,CAmDZ;AAQ2B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;uDAA0B;AAoBxB;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;0DAA0B;AAC1B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;wDAAY;AACX;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;sDAA4B;AAC3B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;2DAAmB;AAClB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;2DAAe;AACd;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;2DAA4D;AAC3D;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;iEAA0D;AAC1D;IAA1B,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;iEAAoC;AAEnC;IAA1B,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;8DAAkB;AACjB;IAA1B,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;yDAQlB;AACoB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;4DAG1B;AAC2B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;sDAAU;AACT;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;4DAAiD;AAY3D;IAAhB,KAAK,EAAE;8DAA6B;AAElB;IAAlB,KAAK,CAAC,UAAU,CAAC;uDAAkB;AAtHzB,wBAAwB;IADpC,aAAa,CAAC,6BAA6B,CAAC;GAChC,wBAAwB,CAqhBpC","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@operato/data-grist'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport {\n DataGrist,\n FetchHandler,\n GristData,\n GristEventHandler,\n GristRecord,\n ZERO_DATA,\n InheritedValueType\n} from '@operato/data-grist'\nimport { client, gqlContext } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\nimport { closePopup } from '@operato/popup'\nimport { adjustFilters, isMobileDevice } from '@operato/utils'\nimport { ButtonContainerStyles, CommonHeaderStyles } from '@operato/styles'\n\n@customElement('ox-selector-resource-object')\nexport class OxSelectorResourceObject extends LitElement {\n static styles = [\n CommonHeaderStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n\n background-color: var(--md-sys-color-surface);\n\n width: var(--overlay-center-normal-width, 50%);\n height: var(--overlay-center-normal-height, 50%);\n }\n\n ox-grist {\n flex: 1;\n }\n\n .header {\n grid-template-areas: 'filters actions';\n }\n\n [filler] {\n margin-left: auto;\n }\n\n /*\n * 꺼진 단추가 왜 꺼졌는지 말하는 한 줄. **단추 바로 앞에 선다** — 멀리 두면 그 단추의\n * 이야기로 읽히지 않는다.\n *\n * ── 색만 조금 세운다 ──────────────────────────────────────────────────\n * on-surface-variant 로 두었더니 너무 조용했다. 꺼진 단추 옆의 흐린 글자는 그 단추의\n * 일부처럼 보여서, 확인이 왜 꺼졌는지 찾는 눈에 걸리지 않았다.\n *\n * 크기와 배치는 그대로 두고 **잉크만** 바꾼다. 붉은색은 오류이고, 이것은 오류가 아니라\n * 남은 일이다.\n *\n * primary 를 먼저 써 봤는데 이 제품에서는 **흑연**이다(#262e38) — 틀 자체가 무채색이라\n * 강조가 되지 않았다. 강조 잉크는 --ui-accent 이고, 그 색은 **작은 글자를 담을 수 있도록\n * 톤을 낮춰 둔** 것이다.\n *\n * [재봤음] 2026-09-05 · --ui-accent #0c7a4c · 팝업 면 #f0f2f4 · 대비 4.79\n * 작은 글자 기준 4.5 를 넘는다\n *\n * accent 가 없는 앱에서는 primary 로 떨어진다.\n */\n [hint] {\n color: var(--ui-accent, var(--md-sys-color-primary));\n font-size: var(--md-sys-typescale-label-medium-size, 0.75rem);\n margin-right: var(--spacing-small, 4px);\n }\n `\n ]\n\n /**\n * 지금 들어 있는 값. **여럿 고르기에서는 배열이다.**\n *\n * 목록을 받아올 때 이 값과 같은 줄을 골라 둔다(fetchHandler). 그래서 팝업을 열면 지금 값이\n * 이미 고른 상태로 보인다.\n */\n @property({ type: Object }) value?: string | string[]\n\n /**\n * 여럿을 고를 수 있나. **부르는 쪽이 켠다.**\n *\n * ── 왜 필요한가 (2026-09-05) ────────────────────────────────────────────\n * 마스터 화면의 관계 칸 다섯이 여러 값을 든다 — 상위 등급(baseIds) · 요구 검사\n * (testSpecificationIds) · 공정의 차례(steps). 이 선택기가 하나만 내주어서 그 칸들이\n * **자유 텍스트로 남아 있었다.**\n *\n * 자유 텍스트는 조용히 틀린다. GUNSAN 을 GUNSAM 이라고 쳐도 저장되고, 그 뒤로 그 참조는\n * 어디에서도 안 걸린다 — 화면에는 값이 있는데.\n *\n * ── 켜면 무엇이 달라지나 ────────────────────────────────────────────────\n * 고르기 줄을 눌러 켜고 끈다(select-row-toggle). 겹쳐 고를 수 있다\n * 두 번 누르기 확정하지 않는다 — 한 줄만 넘기게 되므로\n * confirmCallback 고른 것들의 배열을 넘긴다\n *\n * 켠 쪽이 그 모양을 아니까 콜백을 둘로 나누지 않는다.\n */\n @property({ type: Boolean }) multiple: boolean = false\n @property({ type: Object }) config: any\n @property({ type: Object }) data: GristData = ZERO_DATA\n @property({ type: String }) queryName!: string\n @property({ type: Object }) basicArgs: any\n @property({ type: String }) inherited?: InheritedValueType = InheritedValueType.Include\n @property({ type: Object }) confirmCallback?: (record?: Partial<GristRecord>) => void\n @property({ type: Array }) selectedRecords: GristRecord[] = []\n\n @property({ type: Array }) searchFields: any\n @property({ type: Array }) columns: {\n type: string\n name: string\n header: string\n subFields?: string[]\n hidden: boolean\n queryName: string\n width: number\n }[] = []\n @property({ type: Object }) pagination?: {\n limit: number\n pages: number[]\n }\n @property({ type: Object }) list: any\n @property({ type: String }) valueField: string | ((item: any) => any) = 'id'\n\n /** 설정을 한 번 세웠나 — 열·질의가 바뀔 때만 다시 세운다. */\n private _configured = false\n\n /**\n * 지금 고른 것이 있나 — **바닥 단추가 이 값을 본다.**\n *\n * `selected` 게터는 그리스트를 그때그때 읽으므로 반응형이 아니다. 그래서 단추의 disabled 를\n * 그것으로 묶으면 골라도 다시 그려지지 않는다. 그리스트가 내는 select-record-change 를 듣고\n * 이 상태를 갱신한다.\n */\n @state() private hasSelection = false\n\n @query('ox-grist') grist!: DataGrist\n\n render() {\n return html`\n <!--\n ── .data 를 넘기지 않는다 ────────────────────────────────────────────────\n\n 목록은 아래 fetchHandler 가 채운다. 그런데 .data 로 this.data 를 함께 넘기고\n 있었고, 그 값은 늘 ZERO_DATA(빈 것)였다 — 이 부품에 data 를 주는 부르는 쪽이 없다.\n\n 그리스트는 data 가 설정되면 **reset() 한다**(data-grist 의 updated). 그래서 이 부품이\n 다시 그려지는 순간 빈 값이 다시 내려가 **목록이 통째로 사라진다.**\n\n 여태 안 드러난 이유는 이 부품이 첫 렌더 뒤로 다시 그려질 일이 없었기 때문이다. 바닥\n 단추를 고른 상태에 묶으면서(hasSelection) 비로소 다시 그려지게 되었고, 그때 줄을\n 누르면 목록이 비었다.\n\n [재봤음] 2026-09-05 · 라디오 클릭 → reset() 1회(DataGrist.updated) → 20건 → 0건\n\n 고른 상태를 되돌리는 것이 아니라 **이 바인딩을 걷는다.** 넘길 값이 없으면서 넘기고\n 있던 것이고, 남겨 두면 다음 사람이 같은 곳에 빠진다.\n -->\n <ox-grist\n .mode=${isMobileDevice() ? 'LIST' : 'GRID'}\n .config=${this.config}\n .fetchHandler=${this.fetchHandler.bind(this)}\n .selectedRecords=${this.selectedRecords}\n @select-record-change=${() => {\n this.hasSelection = (this.grist?.selected || []).length > 0\n }}\n >\n <div class=\"header\" slot=\"headroom\">\n <div class=\"filters\">\n <!--\n **검색은 이 영역이 그리지 않는다.**\n 찾기는 화면의 제목줄이 든다(페이지의 표준이 그렇다 — 제목 왼쪽, 찾기 오른쪽 끝).\n 여기서도 그리면 검색창이 둘이 된다. 실제로 한 번 그렇게 됐다.\n\n 이 영역은 **찾기가 아닌 필터**의 자리다. 그것이 하나도 없으면 아래 hideHeadroom 이\n 영역째 감춘다 — 열 것이 없는 문을 두지 않는다.\n -->\n <ox-filters-form autofocus without-search></ox-filters-form>\n </div>\n </div>\n </ox-grist>\n\n <!--\n 바닥 — **세 동작의 무게가 다르다.**\n\n 지정 안 함 이 칸에 아무것도 넣지 않는다. 왼쪽 끝에 따로 선다 — 확정과 나란히 두면 잘못 누른다\n 닫기 아무것도 하지 않고 나간다. 글자만\n 확인 이 팝업이 하러 온 일. 하나만 채운다\n\n 아이콘을 떼었다. 「비우기」에는 체크박스 글리프가 붙어 있었는데, 그것은 **입력칸의\n 글리프**여서 동작이 아니라 「끄고 켜는 것」으로 읽혔다. 닫기의 ⊗ 와 확인의 ✓ 도 걷는다 —\n 낱말이 이미 그 일을 말하고, 곁 단추에 아이콘이 붙으면 무게가 주 동작과 비슷해진다.\n -->\n <div class=\"footer\">\n <!--\n 「비우기」였다. **무엇을** 비우는지 말하지 않는다 — 팝업 안에 목록도 검색창도 있어서\n 「목록을 비우나」로도 읽힌다. 이 단추가 하는 일은 그 칸을 빈 값으로 두고 닫는 것이다.\n\n button.empty 를 그대로 쓰지 않는 이유: 그 문자열은 여러 개를 고르는 팝업들도 함께 쓴다\n (결재자 · 수신자 편집기). 거기서는 「고른 것 전부 지우기」이고, 그것은 「지정 안 함」과\n 다른 말이다. 한 문자열이 두 뜻을 겸하고 있었다.\n -->\n <button @click=${this.onEmpty.bind(this)} clear>${i18next.t('button.unset')}</button>\n\n <div filler></div>\n\n <!--\n 힌트는 **단추 두 개 앞**에 선다. 닫기와 확인은 한 쌍이라, 그 사이에 글자가 끼면\n 쌍이 갈라져 보인다.\n -->\n ${!this.hasSelection\n ? html`<span hint\n >${i18next.t(this.multiple ? 'text.pick-from-the-list' : 'text.pick-one-from-the-list')}</span\n >`\n : ''}\n <button @click=${this.onCancel.bind(this)}>${i18next.t('button.cancel')}</button>\n <!--\n ── 고른 것이 없으면 **확인을 끄고, 왜 껐는지 말한다** ─────────────────\n\n 꺼진 단추만 두면 막다른 길이다. 누른 사람은 「왜 안 되나」를 알 길이 없고, 특히 이\n 팝업은 목록이 여러 쪽이라 자기가 무엇을 안 했는지 스스로 떠올리기 어렵다.\n\n 그래서 한 줄을 함께 둔다. **고르면 사라진다** — 할 일이 남아 있는 동안만 보인다.\n\n ── 그 앞에는 더 나빴다 ────────────────────────────────────────────────\n 고른 것이 없을 때 확인이 **값을 지웠다**. 확인이 「지정 안 함」과 같은 일을 했다\n (onConfirm 주석 참조).\n -->\n <button\n @click=${this.onConfirm.bind(this)}\n ?disabled=${!this.hasSelection}\n title=${!this.hasSelection ? i18next.t('text.pick-one-from-the-list') : ''}\n done\n >\n ${i18next.t('button.confirm')}\n </button>\n </div>\n `\n }\n\n searchText(value: string) {\n this.grist.searchText = value\n }\n\n toggleFilter() {\n this.grist.toggleHeadroom()\n }\n\n onEmpty() {\n this.confirmCallback && this.confirmCallback()\n closePopup(this)\n }\n\n onCancel() {\n closePopup(this)\n }\n\n onConfirm() {\n const selected = this.selected\n\n /*\n * ── 고른 것이 없으면 **아무 일도 하지 않는다** ────────────────────────────\n *\n * 전에는 `confirmCallback(this.selected)` 를 그냥 불렀다. 고른 것이 없으면 `selected` 가\n * undefined 이고, 그것은 **아래 onEmpty 가 넘기는 것과 똑같다** — 즉 확인이 「지정 안 함」과\n * 같은 일을 했다. 값을 지우는 단추가 둘이었고, 그중 하나가 주 동작(채운 단추)이었다.\n *\n * 이것이 조용한 데이터 손실로 이어졌다. 고른 표시는 목록을 받아올 때 **그 쪽에서 값을 찾으면**\n * 켜지므로(아래 fetchHandler), 값이 2쪽에 있으면 1쪽만 받은 상태에서는 빈 채다.\n *\n * [재봤음] 2026-09-05 · 제조법 · 만드는 품목 · 총 106건\n * value=MT10097283 은 1쪽에 없다 → selectedRecords = []\n * 팝업을 열고 아무것도 만지지 않고 확인 → 칸이 빈 값이 되었다\n *\n * 확인의 뜻은 「이 고른 것으로 한다」다. 고른 것이 없으면 확인할 것이 없으므로 닫기와 같다.\n * **값을 지우는 길은 「지정 안 함」 하나다.**\n */\n if (!selected || (Array.isArray(selected) && selected.length === 0)) {\n closePopup(this)\n return\n }\n\n this.confirmCallback && this.confirmCallback(selected)\n closePopup(this)\n }\n\n fetchHandler: FetchHandler = async ({ filters = [], page, limit, sortings = [], inherited }) => {\n if (this.basicArgs?.filters) {\n filters = adjustFilters(filters, this.basicArgs.filters)\n }\n // basicArgs.sorters가 있으면 기본 정렬로 병합\n if (this.basicArgs?.sorters && sortings.length === 0) {\n sortings = [...this.basicArgs.sorters]\n }\n const pagination = { page, limit }\n\n const response = await client.query({\n query: gql`\n query($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!], $inherited: InheritedValueType) {\n fetch: ${\n this.queryName\n } (filters: $filters, pagination: $pagination, sortings: $sortings, inherited: $inherited) {\n ${this.getQueryFields()}\n }\n }\n `,\n variables: {\n filters,\n pagination,\n sortings,\n inherited: inherited || this.inherited\n },\n context: gqlContext()\n })\n\n if (!response.errors) {\n const records = response.data.fetch.items.map((item: any) => {\n let rowValue\n\n if (this.valueField && typeof this.valueField === 'function') {\n rowValue = this.valueField(item)\n } else if (this.valueField) {\n rowValue = item[this.valueField]\n } else {\n rowValue = item.id\n }\n\n /*\n * 지금 값과 같은 줄을 골라 둔다. 여럿 고르기에서는 값이 배열이므로 그 안에 있는지 본다.\n *\n * 값이 이 쪽에 없으면 골라지지 않는다 — 그것이 이 부품의 한계다. 부르는 쪽이 지금 값을\n * 글자로 함께 보여 주는 이유가 그것이다(ops-master 의 참조 팝업).\n */\n const wanted = Array.isArray(this.value) ? this.value : this.value ? [this.value] : []\n\n if (wanted.length && wanted.includes(rowValue)) {\n this.selectedRecords = this.multiple ? [...this.selectedRecords, item] : [item]\n item['__selected__'] = true\n /* 받아온 쪽에서 값을 찾았다 — 바닥 단추도 그것을 알아야 한다. */\n this.hasSelection = true\n }\n\n return item\n })\n const total = response.data.fetch.total\n\n return {\n records,\n total,\n limit,\n page\n }\n }\n }\n\n /**\n * 표의 설정을 **첫 렌더 전에** 세운다.\n *\n * ── 왜 firstUpdated 가 아닌가 ──────────────────────────────────────────────\n * 여기 있던 것을 `firstUpdated` 에서 만들고 있었다. 그러면 `<ox-grist>` 와 그 안의 필터 폼이\n * **먼저 붙고** 설정이 나중에 온다. 필터 폼은 붙는 순간의 설정을 한 번 읽어 두므로, 그 스냅숏이\n * 병합 전 것이었다 — 열 일곱 개 중 넷만 든 설정이라 필터가 하나도 없었고, 그래서 필터 영역이\n * 빈 채로 32px 만 서 있었다.\n *\n * `willUpdate` 는 렌더 전에 돈다. 폼이 붙을 때 이미 완성된 설정을 읽는다.\n */\n willUpdate(changed: PropertyValues<this>) {\n /* 열·질의가 바뀌면 다시 세운다. 그 밖의 변화에는 손대지 않는다. */\n /* multiple 이 바뀌면 거터와 고르기 규칙이 달라지므로 설정을 다시 세운다. */\n if (\n this._configured &&\n !changed.has('columns') &&\n !changed.has('queryName') &&\n !changed.has('list') &&\n !changed.has('multiple')\n ) {\n return\n }\n\n this._configured = true\n\n const config = {\n list: this.list,\n columns: [\n {\n type: 'gutter',\n gutterName: 'sequence'\n },\n {\n type: 'gutter',\n gutterName: 'row-selector',\n multiple: this.multiple\n }\n ],\n rows: {\n selectable: {\n multiple: this.multiple\n },\n handlers: {\n /*\n * 하나만 고를 때는 누르면 그 줄로 바뀐다. 여럿일 때는 눌러 켜고 끈다 — 앞의 것을\n * 풀면서 고르면 여러 개를 담을 수 없다.\n */\n click: this.multiple ? 'select-row-toggle' : 'select-row',\n /*\n * 두 번 눌러 확정하는 것은 하나만 고를 때다. 여럿일 때 그렇게 두면 **그 한 줄만**\n * 넘어가고 앞서 고른 것이 사라진다.\n */\n ...(this.multiple\n ? {}\n : {\n dblclick: ((columns, data, column, record, rowIndex, field) => {\n this.onConfirm()\n }) as GristEventHandler\n })\n },\n appendable: false\n },\n pagination: this.pagination\n }\n\n const columns = this.columns || [\n {\n type: 'string',\n name: 'id',\n header: i18next.t('field.id'),\n hidden: true\n },\n {\n type: 'string',\n name: 'name',\n header: i18next.t('field.name'),\n record: {\n align: 'left'\n },\n sortable: true,\n filter: 'search',\n width: 160\n },\n {\n type: 'string',\n name: 'description',\n header: i18next.t('field.description'),\n record: {\n align: 'left'\n },\n sortable: true,\n filter: 'search',\n /*\n * 남는 폭을 이 열이 채운다.\n *\n * 열 폭은 grid-template-columns 에 그대로 들어가므로 문자열도 된다(data-grist 의\n * setGridTemplateColumns). 고정 300px 이었을 때는 오른쪽에 200px 가까운 죽은 자리와\n * 세로선 하나가 남았다 — 목록이 상자 한쪽에 몰려 보인다.\n */\n width: 'minmax(240px, 1fr)'\n }\n ]\n\n /*\n * **밖에서 준 설정을 덮어쓰지 않는다.**\n *\n * 여기서 `this.config` 를 통째로 갈아 끼우고 있었다. 그래서 부르는 쪽이 `config` 를 주어도\n * 사라졌다 — 빈 목록에 무슨 말을 할지(`emptyNote`)를 밖에서 정할 길이 없었다.\n *\n * 빈 목록은 **두 가지 다른 사실**을 말해야 하는 자리다. 「이 표에 아직 아무것도 없다」와\n * 「검색에 걸린 것이 없다」는 다르고, 하나로 합치면 결함이 「고를 게 없다」로 보인다. 실제로\n * 그런 일이 있었다(배열 모양이 달라 목록이 비었는데 아무도 결함인 줄 몰랐다).\n */\n const given = this.config || {}\n\n this.config = {\n ...config,\n ...given,\n columns: [\n ...config.columns,\n ...columns.map(selectField => {\n return {\n ...selectField,\n type: selectField.type || 'string',\n width: selectField.width || 160,\n header: selectField.header || i18next.t(`field.${selectField.name}`)\n }\n })\n ]\n }\n\n /*\n * 걸러 볼 것이 하나도 없으면 그 영역을 감춘다.\n *\n * **병합된 설정으로 판단한다.** 전에는 밖에서 받은 `columns` 만 보았는데, 기본 열(이름·설명)이\n * 이미 검색 필터를 갖고 있어서 그 판단이 실제와 달랐다.\n */\n requestAnimationFrame(() => {\n /*\n * **찾기가 아닌 필터**가 하나라도 있나로 판단한다. 찾기는 이 영역이 안 그리므로(위 주석),\n * `search` 형 필터만 있는 표에서는 여기 그릴 것이 없다.\n */\n const filterable = this.config.columns.some((column: any) => {\n const filter = column.filter\n return filter && filter !== 'search' && filter?.operator !== 'search'\n })\n\n if (!filterable) {\n this.grist?.hideHeadroom()\n }\n })\n }\n\n getQueryFields() {\n if (this.columns && this.columns.length > 0) {\n return `items {\n ${this.columns.map(selectField => {\n return selectField.type === 'object'\n ? `${selectField.name} { ${\n selectField.subFields && selectField.subFields.length > 0\n ? selectField.subFields.join(' ')\n : `id name description`\n } }`\n : `${selectField.name}`\n })}\n }\n total`\n } else {\n return `\n items {\n id\n name\n description\n }\n total\n `\n }\n }\n\n /**\n * 고른 것. **여럿 고르기에서는 배열이고, 아니면 하나다.**\n *\n * 켠 쪽이 그 모양을 아니까 두 가지를 한 자리에서 낸다.\n */\n get selected(): any {\n var grist = this.renderRoot.querySelector('ox-grist') as DataGrist\n\n var selected = grist.selected || []\n\n if (this.multiple) {\n return selected\n }\n\n return selected.length > 0 ? selected[0] : undefined\n }\n}\n"]}
1
+ {"version":3,"file":"ox-selector-resource-object.js","sourceRoot":"","sources":["../../../src/selector/ox-selector-resource-object.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '@operato/data-grist'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, PropertyValues } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport {\n DataGrist,\n FetchHandler,\n GristData,\n GristEventHandler,\n GristRecord,\n ZERO_DATA,\n InheritedValueType\n} from '@operato/data-grist'\nimport { client, gqlContext } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\nimport { closePopup } from '@operato/popup'\nimport { adjustFilters, isMobileDevice } from '@operato/utils'\nimport { ButtonContainerStyles, CommonHeaderStyles } from '@operato/styles'\n\n@customElement('ox-selector-resource-object')\nexport class OxSelectorResourceObject extends LitElement {\n static styles = [\n CommonHeaderStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n\n background-color: var(--md-sys-color-surface);\n\n width: var(--overlay-center-normal-width, 50%);\n height: var(--overlay-center-normal-height, 50%);\n }\n\n ox-grist {\n flex: 1;\n }\n\n .header {\n grid-template-areas: 'filters actions';\n }\n\n [filler] {\n margin-left: auto;\n }\n\n /*\n * 꺼진 단추가 왜 꺼졌는지 말하는 한 줄. **단추 바로 앞에 선다** — 멀리 두면 그 단추의\n * 이야기로 읽히지 않는다.\n *\n * ── 색만 조금 세운다 ──────────────────────────────────────────────────\n * on-surface-variant 로 두었더니 너무 조용했다. 꺼진 단추 옆의 흐린 글자는 그 단추의\n * 일부처럼 보여서, 확인이 왜 꺼졌는지 찾는 눈에 걸리지 않았다.\n *\n * 크기와 배치는 그대로 두고 **잉크만** 바꾼다. 붉은색은 오류이고, 이것은 오류가 아니라\n * 남은 일이다.\n *\n * primary 를 먼저 써 봤는데 이 제품에서는 **흑연**이다(#262e38) — 틀 자체가 무채색이라\n * 강조가 되지 않았다. 강조 잉크는 --ui-accent 이고, 그 색은 **작은 글자를 담을 수 있도록\n * 톤을 낮춰 둔** 것이다.\n *\n * [확인함] 2026-09-05 · --ui-accent #0c7a4c · 팝업 면 #f0f2f4 · 대비 4.79\n * 작은 글자 기준 4.5 를 넘는다\n *\n * accent 가 없는 앱에서는 primary 로 떨어진다.\n */\n [hint] {\n color: var(--ui-accent, var(--md-sys-color-primary));\n font-size: var(--md-sys-typescale-label-medium-size, 0.75rem);\n margin-right: var(--spacing-small, 4px);\n }\n `\n ]\n\n /**\n * 지금 들어 있는 값. **여럿 고르기에서는 배열이다.**\n *\n * 목록을 받아올 때 이 값과 같은 줄을 골라 둔다(fetchHandler). 그래서 팝업을 열면 지금 값이\n * 이미 고른 상태로 보인다.\n */\n @property({ type: Object }) value?: string | string[]\n\n /**\n * 여럿을 고를 수 있나. **부르는 쪽이 켠다.**\n *\n * ── 왜 필요한가 (2026-09-05) ────────────────────────────────────────────\n * 마스터 화면의 관계 칸 다섯이 여러 값을 든다 — 상위 등급(baseIds) · 요구 검사\n * (testSpecificationIds) · 공정의 차례(steps). 이 선택기가 하나만 내주어서 그 칸들이\n * **자유 텍스트로 남아 있었다.**\n *\n * 자유 텍스트는 조용히 틀린다. GUNSAN 을 GUNSAM 이라고 쳐도 저장되고, 그 뒤로 그 참조는\n * 어디에서도 안 걸린다 — 화면에는 값이 있는데.\n *\n * ── 켜면 무엇이 달라지나 ────────────────────────────────────────────────\n * 고르기 줄을 눌러 켜고 끈다(select-row-toggle). 겹쳐 고를 수 있다\n * 두 번 누르기 확정하지 않는다 — 한 줄만 넘기게 되므로\n * confirmCallback 고른 것들의 배열을 넘긴다\n *\n * 켠 쪽이 그 모양을 아니까 콜백을 둘로 나누지 않는다.\n */\n @property({ type: Boolean }) multiple: boolean = false\n @property({ type: Object }) config: any\n @property({ type: Object }) data: GristData = ZERO_DATA\n @property({ type: String }) queryName!: string\n @property({ type: Object }) basicArgs: any\n @property({ type: String }) inherited?: InheritedValueType = InheritedValueType.Include\n @property({ type: Object }) confirmCallback?: (record?: Partial<GristRecord>) => void\n @property({ type: Array }) selectedRecords: GristRecord[] = []\n\n @property({ type: Array }) searchFields: any\n @property({ type: Array }) columns: {\n type: string\n name: string\n header: string\n subFields?: string[]\n hidden: boolean\n queryName: string\n width: number\n }[] = []\n @property({ type: Object }) pagination?: {\n limit: number\n pages: number[]\n }\n @property({ type: Object }) list: any\n @property({ type: String }) valueField: string | ((item: any) => any) = 'id'\n\n /** 설정을 한 번 세웠나 — 열·질의가 바뀔 때만 다시 세운다. */\n private _configured = false\n\n /**\n * 지금 고른 것이 있나 — **바닥 단추가 이 값을 본다.**\n *\n * `selected` 게터는 그리스트를 그때그때 읽으므로 반응형이 아니다. 그래서 단추의 disabled 를\n * 그것으로 묶으면 골라도 다시 그려지지 않는다. 그리스트가 내는 select-record-change 를 듣고\n * 이 상태를 갱신한다.\n */\n @state() private hasSelection = false\n\n @query('ox-grist') grist!: DataGrist\n\n render() {\n return html`\n <!--\n ── .data 를 넘기지 않는다 ────────────────────────────────────────────────\n\n 목록은 아래 fetchHandler 가 채운다. 그런데 .data 로 this.data 를 함께 넘기고\n 있었고, 그 값은 늘 ZERO_DATA(빈 것)였다 — 이 부품에 data 를 주는 부르는 쪽이 없다.\n\n 그리스트는 data 가 설정되면 **reset() 한다**(data-grist 의 updated). 그래서 이 부품이\n 다시 그려지는 순간 빈 값이 다시 내려가 **목록이 통째로 사라진다.**\n\n 여태 안 드러난 이유는 이 부품이 첫 렌더 뒤로 다시 그려질 일이 없었기 때문이다. 바닥\n 단추를 고른 상태에 묶으면서(hasSelection) 비로소 다시 그려지게 되었고, 그때 줄을\n 누르면 목록이 비었다.\n\n [확인함] 2026-09-05 · 라디오 클릭 → reset() 1회(DataGrist.updated) → 20건 → 0건\n\n 고른 상태를 되돌리는 것이 아니라 **이 바인딩을 걷는다.** 넘길 값이 없으면서 넘기고\n 있던 것이고, 남겨 두면 다음 사람이 같은 곳에 빠진다.\n -->\n <ox-grist\n .mode=${isMobileDevice() ? 'LIST' : 'GRID'}\n .config=${this.config}\n .fetchHandler=${this.fetchHandler.bind(this)}\n .selectedRecords=${this.selectedRecords}\n @select-record-change=${() => {\n this.hasSelection = (this.grist?.selected || []).length > 0\n }}\n >\n <div class=\"header\" slot=\"headroom\">\n <div class=\"filters\">\n <!--\n **검색은 이 영역이 그리지 않는다.**\n 찾기는 화면의 제목줄이 든다(페이지의 표준이 그렇다 — 제목 왼쪽, 찾기 오른쪽 끝).\n 여기서도 그리면 검색창이 둘이 된다. 실제로 한 번 그렇게 됐다.\n\n 이 영역은 **찾기가 아닌 필터**의 자리다. 그것이 하나도 없으면 아래 hideHeadroom 이\n 영역째 감춘다 — 열 것이 없는 문을 두지 않는다.\n -->\n <ox-filters-form autofocus without-search></ox-filters-form>\n </div>\n </div>\n </ox-grist>\n\n <!--\n 바닥 — **세 동작의 무게가 다르다.**\n\n 지정 안 함 이 칸에 아무것도 넣지 않는다. 왼쪽 끝에 따로 선다 — 확정과 나란히 두면 잘못 누른다\n 닫기 아무것도 하지 않고 나간다. 글자만\n 확인 이 팝업이 하러 온 일. 하나만 채운다\n\n 아이콘을 떼었다. 「비우기」에는 체크박스 글리프가 붙어 있었는데, 그것은 **입력칸의\n 글리프**여서 동작이 아니라 「끄고 켜는 것」으로 읽혔다. 닫기의 ⊗ 와 확인의 ✓ 도 걷는다 —\n 낱말이 이미 그 일을 말하고, 곁 단추에 아이콘이 붙으면 무게가 주 동작과 비슷해진다.\n -->\n <div class=\"footer\">\n <!--\n 「비우기」였다. **무엇을** 비우는지 말하지 않는다 — 팝업 안에 목록도 검색창도 있어서\n 「목록을 비우나」로도 읽힌다. 이 단추가 하는 일은 그 칸을 빈 값으로 두고 닫는 것이다.\n\n button.empty 를 그대로 쓰지 않는 이유: 그 문자열은 여러 개를 고르는 팝업들도 함께 쓴다\n (결재자 · 수신자 편집기). 거기서는 「고른 것 전부 지우기」이고, 그것은 「지정 안 함」과\n 다른 말이다. 한 문자열이 두 뜻을 겸하고 있었다.\n -->\n <button @click=${this.onEmpty.bind(this)} clear>${i18next.t('button.unset')}</button>\n\n <div filler></div>\n\n <!--\n 힌트는 **단추 두 개 앞**에 선다. 닫기와 확인은 한 쌍이라, 그 사이에 글자가 끼면\n 쌍이 갈라져 보인다.\n -->\n ${!this.hasSelection\n ? html`<span hint\n >${i18next.t(this.multiple ? 'text.pick-from-the-list' : 'text.pick-one-from-the-list')}</span\n >`\n : ''}\n <button @click=${this.onCancel.bind(this)}>${i18next.t('button.cancel')}</button>\n <!--\n ── 고른 것이 없으면 **확인을 끄고, 왜 껐는지 말한다** ─────────────────\n\n 꺼진 단추만 두면 막다른 길이다. 누른 사람은 「왜 안 되나」를 알 길이 없고, 특히 이\n 팝업은 목록이 여러 쪽이라 자기가 무엇을 안 했는지 스스로 떠올리기 어렵다.\n\n 그래서 한 줄을 함께 둔다. **고르면 사라진다** — 할 일이 남아 있는 동안만 보인다.\n\n ── 그 앞에는 더 나빴다 ────────────────────────────────────────────────\n 고른 것이 없을 때 확인이 **값을 지웠다**. 확인이 「지정 안 함」과 같은 일을 했다\n (onConfirm 주석 참조).\n -->\n <button\n @click=${this.onConfirm.bind(this)}\n ?disabled=${!this.hasSelection}\n title=${!this.hasSelection ? i18next.t('text.pick-one-from-the-list') : ''}\n done\n >\n ${i18next.t('button.confirm')}\n </button>\n </div>\n `\n }\n\n searchText(value: string) {\n this.grist.searchText = value\n }\n\n toggleFilter() {\n this.grist.toggleHeadroom()\n }\n\n onEmpty() {\n this.confirmCallback && this.confirmCallback()\n closePopup(this)\n }\n\n onCancel() {\n closePopup(this)\n }\n\n onConfirm() {\n const selected = this.selected\n\n /*\n * ── 고른 것이 없으면 **아무 일도 하지 않는다** ────────────────────────────\n *\n * 전에는 `confirmCallback(this.selected)` 를 그냥 불렀다. 고른 것이 없으면 `selected` 가\n * undefined 이고, 그것은 **아래 onEmpty 가 넘기는 것과 똑같다** — 즉 확인이 「지정 안 함」과\n * 같은 일을 했다. 값을 지우는 단추가 둘이었고, 그중 하나가 주 동작(채운 단추)이었다.\n *\n * 이것이 조용한 데이터 손실로 이어졌다. 고른 표시는 목록을 받아올 때 **그 쪽에서 값을 찾으면**\n * 켜지므로(아래 fetchHandler), 값이 2쪽에 있으면 1쪽만 받은 상태에서는 빈 채다.\n *\n * [확인함] 2026-09-05 · 제조법 · 만드는 품목 · 총 106건\n * value=MT10097283 은 1쪽에 없다 → selectedRecords = []\n * 팝업을 열고 아무것도 만지지 않고 확인 → 칸이 빈 값이 되었다\n *\n * 확인의 뜻은 「이 고른 것으로 한다」다. 고른 것이 없으면 확인할 것이 없으므로 닫기와 같다.\n * **값을 지우는 길은 「지정 안 함」 하나다.**\n */\n if (!selected || (Array.isArray(selected) && selected.length === 0)) {\n closePopup(this)\n return\n }\n\n this.confirmCallback && this.confirmCallback(selected)\n closePopup(this)\n }\n\n fetchHandler: FetchHandler = async ({ filters = [], page, limit, sortings = [], inherited }) => {\n if (this.basicArgs?.filters) {\n filters = adjustFilters(filters, this.basicArgs.filters)\n }\n // basicArgs.sorters가 있으면 기본 정렬로 병합\n if (this.basicArgs?.sorters && sortings.length === 0) {\n sortings = [...this.basicArgs.sorters]\n }\n const pagination = { page, limit }\n\n const response = await client.query({\n query: gql`\n query($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!], $inherited: InheritedValueType) {\n fetch: ${\n this.queryName\n } (filters: $filters, pagination: $pagination, sortings: $sortings, inherited: $inherited) {\n ${this.getQueryFields()}\n }\n }\n `,\n variables: {\n filters,\n pagination,\n sortings,\n inherited: inherited || this.inherited\n },\n context: gqlContext()\n })\n\n if (!response.errors) {\n const records = response.data.fetch.items.map((item: any) => {\n let rowValue\n\n if (this.valueField && typeof this.valueField === 'function') {\n rowValue = this.valueField(item)\n } else if (this.valueField) {\n rowValue = item[this.valueField]\n } else {\n rowValue = item.id\n }\n\n /*\n * 지금 값과 같은 줄을 골라 둔다. 여럿 고르기에서는 값이 배열이므로 그 안에 있는지 본다.\n *\n * 값이 이 쪽에 없으면 골라지지 않는다 — 그것이 이 부품의 한계다. 부르는 쪽이 지금 값을\n * 글자로 함께 보여 주는 이유가 그것이다(ops-master 의 참조 팝업).\n */\n const wanted = Array.isArray(this.value) ? this.value : this.value ? [this.value] : []\n\n if (wanted.length && wanted.includes(rowValue)) {\n this.selectedRecords = this.multiple ? [...this.selectedRecords, item] : [item]\n item['__selected__'] = true\n /* 받아온 쪽에서 값을 찾았다 — 바닥 단추도 그것을 알아야 한다. */\n this.hasSelection = true\n }\n\n return item\n })\n const total = response.data.fetch.total\n\n return {\n records,\n total,\n limit,\n page\n }\n }\n }\n\n /**\n * 표의 설정을 **첫 렌더 전에** 세운다.\n *\n * ── 왜 firstUpdated 가 아닌가 ──────────────────────────────────────────────\n * 여기 있던 것을 `firstUpdated` 에서 만들고 있었다. 그러면 `<ox-grist>` 와 그 안의 필터 폼이\n * **먼저 붙고** 설정이 나중에 온다. 필터 폼은 붙는 순간의 설정을 한 번 읽어 두므로, 그 스냅숏이\n * 병합 전 것이었다 — 열 일곱 개 중 넷만 든 설정이라 필터가 하나도 없었고, 그래서 필터 영역이\n * 빈 채로 32px 만 서 있었다.\n *\n * `willUpdate` 는 렌더 전에 돈다. 폼이 붙을 때 이미 완성된 설정을 읽는다.\n */\n willUpdate(changed: PropertyValues<this>) {\n /* 열·질의가 바뀌면 다시 세운다. 그 밖의 변화에는 손대지 않는다. */\n /* multiple 이 바뀌면 거터와 고르기 규칙이 달라지므로 설정을 다시 세운다. */\n if (\n this._configured &&\n !changed.has('columns') &&\n !changed.has('queryName') &&\n !changed.has('list') &&\n !changed.has('multiple')\n ) {\n return\n }\n\n this._configured = true\n\n const config = {\n list: this.list,\n columns: [\n {\n type: 'gutter',\n gutterName: 'sequence'\n },\n {\n type: 'gutter',\n gutterName: 'row-selector',\n multiple: this.multiple\n }\n ],\n rows: {\n selectable: {\n multiple: this.multiple\n },\n handlers: {\n /*\n * 하나만 고를 때는 누르면 그 줄로 바뀐다. 여럿일 때는 눌러 켜고 끈다 — 앞의 것을\n * 풀면서 고르면 여러 개를 담을 수 없다.\n */\n click: this.multiple ? 'select-row-toggle' : 'select-row',\n /*\n * 두 번 눌러 확정하는 것은 하나만 고를 때다. 여럿일 때 그렇게 두면 **그 한 줄만**\n * 넘어가고 앞서 고른 것이 사라진다.\n */\n ...(this.multiple\n ? {}\n : {\n dblclick: ((columns, data, column, record, rowIndex, field) => {\n this.onConfirm()\n }) as GristEventHandler\n })\n },\n appendable: false\n },\n pagination: this.pagination\n }\n\n const columns = this.columns || [\n {\n type: 'string',\n name: 'id',\n header: i18next.t('field.id'),\n hidden: true\n },\n {\n type: 'string',\n name: 'name',\n header: i18next.t('field.name'),\n record: {\n align: 'left'\n },\n sortable: true,\n filter: 'search',\n width: 160\n },\n {\n type: 'string',\n name: 'description',\n header: i18next.t('field.description'),\n record: {\n align: 'left'\n },\n sortable: true,\n filter: 'search',\n /*\n * 남는 폭을 이 열이 채운다.\n *\n * 열 폭은 grid-template-columns 에 그대로 들어가므로 문자열도 된다(data-grist 의\n * setGridTemplateColumns). 고정 300px 이었을 때는 오른쪽에 200px 가까운 죽은 자리와\n * 세로선 하나가 남았다 — 목록이 상자 한쪽에 몰려 보인다.\n */\n width: 'minmax(240px, 1fr)'\n }\n ]\n\n /*\n * **밖에서 준 설정을 덮어쓰지 않는다.**\n *\n * 여기서 `this.config` 를 통째로 갈아 끼우고 있었다. 그래서 부르는 쪽이 `config` 를 주어도\n * 사라졌다 — 빈 목록에 무슨 말을 할지(`emptyNote`)를 밖에서 정할 길이 없었다.\n *\n * 빈 목록은 **두 가지 다른 사실**을 말해야 하는 자리다. 「이 표에 아직 아무것도 없다」와\n * 「검색에 걸린 것이 없다」는 다르고, 하나로 합치면 결함이 「고를 게 없다」로 보인다. 실제로\n * 그런 일이 있었다(배열 모양이 달라 목록이 비었는데 아무도 결함인 줄 몰랐다).\n */\n const given = this.config || {}\n\n this.config = {\n ...config,\n ...given,\n columns: [\n ...config.columns,\n ...columns.map(selectField => {\n return {\n ...selectField,\n type: selectField.type || 'string',\n width: selectField.width || 160,\n header: selectField.header || i18next.t(`field.${selectField.name}`)\n }\n })\n ]\n }\n\n /*\n * 걸러 볼 것이 하나도 없으면 그 영역을 감춘다.\n *\n * **병합된 설정으로 판단한다.** 전에는 밖에서 받은 `columns` 만 보았는데, 기본 열(이름·설명)이\n * 이미 검색 필터를 갖고 있어서 그 판단이 실제와 달랐다.\n */\n requestAnimationFrame(() => {\n /*\n * **찾기가 아닌 필터**가 하나라도 있나로 판단한다. 찾기는 이 영역이 안 그리므로(위 주석),\n * `search` 형 필터만 있는 표에서는 여기 그릴 것이 없다.\n */\n const filterable = this.config.columns.some((column: any) => {\n const filter = column.filter\n return filter && filter !== 'search' && filter?.operator !== 'search'\n })\n\n if (!filterable) {\n this.grist?.hideHeadroom()\n }\n })\n }\n\n getQueryFields() {\n if (this.columns && this.columns.length > 0) {\n return `items {\n ${this.columns.map(selectField => {\n return selectField.type === 'object'\n ? `${selectField.name} { ${\n selectField.subFields && selectField.subFields.length > 0\n ? selectField.subFields.join(' ')\n : `id name description`\n } }`\n : `${selectField.name}`\n })}\n }\n total`\n } else {\n return `\n items {\n id\n name\n description\n }\n total\n `\n }\n }\n\n /**\n * 고른 것. **여럿 고르기에서는 배열이고, 아니면 하나다.**\n *\n * 켠 쪽이 그 모양을 아니까 두 가지를 한 자리에서 낸다.\n */\n get selected(): any {\n var grist = this.renderRoot.querySelector('ox-grist') as DataGrist\n\n var selected = grist.selected || []\n\n if (this.multiple) {\n return selected\n }\n\n return selected.length > 0 ? selected[0] : undefined\n }\n}\n"]}
@@ -17,7 +17,7 @@ import { expect } from '@open-wc/testing';
17
17
  * 표에서는 안 드러났고, 여러 쪽이면 값이 2쪽에 있을 때 빈 채였다.
18
18
  *
19
19
  * ```
20
- * [재봤음] 제조법 · 만드는 품목 · 총 106건 · value=MT10097283 은 1쪽에 없다
20
+ * [확인함] 제조법 · 만드는 품목 · 총 106건 · value=MT10097283 은 1쪽에 없다
21
21
  * 팝업을 열고 아무것도 만지지 않고 확인 → 칸이 빈 값이 되었다
22
22
  * ```
23
23
  *
@@ -82,7 +82,7 @@ describe('참조 선택기 · 확인은 값을 지우지 않는다', () => {
82
82
  * 내려가 목록이 통째로 사라졌다.
83
83
  *
84
84
  * ```
85
- * [재봤음] 2026-09-05 · 라디오 클릭 → reset() 1회(DataGrist.updated) → 20건 → 0건
85
+ * [확인함] 2026-09-05 · 라디오 클릭 → reset() 1회(DataGrist.updated) → 20건 → 0건
86
86
  * ```
87
87
  *
88
88
  * 첫 렌더 뒤로 다시 그릴 일이 없어서 여태 안 드러났다. 바닥 단추를 고른 상태에 묶으면서
@@ -1 +1 @@
1
- {"version":3,"file":"selector-confirm-keeps-value.test.js","sourceRoot":"","sources":["../../test/selector-confirm-keeps-value.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect } from '@open-wc/testing'\n\n/**\n * 참조 팝업의 **확인이 값을 지우지 않는다.**\n *\n * ## 무엇을 지키나\n *\n * `ox-selector-resource-object` 의 확인은 「이 고른 것으로 한다」다. 고른 것이 없으면 확인할 것이\n * 없으므로 닫기와 같아야 한다. **값을 지우는 길은 「지정 안 함」 하나다.**\n *\n * ## 왜 이 시험이 있나 (2026-09-05)\n *\n * 전에는 `confirmCallback(this.selected)` 를 조건 없이 불렀다. 고른 것이 없으면 `selected` 가\n * undefined 이고, 그것은 `onEmpty` 가 넘기는 것과 **똑같다** — 확인이 「지정 안 함」과 같은 일을\n * 했다. 값을 지우는 단추가 둘이었고 그중 하나가 주 동작(채운 단추)이었다.\n *\n * 고른 표시는 목록을 받아올 때 그 쪽에서 값을 찾으면 켜진다. 그래서 목록이 한 쪽에 다 들어가는\n * 표에서는 안 드러났고, 여러 쪽이면 값이 2쪽에 있을 때 빈 채였다.\n *\n * ```\n * [재봤음] 제조법 · 만드는 품목 · 총 106건 · value=MT10097283 은 1쪽에 없다\n * 팝업을 열고 아무것도 만지지 않고 확인 → 칸이 빈 값이 되었다\n * ```\n *\n * ## 왜 부품을 세우지 않고 원문을 보나\n *\n * 이 부품은 `@operato/graphql` 의 클라이언트를 모듈 적재 시점에 끌어온다. 시험 안에서 그것을 세우면\n * 서버가 필요하고, 그 무거움이 이 한 줄의 규칙을 지키는 값보다 크다.\n *\n * 대신 **그 규칙이 코드에 남아 있는지**를 본다. 조건 없이 부르는 모양으로 되돌아가면 빨갛게 난다.\n * 부품을 세우는 시험은 그래프가 가벼워지면 그때 더한다.\n */\n/**\n * `onConfirm` 의 본문만 떼어 낸다.\n *\n * 처음에 `indexOf('fetchHandler')` 를 끝 경계로 썼다가 빈 문자열이 나왔다 — 그 낱말은 render 의\n * 템플릿(`.fetchHandler=…`)에 **먼저** 나온다. 메서드 선언을 경계로 삼는다.\n */\nfunction onConfirmBody(source: string): string {\n const start = source.indexOf(' onConfirm() {')\n if (start < 0) return ''\n const rest = source.slice(start)\n const end = rest.indexOf('\\n }')\n return end < 0 ? rest : rest.slice(0, end + 4)\n}\n\ndescribe('참조 선택기 · 확인은 값을 지우지 않는다', () => {\n let source: string\n\n before(async () => {\n const response = await fetch('/src/selector/ox-selector-resource-object.ts')\n expect(response.ok, '원문을 읽을 수 있어야 한다').to.be.true\n source = await response.text()\n })\n\n it('확인은 고른 것이 없으면 콜백을 부르지 않는다', () => {\n const body = onConfirmBody(source)\n\n expect(body, 'onConfirm 을 찾아야 한다').to.include('onConfirm')\n\n /*\n * 고른 것이 없을 때 빠져나가는 길이 있어야 한다.\n *\n * 조건 안에 다른 절이 더 붙어도 통과시킨다 — 여럿 고르기가 들어오면서 빈 배열도 함께 봐야\n * 했다. 지키려는 것은 「!selected 를 보고 닫고 끝낸다」이지 조건의 글자 수가 아니다.\n */\n expect(body.replace(/\\s+/g, ' '), '고른 것이 없으면 닫고 끝낸다').to.match(\n /if\\s*\\([^)]*!\\s*selected[^{]*\\)\\s*\\{\\s*closePopup\\(this\\)\\s*;?\\s*return/\n )\n })\n\n it('확인이 넘기는 것은 고른 것 하나다 — this.selected 를 조건 없이 넘기지 않는다', () => {\n const body = onConfirmBody(source).replace(/\\s+/g, ' ')\n\n /*\n * 되돌아간 모양을 직접 막는다. 주석 안에 같은 글자가 있어도 걸리지 않도록 앞의 주석을 걷는다.\n */\n const code = body.replace(/\\/\\*[\\s\\S]*?\\*\\//g, '')\n\n expect(code, '조건 없이 this.selected 를 넘기는 모양으로 돌아가면 안 된다').to.not.include(\n 'confirmCallback(this.selected)'\n )\n })\n\n it('값을 지우는 길은 지정 안 함 하나다', () => {\n const empty = source.slice(source.indexOf('onEmpty()'), source.indexOf('onCancel()')).replace(/\\s+/g, ' ')\n\n /* 인자 없이 부르는 것이 「지우기」의 뜻이다. */\n expect(empty, '지정 안 함은 빈 값을 넘긴다').to.include('confirmCallback()')\n })\n\n /**\n * 그리스트에 **빈 data 를 넘기지 않는다.**\n *\n * data-grist 는 data 가 설정되면 reset() 한다. 이 부품은 fetchHandler 로 목록을 채우면서\n * `.data` 로 늘 ZERO_DATA 를 함께 넘기고 있었다. 그래서 이 부품이 다시 그려지는 순간 빈 값이\n * 내려가 목록이 통째로 사라졌다.\n *\n * ```\n * [재봤음] 2026-09-05 · 라디오 클릭 → reset() 1회(DataGrist.updated) → 20건 → 0건\n * ```\n *\n * 첫 렌더 뒤로 다시 그릴 일이 없어서 여태 안 드러났다. 바닥 단추를 고른 상태에 묶으면서\n * 드러났고, 그것을 되돌리는 대신 이 바인딩을 걷었다.\n */\n it('ox-grist 에 .data 를 넘기지 않는다', () => {\n const template = source.slice(source.indexOf('<ox-grist'), source.indexOf('</ox-grist>'))\n\n expect(template, 'ox-grist 를 찾아야 한다').to.include('.fetchHandler=')\n expect(template.replace(/<!--[\\s\\S]*?-->/g, ''), '.data 를 다시 넘기면 목록이 사라진다').to.not.include(\n '.data='\n )\n })\n\n /**\n * **여럿 고르기에서 빈 배열도 막는다.**\n *\n * multiple 을 켜면 `selected` 가 배열이다. 아무것도 안 고른 상태는 undefined 가 아니라 `[]` 이고,\n * 그것은 truthy 다 — `!selected` 만으로는 빠져나가지 못하고 빈 배열이 그대로 넘어간다. 받는 쪽이\n * 그것을 「전부 지워라」로 읽으면 하나만 고르기 때와 같은 데이터 손실이 난다.\n */\n it('여럿 고르기에서 빈 배열을 넘기지 않는다', () => {\n const body = onConfirmBody(source).replace(/\\s+/g, ' ')\n\n expect(body, '빈 배열도 걸러야 한다').to.match(/Array\\.isArray\\(selected\\)\\s*&&\\s*selected\\.length\\s*===?\\s*0/)\n })\n})\n"]}
1
+ {"version":3,"file":"selector-confirm-keeps-value.test.js","sourceRoot":"","sources":["../../test/selector-confirm-keeps-value.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect } from '@open-wc/testing'\n\n/**\n * 참조 팝업의 **확인이 값을 지우지 않는다.**\n *\n * ## 무엇을 지키나\n *\n * `ox-selector-resource-object` 의 확인은 「이 고른 것으로 한다」다. 고른 것이 없으면 확인할 것이\n * 없으므로 닫기와 같아야 한다. **값을 지우는 길은 「지정 안 함」 하나다.**\n *\n * ## 왜 이 시험이 있나 (2026-09-05)\n *\n * 전에는 `confirmCallback(this.selected)` 를 조건 없이 불렀다. 고른 것이 없으면 `selected` 가\n * undefined 이고, 그것은 `onEmpty` 가 넘기는 것과 **똑같다** — 확인이 「지정 안 함」과 같은 일을\n * 했다. 값을 지우는 단추가 둘이었고 그중 하나가 주 동작(채운 단추)이었다.\n *\n * 고른 표시는 목록을 받아올 때 그 쪽에서 값을 찾으면 켜진다. 그래서 목록이 한 쪽에 다 들어가는\n * 표에서는 안 드러났고, 여러 쪽이면 값이 2쪽에 있을 때 빈 채였다.\n *\n * ```\n * [확인함] 제조법 · 만드는 품목 · 총 106건 · value=MT10097283 은 1쪽에 없다\n * 팝업을 열고 아무것도 만지지 않고 확인 → 칸이 빈 값이 되었다\n * ```\n *\n * ## 왜 부품을 세우지 않고 원문을 보나\n *\n * 이 부품은 `@operato/graphql` 의 클라이언트를 모듈 적재 시점에 끌어온다. 시험 안에서 그것을 세우면\n * 서버가 필요하고, 그 무거움이 이 한 줄의 규칙을 지키는 값보다 크다.\n *\n * 대신 **그 규칙이 코드에 남아 있는지**를 본다. 조건 없이 부르는 모양으로 되돌아가면 빨갛게 난다.\n * 부품을 세우는 시험은 그래프가 가벼워지면 그때 더한다.\n */\n/**\n * `onConfirm` 의 본문만 떼어 낸다.\n *\n * 처음에 `indexOf('fetchHandler')` 를 끝 경계로 썼다가 빈 문자열이 나왔다 — 그 낱말은 render 의\n * 템플릿(`.fetchHandler=…`)에 **먼저** 나온다. 메서드 선언을 경계로 삼는다.\n */\nfunction onConfirmBody(source: string): string {\n const start = source.indexOf(' onConfirm() {')\n if (start < 0) return ''\n const rest = source.slice(start)\n const end = rest.indexOf('\\n }')\n return end < 0 ? rest : rest.slice(0, end + 4)\n}\n\ndescribe('참조 선택기 · 확인은 값을 지우지 않는다', () => {\n let source: string\n\n before(async () => {\n const response = await fetch('/src/selector/ox-selector-resource-object.ts')\n expect(response.ok, '원문을 읽을 수 있어야 한다').to.be.true\n source = await response.text()\n })\n\n it('확인은 고른 것이 없으면 콜백을 부르지 않는다', () => {\n const body = onConfirmBody(source)\n\n expect(body, 'onConfirm 을 찾아야 한다').to.include('onConfirm')\n\n /*\n * 고른 것이 없을 때 빠져나가는 길이 있어야 한다.\n *\n * 조건 안에 다른 절이 더 붙어도 통과시킨다 — 여럿 고르기가 들어오면서 빈 배열도 함께 봐야\n * 했다. 지키려는 것은 「!selected 를 보고 닫고 끝낸다」이지 조건의 글자 수가 아니다.\n */\n expect(body.replace(/\\s+/g, ' '), '고른 것이 없으면 닫고 끝낸다').to.match(\n /if\\s*\\([^)]*!\\s*selected[^{]*\\)\\s*\\{\\s*closePopup\\(this\\)\\s*;?\\s*return/\n )\n })\n\n it('확인이 넘기는 것은 고른 것 하나다 — this.selected 를 조건 없이 넘기지 않는다', () => {\n const body = onConfirmBody(source).replace(/\\s+/g, ' ')\n\n /*\n * 되돌아간 모양을 직접 막는다. 주석 안에 같은 글자가 있어도 걸리지 않도록 앞의 주석을 걷는다.\n */\n const code = body.replace(/\\/\\*[\\s\\S]*?\\*\\//g, '')\n\n expect(code, '조건 없이 this.selected 를 넘기는 모양으로 돌아가면 안 된다').to.not.include(\n 'confirmCallback(this.selected)'\n )\n })\n\n it('값을 지우는 길은 지정 안 함 하나다', () => {\n const empty = source.slice(source.indexOf('onEmpty()'), source.indexOf('onCancel()')).replace(/\\s+/g, ' ')\n\n /* 인자 없이 부르는 것이 「지우기」의 뜻이다. */\n expect(empty, '지정 안 함은 빈 값을 넘긴다').to.include('confirmCallback()')\n })\n\n /**\n * 그리스트에 **빈 data 를 넘기지 않는다.**\n *\n * data-grist 는 data 가 설정되면 reset() 한다. 이 부품은 fetchHandler 로 목록을 채우면서\n * `.data` 로 늘 ZERO_DATA 를 함께 넘기고 있었다. 그래서 이 부품이 다시 그려지는 순간 빈 값이\n * 내려가 목록이 통째로 사라졌다.\n *\n * ```\n * [확인함] 2026-09-05 · 라디오 클릭 → reset() 1회(DataGrist.updated) → 20건 → 0건\n * ```\n *\n * 첫 렌더 뒤로 다시 그릴 일이 없어서 여태 안 드러났다. 바닥 단추를 고른 상태에 묶으면서\n * 드러났고, 그것을 되돌리는 대신 이 바인딩을 걷었다.\n */\n it('ox-grist 에 .data 를 넘기지 않는다', () => {\n const template = source.slice(source.indexOf('<ox-grist'), source.indexOf('</ox-grist>'))\n\n expect(template, 'ox-grist 를 찾아야 한다').to.include('.fetchHandler=')\n expect(template.replace(/<!--[\\s\\S]*?-->/g, ''), '.data 를 다시 넘기면 목록이 사라진다').to.not.include(\n '.data='\n )\n })\n\n /**\n * **여럿 고르기에서 빈 배열도 막는다.**\n *\n * multiple 을 켜면 `selected` 가 배열이다. 아무것도 안 고른 상태는 undefined 가 아니라 `[]` 이고,\n * 그것은 truthy 다 — `!selected` 만으로는 빠져나가지 못하고 빈 배열이 그대로 넘어간다. 받는 쪽이\n * 그것을 「전부 지워라」로 읽으면 하나만 고르기 때와 같은 데이터 손실이 난다.\n */\n it('여럿 고르기에서 빈 배열을 넘기지 않는다', () => {\n const body = onConfirmBody(source).replace(/\\s+/g, ' ')\n\n expect(body, '빈 배열도 걸러야 한다').to.match(/Array\\.isArray\\(selected\\)\\s*&&\\s*selected\\.length\\s*===?\\s*0/)\n })\n})\n"]}