@operato/data-grist 10.17.0 → 10.22.0

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":"data-provider.js","sourceRoot":"","sources":["../../src/data-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { ZERO_RECORDS } from './configure/zero-config.js'\nimport { DataConsumer } from './data-consumer.js'\nimport { FetchHandler, FetchOption, FilterValue, GristRecord, SorterConfig, SortersConfig } from './types.js'\n\nfunction EMPTY_FETCHHANDLER() {\n return {\n total: 0,\n records: []\n }\n}\n\nfunction _calculateTotalPage(limit: number, total: number) {\n /*\n * total page는 1이상이어야 한다.\n * 즉, 레코드가 하나도 없어도, 페이지 갯수는 1이 되어야 한다.\n */\n return Math.max(1, Math.ceil(total / limit))\n}\n\n/*\n * For fetches nobody awaits (page and limit changes, filter and option changes). This does not hide a\n * failure: fetchFailed has already drawn it on the grid before the rejection gets here. It only stops\n * the same failure from also escaping as an unhandled rejection. Do not copy it to a place where the\n * failure is not already shown.\n */\nconst shownByConsumer = () => {}\n\nexport class DataProvider {\n page: number = 1\n limit: number = 20\n total: number = 0\n records: GristRecord[] = []\n\n private consumer?: DataConsumer\n private _fetchHandler?: FetchHandler\n private _sorters?: SorterConfig[]\n private _filters?: FilterValue[]\n\n private _pageChangeHandler: EventListener = this.onPageChange.bind(this)\n private _limitChangeHandler = this.onLimitChange.bind(this)\n private _fetchParamsChangeHandler = this.onFetchParamsChange.bind(this)\n private _recordChangeHandler = this.onRecordChange.bind(this)\n private _attachPageHandler: EventListener = this.onAttachPage.bind(this)\n\n private _fetchHandlerWrap: any\n private _fetchOptions: any\n\n constructor(consumer: DataConsumer) {\n this.consumer = consumer\n\n this.fetchHandler = consumer.fetchHandler\n\n this.consumer.addEventListener('attach-page', this._attachPageHandler)\n this.consumer.addEventListener('page-change', this._pageChangeHandler)\n this.consumer.addEventListener('limit-change', this._limitChangeHandler)\n this.consumer.addEventListener('fetch-params-change', this._fetchParamsChangeHandler)\n this.consumer.addEventListener('record-change', this._recordChangeHandler)\n }\n\n dispose() {\n this.consumer?.removeEventListener('attach-page', this._attachPageHandler)\n this.consumer?.removeEventListener('page-change', this._pageChangeHandler)\n this.consumer?.removeEventListener('limit-change', this._limitChangeHandler)\n this.consumer?.removeEventListener('fetch-params-change', this._fetchParamsChangeHandler)\n this.consumer?.removeEventListener('record-change', this._recordChangeHandler)\n }\n\n onAttachPage() {\n this.attach().catch(shownByConsumer)\n }\n\n onPageChange(e: Event) {\n var page = (e as CustomEvent).detail\n this.fetch({ page }).catch(shownByConsumer)\n }\n\n onLimitChange(e: Event) {\n var limit = (e as CustomEvent).detail\n this.fetch({ limit }).catch(shownByConsumer)\n }\n\n onFetchParamsChange(e: Event) {\n const { sorters, filters, from } = (e as CustomEvent).detail || {}\n\n sorters && (this.sorters = sorters)\n filters && (this.filters = filters)\n\n if (this.consumer?.mode !== 'GRID') {\n this.page = 0\n }\n\n from !== 'config' && this.fetch().catch(shownByConsumer)\n }\n\n onRecordChange(e: Event) {\n this.consumer?.checkDirties()\n }\n\n get fetchOptions() {\n return this._fetchOptions\n }\n\n set fetchOptions(fetchOptions) {\n this._fetchOptions = fetchOptions\n\n this.fetch().catch(shownByConsumer)\n }\n\n get fetchHandler() {\n if (!this._fetchHandlerWrap) {\n this._fetchHandlerWrap = async (options: FetchOption) => {\n if (!this._fetchHandler) {\n return\n }\n\n try {\n this.consumer?.showSpinner()\n const result = await (this._fetchHandler || EMPTY_FETCHHANDLER)(options)\n this.consumer?.fetchSucceeded?.()\n return result\n } catch (error) {\n /*\n * A failed read is not an empty list. The grid is told, so it can say \"could not load\"\n * instead of \"nothing to show\" - and the error still reaches whoever awaited the fetch.\n */\n this.consumer?.fetchFailed?.(error)\n throw error\n } finally {\n this.consumer?.hideSpinner()\n }\n }\n }\n\n return this._fetchHandlerWrap\n }\n\n set fetchHandler(fetchHandler) {\n this._fetchHandler = fetchHandler\n delete this._fetchHandlerWrap\n }\n\n get sorters() {\n return this._sorters\n }\n\n set sorters(sorters) {\n this._sorters = sorters\n }\n\n /* alias for sorters */\n get sortings() {\n return this._sorters\n }\n\n set sortings(sorters) {\n this._sorters = sorters\n }\n\n get filters() {\n return this._filters\n }\n\n set filters(filters) {\n this._filters = filters\n }\n\n async attach(reset = false) {\n var { page = 0, limit = 20 } = this\n\n /*\n * page는 0 based index가 아님에 주의한다.\n * 즉, page 값이 1 은 첫페이지를 의미한다.\n */\n if (reset) {\n this.records = ZERO_RECORDS\n page = 1\n } else {\n /* attach의 경우는 grist data의 변경상태를 유지하기 위해서, grist._data 를 기반으로 한다. */\n this.records = this.consumer?._data ? this.consumer._data.records : ZERO_RECORDS\n page = page + 1\n }\n\n return this._update(\n {\n /* fetch에서 limit과 page를 제공하지 않는 경우를 대비함. */\n limit,\n page,\n ...(await this.fetchHandler.call(null, {\n page,\n limit,\n sorters: this.sorters,\n sortings: this.sorters,\n filters: this.filters,\n options: this.fetchOptions\n }))\n },\n reset\n )\n }\n\n async fetch({\n page = this.page,\n limit = this.limit,\n sorters,\n sortings,\n filters\n }: {\n page?: number\n limit?: number\n sorters?: SortersConfig\n sortings?: SortersConfig\n filters?: FilterValue[]\n } = {}) {\n /* sortings property is only for things-factory server-side list parameter convention */\n /* fetchHandler should reture { page, limit, total, records } */\n this.records = ZERO_RECORDS\n\n sorters = sorters || sortings || this.sorters\n filters = filters || this.filters\n\n this.sorters = sorters\n\n return this._update({\n /* fetch에서 limit과 page를 제공하지 않는 경우를 대비함. */\n limit,\n page,\n ...(await this.fetchHandler.call(null, {\n page,\n limit,\n sorters,\n sortings: sorters,\n filters,\n options: this.fetchOptions\n }))\n })\n }\n\n async _update(\n {\n page,\n limit,\n total,\n records\n }: {\n page: number\n limit: number\n total: number\n records: GristRecord[]\n },\n reset?: boolean\n ): Promise<void> {\n // total을 감안해서 page가 최대값을 넘지 않도록 한다.\n var maxpage = _calculateTotalPage(limit, total)\n if (maxpage < page) {\n return await this.fetch({ page: maxpage, limit })\n }\n\n // page와 limit이 없는 경우 records 검사 전에 초기화\n this.page = this.page || page\n this.limit = this.limit || limit\n\n if (!records) {\n return\n }\n\n if (this.records === ZERO_RECORDS) {\n this.records = records\n } else if (this.page < page) {\n // attach인 경우에는 records를 append한다.\n this.records = [...this.records, ...records]\n } else {\n return\n }\n\n this.limit = limit\n this.total = total\n this.page = page\n\n this.consumer &&\n (this.consumer.data = {\n page: this.page,\n limit: this.limit,\n total: this.total,\n\n records: this.records\n })\n }\n}\n"]}
1
+ {"version":3,"file":"data-provider.js","sourceRoot":"","sources":["../../src/data-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { ZERO_RECORDS } from './configure/zero-config.js'\nimport { DataConsumer } from './data-consumer.js'\nimport { FetchHandler, FetchOption, FilterValue, GristRecord, SorterConfig, SortersConfig } from './types.js'\n\nfunction EMPTY_FETCHHANDLER() {\n return {\n total: 0,\n records: []\n }\n}\n\nfunction _calculateTotalPage(limit: number, total: number) {\n /*\n * total page는 1이상이어야 한다.\n * 즉, 레코드가 하나도 없어도, 페이지 갯수는 1이 되어야 한다.\n */\n return Math.max(1, Math.ceil(total / limit))\n}\n\n/*\n * For fetches nobody awaits (page and limit changes, filter and option changes). This does not hide a\n * failure: fetchFailed has already drawn it on the grid before the rejection gets here. It only stops\n * the same failure from also escaping as an unhandled rejection. Do not copy it to a place where the\n * failure is not already shown.\n */\nconst shownByConsumer = () => {}\n\nexport class DataProvider {\n page: number = 1\n limit: number = 20\n total: number = 0\n records: GristRecord[] = []\n\n private consumer?: DataConsumer\n private _fetchHandler?: FetchHandler\n private _sorters?: SorterConfig[]\n private _filters?: FilterValue[]\n /*\n * 검색 낱말 — `search-mode=\"term\"` 에서만 찬다. 옛 길은 낱말을 칸별 필터로 바꿔 `_filters` 에\n * 넣으므로 이 자리는 비어 있고, 그래서 두 길이 한 화면에서 같이 서지 않는다.\n */\n private _search?: string\n\n private _pageChangeHandler: EventListener = this.onPageChange.bind(this)\n private _limitChangeHandler = this.onLimitChange.bind(this)\n private _fetchParamsChangeHandler = this.onFetchParamsChange.bind(this)\n private _recordChangeHandler = this.onRecordChange.bind(this)\n private _attachPageHandler: EventListener = this.onAttachPage.bind(this)\n\n private _fetchHandlerWrap: any\n private _fetchOptions: any\n\n constructor(consumer: DataConsumer) {\n this.consumer = consumer\n\n this.fetchHandler = consumer.fetchHandler\n\n this.consumer.addEventListener('attach-page', this._attachPageHandler)\n this.consumer.addEventListener('page-change', this._pageChangeHandler)\n this.consumer.addEventListener('limit-change', this._limitChangeHandler)\n this.consumer.addEventListener('fetch-params-change', this._fetchParamsChangeHandler)\n this.consumer.addEventListener('record-change', this._recordChangeHandler)\n }\n\n dispose() {\n this.consumer?.removeEventListener('attach-page', this._attachPageHandler)\n this.consumer?.removeEventListener('page-change', this._pageChangeHandler)\n this.consumer?.removeEventListener('limit-change', this._limitChangeHandler)\n this.consumer?.removeEventListener('fetch-params-change', this._fetchParamsChangeHandler)\n this.consumer?.removeEventListener('record-change', this._recordChangeHandler)\n }\n\n onAttachPage() {\n this.attach().catch(shownByConsumer)\n }\n\n onPageChange(e: Event) {\n var page = (e as CustomEvent).detail\n this.fetch({ page }).catch(shownByConsumer)\n }\n\n onLimitChange(e: Event) {\n var limit = (e as CustomEvent).detail\n this.fetch({ limit }).catch(shownByConsumer)\n }\n\n onFetchParamsChange(e: Event) {\n const { sorters, filters, search, from } = (e as CustomEvent).detail || {}\n\n sorters && (this.sorters = sorters)\n filters && (this.filters = filters)\n /* 빈 낱말도 값이다 — 「검색을 지웠다」를 지난 낱말로 덮으면 목록이 안 돌아온다. */\n search !== undefined && (this._search = search)\n\n if (this.consumer?.mode !== 'GRID') {\n this.page = 0\n }\n\n from !== 'config' && this.fetch().catch(shownByConsumer)\n }\n\n onRecordChange(e: Event) {\n this.consumer?.checkDirties()\n }\n\n get fetchOptions() {\n return this._fetchOptions\n }\n\n set fetchOptions(fetchOptions) {\n this._fetchOptions = fetchOptions\n\n this.fetch().catch(shownByConsumer)\n }\n\n get fetchHandler() {\n if (!this._fetchHandlerWrap) {\n this._fetchHandlerWrap = async (options: FetchOption) => {\n if (!this._fetchHandler) {\n return\n }\n\n try {\n this.consumer?.showSpinner()\n const result = await (this._fetchHandler || EMPTY_FETCHHANDLER)(options)\n this.consumer?.fetchSucceeded?.()\n return result\n } catch (error) {\n /*\n * A failed read is not an empty list. The grid is told, so it can say \"could not load\"\n * instead of \"nothing to show\" - and the error still reaches whoever awaited the fetch.\n */\n this.consumer?.fetchFailed?.(error)\n throw error\n } finally {\n this.consumer?.hideSpinner()\n }\n }\n }\n\n return this._fetchHandlerWrap\n }\n\n set fetchHandler(fetchHandler) {\n this._fetchHandler = fetchHandler\n delete this._fetchHandlerWrap\n }\n\n get sorters() {\n return this._sorters\n }\n\n set sorters(sorters) {\n this._sorters = sorters\n }\n\n /* alias for sorters */\n get sortings() {\n return this._sorters\n }\n\n set sortings(sorters) {\n this._sorters = sorters\n }\n\n get filters() {\n return this._filters\n }\n\n set filters(filters) {\n this._filters = filters\n }\n\n async attach(reset = false) {\n var { page = 0, limit = 20 } = this\n\n /*\n * page는 0 based index가 아님에 주의한다.\n * 즉, page 값이 1 은 첫페이지를 의미한다.\n */\n if (reset) {\n this.records = ZERO_RECORDS\n page = 1\n } else {\n /* attach의 경우는 grist data의 변경상태를 유지하기 위해서, grist._data 를 기반으로 한다. */\n this.records = this.consumer?._data ? this.consumer._data.records : ZERO_RECORDS\n page = page + 1\n }\n\n return this._update(\n {\n /* fetch에서 limit과 page를 제공하지 않는 경우를 대비함. */\n limit,\n page,\n ...(await this.fetchHandler.call(null, {\n page,\n limit,\n sorters: this.sorters,\n sortings: this.sorters,\n filters: this.filters,\n options: this.fetchOptions\n }))\n },\n reset\n )\n }\n\n async fetch({\n page = this.page,\n limit = this.limit,\n sorters,\n sortings,\n filters\n }: {\n page?: number\n limit?: number\n sorters?: SortersConfig\n sortings?: SortersConfig\n filters?: FilterValue[]\n } = {}) {\n /* sortings property is only for things-factory server-side list parameter convention */\n /* fetchHandler should reture { page, limit, total, records } */\n this.records = ZERO_RECORDS\n\n sorters = sorters || sortings || this.sorters\n filters = filters || this.filters\n\n this.sorters = sorters\n\n return this._update({\n /* fetch에서 limit과 page를 제공하지 않는 경우를 대비함. */\n limit,\n page,\n ...(await this.fetchHandler.call(null, {\n page,\n limit,\n sorters,\n sortings: sorters,\n /* 안 쓰는 화면에 빈 칸을 보내지 않는다 — 옛 길 소비자의 fetchHandler 가 그날 안 바뀐다. */\n ...(this._search ? { search: this._search } : {}),\n filters,\n options: this.fetchOptions\n }))\n })\n }\n\n async _update(\n {\n page,\n limit,\n total,\n records\n }: {\n page: number\n limit: number\n total: number\n records: GristRecord[]\n },\n reset?: boolean\n ): Promise<void> {\n // total을 감안해서 page가 최대값을 넘지 않도록 한다.\n var maxpage = _calculateTotalPage(limit, total)\n if (maxpage < page) {\n return await this.fetch({ page: maxpage, limit })\n }\n\n // page와 limit이 없는 경우 records 검사 전에 초기화\n this.page = this.page || page\n this.limit = this.limit || limit\n\n if (!records) {\n return\n }\n\n if (this.records === ZERO_RECORDS) {\n this.records = records\n } else if (this.page < page) {\n // attach인 경우에는 records를 append한다.\n this.records = [...this.records, ...records]\n } else {\n return\n }\n\n this.limit = limit\n this.total = total\n this.page = page\n\n this.consumer &&\n (this.consumer.data = {\n page: this.page,\n limit: this.limit,\n total: this.total,\n\n records: this.records\n })\n }\n}\n"]}
@@ -179,6 +179,7 @@ export declare enum InheritedValueType {
179
179
  * @property {SortersConfig} [sorters] - An array of sorting configurations for data. Only one of these options needs to be set.
180
180
  * @property {SortersConfig} [sortings] - An array of sorting configurations for data. Only one of these options needs to be set.
181
181
  * @property {QueryFilter[]} [filters] - An array of filtering criteria.
182
+ * @property {string} [search] - A single free-text term, carried as given. The resolver matches it across the fields it declares as searchable, so the screen does not carry a copy of that list.
182
183
  * @property {InheritedValueType} [inherited] - Specifies the inheritance behavior for including data from parent domains.
183
184
  * @property {object} [options] - Additional options for customizing data fetching behavior.
184
185
  */
@@ -188,6 +189,7 @@ export type FetchOption = {
188
189
  sorters?: SortersConfig;
189
190
  sortings?: SortersConfig;
190
191
  filters?: QueryFilter[];
192
+ search?: string;
191
193
  inherited?: InheritedValueType;
192
194
  options?: object;
193
195
  };
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AA6LA;;;;;;;;GAQG;AACH,MAAM,CAAN,IAAY,kBAIX;AAJD,WAAY,kBAAkB;IAC5B,mCAAa,CAAA;IACb,yCAAmB,CAAA;IACnB,mCAAa,CAAA;AACf,CAAC,EAJW,kBAAkB,KAAlB,kBAAkB,QAI7B;AAooBD,MAAM,CAAN,IAAY,gBAKX;AALD,WAAY,gBAAgB;IAC1B,2CAAuB,CAAA;IACvB,qCAAiB,CAAA;IACjB,mCAAe,CAAA;IACf,qCAAiB,CAAA;AACnB,CAAC,EALW,gBAAgB,KAAhB,gBAAgB,QAK3B","sourcesContent":["import { TemplateResult } from 'lit-html'\n\nimport { DataCardField } from './data-card/data-card-field.js'\nimport { DataCardGutter } from './data-card/data-card-gutter.js'\nimport { RecordCard } from './data-card/record-card.js'\nimport { DataGridField } from './data-grid/data-grid-field.js'\nimport { DataListField } from './data-list/data-list-field.js'\nimport { DataListGutter } from './data-list/data-list-gutter.js'\nimport { RecordPartial } from './data-list/record-partial.js'\nimport { DataReportField } from './data-report/data-report-field.js'\nimport { OxGristEditor } from './editors/index.js'\nimport { QueryFilter, OxFiltersForm } from './filters/index.js'\nimport { OxGristRenderer } from './renderers/ox-grist-renderer.js'\n\n/**\n * Configuration object for defining the structure and behavior of a Grist table.\n *\n * @typedef {Object} GristConfig\n * @property {ColumnConfig[]} columns - An array of column configurations.\n * @property {RowsConfig} rows - Configuration for rows and their behavior.\n * @property {ListConfig} list - Configuration for the list view.\n * @property {TreeConfig} tree - Configuration for tree-related settings.\n * @property {PaginationConfig} [pagination] - Configuration for pagination settings (optional).\n * @property {SortersConfig} [sorters] - Configuration for sorting settings (optional).\n * @property {FiltersConfig} [filters] - Configuration for filtering settings (optional).\n */\nexport type GristConfig = {\n columns: ColumnConfig[]\n rows: RowsConfig\n list: ListConfig\n tree: TreeConfig\n pagination?: PaginationConfig\n sorters?: SortersConfig\n filters?: FiltersConfig\n /**\n * 아직 아무것도 없을 때 화면이 하는 말.\n *\n * 전에는 「NO RECORDS」가 컴포넌트에 박혀 있었다. 그 문장은 다음에 무엇을 할지 알려 주지 않는다 —\n * **비어 있는 화면이야말로** 「여기서 무엇을 만들 수 있고 그것이 무엇에 쓰이나」를 말해야 하는 자리이고,\n * 처음 오는 사람이 가장 먼저 보는 화면이기도 하다.\n *\n * 정하지 않으면 예전 문장이 그대로 나온다.\n */\n emptyNote?: { title?: string; description?: string; icon?: string }\n}\n\n/**\n * Configuration object for specifying sorting options.\n *\n * @typedef {Object} SorterConfig\n * @property {string} name - The name of the sorting option.\n * @property {boolean} [desc] - Optional. Indicates whether the sorting is in descending order (optional).\n */\nexport type SorterConfig = { name: string; desc?: boolean }\n\n/**\n * Configuration array for specifying multiple sorting options.\n *\n * @typedef {SorterConfig[]} SortersConfig\n */\nexport type SortersConfig = SorterConfig[]\n\n/**\n * Enumeration of filter operators used to define filter conditions.\n *\n * @typedef {'search' | 'eq' | 'between' | 'gte' | 'lte' | 'is_not_true' | 'in' | 'like' | 'i_like' | 'noteq' |\n * 'is_empty_num_id' | 'is_blank' | 'is_present' | 'is_not_false' | 'is_true' | 'is_false' | 'is_not_null' |\n * 'is_null' | 'notin_with_null' | 'notin' | 'gt' | 'lt' | 'i_nlike' | 'nlike'} FilterOperator\n */\nexport type FilterOperator =\n | 'search'\n | 'eq'\n | 'between'\n | 'gte'\n | 'lte'\n | 'is_not_true'\n | 'in'\n | 'like'\n | 'i_like'\n | 'noteq'\n | 'is_empty_num_id'\n | 'is_blank'\n | 'is_present'\n | 'is_not_false'\n | 'is_true'\n | 'is_false'\n | 'is_not_null'\n | 'is_null'\n | 'notin_with_null'\n | 'notin'\n | 'gt'\n | 'lt'\n | 'i_nlike'\n | 'nlike'\n\nexport type SelectOptionObject =\n | {\n name: string\n display?: never\n value: string\n }\n | {\n display: string\n name?: never\n value: string\n }\n\nexport type SelectOption = SelectOptionObject | string\n\nexport type FilterChangedCallback = (value: any, form: OxFiltersForm) => boolean\n\n/**\n * Configuration object for specifying filter conditions.\n *\n * @typedef {Object} FilterConfigObject\n * @property {string} type - The type of the filter condition.\n * @property {FilterOperator} [operator] - The filter operator used to compare values (optional).\n * @property {Object} [options] - Additional options or parameters for the filter condition (optional).\n * @property {boolean|undefined} [hidden] - The hidden flag for the filter condition (optional).\n * @property {string|number|boolean|string[]|number[]|undefined} [value] - The value to compare with in the filter condition (optional).\n * @property {string} [label] - The label to display for the filter condition (optional).\n */\nexport type FilterConfigObject = {\n type: string\n operator?: FilterOperator\n options?: { [key: string]: any }\n value?: string | number | boolean | string[] | number[] | undefined\n label?: string\n boundTo?: string[]\n hidden?: boolean\n onchange?: FilterChangedCallback\n}\n\n/**\n * Configuration option for specifying filter conditions.\n *\n * The `FilterConfig` type can take one of the following forms:\n * - A `FilterConfigObject` representing a specific filter condition.\n * - A `FilterOperator` representing a predefined filter operator.\n * - A boolean value to enable or disable filtering for a specific column.\n *\n * @typedef {Object|FilterOperator|boolean} FilterConfig\n */\nexport type FilterConfig = FilterConfigObject | FilterOperator | boolean\n\n/**\n * Represents a filter condition with the following properties:\n *\n * - `name`: The name of the column or field being filtered.\n * - `operator`: The filter operator used for comparison.\n * - `value`: The value or values to compare against.\n *\n * @typedef {Object} FilterValue\n * @property {string} name - The name of the column or field.\n * @property {FilterOperator} operator - The filter operator.\n * @property {string|number|boolean|string[]|number[]|undefined} value - The value(s) to compare.\n */\nexport type FilterValue = {\n name: string\n operator: FilterOperator\n value: string | number | boolean | string[] | number[] | undefined\n}\n\n/**\n * Configuration options for filters.\n *\n * @typedef {Object} FiltersConfig\n * @property {boolean} [header] - Specifies whether to provide filtering functionality in the header.\n */\nexport type FiltersConfig = {\n header?: boolean\n}\n\n/**\n * Configuration options for pagination.\n *\n * @typedef {Object} PaginationConfig\n * @property {number} [page] - The current page number.\n * @property {number} [limit] - The maximum number of records to display per page.\n * @property {number[]} [pages] - An array of available page numbers.\n * @property {boolean} [infinite] - Specifies whether to use infinite scrolling for pagination.\n */\nexport type PaginationConfig = {\n page?: number\n limit?: number\n pages?: number[]\n infinite?: boolean\n}\n\n/**\n * Option to specify the inheritance behavior for including data from parent domains.\n *\n * - 'None': Do not include data from the parent domain.\n * - 'Include': Include data from the parent domain along with current domain data.\n * - 'Only': Include data only from the parent domain, excluding current domain data.\n *\n * @enum {string}\n */\nexport enum InheritedValueType {\n None = 'None',\n Include = 'Include',\n Only = 'Only'\n}\n\n/**\n * Configuration options for fetching data from a data source.\n *\n * @typedef {Object} FetchOption\n * @property {number} [page] - The page number to retrieve.\n * @property {number} [limit] - The maximum number of records to retrieve per page.\n * @property {SortersConfig} [sorters] - An array of sorting configurations for data. Only one of these options needs to be set.\n * @property {SortersConfig} [sortings] - An array of sorting configurations for data. Only one of these options needs to be set.\n * @property {QueryFilter[]} [filters] - An array of filtering criteria.\n * @property {InheritedValueType} [inherited] - Specifies the inheritance behavior for including data from parent domains.\n * @property {object} [options] - Additional options for customizing data fetching behavior.\n */\nexport type FetchOption = {\n page?: number\n limit?: number\n sorters?: SortersConfig\n sortings?: SortersConfig\n filters?: QueryFilter[]\n inherited?: InheritedValueType\n options?: object\n}\n\n/**\n * Represents the result of a data fetching operation.\n *\n * @typedef {Object} FetchResult\n * @property {number} [page] - The page number of the fetched data.\n * @property {number} [limit] - The maximum number of records per page.\n * @property {number} total - The total number of records in the data source.\n * @property {GristRecord[]} records - An array of fetched data records.\n */\nexport type FetchResult = {\n page?: number\n limit?: number\n total: number\n records: GristRecord[]\n} | void\n\n/**\n * A function that handles data fetching operations.\n *\n * @param param - The fetch options specifying how data should be retrieved.\n * @returns A promise that resolves to a `FetchResult`.\n */\nexport type FetchHandler = (param: FetchOption) => Promise<FetchResult>\n\n/**\n * Represents a Grist event handler function.\n *\n * @typedef {Function} GristEventHandler\n * @param {ColumnConfig[]} columns - An array of column configurations.\n * @param {GristData} [data] - The Grist data associated with the event.\n * @param {ColumnConfig} [column] - The column configuration related to the event (if applicable).\n * @param {GristRecord} [record] - The Grist record related to the event (if applicable).\n * @param {number} [rowIndex] - The index of the row related to the event (if applicable).\n * @param {any} [target] - The target element or object related to the event (if applicable).\n * @param {Event} [e] - The event object (if applicable).\n * @returns {void}\n */\nexport type GristEventHandler = (\n columns: ColumnConfig[],\n data?: GristData,\n column?: ColumnConfig,\n record?: GristRecord,\n rowIndex?: number,\n target?: any,\n e?: Event\n) => void\n\n/**\n * Represents an accumulator function for data aggregation and accumulation.\n *\n * @typedef {string|'sum'|'avg'|'count'|'min'|'max'|Function} AccumulatorFunc\n * @param {GristData} data - The Grist data for aggregation.\n * @param {ColumnConfig} column - The column configuration for aggregation.\n * @returns {string|number} - The aggregated result.\n */\nexport type AccumulatorFunc =\n | 'sum'\n | 'avg'\n | 'count'\n | 'min'\n | 'max'\n | ((data: GristData, column: ColumnConfig) => string | number)\n\n/**\n * Type representing an accumulator function or configuration object.\n *\n * An accumulator is used for data aggregation and accumulation purposes. It can be either\n * a predefined accumulator function (e.g., 'sum', 'avg', 'count', etc.) or a configuration\n * object specifying the type of accumulator and labeling options.\n *\n * @typedef {AccumulatorFunc|{type: AccumulatorFunc, tag?: boolean}} AccumulatorObject\n * @property {AccumulatorFunc} [type] - The type of accumulator function or predefined function name.\n * @property {boolean} [tag] - An option for adding a label to represent the result of an aggregation function. This label is added in front of the aggregated value.\n *\n * @example\n * // Using a predefined accumulator function:\n * const accumulator: AccumulatorObject = 'sum'; // Represents a 'sum' accumulator.\n *\n * // Using an accumulator configuration object:\n * const accumulatorConfig: AccumulatorObject = {\n * type: 'avg', // Specifies the type of accumulator ('avg' for average).\n * tag: true, // Option for adding a label to represent the result of an aggregation function. This label is added in front of the aggregated value.\n * };\n */\nexport type AccumulatorObject =\n | AccumulatorFunc\n | {\n type: AccumulatorFunc\n tag?: boolean\n }\n\n/**\n * Type representing column configuration information.\n *\n * @typedef {object} ColumnConfig\n * @property {string} type - Represents the data type of the column (e.g., 'text', 'number', 'date', 'gutter', etc.).\n * @property {string} name - Represents the name of the column.\n * @property {('button'|'sequence'|'row-selector'|'dirty')} [gutterName] - If the column type is 'gutter', specifies the name of one of the registered gutters (only set when the type is 'gutter').\n * @property {boolean} [fixed] - In case of a grid type column, specifies whether the column's position should be fixed and unaffected by horizontal scrolling (optional).\n * @property {HeaderConfig} header - Object representing the header configuration of the column.\n * @property {RecordConfig} record - Object representing the record configuration of the column.\n * @property {GristEventHandlerSet} handlers - Object representing the Grist event handler settings.\n * @property {LabelConfig} label - Object representing the label configuration of the column. This property is used to represent the label of the column's information in list mode, card mode, and when displaying the column in a filter form (ox-filters-form).\n * @property {boolean} [hidden] - Indicates whether the column is hidden or not (optional).\n * @property {boolean} [sortable] - Indicates whether the column is sortable or not (optional). If this setting is true, the header provides the ability to toggle the sorting direction.\n * @property {boolean} [resizable] - Indicates whether the column is resizable or not (optional). This setting determines whether the column's width can be adjusted.\n * @property {(number|string|ColumnWidthCallback)} [width] - Represents the width of the column (e.g., 100, '50%', or a callback function to calculate width).\n * @property {boolean} [forList] - Indicates whether the column is intended for display in list mode (optional, applicable only to gutter type columns).\n * @property {boolean} [forCard] - Indicates whether the column is intended for display in card mode (optional, applicable only to gutter type columns).\n * @property {ValidationCallback} [validation] - Callback function for column validation (optional). This function validates whether the value of the column is valid when edited.\n * @property {AccumulatorObject} [accumulator] - Object used for accumulating values of the column (optional, applicable only in grid mode). It specifies a function to automatically aggregate the values of the column for all records. The aggregated result is displayed in a row below the last record (accumulation record).\n * @property {FilterConfig} [filter] - Object representing the filter configuration of the column.\n * @property {(ImexConfig|boolean)} [imex] - Object or boolean value representing the configuration for importing and exporting column data.\n * @property {boolean} [multiple] - Indicates whether the column allows multiple selections or not (optional).\n * @property {boolean} [rowCount] - Indicates whether the column shows the row count or not (optional).\n */\nexport type ColumnConfig = {\n type: string\n name: string\n /**\n * \"gutter\" 타입의 컬럼인 경우, 등록된 gutter들 중의 하나의 이름을 명시합니다(type이 gutter인 경우에만 설정합니다).\n * (e.g., 'button', 'sequence', 'row-selector', 'dirty', etc)\n *\n * \"Gutter\" 는 테이블에서 각 행의 왼쪽이나 오른쪽에 놓이는 추가 열(column)을 뜻합니다.\n * 이 열은 주로 각 행(row)을 식별하거나 특정 작업을 수행하기 위한 버튼 또는 링크와 같은 요소를 표시하는 데 사용됩니다.\n * Gutter 열은 주로 데이터 행에 대한 조작 또는 행의 상태를 나타내는 데 사용됩니다.\n * 예를 들어, 테이블에서 각 행이 특정 작업을 수행하는 버튼을 포함할 때, 이러한 버튼이 Gutter 열에 배치될 수 있습니다.\n * 또한 Gutter 열은 행을 선택하거나 행의 상태를 나타내는 체크박스를 포함할 수도 있습니다.\n */\n gutterName?: 'button' | 'sequence' | 'row-selector' | 'dirty'\n title?: string\n fixed?: boolean\n /** [begin] only for button gutter column */\n icon?: string\n iconOnly?: boolean\n danger?: boolean\n /** [end] only for button gutter column */\n header: HeaderConfig\n record: RecordConfig\n handlers: GristEventHandlerSet\n label: LabelConfig\n hidden?: boolean\n sortable?: boolean\n resizable?: boolean\n width?: number | string | ColumnWidthCallback\n forList?: boolean\n forCard?: boolean\n validation?: ValidationCallback\n accumulator?: AccumulatorObject\n filter?: FilterConfig\n imex?: ImexConfig | boolean\n multiple?: boolean\n rowCount?: boolean\n /** 특정 도구에 의해서 사용되는 옵션으로, 일반적인 용도로 사용되지 않음을 표현할 수 있다. */\n unusable?: boolean\n multiline?: boolean // 멀티라인 여부\n}\n\n/**\n * Callback function type for column validation.\n *\n * This function is used to validate whether the value of a column is valid when edited.\n *\n * @callback ValidationCallback\n * @param {any} after - The new value of the column after editing.\n * @param {any} before - The previous value of the column before editing.\n * @param {GristRecord} record - The record being edited.\n * @param {ColumnConfig} column - The configuration of the column being edited.\n * @returns {boolean} - Returns `true` if the value is valid, `false` otherwise.\n */\nexport type ValidationCallback = (\n after: any,\n before: any,\n record: GristRecord,\n column: ColumnConfig\n) => boolean | Promise<boolean>\n\n/**\n * Configuration options for column labels.\n *\n * The label for a column can be customized using various options.\n *\n * @typedef {string|boolean|Object} LabelConfig\n * @property {LabelRenderer} [renderer] - A custom renderer function for the column label.\n *\n * @example\n * // Using a string as a label:\n * const label: LabelConfig = \"Column Label\"; // Sets the label as \"Column Label\".\n *\n * // Using a boolean to determine label visibility:\n * const label: LabelConfig = true; // Shows the default label based on the header configuration.\n *\n * // Using a custom renderer function for the label:\n * const label: LabelConfig = {\n * renderer: customLabelRenderer, // Specifies a custom renderer function.\n * };\n */\nexport type LabelConfig =\n | string\n | boolean\n | {\n renderer: LabelRenderer\n /** Same as HeaderConfig.text — the name itself, not what was drawn from it. */\n text?: string\n }\n\n/**\n * Custom label renderer function for generating column labels.\n *\n * @callback LabelRenderer\n * @param {ColumnConfig} column - The column configuration object for which the label is being generated.\n * @returns {void}\n */\nexport type LabelRenderer = (column: ColumnConfig) => void\n\n/**\n * Custom callback function for calculating column width.\n *\n * @callback ColumnWidthCallback\n * @param {ColumnConfig} column - The column configuration object for which the width is being calculated.\n * @returns {string} - The calculated width as a string (e.g., '100', '50%').\n */\nexport type ColumnWidthCallback = (column: ColumnConfig) => string\n\n/**\n * Configuration for defining the header of a column.\n *\n * @typedef {Object} HeaderConfig\n * @property {HeaderRenderer} renderer - The function used to render the column header.\n * @property {string} [style] - Optional CSS style for the column header.\n * @property {string} [group] - Optional group identifier for the column header.\n * @property {string} [groupStyle] - Optional CSS style for the header group.\n */\nexport type HeaderConfig = {\n renderer: HeaderRenderer\n /**\n * The column's name as plain text.\n *\n * `renderer` returns whatever gets drawn — a lit template, an icon — and the name cannot be read\n * back out of that. So a name given as a string in the config is kept here, for the places that\n * need it outside of rendering: the accessible name of a cell, and header filter inputs.\n */\n text?: string\n style?: string\n group?: string\n groupStyle?: string\n}\n\n/**\n * Function type for rendering column headers.\n *\n * @callback HeaderRenderer\n * @param {ColumnConfig} column - The column configuration object.\n * @returns {*} - The rendered header content.\n */\nexport type HeaderRenderer = (column: ColumnConfig) => any\n\n/**\n * Configuration for specifying default values for fields in a record.\n * Default values can be set using predefined value generator functions or custom user-defined functions.\n * This configuration allows you to define the default value generation method and any additional parameters.\n *\n * @typedef {Object|Function} DefaultValueFnConfig\n * @property {string} [name] - The name of the default value function to be used for the column.\n * @property {any[]} [params] - The parameters to be passed to the default value function.\n * @property {Function} [Function] - A custom user-defined function for generating default values.\n */\nexport type DefaultValueFnConfig =\n | {\n /**\n * The name of the default value function to be used for the column.\n */\n name: string\n\n /**\n * The parameters to be passed to the default value function.\n */\n params?: any[]\n }\n | Function\n\n/**\n * Configuration for defining fields within a record.\n * Each field can have various settings such as rendering, editing, alignment, etc.\n * The 'defaultValue' property is used to specify the default value generation method and parameters.\n *\n * @typedef {Object} RecordConfig\n * @property {FieldRenderer} renderer - The rendering function for the field.\n * @property {FieldEditor|undefined} [editor] - The editing function for the field (optional).\n * @property {boolean|Function} [editable] - Specifies if the field is editable. It can be a boolean or a function (optional).\n * @property {boolean} [mandatory] - Specifies if the field is mandatory (optional).\n * @property {GristClassifier} classifier - A classifier function for the field.\n * @property {'left'|'right'|'center'} [align] - The alignment of the field's content (optional).\n * @property {*} options - Additional options for the field.\n * @property {string|undefined} [rowOptionField] - The name of a field for row-level options associated with this field (optional).\n * @property {DefaultValueFnConfig|undefined} [defaultValue] - Configuration for specifying the default value for the field.\n * It can be a predefined value generator function or a custom user-defined function (optional).\n * @property {Object.<string, *>|undefined} [extended] - Additional extended properties that can be added as needed for specific field configurations (optional).\n * @property {boolean} [wide] - Specifies if the field should occupy a larger width within the viewer or editor.\n * When set to `true`, the field will attempt to span across multiple columns or occupy more space horizontally.\n */\nexport type RecordConfig = {\n renderer: FieldRenderer\n editor?: FieldEditor\n editable?: boolean | Function\n mandatory?: boolean\n disabled?: boolean | Function\n classifier: GristClassifier\n align?: 'left' | 'right' | 'center'\n options: any\n rowOptionField?: string\n defaultValue?: DefaultValueFnConfig\n wide?: boolean\n /**\n * Draw the field even when the record has no value for it (card mode's thumbnail).\n *\n * A thumbnail with no value is normally not drawn at all, so a list of records without images\n * does not show a column of broken-image marks. A renderer that draws the empty case itself —\n * and anything it overlays on the picture — needs the element regardless, and only the renderer\n * knows that. Off by default.\n */\n renderEmpty?: boolean\n [extended: string]: any\n}\n\n/**\n * A function type used for rendering the content of a field in various components.\n *\n * @callback FieldRenderer\n * @param {*} value - The value of the field to be rendered.\n * @param {ColumnConfig} column - The configuration of the column to which the field belongs.\n * @param {GristRecord} record - The record object containing the field's data.\n * @param {number} rowIndex - The index of the row to which the field belongs.\n * @param {DataGridField|RecordCard|DataCardGutter|DataCardField|DataListGutter|DataListField|RecordPartial|DataReportField|Element} owner - The component or element that owns the field.\n * @returns {OxGristRenderer|TemplateResult|string|void} - The rendered content, which can be of different types depending on the implementation.\n */\nexport type FieldRenderer = (\n value: any,\n column: ColumnConfig,\n record: GristRecord,\n rowIndex: number,\n owner:\n | DataGridField\n | RecordCard\n | DataCardGutter\n | DataCardField\n | DataListGutter\n | DataListField\n | RecordPartial\n | DataReportField\n | Element\n) => OxGristRenderer | TemplateResult | string | void\n\n/**\n * A function type used for defining a custom editor for a field in a data grid.\n *\n * @callback FieldEditor\n * @param {*} value - The current value of the field.\n * @param {ColumnConfig} column - The configuration of the column to which the field belongs.\n * @param {GristRecord} record - The record object containing the field's data.\n * @param {number} rowIndex - The index of the row to which the field belongs.\n * @param {DataGridField} field - The data grid field that owns the editor.\n * @returns {OxGristEditor} - The custom editor component.\n */\nexport type FieldEditor = (\n value: any,\n column: ColumnConfig,\n record: GristRecord,\n rowIndex: number,\n field: DataGridField\n) => OxGristEditor\n\n/**\n * A function type used for rendering the filter select options in a filter form.\n *\n * @callback FilterSelectRenderer\n * @param {ColumnConfig} column - The configuration of the column for which the filter is being rendered.\n * @param {(string|number|boolean|string[]|number[]|any|undefined)} value - The current value of the filter.\n * @param {Element} owner - The DOM element that owns the filter select renderer.\n * @returns {(TemplateResult|string|void)} - The rendered filter select options as a Lit HTML template result, a string, or nothing.\n */\nexport type FilterSelectRenderer = (\n column: ColumnConfig,\n value: string | number | boolean | string[] | number[] | any | undefined,\n owner: Element\n) => TemplateResult | string | void\n\n/**\n * An object representing a set of event handler functions for various events in Grist.\n *\n * @typedef {Object} GristEventHandlerSet\n * @property {GristEventHandler} [click] - The click event handler function.\n * @property {GristEventHandler} [dblclick] - The double-click event handler function.\n * @property {GristEventHandler} [focus] - The focus event handler function.\n * @property {GristEventHandler} [contextmenu] - The context menu event handler function.\n */\nexport type GristEventHandlerSet = {\n click?: GristEventHandler\n dblclick?: GristEventHandler\n focus?: GristEventHandler\n contextmenu?: GristEventHandler\n}\n\n/**\n * Configuration options for defining how records are displayed in list mode in a Grist.\n *\n * @typedef {Object} ListConfig\n * @property {string} [thumbnail] - The name of the field to use as a thumbnail image for records in list mode.\n * @property {object} [emptyThumbnail] - What to draw where a record has no thumbnail. The slot keeps its\n * place either way so cards stay the same height; this says what it should say. Without it the slot is\n * drawn empty.\n * @property {string[]} fields - An array of field names to display in the list mode.\n * @property {string[]} details - An array of field names to display as additional details in the list mode.\n */\nexport type ListConfig = {\n thumbnail?: string\n emptyThumbnail?: {\n /** Material symbol name. */\n icon?: string\n /** One short line — already translated by the caller. */\n label?: string\n }\n fields: string[]\n details: string[]\n}\n\n/**\n * Configuration options for managing tree-like structures in a Grist table.\n *\n * @typedef {Object} TreeConfig\n * @property {string} [childrenProperty] - The property name that specifies the children of a record.\n * @property {boolean | Function} [expanded] - Specifies whether tree nodes are initially expanded or a function to determine the initial expansion state for a given record.\n */\nexport type TreeConfig = {\n childrenProperty?: string\n expanded?: boolean | ((x: GristRecord) => boolean)\n}\n\n/**\n * Configuration options for importing and exporting column data.\n *\n * @typedef {Object} ImexConfig\n * @property {string} header - The header text for the column in import/export settings.\n * @property {string} key - The key or identifier for the column in import/export settings.\n * @property {number} width - The width of the column in import/export settings.\n * @property {string} type - The data type of the column in import/export settings.\n */\nexport type ImexConfig = {\n header: string\n key: string\n width: number\n type: string\n}\n\n/**\n * Configuration options for defining rows within a Grist table or view.\n *\n * @typedef {Object} RowsConfig\n * @property {boolean} [accumulator] - Specifies whether an accumulator row should be displayed.\n * @property {boolean} appendable - Indicates whether new rows can be appended to the table.\n * @property {boolean} insertable - Indicates whether new rows can be inserted into the table.\n * @property {RowSelectableConfig} [selectable] - Configuration for row selection options.\n * @property {GroupConfig[]} groups - An array of group configuration options.\n * @property {string[]} totals - An array of field names for which totals should be calculated and displayed.\n * @property {GristClassifier} classifier - A function that classifies rows based on their attributes.\n * @property {GristEventHandlerSet} handlers - An object containing event handler functions for various row-level events.\n */\nexport type RowsConfig = {\n accumulator?: boolean\n appendable: boolean\n editable: boolean\n insertable: boolean\n selectable?: RowSelectableConfig\n groups: GroupConfig[]\n totals: string[]\n classifier: GristClassifier\n handlers: GristEventHandlerSet\n}\n\n/**\n * A function used to classify and style individual records in a Grist table.\n *\n * @typedef {Function} GristClassifier\n *\n * @param {GristRecord} record - The record to be classified.\n * @param {number} rowIndex - The index of the row in the table.\n *\n * @returns {Object|void} An object containing classification properties or `void`.\n * - `emphasized` (optional): A boolean, string, or array of strings indicating the emphasis style.\n * - Additional properties can be added as needed for custom styling.\n */\nexport type GristClassifier = (\n record: GristRecord,\n rowIndex: number\n) => { emphasized?: boolean | string | string[]; [key: string]: any } | void\n\n/**\n * Configuration options for defining group headers in a Grist table.\n *\n * @typedef {Object} GroupConfig\n *\n * @property {string} align - The alignment of the group header ('left', 'center', or 'right').\n * @property {ColumnConfig} [titleColumn] - The column configuration used as the title of the group (optional).\n * @property {string} title - The title of the group.\n * @property {string} [value] - A value associated with the group (optional).\n * @property {string} [groupName] - The name of the group (optional).\n * @property {number} [row] - The row index where the group header should appear (optional).\n * @property {string|number} column - The column name or index where the group header should appear.\n * @property {number} rowspan - The number of rows the group header should span.\n * @property {number} [colspan] - The number of columns the group header should span (optional).\n */\nexport type GroupConfig = {\n align: string\n titleColumn?: ColumnConfig\n title: string\n value?: string\n groupName?: string\n row?: number\n column: string | number\n rowspan: number\n colspan?: number\n}\n\n/**\n * Configuration options for specifying row selectability in a Grist table.\n *\n * @typedef {Object} RowSelectableConfig\n *\n * @property {boolean} [multiple] - Indicates whether multiple rows can be selected (optional).\n */\nexport type RowSelectableConfig = {\n multiple?: boolean\n}\n\n/**\n * Represents a data record in Grist.\n *\n * @typedef {Object} GristRecord\n * @property {string} [id] - The unique identifier for the record.\n * @property {string} [name] - The name or label associated with the record.\n * @property {GristRecord[]} [children] - An array of child records, if applicable.\n * @property {number} [__seq__] - A numeric sequence identifier for the record.\n * @property {string} [__dirty__] - Indicates if the record is dirty (changed).\n * @property {boolean} [__selected__] - Indicates if the record is selected.\n * @property {object[]} [__changes__] - An array of changes made to the record.\n * @property {object} [__dirtyfields__] - An object representing dirty (changed) fields in the record.\n * @property {any} [__origin__] - The original data or source of the record.\n * @property {boolean} [__collapsed__] - Indicates if the record is collapsed (e.g., in a tree view).\n * @property {number} [__depth__] - The depth or level of the record in a hierarchical structure.\n * @property {'checked' | 'half-checked' | 'unchecked'} [__check_in_tree__] - Indicates the check state of the record in a tree view.\n * @property {GristRecord[]} [__children__] - An array of child records in a tree view.\n * @property {any} [key] - Additional custom properties specific to the record.\n */\nexport type GristRecord = {\n id?: string\n name?: string\n children?: GristRecord[]\n __seq__?: number\n __dirty__?: string\n __selected__?: boolean\n __changes__?: object[]\n __dirtyfields__?: { [key: string]: any }\n __origin__?: any\n __collapsed__?: boolean\n __depth__?: number\n __check_in_tree__?: 'checked' | 'half-checked' | 'unchecked'\n __children__?: GristRecord[]\n [key: string]: any\n}\n\n/**\n * Represents a set of data retrieved from a Grist table.\n *\n * @typedef {Object} GristData\n *\n * @property {number} [page] - The page number of the retrieved data (optional).\n * @property {number} [total] - The total number of records in the data source (optional).\n * @property {number} [limit] - The maximum number of records per page (optional).\n * @property {GristRecord[]} records - An array of fetched data records.\n */\nexport type GristData = {\n page?: number\n total?: number\n limit?: number\n records: GristRecord[]\n}\n\n/**\n * A function that determines whether a Grist record should be selected or not.\n *\n * @callback GristSelectFunction\n * @param {GristRecord} record - The Grist record to evaluate.\n * @returns {boolean} - `true` if the record should be selected, `false` otherwise.\n */\nexport type GristSelectFunction = (record: GristRecord) => boolean\n\n/**\n * Defines a type for personalized grid settings. It includes individual column settings and additional configurations specific to a user's grid view.\n *\n * @typedef {Object} PersonalGristPreference\n * @property {Partial<ColumnConfig>[]} [columns] - Partially defines the configuration for each column in the grid.\n * Each element can include only some properties of the `ColumnConfig`, used for optionally overriding column settings.\n * @property {any} [key] - Allows for storing additional user-defined properties with dynamic keys.\n * This property can include various custom settings beyond the grid configuration, and the keys can be freely defined.\n */\nexport type PersonalGristPreference = {\n columns?: Partial<ColumnConfig>[]\n filters?: FilterPreference[]\n pagination?: PaginationConfig\n sorters?: SortersConfig\n mode?: 'GRID' | 'LIST' | 'CARD'\n [key: string]: any\n}\n\nexport type FilterPreference = {\n name: string\n hidden?: boolean\n value?: any\n}\n\nexport enum ValidationReason {\n MANDATORY = 'MANDATORY',\n FORMAT = 'FORMAT',\n RANGE = 'RANGE',\n UNIQUE = 'UNIQUE'\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AA6LA;;;;;;;;GAQG;AACH,MAAM,CAAN,IAAY,kBAIX;AAJD,WAAY,kBAAkB;IAC5B,mCAAa,CAAA;IACb,yCAAmB,CAAA;IACnB,mCAAa,CAAA;AACf,CAAC,EAJW,kBAAkB,KAAlB,kBAAkB,QAI7B;AAsoBD,MAAM,CAAN,IAAY,gBAKX;AALD,WAAY,gBAAgB;IAC1B,2CAAuB,CAAA;IACvB,qCAAiB,CAAA;IACjB,mCAAe,CAAA;IACf,qCAAiB,CAAA;AACnB,CAAC,EALW,gBAAgB,KAAhB,gBAAgB,QAK3B","sourcesContent":["import { TemplateResult } from 'lit-html'\n\nimport { DataCardField } from './data-card/data-card-field.js'\nimport { DataCardGutter } from './data-card/data-card-gutter.js'\nimport { RecordCard } from './data-card/record-card.js'\nimport { DataGridField } from './data-grid/data-grid-field.js'\nimport { DataListField } from './data-list/data-list-field.js'\nimport { DataListGutter } from './data-list/data-list-gutter.js'\nimport { RecordPartial } from './data-list/record-partial.js'\nimport { DataReportField } from './data-report/data-report-field.js'\nimport { OxGristEditor } from './editors/index.js'\nimport { QueryFilter, OxFiltersForm } from './filters/index.js'\nimport { OxGristRenderer } from './renderers/ox-grist-renderer.js'\n\n/**\n * Configuration object for defining the structure and behavior of a Grist table.\n *\n * @typedef {Object} GristConfig\n * @property {ColumnConfig[]} columns - An array of column configurations.\n * @property {RowsConfig} rows - Configuration for rows and their behavior.\n * @property {ListConfig} list - Configuration for the list view.\n * @property {TreeConfig} tree - Configuration for tree-related settings.\n * @property {PaginationConfig} [pagination] - Configuration for pagination settings (optional).\n * @property {SortersConfig} [sorters] - Configuration for sorting settings (optional).\n * @property {FiltersConfig} [filters] - Configuration for filtering settings (optional).\n */\nexport type GristConfig = {\n columns: ColumnConfig[]\n rows: RowsConfig\n list: ListConfig\n tree: TreeConfig\n pagination?: PaginationConfig\n sorters?: SortersConfig\n filters?: FiltersConfig\n /**\n * 아직 아무것도 없을 때 화면이 하는 말.\n *\n * 전에는 「NO RECORDS」가 컴포넌트에 박혀 있었다. 그 문장은 다음에 무엇을 할지 알려 주지 않는다 —\n * **비어 있는 화면이야말로** 「여기서 무엇을 만들 수 있고 그것이 무엇에 쓰이나」를 말해야 하는 자리이고,\n * 처음 오는 사람이 가장 먼저 보는 화면이기도 하다.\n *\n * 정하지 않으면 예전 문장이 그대로 나온다.\n */\n emptyNote?: { title?: string; description?: string; icon?: string }\n}\n\n/**\n * Configuration object for specifying sorting options.\n *\n * @typedef {Object} SorterConfig\n * @property {string} name - The name of the sorting option.\n * @property {boolean} [desc] - Optional. Indicates whether the sorting is in descending order (optional).\n */\nexport type SorterConfig = { name: string; desc?: boolean }\n\n/**\n * Configuration array for specifying multiple sorting options.\n *\n * @typedef {SorterConfig[]} SortersConfig\n */\nexport type SortersConfig = SorterConfig[]\n\n/**\n * Enumeration of filter operators used to define filter conditions.\n *\n * @typedef {'search' | 'eq' | 'between' | 'gte' | 'lte' | 'is_not_true' | 'in' | 'like' | 'i_like' | 'noteq' |\n * 'is_empty_num_id' | 'is_blank' | 'is_present' | 'is_not_false' | 'is_true' | 'is_false' | 'is_not_null' |\n * 'is_null' | 'notin_with_null' | 'notin' | 'gt' | 'lt' | 'i_nlike' | 'nlike'} FilterOperator\n */\nexport type FilterOperator =\n | 'search'\n | 'eq'\n | 'between'\n | 'gte'\n | 'lte'\n | 'is_not_true'\n | 'in'\n | 'like'\n | 'i_like'\n | 'noteq'\n | 'is_empty_num_id'\n | 'is_blank'\n | 'is_present'\n | 'is_not_false'\n | 'is_true'\n | 'is_false'\n | 'is_not_null'\n | 'is_null'\n | 'notin_with_null'\n | 'notin'\n | 'gt'\n | 'lt'\n | 'i_nlike'\n | 'nlike'\n\nexport type SelectOptionObject =\n | {\n name: string\n display?: never\n value: string\n }\n | {\n display: string\n name?: never\n value: string\n }\n\nexport type SelectOption = SelectOptionObject | string\n\nexport type FilterChangedCallback = (value: any, form: OxFiltersForm) => boolean\n\n/**\n * Configuration object for specifying filter conditions.\n *\n * @typedef {Object} FilterConfigObject\n * @property {string} type - The type of the filter condition.\n * @property {FilterOperator} [operator] - The filter operator used to compare values (optional).\n * @property {Object} [options] - Additional options or parameters for the filter condition (optional).\n * @property {boolean|undefined} [hidden] - The hidden flag for the filter condition (optional).\n * @property {string|number|boolean|string[]|number[]|undefined} [value] - The value to compare with in the filter condition (optional).\n * @property {string} [label] - The label to display for the filter condition (optional).\n */\nexport type FilterConfigObject = {\n type: string\n operator?: FilterOperator\n options?: { [key: string]: any }\n value?: string | number | boolean | string[] | number[] | undefined\n label?: string\n boundTo?: string[]\n hidden?: boolean\n onchange?: FilterChangedCallback\n}\n\n/**\n * Configuration option for specifying filter conditions.\n *\n * The `FilterConfig` type can take one of the following forms:\n * - A `FilterConfigObject` representing a specific filter condition.\n * - A `FilterOperator` representing a predefined filter operator.\n * - A boolean value to enable or disable filtering for a specific column.\n *\n * @typedef {Object|FilterOperator|boolean} FilterConfig\n */\nexport type FilterConfig = FilterConfigObject | FilterOperator | boolean\n\n/**\n * Represents a filter condition with the following properties:\n *\n * - `name`: The name of the column or field being filtered.\n * - `operator`: The filter operator used for comparison.\n * - `value`: The value or values to compare against.\n *\n * @typedef {Object} FilterValue\n * @property {string} name - The name of the column or field.\n * @property {FilterOperator} operator - The filter operator.\n * @property {string|number|boolean|string[]|number[]|undefined} value - The value(s) to compare.\n */\nexport type FilterValue = {\n name: string\n operator: FilterOperator\n value: string | number | boolean | string[] | number[] | undefined\n}\n\n/**\n * Configuration options for filters.\n *\n * @typedef {Object} FiltersConfig\n * @property {boolean} [header] - Specifies whether to provide filtering functionality in the header.\n */\nexport type FiltersConfig = {\n header?: boolean\n}\n\n/**\n * Configuration options for pagination.\n *\n * @typedef {Object} PaginationConfig\n * @property {number} [page] - The current page number.\n * @property {number} [limit] - The maximum number of records to display per page.\n * @property {number[]} [pages] - An array of available page numbers.\n * @property {boolean} [infinite] - Specifies whether to use infinite scrolling for pagination.\n */\nexport type PaginationConfig = {\n page?: number\n limit?: number\n pages?: number[]\n infinite?: boolean\n}\n\n/**\n * Option to specify the inheritance behavior for including data from parent domains.\n *\n * - 'None': Do not include data from the parent domain.\n * - 'Include': Include data from the parent domain along with current domain data.\n * - 'Only': Include data only from the parent domain, excluding current domain data.\n *\n * @enum {string}\n */\nexport enum InheritedValueType {\n None = 'None',\n Include = 'Include',\n Only = 'Only'\n}\n\n/**\n * Configuration options for fetching data from a data source.\n *\n * @typedef {Object} FetchOption\n * @property {number} [page] - The page number to retrieve.\n * @property {number} [limit] - The maximum number of records to retrieve per page.\n * @property {SortersConfig} [sorters] - An array of sorting configurations for data. Only one of these options needs to be set.\n * @property {SortersConfig} [sortings] - An array of sorting configurations for data. Only one of these options needs to be set.\n * @property {QueryFilter[]} [filters] - An array of filtering criteria.\n * @property {string} [search] - A single free-text term, carried as given. The resolver matches it across the fields it declares as searchable, so the screen does not carry a copy of that list.\n * @property {InheritedValueType} [inherited] - Specifies the inheritance behavior for including data from parent domains.\n * @property {object} [options] - Additional options for customizing data fetching behavior.\n */\nexport type FetchOption = {\n page?: number\n limit?: number\n sorters?: SortersConfig\n sortings?: SortersConfig\n filters?: QueryFilter[]\n search?: string\n inherited?: InheritedValueType\n options?: object\n}\n\n/**\n * Represents the result of a data fetching operation.\n *\n * @typedef {Object} FetchResult\n * @property {number} [page] - The page number of the fetched data.\n * @property {number} [limit] - The maximum number of records per page.\n * @property {number} total - The total number of records in the data source.\n * @property {GristRecord[]} records - An array of fetched data records.\n */\nexport type FetchResult = {\n page?: number\n limit?: number\n total: number\n records: GristRecord[]\n} | void\n\n/**\n * A function that handles data fetching operations.\n *\n * @param param - The fetch options specifying how data should be retrieved.\n * @returns A promise that resolves to a `FetchResult`.\n */\nexport type FetchHandler = (param: FetchOption) => Promise<FetchResult>\n\n/**\n * Represents a Grist event handler function.\n *\n * @typedef {Function} GristEventHandler\n * @param {ColumnConfig[]} columns - An array of column configurations.\n * @param {GristData} [data] - The Grist data associated with the event.\n * @param {ColumnConfig} [column] - The column configuration related to the event (if applicable).\n * @param {GristRecord} [record] - The Grist record related to the event (if applicable).\n * @param {number} [rowIndex] - The index of the row related to the event (if applicable).\n * @param {any} [target] - The target element or object related to the event (if applicable).\n * @param {Event} [e] - The event object (if applicable).\n * @returns {void}\n */\nexport type GristEventHandler = (\n columns: ColumnConfig[],\n data?: GristData,\n column?: ColumnConfig,\n record?: GristRecord,\n rowIndex?: number,\n target?: any,\n e?: Event\n) => void\n\n/**\n * Represents an accumulator function for data aggregation and accumulation.\n *\n * @typedef {string|'sum'|'avg'|'count'|'min'|'max'|Function} AccumulatorFunc\n * @param {GristData} data - The Grist data for aggregation.\n * @param {ColumnConfig} column - The column configuration for aggregation.\n * @returns {string|number} - The aggregated result.\n */\nexport type AccumulatorFunc =\n | 'sum'\n | 'avg'\n | 'count'\n | 'min'\n | 'max'\n | ((data: GristData, column: ColumnConfig) => string | number)\n\n/**\n * Type representing an accumulator function or configuration object.\n *\n * An accumulator is used for data aggregation and accumulation purposes. It can be either\n * a predefined accumulator function (e.g., 'sum', 'avg', 'count', etc.) or a configuration\n * object specifying the type of accumulator and labeling options.\n *\n * @typedef {AccumulatorFunc|{type: AccumulatorFunc, tag?: boolean}} AccumulatorObject\n * @property {AccumulatorFunc} [type] - The type of accumulator function or predefined function name.\n * @property {boolean} [tag] - An option for adding a label to represent the result of an aggregation function. This label is added in front of the aggregated value.\n *\n * @example\n * // Using a predefined accumulator function:\n * const accumulator: AccumulatorObject = 'sum'; // Represents a 'sum' accumulator.\n *\n * // Using an accumulator configuration object:\n * const accumulatorConfig: AccumulatorObject = {\n * type: 'avg', // Specifies the type of accumulator ('avg' for average).\n * tag: true, // Option for adding a label to represent the result of an aggregation function. This label is added in front of the aggregated value.\n * };\n */\nexport type AccumulatorObject =\n | AccumulatorFunc\n | {\n type: AccumulatorFunc\n tag?: boolean\n }\n\n/**\n * Type representing column configuration information.\n *\n * @typedef {object} ColumnConfig\n * @property {string} type - Represents the data type of the column (e.g., 'text', 'number', 'date', 'gutter', etc.).\n * @property {string} name - Represents the name of the column.\n * @property {('button'|'sequence'|'row-selector'|'dirty')} [gutterName] - If the column type is 'gutter', specifies the name of one of the registered gutters (only set when the type is 'gutter').\n * @property {boolean} [fixed] - In case of a grid type column, specifies whether the column's position should be fixed and unaffected by horizontal scrolling (optional).\n * @property {HeaderConfig} header - Object representing the header configuration of the column.\n * @property {RecordConfig} record - Object representing the record configuration of the column.\n * @property {GristEventHandlerSet} handlers - Object representing the Grist event handler settings.\n * @property {LabelConfig} label - Object representing the label configuration of the column. This property is used to represent the label of the column's information in list mode, card mode, and when displaying the column in a filter form (ox-filters-form).\n * @property {boolean} [hidden] - Indicates whether the column is hidden or not (optional).\n * @property {boolean} [sortable] - Indicates whether the column is sortable or not (optional). If this setting is true, the header provides the ability to toggle the sorting direction.\n * @property {boolean} [resizable] - Indicates whether the column is resizable or not (optional). This setting determines whether the column's width can be adjusted.\n * @property {(number|string|ColumnWidthCallback)} [width] - Represents the width of the column (e.g., 100, '50%', or a callback function to calculate width).\n * @property {boolean} [forList] - Indicates whether the column is intended for display in list mode (optional, applicable only to gutter type columns).\n * @property {boolean} [forCard] - Indicates whether the column is intended for display in card mode (optional, applicable only to gutter type columns).\n * @property {ValidationCallback} [validation] - Callback function for column validation (optional). This function validates whether the value of the column is valid when edited.\n * @property {AccumulatorObject} [accumulator] - Object used for accumulating values of the column (optional, applicable only in grid mode). It specifies a function to automatically aggregate the values of the column for all records. The aggregated result is displayed in a row below the last record (accumulation record).\n * @property {FilterConfig} [filter] - Object representing the filter configuration of the column.\n * @property {(ImexConfig|boolean)} [imex] - Object or boolean value representing the configuration for importing and exporting column data.\n * @property {boolean} [multiple] - Indicates whether the column allows multiple selections or not (optional).\n * @property {boolean} [rowCount] - Indicates whether the column shows the row count or not (optional).\n */\nexport type ColumnConfig = {\n type: string\n name: string\n /**\n * \"gutter\" 타입의 컬럼인 경우, 등록된 gutter들 중의 하나의 이름을 명시합니다(type이 gutter인 경우에만 설정합니다).\n * (e.g., 'button', 'sequence', 'row-selector', 'dirty', etc)\n *\n * \"Gutter\" 는 테이블에서 각 행의 왼쪽이나 오른쪽에 놓이는 추가 열(column)을 뜻합니다.\n * 이 열은 주로 각 행(row)을 식별하거나 특정 작업을 수행하기 위한 버튼 또는 링크와 같은 요소를 표시하는 데 사용됩니다.\n * Gutter 열은 주로 데이터 행에 대한 조작 또는 행의 상태를 나타내는 데 사용됩니다.\n * 예를 들어, 테이블에서 각 행이 특정 작업을 수행하는 버튼을 포함할 때, 이러한 버튼이 Gutter 열에 배치될 수 있습니다.\n * 또한 Gutter 열은 행을 선택하거나 행의 상태를 나타내는 체크박스를 포함할 수도 있습니다.\n */\n gutterName?: 'button' | 'sequence' | 'row-selector' | 'dirty'\n title?: string\n fixed?: boolean\n /** [begin] only for button gutter column */\n icon?: string\n iconOnly?: boolean\n danger?: boolean\n /** [end] only for button gutter column */\n header: HeaderConfig\n record: RecordConfig\n handlers: GristEventHandlerSet\n label: LabelConfig\n hidden?: boolean\n sortable?: boolean\n resizable?: boolean\n width?: number | string | ColumnWidthCallback\n forList?: boolean\n forCard?: boolean\n validation?: ValidationCallback\n accumulator?: AccumulatorObject\n filter?: FilterConfig\n imex?: ImexConfig | boolean\n multiple?: boolean\n rowCount?: boolean\n /** 특정 도구에 의해서 사용되는 옵션으로, 일반적인 용도로 사용되지 않음을 표현할 수 있다. */\n unusable?: boolean\n multiline?: boolean // 멀티라인 여부\n}\n\n/**\n * Callback function type for column validation.\n *\n * This function is used to validate whether the value of a column is valid when edited.\n *\n * @callback ValidationCallback\n * @param {any} after - The new value of the column after editing.\n * @param {any} before - The previous value of the column before editing.\n * @param {GristRecord} record - The record being edited.\n * @param {ColumnConfig} column - The configuration of the column being edited.\n * @returns {boolean} - Returns `true` if the value is valid, `false` otherwise.\n */\nexport type ValidationCallback = (\n after: any,\n before: any,\n record: GristRecord,\n column: ColumnConfig\n) => boolean | Promise<boolean>\n\n/**\n * Configuration options for column labels.\n *\n * The label for a column can be customized using various options.\n *\n * @typedef {string|boolean|Object} LabelConfig\n * @property {LabelRenderer} [renderer] - A custom renderer function for the column label.\n *\n * @example\n * // Using a string as a label:\n * const label: LabelConfig = \"Column Label\"; // Sets the label as \"Column Label\".\n *\n * // Using a boolean to determine label visibility:\n * const label: LabelConfig = true; // Shows the default label based on the header configuration.\n *\n * // Using a custom renderer function for the label:\n * const label: LabelConfig = {\n * renderer: customLabelRenderer, // Specifies a custom renderer function.\n * };\n */\nexport type LabelConfig =\n | string\n | boolean\n | {\n renderer: LabelRenderer\n /** Same as HeaderConfig.text — the name itself, not what was drawn from it. */\n text?: string\n }\n\n/**\n * Custom label renderer function for generating column labels.\n *\n * @callback LabelRenderer\n * @param {ColumnConfig} column - The column configuration object for which the label is being generated.\n * @returns {void}\n */\nexport type LabelRenderer = (column: ColumnConfig) => void\n\n/**\n * Custom callback function for calculating column width.\n *\n * @callback ColumnWidthCallback\n * @param {ColumnConfig} column - The column configuration object for which the width is being calculated.\n * @returns {string} - The calculated width as a string (e.g., '100', '50%').\n */\nexport type ColumnWidthCallback = (column: ColumnConfig) => string\n\n/**\n * Configuration for defining the header of a column.\n *\n * @typedef {Object} HeaderConfig\n * @property {HeaderRenderer} renderer - The function used to render the column header.\n * @property {string} [style] - Optional CSS style for the column header.\n * @property {string} [group] - Optional group identifier for the column header.\n * @property {string} [groupStyle] - Optional CSS style for the header group.\n */\nexport type HeaderConfig = {\n renderer: HeaderRenderer\n /**\n * The column's name as plain text.\n *\n * `renderer` returns whatever gets drawn — a lit template, an icon — and the name cannot be read\n * back out of that. So a name given as a string in the config is kept here, for the places that\n * need it outside of rendering: the accessible name of a cell, and header filter inputs.\n */\n text?: string\n style?: string\n group?: string\n groupStyle?: string\n}\n\n/**\n * Function type for rendering column headers.\n *\n * @callback HeaderRenderer\n * @param {ColumnConfig} column - The column configuration object.\n * @returns {*} - The rendered header content.\n */\nexport type HeaderRenderer = (column: ColumnConfig) => any\n\n/**\n * Configuration for specifying default values for fields in a record.\n * Default values can be set using predefined value generator functions or custom user-defined functions.\n * This configuration allows you to define the default value generation method and any additional parameters.\n *\n * @typedef {Object|Function} DefaultValueFnConfig\n * @property {string} [name] - The name of the default value function to be used for the column.\n * @property {any[]} [params] - The parameters to be passed to the default value function.\n * @property {Function} [Function] - A custom user-defined function for generating default values.\n */\nexport type DefaultValueFnConfig =\n | {\n /**\n * The name of the default value function to be used for the column.\n */\n name: string\n\n /**\n * The parameters to be passed to the default value function.\n */\n params?: any[]\n }\n | Function\n\n/**\n * Configuration for defining fields within a record.\n * Each field can have various settings such as rendering, editing, alignment, etc.\n * The 'defaultValue' property is used to specify the default value generation method and parameters.\n *\n * @typedef {Object} RecordConfig\n * @property {FieldRenderer} renderer - The rendering function for the field.\n * @property {FieldEditor|undefined} [editor] - The editing function for the field (optional).\n * @property {boolean|Function} [editable] - Specifies if the field is editable. It can be a boolean or a function (optional).\n * @property {boolean} [mandatory] - Specifies if the field is mandatory (optional).\n * @property {GristClassifier} classifier - A classifier function for the field.\n * @property {'left'|'right'|'center'} [align] - The alignment of the field's content (optional).\n * @property {*} options - Additional options for the field.\n * @property {string|undefined} [rowOptionField] - The name of a field for row-level options associated with this field (optional).\n * @property {DefaultValueFnConfig|undefined} [defaultValue] - Configuration for specifying the default value for the field.\n * It can be a predefined value generator function or a custom user-defined function (optional).\n * @property {Object.<string, *>|undefined} [extended] - Additional extended properties that can be added as needed for specific field configurations (optional).\n * @property {boolean} [wide] - Specifies if the field should occupy a larger width within the viewer or editor.\n * When set to `true`, the field will attempt to span across multiple columns or occupy more space horizontally.\n */\nexport type RecordConfig = {\n renderer: FieldRenderer\n editor?: FieldEditor\n editable?: boolean | Function\n mandatory?: boolean\n disabled?: boolean | Function\n classifier: GristClassifier\n align?: 'left' | 'right' | 'center'\n options: any\n rowOptionField?: string\n defaultValue?: DefaultValueFnConfig\n wide?: boolean\n /**\n * Draw the field even when the record has no value for it (card mode's thumbnail).\n *\n * A thumbnail with no value is normally not drawn at all, so a list of records without images\n * does not show a column of broken-image marks. A renderer that draws the empty case itself —\n * and anything it overlays on the picture — needs the element regardless, and only the renderer\n * knows that. Off by default.\n */\n renderEmpty?: boolean\n [extended: string]: any\n}\n\n/**\n * A function type used for rendering the content of a field in various components.\n *\n * @callback FieldRenderer\n * @param {*} value - The value of the field to be rendered.\n * @param {ColumnConfig} column - The configuration of the column to which the field belongs.\n * @param {GristRecord} record - The record object containing the field's data.\n * @param {number} rowIndex - The index of the row to which the field belongs.\n * @param {DataGridField|RecordCard|DataCardGutter|DataCardField|DataListGutter|DataListField|RecordPartial|DataReportField|Element} owner - The component or element that owns the field.\n * @returns {OxGristRenderer|TemplateResult|string|void} - The rendered content, which can be of different types depending on the implementation.\n */\nexport type FieldRenderer = (\n value: any,\n column: ColumnConfig,\n record: GristRecord,\n rowIndex: number,\n owner:\n | DataGridField\n | RecordCard\n | DataCardGutter\n | DataCardField\n | DataListGutter\n | DataListField\n | RecordPartial\n | DataReportField\n | Element\n) => OxGristRenderer | TemplateResult | string | void\n\n/**\n * A function type used for defining a custom editor for a field in a data grid.\n *\n * @callback FieldEditor\n * @param {*} value - The current value of the field.\n * @param {ColumnConfig} column - The configuration of the column to which the field belongs.\n * @param {GristRecord} record - The record object containing the field's data.\n * @param {number} rowIndex - The index of the row to which the field belongs.\n * @param {DataGridField} field - The data grid field that owns the editor.\n * @returns {OxGristEditor} - The custom editor component.\n */\nexport type FieldEditor = (\n value: any,\n column: ColumnConfig,\n record: GristRecord,\n rowIndex: number,\n field: DataGridField\n) => OxGristEditor\n\n/**\n * A function type used for rendering the filter select options in a filter form.\n *\n * @callback FilterSelectRenderer\n * @param {ColumnConfig} column - The configuration of the column for which the filter is being rendered.\n * @param {(string|number|boolean|string[]|number[]|any|undefined)} value - The current value of the filter.\n * @param {Element} owner - The DOM element that owns the filter select renderer.\n * @returns {(TemplateResult|string|void)} - The rendered filter select options as a Lit HTML template result, a string, or nothing.\n */\nexport type FilterSelectRenderer = (\n column: ColumnConfig,\n value: string | number | boolean | string[] | number[] | any | undefined,\n owner: Element\n) => TemplateResult | string | void\n\n/**\n * An object representing a set of event handler functions for various events in Grist.\n *\n * @typedef {Object} GristEventHandlerSet\n * @property {GristEventHandler} [click] - The click event handler function.\n * @property {GristEventHandler} [dblclick] - The double-click event handler function.\n * @property {GristEventHandler} [focus] - The focus event handler function.\n * @property {GristEventHandler} [contextmenu] - The context menu event handler function.\n */\nexport type GristEventHandlerSet = {\n click?: GristEventHandler\n dblclick?: GristEventHandler\n focus?: GristEventHandler\n contextmenu?: GristEventHandler\n}\n\n/**\n * Configuration options for defining how records are displayed in list mode in a Grist.\n *\n * @typedef {Object} ListConfig\n * @property {string} [thumbnail] - The name of the field to use as a thumbnail image for records in list mode.\n * @property {object} [emptyThumbnail] - What to draw where a record has no thumbnail. The slot keeps its\n * place either way so cards stay the same height; this says what it should say. Without it the slot is\n * drawn empty.\n * @property {string[]} fields - An array of field names to display in the list mode.\n * @property {string[]} details - An array of field names to display as additional details in the list mode.\n */\nexport type ListConfig = {\n thumbnail?: string\n emptyThumbnail?: {\n /** Material symbol name. */\n icon?: string\n /** One short line — already translated by the caller. */\n label?: string\n }\n fields: string[]\n details: string[]\n}\n\n/**\n * Configuration options for managing tree-like structures in a Grist table.\n *\n * @typedef {Object} TreeConfig\n * @property {string} [childrenProperty] - The property name that specifies the children of a record.\n * @property {boolean | Function} [expanded] - Specifies whether tree nodes are initially expanded or a function to determine the initial expansion state for a given record.\n */\nexport type TreeConfig = {\n childrenProperty?: string\n expanded?: boolean | ((x: GristRecord) => boolean)\n}\n\n/**\n * Configuration options for importing and exporting column data.\n *\n * @typedef {Object} ImexConfig\n * @property {string} header - The header text for the column in import/export settings.\n * @property {string} key - The key or identifier for the column in import/export settings.\n * @property {number} width - The width of the column in import/export settings.\n * @property {string} type - The data type of the column in import/export settings.\n */\nexport type ImexConfig = {\n header: string\n key: string\n width: number\n type: string\n}\n\n/**\n * Configuration options for defining rows within a Grist table or view.\n *\n * @typedef {Object} RowsConfig\n * @property {boolean} [accumulator] - Specifies whether an accumulator row should be displayed.\n * @property {boolean} appendable - Indicates whether new rows can be appended to the table.\n * @property {boolean} insertable - Indicates whether new rows can be inserted into the table.\n * @property {RowSelectableConfig} [selectable] - Configuration for row selection options.\n * @property {GroupConfig[]} groups - An array of group configuration options.\n * @property {string[]} totals - An array of field names for which totals should be calculated and displayed.\n * @property {GristClassifier} classifier - A function that classifies rows based on their attributes.\n * @property {GristEventHandlerSet} handlers - An object containing event handler functions for various row-level events.\n */\nexport type RowsConfig = {\n accumulator?: boolean\n appendable: boolean\n editable: boolean\n insertable: boolean\n selectable?: RowSelectableConfig\n groups: GroupConfig[]\n totals: string[]\n classifier: GristClassifier\n handlers: GristEventHandlerSet\n}\n\n/**\n * A function used to classify and style individual records in a Grist table.\n *\n * @typedef {Function} GristClassifier\n *\n * @param {GristRecord} record - The record to be classified.\n * @param {number} rowIndex - The index of the row in the table.\n *\n * @returns {Object|void} An object containing classification properties or `void`.\n * - `emphasized` (optional): A boolean, string, or array of strings indicating the emphasis style.\n * - Additional properties can be added as needed for custom styling.\n */\nexport type GristClassifier = (\n record: GristRecord,\n rowIndex: number\n) => { emphasized?: boolean | string | string[]; [key: string]: any } | void\n\n/**\n * Configuration options for defining group headers in a Grist table.\n *\n * @typedef {Object} GroupConfig\n *\n * @property {string} align - The alignment of the group header ('left', 'center', or 'right').\n * @property {ColumnConfig} [titleColumn] - The column configuration used as the title of the group (optional).\n * @property {string} title - The title of the group.\n * @property {string} [value] - A value associated with the group (optional).\n * @property {string} [groupName] - The name of the group (optional).\n * @property {number} [row] - The row index where the group header should appear (optional).\n * @property {string|number} column - The column name or index where the group header should appear.\n * @property {number} rowspan - The number of rows the group header should span.\n * @property {number} [colspan] - The number of columns the group header should span (optional).\n */\nexport type GroupConfig = {\n align: string\n titleColumn?: ColumnConfig\n title: string\n value?: string\n groupName?: string\n row?: number\n column: string | number\n rowspan: number\n colspan?: number\n}\n\n/**\n * Configuration options for specifying row selectability in a Grist table.\n *\n * @typedef {Object} RowSelectableConfig\n *\n * @property {boolean} [multiple] - Indicates whether multiple rows can be selected (optional).\n */\nexport type RowSelectableConfig = {\n multiple?: boolean\n}\n\n/**\n * Represents a data record in Grist.\n *\n * @typedef {Object} GristRecord\n * @property {string} [id] - The unique identifier for the record.\n * @property {string} [name] - The name or label associated with the record.\n * @property {GristRecord[]} [children] - An array of child records, if applicable.\n * @property {number} [__seq__] - A numeric sequence identifier for the record.\n * @property {string} [__dirty__] - Indicates if the record is dirty (changed).\n * @property {boolean} [__selected__] - Indicates if the record is selected.\n * @property {object[]} [__changes__] - An array of changes made to the record.\n * @property {object} [__dirtyfields__] - An object representing dirty (changed) fields in the record.\n * @property {any} [__origin__] - The original data or source of the record.\n * @property {boolean} [__collapsed__] - Indicates if the record is collapsed (e.g., in a tree view).\n * @property {number} [__depth__] - The depth or level of the record in a hierarchical structure.\n * @property {'checked' | 'half-checked' | 'unchecked'} [__check_in_tree__] - Indicates the check state of the record in a tree view.\n * @property {GristRecord[]} [__children__] - An array of child records in a tree view.\n * @property {any} [key] - Additional custom properties specific to the record.\n */\nexport type GristRecord = {\n id?: string\n name?: string\n children?: GristRecord[]\n __seq__?: number\n __dirty__?: string\n __selected__?: boolean\n __changes__?: object[]\n __dirtyfields__?: { [key: string]: any }\n __origin__?: any\n __collapsed__?: boolean\n __depth__?: number\n __check_in_tree__?: 'checked' | 'half-checked' | 'unchecked'\n __children__?: GristRecord[]\n [key: string]: any\n}\n\n/**\n * Represents a set of data retrieved from a Grist table.\n *\n * @typedef {Object} GristData\n *\n * @property {number} [page] - The page number of the retrieved data (optional).\n * @property {number} [total] - The total number of records in the data source (optional).\n * @property {number} [limit] - The maximum number of records per page (optional).\n * @property {GristRecord[]} records - An array of fetched data records.\n */\nexport type GristData = {\n page?: number\n total?: number\n limit?: number\n records: GristRecord[]\n}\n\n/**\n * A function that determines whether a Grist record should be selected or not.\n *\n * @callback GristSelectFunction\n * @param {GristRecord} record - The Grist record to evaluate.\n * @returns {boolean} - `true` if the record should be selected, `false` otherwise.\n */\nexport type GristSelectFunction = (record: GristRecord) => boolean\n\n/**\n * Defines a type for personalized grid settings. It includes individual column settings and additional configurations specific to a user's grid view.\n *\n * @typedef {Object} PersonalGristPreference\n * @property {Partial<ColumnConfig>[]} [columns] - Partially defines the configuration for each column in the grid.\n * Each element can include only some properties of the `ColumnConfig`, used for optionally overriding column settings.\n * @property {any} [key] - Allows for storing additional user-defined properties with dynamic keys.\n * This property can include various custom settings beyond the grid configuration, and the keys can be freely defined.\n */\nexport type PersonalGristPreference = {\n columns?: Partial<ColumnConfig>[]\n filters?: FilterPreference[]\n pagination?: PaginationConfig\n sorters?: SortersConfig\n mode?: 'GRID' | 'LIST' | 'CARD'\n [key: string]: any\n}\n\nexport type FilterPreference = {\n name: string\n hidden?: boolean\n value?: any\n}\n\nexport enum ValidationReason {\n MANDATORY = 'MANDATORY',\n FORMAT = 'FORMAT',\n RANGE = 'RANGE',\n UNIQUE = 'UNIQUE'\n}\n"]}
@@ -0,0 +1 @@
1
+ import '../src/data-grist.js';
@@ -0,0 +1,108 @@
1
+ /* Elements are compared by presence, not by value: a failing element comparison makes chai render the DOM and hang the runner. */
2
+ import { expect, fixture } from '@open-wc/testing';
3
+ import { html } from 'lit';
4
+ import '../src/data-grist.js';
5
+ const columns = [
6
+ { type: 'string', name: 'id', hidden: true },
7
+ { type: 'string', name: 'name', header: 'name', filter: 'search' },
8
+ { type: 'string', name: 'description', header: 'description', filter: 'search' },
9
+ { type: 'string', name: 'state', header: 'state' }
10
+ ];
11
+ const settle = (ms = 150) => new Promise(resolve => setTimeout(resolve, ms));
12
+ async function grist(searchMode) {
13
+ const seen = [];
14
+ const el = (await fixture(html `
15
+ <ox-grist
16
+ style="height: 300px"
17
+ mode="GRID"
18
+ search-mode=${searchMode !== null && searchMode !== void 0 ? searchMode : 'columns'}
19
+ .config=${{ columns, pagination: { pages: [20] } }}
20
+ .fetchHandler=${async (param) => {
21
+ seen.push({ filters: param.filters, search: param.search });
22
+ return { page: 1, limit: 20, total: 0, records: [] };
23
+ }}
24
+ ></ox-grist>
25
+ `));
26
+ await el.fetch().catch(() => { });
27
+ await settle();
28
+ return { el, seen };
29
+ }
30
+ const searchFilters = (seen) => { var _a; return ((_a = seen[seen.length - 1].filters) !== null && _a !== void 0 ? _a : []).filter(one => one.operator === 'search'); };
31
+ describe('검색 낱말이 나가는 길', () => {
32
+ /*
33
+ * fixture 안의 격자는 붙는 순간 Chrome 의 `ResizeObserver loop completed` 를 던진다. 브라우저가 한
34
+ * 틱에 두 번 재는 것뿐이고 이 시험이 보는 것과 무관한데, mocha 는 그것을 **시험 실패로 센다** —
35
+ * 안 걸러 두면 여기 여섯이 통째로 빨강이고 까닭은 실패 이름에 안 나온다. `fetch-failure-state` 가
36
+ * 쓰는 것과 같은 거르개다(리스너 하나로는 안 된다 — mocha 는 `window.onerror` 쪽도 본다).
37
+ */
38
+ const ignoreResizeLoop = (e) => {
39
+ if (String(e.message).includes('ResizeObserver loop')) {
40
+ e.stopImmediatePropagation();
41
+ e.preventDefault();
42
+ }
43
+ };
44
+ let previousOnError = null;
45
+ before(() => {
46
+ window.addEventListener('error', ignoreResizeLoop, true);
47
+ previousOnError = window.onerror;
48
+ window.onerror = (message, ...rest) => String(message).includes('ResizeObserver loop') ? true : previousOnError === null || previousOnError === void 0 ? void 0 : previousOnError.call(window, message, ...rest);
49
+ });
50
+ after(() => {
51
+ window.removeEventListener('error', ignoreResizeLoop, true);
52
+ window.onerror = previousOnError;
53
+ });
54
+ it('옛 길은 칸마다 필터를 만든다 — 지금 거동 그대로', async () => {
55
+ const { el, seen } = await grist();
56
+ el.searchText = '구본';
57
+ await settle();
58
+ expect(searchFilters(seen).map(one => one.name)).to.eql(['name', 'description']);
59
+ expect(searchFilters(seen)[0].value).to.equal('%구본%');
60
+ expect(seen[seen.length - 1].search).to.equal(undefined);
61
+ });
62
+ it('옛 길에서 낱말을 되읽는다', async () => {
63
+ const { el } = await grist();
64
+ el.searchText = '구본';
65
+ await settle();
66
+ expect(el.searchText).to.equal('구본');
67
+ el.searchText = '';
68
+ await settle();
69
+ expect(el.searchText).to.equal('');
70
+ });
71
+ it('새 길은 낱말을 그대로 싣고 칸 선언을 읽지 않는다', async () => {
72
+ /*
73
+ * 칸 둘이 `filter: 'search'` 를 선언한 채로 둔다. 같은 낱말이 두 번 걸리지 않아야 한다 —
74
+ * 한 화면에 두 길이 같이 서는 것이 이 설계에서 제일 막아야 하는 것이다.
75
+ */
76
+ const { el, seen } = await grist('term');
77
+ el.searchText = '구본';
78
+ await settle();
79
+ expect(seen[seen.length - 1].search).to.equal('구본');
80
+ expect(searchFilters(seen)).to.eql([]);
81
+ });
82
+ it('새 길에서도 낱말을 되읽는다 — 제목 줄이 이것으로 자기 값을 그린다', async () => {
83
+ /*
84
+ * 옛 길의 되읽기는 `filters` 에서 `%낱말%` 을 벗겨 답했다. 새 길에는 그 필터가 없으므로 격자가
85
+ * 자기 상태로 들어야 한다. 이 자리가 이 변경에서 제일 조용히 깨질 곳이다.
86
+ */
87
+ const { el } = await grist('term');
88
+ el.searchText = '구본';
89
+ await settle();
90
+ expect(el.searchText).to.equal('구본');
91
+ });
92
+ it('새 길에서 낱말을 비우면 되읽은 것도 비고, 낱말도 안 나간다', async () => {
93
+ const { el, seen } = await grist('term');
94
+ el.searchText = '구본';
95
+ await settle();
96
+ el.searchText = '';
97
+ await settle();
98
+ expect(el.searchText).to.equal('');
99
+ expect(seen[seen.length - 1].search || '').to.equal('');
100
+ });
101
+ it('길을 안 고르면 옛 길이다 — 밖의 소비자가 그날 안 바뀐다', async () => {
102
+ const el = (await fixture(html `
103
+ <ox-grist style="height: 300px" mode="GRID" .config=${{ columns, pagination: { pages: [20] } }}></ox-grist>
104
+ `));
105
+ expect(el.searchMode).to.equal('columns');
106
+ });
107
+ });
108
+ //# sourceMappingURL=search-term.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-term.test.js","sourceRoot":"","sources":["../../test/search-term.test.ts"],"names":[],"mappings":"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","sourcesContent":["/* Elements are compared by presence, not by value: a failing element comparison makes chai render the DOM and hang the runner. */\nimport { expect, fixture } from '@open-wc/testing'\nimport { html } from 'lit'\n\nimport '../src/data-grist.js'\n\n/**\n * 검색 낱말이 서버까지 닿는 두 길.\n *\n * ── 옛 길(`columns`, 지금 기본) ────────────────────────────────────────────\n * 격자가 **칸의 선언**을 보고 필드마다 `{name, operator:'search', value:'%낱말%'}` 를 만든다. 그래서\n * 화면이 서버의 `searchables` 를 손으로 베껴 칸에 적어야 하고, 하나도 안 적으면 낱말이 **조용히\n * 버려진다** — 목록은 오류 없이 통째로 오고 사람은 「그 번호가 없구나」로 읽는다. 프레임워크 화면\n * 아홉이 그 상태였다(2026-09-19).\n *\n * ── 새 길(`term`) ─────────────────────────────────────────────────────────\n * 격자가 낱말을 그대로 싣고 서버가 자기 `searchables` 로 푼다(`ListParam.search`). 화면에서 사본이\n * 사라지므로 어긋날 자리도 사라진다.\n *\n * ── 기본을 안 바꾼다 ──────────────────────────────────────────────────────\n * 이 부품은 우리 저장소 밖에서도 쓴다(dssp 40 파일 · fmsim 6). 그래서 새 길은 **켜는 쪽**이고, 옛\n * 길의 거동은 글자까지 그대로 둔다. 기본값을 뒤집는 것은 그쪽에 알린 뒤의 별도 결정이다.\n */\n\ntype Seen = { filters?: any[]; search?: string }\n\nconst columns = [\n { type: 'string', name: 'id', hidden: true },\n { type: 'string', name: 'name', header: 'name', filter: 'search' },\n { type: 'string', name: 'description', header: 'description', filter: 'search' },\n { type: 'string', name: 'state', header: 'state' }\n]\n\nconst settle = (ms = 150) => new Promise(resolve => setTimeout(resolve, ms))\n\nasync function grist(searchMode?: 'columns' | 'term') {\n const seen: Seen[] = []\n const el = (await fixture(html`\n <ox-grist\n style=\"height: 300px\"\n mode=\"GRID\"\n search-mode=${searchMode ?? 'columns'}\n .config=${{ columns, pagination: { pages: [20] } }}\n .fetchHandler=${async (param: any) => {\n seen.push({ filters: param.filters, search: param.search })\n return { page: 1, limit: 20, total: 0, records: [] }\n }}\n ></ox-grist>\n `)) as any\n\n await el.fetch().catch(() => {})\n await settle()\n return { el, seen }\n}\n\nconst searchFilters = (seen: Seen[]) => (seen[seen.length - 1].filters ?? []).filter(one => one.operator === 'search')\n\ndescribe('검색 낱말이 나가는 길', () => {\n /*\n * fixture 안의 격자는 붙는 순간 Chrome 의 `ResizeObserver loop completed` 를 던진다. 브라우저가 한\n * 틱에 두 번 재는 것뿐이고 이 시험이 보는 것과 무관한데, mocha 는 그것을 **시험 실패로 센다** —\n * 안 걸러 두면 여기 여섯이 통째로 빨강이고 까닭은 실패 이름에 안 나온다. `fetch-failure-state` 가\n * 쓰는 것과 같은 거르개다(리스너 하나로는 안 된다 — mocha 는 `window.onerror` 쪽도 본다).\n */\n const ignoreResizeLoop = (e: ErrorEvent) => {\n if (String(e.message).includes('ResizeObserver loop')) {\n e.stopImmediatePropagation()\n e.preventDefault()\n }\n }\n let previousOnError: OnErrorEventHandler = null\n\n before(() => {\n window.addEventListener('error', ignoreResizeLoop, true)\n previousOnError = window.onerror\n window.onerror = (message, ...rest) =>\n String(message).includes('ResizeObserver loop') ? true : previousOnError?.call(window, message, ...rest)\n })\n\n after(() => {\n window.removeEventListener('error', ignoreResizeLoop, true)\n window.onerror = previousOnError\n })\n\n it('옛 길은 칸마다 필터를 만든다 — 지금 거동 그대로', async () => {\n const { el, seen } = await grist()\n\n el.searchText = '구본'\n await settle()\n\n expect(searchFilters(seen).map(one => one.name)).to.eql(['name', 'description'])\n expect(searchFilters(seen)[0].value).to.equal('%구본%')\n expect(seen[seen.length - 1].search).to.equal(undefined)\n })\n\n it('옛 길에서 낱말을 되읽는다', async () => {\n const { el } = await grist()\n\n el.searchText = '구본'\n await settle()\n\n expect(el.searchText).to.equal('구본')\n\n el.searchText = ''\n await settle()\n\n expect(el.searchText).to.equal('')\n })\n\n it('새 길은 낱말을 그대로 싣고 칸 선언을 읽지 않는다', async () => {\n /*\n * 칸 둘이 `filter: 'search'` 를 선언한 채로 둔다. 같은 낱말이 두 번 걸리지 않아야 한다 —\n * 한 화면에 두 길이 같이 서는 것이 이 설계에서 제일 막아야 하는 것이다.\n */\n const { el, seen } = await grist('term')\n\n el.searchText = '구본'\n await settle()\n\n expect(seen[seen.length - 1].search).to.equal('구본')\n expect(searchFilters(seen)).to.eql([])\n })\n\n it('새 길에서도 낱말을 되읽는다 — 제목 줄이 이것으로 자기 값을 그린다', async () => {\n /*\n * 옛 길의 되읽기는 `filters` 에서 `%낱말%` 을 벗겨 답했다. 새 길에는 그 필터가 없으므로 격자가\n * 자기 상태로 들어야 한다. 이 자리가 이 변경에서 제일 조용히 깨질 곳이다.\n */\n const { el } = await grist('term')\n\n el.searchText = '구본'\n await settle()\n\n expect(el.searchText).to.equal('구본')\n })\n\n it('새 길에서 낱말을 비우면 되읽은 것도 비고, 낱말도 안 나간다', async () => {\n const { el, seen } = await grist('term')\n\n el.searchText = '구본'\n await settle()\n el.searchText = ''\n await settle()\n\n expect(el.searchText).to.equal('')\n expect(seen[seen.length - 1].search || '').to.equal('')\n })\n\n it('길을 안 고르면 옛 길이다 — 밖의 소비자가 그날 안 바뀐다', async () => {\n const el = (await fixture(html`\n <ox-grist style=\"height: 300px\" mode=\"GRID\" .config=${{ columns, pagination: { pages: [20] } }}></ox-grist>\n `)) as any\n\n expect(el.searchMode).to.equal('columns')\n })\n})\n"]}