@operato/data-grist 10.4.0 → 10.6.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-grid-footer.js","sourceRoot":"","sources":["../../../src/data-grid/data-grid-footer.ts"],"names":[],"mappings":"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","sourcesContent":["import i18next from 'i18next'\nimport '@material/web/icon/icon.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { ZERO_DATA, ZERO_PAGES } from '../configure/zero-config.js'\nimport { GristData, PaginationConfig } from '../types.js'\nimport { isMobileDevice, stringifyBigNumber } from '@operato/utils'\n\n@customElement('ox-grid-footer')\nexport class DataGridFooter extends LitElement {\n static styles = [\n css`\n :host {\n display: flex;\n flex-direction: row;\n gap: var(--spacing-small);\n overflow: hidden;\n\n padding: var(--grid-footer-padding);\n background-color: var(--grid-footer-background-color);\n font-size: var(--grid-footer-font-size);\n align-items: center;\n\n user-select: none;\n }\n\n :host * {\n white-space: nowrap;\n overflow: hidden;\n\n text-overflow: ellipsis;\n text-align: center;\n color: var(--grid-footer-color);\n }\n\n .filler {\n flex: 1;\n }\n\n md-icon {\n font-size: 1.5em;\n vertical-align: middle;\n\n font-variation-settings: 'FILL' 1;\n }\n\n .limit {\n display: flex;\n flex-direction: row;\n gap: var(--spacing-small);\n align-items: center;\n }\n\n .limit a {\n color: var(--grid-footer-limit-color);\n }\n\n .limit a[selected] {\n color: var(--grid-footer-color);\n font-weight: bold;\n text-decoration: underline;\n }\n\n a[inactive] * {\n color: var(--grid-footer-inactive-color);\n }\n\n .pages {\n display: flex;\n flex-direction: row;\n gap: 6px;\n align-items: center;\n }\n\n .pages a {\n color: var(--grid-footer-limit-color);\n cursor: pointer;\n }\n\n .pages a[selected] {\n color: var(--grid-footer-color);\n font-weight: bold;\n text-decoration: underline;\n cursor: default;\n }\n\n .page-input-container {\n margin-left: 10px;\n }\n\n .page-input {\n width: 30px;\n text-align: center;\n color: var(--grid-footer-limit-color);\n background: transparent;\n border: 1px solid var(--grid-footer-color);\n border-radius: 4px;\n padding: 0.125rem 0.25rem;\n }\n\n @media screen and (max-width: 460px) {\n .mhidden {\n display: none;\n }\n }\n `\n ]\n\n @property() data: GristData = ZERO_DATA\n @property() pagination: PaginationConfig = {}\n\n _gotoPage(page: number) {\n var { pages = ZERO_PAGES } = this.pagination || {}\n var { limit = pages[0], total = 0 } = this.data\n\n if (page > Math.ceil(total / limit) || page <= 0) {\n return\n }\n this.dispatchEvent(new CustomEvent('page-change', { bubbles: true, composed: true, detail: page }))\n }\n\n _changeLimit(limit: number) {\n this.dispatchEvent(new CustomEvent('limit-change', { bubbles: true, composed: true, detail: limit }))\n }\n\n _commitPageInput(e: Event) {\n var target = e.target as HTMLInputElement\n if (!target) return\n\n var value = parseInt(target.value as string, 10)\n if (isNaN(value)) return\n\n var { pages = ZERO_PAGES } = this.pagination || {}\n var { limit = pages[0], total = 0 } = this.data\n var totalPage = Math.max(1, Math.ceil(total / limit))\n\n var targetPage = Math.min(Math.max(1, value), totalPage)\n this._gotoPage(targetPage)\n }\n\n _onPageInputKeydown(e: KeyboardEvent) {\n if (e.key === 'Enter') {\n this._commitPageInput(e as unknown as Event)\n }\n }\n\n render() {\n var { pages = ZERO_PAGES } = this.pagination || {}\n var { records = [], page = 1, limit = pages[0], total = 0 } = this.data\n\n var begin = records.length == 0 ? 0 : limit * (page - 1) + 1\n var end = records.length == 0 ? 0 : begin + records.length - 1\n var totalPage = Math.max(1, Math.ceil(total / limit))\n\n var numbersToShow = Math.min(isMobileDevice() ? 5 : 10, totalPage)\n var startNum = Math.max(1, page - Math.floor(numbersToShow / 2))\n var endNum = startNum + numbersToShow - 1\n if (endNum > totalPage) {\n endNum = totalPage\n startNum = Math.max(1, endNum - numbersToShow + 1)\n }\n var pageNumbers: number[] = []\n for (var i = startNum; i <= endNum; i++) {\n pageNumbers.push(i)\n }\n\n return html`\n <a ?inactive=${page <= 1} @click=${() => this._gotoPage(1)}><md-icon>skip_previous</md-icon></a>\n <a ?inactive=${page <= 1} @click=${() => this._gotoPage(page - 1)}><md-icon>navigate_before</md-icon></a>\n <span class=\"pages\">\n ${pageNumbers.map(n => html`<a ?selected=${n == page} @click=${() => this._gotoPage(n)}>${n}</a>`)}\n </span>\n <a ?inactive=${page >= totalPage} @click=${() => this._gotoPage(page + 1)}><md-icon>navigate_next</md-icon></a>\n <a ?inactive=${page >= totalPage} @click=${() => this._gotoPage(totalPage)}><md-icon>skip_next</md-icon></a>\n\n <span class=\"page-input-container mhidden\">\n <input\n class=\"page-input\"\n type=\"text\"\n min=\"1\"\n max=${String(totalPage)}\n .value=${String(page)}\n aria-label=\"Current page\"\n @keydown=${(e: KeyboardEvent) => this._onPageInputKeydown(e)}\n @change=${(e: Event) => this._commitPageInput(e)}\n />\n &nbsp;/&nbsp;${totalPage}\n </span>\n\n <span class=\"filler mhidden\"></span>\n\n <span class=\"limit mhidden\">\n ${pages.map(\n size => html`\n <a ?selected=${limit == size} @click=${() => this._changeLimit(size)}>${stringifyBigNumber(size)}</a>\n `\n )}\n </span>\n <span class=\"mhidden\">&nbsp;/&nbsp;</span>\n <span>${i18next.t('text.grid-total-records', { total: total || 0, defaultValue: `total ${total || 0} records.` })}</span>\n `\n }\n}\n"]}
1
+ {"version":3,"file":"data-grid-footer.js","sourceRoot":"","sources":["../../../src/data-grid/data-grid-footer.ts"],"names":[],"mappings":"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","sourcesContent":["import i18next from 'i18next'\nimport '@material/web/icon/icon.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { ZERO_DATA, ZERO_PAGES } from '../configure/zero-config.js'\nimport { GristData, PaginationConfig } from '../types.js'\nimport { isMobileDevice, stringifyBigNumber } from '@operato/utils'\n\n@customElement('ox-grid-footer')\nexport class DataGridFooter extends LitElement {\n static styles = [\n css`\n :host {\n display: flex;\n flex-direction: row;\n gap: var(--spacing-small);\n overflow: hidden;\n\n padding: var(--grid-footer-padding);\n background-color: var(--grid-footer-background-color);\n font-size: var(--grid-footer-font-size);\n align-items: center;\n\n user-select: none;\n }\n\n :host * {\n white-space: nowrap;\n overflow: hidden;\n\n text-overflow: ellipsis;\n text-align: center;\n color: var(--grid-footer-color);\n }\n\n .filler {\n flex: 1;\n }\n\n /*\n * 아이콘 상자와 글리프 크기를 같이 준다.\n *\n * font-size: 1.5em 만 두면 글리프가 21px 인데 상자는 --md-icon-size(14px)라 **글리프가 상자\n * 밖으로 넘친다.** 둘을 같은 값으로 못박는다.\n */\n /*\n * host 를 앞에 붙여 특이도를 올린다. 위의 host 자식 규칙이 (0,1,0)이고 이 규칙이 (0,0,1)이라\n * **아이콘까지 글자 크기로 줄어들었다** — 앞뒤 화살표가 12px 이 됐다. [재봤음] 2026-09-02\n */\n :host md-icon {\n --md-icon-size: 18px;\n font-size: 18px;\n width: 18px;\n height: 18px;\n vertical-align: middle;\n\n font-variation-settings: 'FILL' 1;\n }\n\n .limit {\n display: flex;\n flex-direction: row;\n gap: var(--spacing-small);\n align-items: center;\n }\n\n .limit a {\n color: var(--grid-footer-limit-color);\n }\n\n /*\n * 지금 고른 것은 **굵기만**으로 말한다.\n *\n * 밑줄은 「누를 수 있다」의 표시이고 굵기는 「지금 이것」의 표시다. 겹쳐 쓰면 두 뜻이 섞이고,\n * 안 고른 것들도 누를 수 있는데 아무 표시가 없어진다.\n */\n .limit a[selected] {\n color: var(--grid-footer-color);\n font-weight: 600;\n }\n\n a[inactive] * {\n color: var(--grid-footer-inactive-color);\n }\n\n .pages {\n display: flex;\n flex-direction: row;\n gap: 6px;\n align-items: center;\n }\n\n .pages a {\n color: var(--grid-footer-limit-color);\n cursor: pointer;\n }\n\n .pages a[selected] {\n color: var(--grid-footer-color);\n font-weight: 600;\n cursor: default;\n }\n\n .page-input-container {\n margin-left: 10px;\n }\n\n .page-input {\n width: 30px;\n text-align: center;\n /*\n * 글꼴을 물려받는다. input 은 기본으로 물려받지 않아서 한 줄 안에 13.33px 과 14px 이 섞여\n * 있었다 — 상자 안은 브라우저 기본, 바로 옆 「/ 1」 은 푸터 크기였다.\n */\n font: inherit;\n /*\n * 줄 높이를 못박는다. font: inherit 만으로는 물려받은 줄 높이(20px)가 그대로 와서 상자가 26px 이\n * 되고, 옆 글자(20px)보다 튀어나온다 — 푸터에서 가장 큰 것이 쪽 번호 상자가 된다.\n */\n line-height: 17px;\n color: var(--grid-footer-color);\n background: transparent;\n border: var(--grid-footer-input-border);\n border-radius: 4px;\n padding: 1px 4px;\n }\n\n @media screen and (max-width: 460px) {\n .mhidden {\n display: none;\n }\n }\n `\n ]\n\n @property() data: GristData = ZERO_DATA\n @property() pagination: PaginationConfig = {}\n\n _gotoPage(page: number) {\n var { pages = ZERO_PAGES } = this.pagination || {}\n var { limit = pages[0], total = 0 } = this.data\n\n if (page > Math.ceil(total / limit) || page <= 0) {\n return\n }\n this.dispatchEvent(new CustomEvent('page-change', { bubbles: true, composed: true, detail: page }))\n }\n\n _changeLimit(limit: number) {\n this.dispatchEvent(new CustomEvent('limit-change', { bubbles: true, composed: true, detail: limit }))\n }\n\n _commitPageInput(e: Event) {\n var target = e.target as HTMLInputElement\n if (!target) return\n\n var value = parseInt(target.value as string, 10)\n if (isNaN(value)) return\n\n var { pages = ZERO_PAGES } = this.pagination || {}\n var { limit = pages[0], total = 0 } = this.data\n var totalPage = Math.max(1, Math.ceil(total / limit))\n\n var targetPage = Math.min(Math.max(1, value), totalPage)\n this._gotoPage(targetPage)\n }\n\n _onPageInputKeydown(e: KeyboardEvent) {\n if (e.key === 'Enter') {\n this._commitPageInput(e as unknown as Event)\n }\n }\n\n render() {\n var { pages = ZERO_PAGES } = this.pagination || {}\n var { records = [], page = 1, limit = pages[0], total = 0 } = this.data\n\n var begin = records.length == 0 ? 0 : limit * (page - 1) + 1\n var end = records.length == 0 ? 0 : begin + records.length - 1\n var totalPage = Math.max(1, Math.ceil(total / limit))\n\n var numbersToShow = Math.min(isMobileDevice() ? 5 : 10, totalPage)\n var startNum = Math.max(1, page - Math.floor(numbersToShow / 2))\n var endNum = startNum + numbersToShow - 1\n if (endNum > totalPage) {\n endNum = totalPage\n startNum = Math.max(1, endNum - numbersToShow + 1)\n }\n var pageNumbers: number[] = []\n for (var i = startNum; i <= endNum; i++) {\n pageNumbers.push(i)\n }\n\n return html`\n <a ?inactive=${page <= 1} @click=${() => this._gotoPage(1)}><md-icon>skip_previous</md-icon></a>\n <a ?inactive=${page <= 1} @click=${() => this._gotoPage(page - 1)}><md-icon>navigate_before</md-icon></a>\n <span class=\"pages\">\n ${pageNumbers.map(n => html`<a ?selected=${n == page} @click=${() => this._gotoPage(n)}>${n}</a>`)}\n </span>\n <a ?inactive=${page >= totalPage} @click=${() => this._gotoPage(page + 1)}><md-icon>navigate_next</md-icon></a>\n <a ?inactive=${page >= totalPage} @click=${() => this._gotoPage(totalPage)}><md-icon>skip_next</md-icon></a>\n\n <span class=\"page-input-container mhidden\">\n <input\n class=\"page-input\"\n type=\"text\"\n min=\"1\"\n max=${String(totalPage)}\n .value=${String(page)}\n aria-label=\"Current page\"\n @keydown=${(e: KeyboardEvent) => this._onPageInputKeydown(e)}\n @change=${(e: Event) => this._commitPageInput(e)}\n />\n &nbsp;/&nbsp;${totalPage}\n </span>\n\n <span class=\"filler mhidden\"></span>\n\n <span class=\"limit mhidden\">\n ${pages.map(\n size => html`\n <a ?selected=${limit == size} @click=${() => this._changeLimit(size)}>${stringifyBigNumber(size)}</a>\n `\n )}\n </span>\n <span class=\"mhidden\">&nbsp;/&nbsp;</span>\n <span>${i18next.t('text.grid-total-records', { total: total || 0, defaultValue: `total ${total || 0} records.` })}</span>\n `\n }\n}\n"]}
@@ -10,6 +10,12 @@ import { TooltipReactiveController, closestElement } from '@operato/utils';
10
10
  import { ZERO_COLUMNS, ZERO_DATA } from '../configure/zero-config.js';
11
11
  import { FilterStyles } from '../filters/filter-styles.js';
12
12
  import { getFilterRenderer } from '../filters/registry.js';
13
+ /** 칸의 정렬 선언(record.align)을 flex 의 말로 옮긴다. */
14
+ const ALIGN_JUSTIFY = {
15
+ left: 'flex-start',
16
+ center: 'center',
17
+ right: 'flex-end'
18
+ };
13
19
  let DataGridHeader = class DataGridHeader extends LitElement {
14
20
  constructor() {
15
21
  super(...arguments);
@@ -68,10 +74,33 @@ let DataGridHeader = class DataGridHeader extends LitElement {
68
74
  `;
69
75
  }
70
76
  renderHeaderColumn({ column, clazz, start, size, align, index, group }) {
71
- var _a, _b, _c;
77
+ var _a, _b, _c, _d;
72
78
  if (column.hidden) {
73
79
  return html `${nothing}`;
74
80
  }
81
+ /*
82
+ * 거터 머리는 flex 로 정렬한다.
83
+ *
84
+ * 아래 span 의 `text-align` 은 거터에서 듣지 않는다 — 그 span 이 내용물 크기로 줄어 있어서
85
+ * (위 div[gutter] 머리말 참조) 글자를 밀 여백이 span 안에 없다. 그래서 칸이 밀어야 한다.
86
+ *
87
+ * 값은 그 거터가 이미 선언한 것을 본다. 순번은 right, 선택과 더러움 표식은 center 다. 여기에 따로
88
+ * 적으면 거터를 하나 더할 때 두 곳을 맞춰야 한다.
89
+ */
90
+ /*
91
+ * 정렬은 **칸이 flex 로 민다.** 아래 span 의 text-align 에 기대지 않는다.
92
+ *
93
+ * 그 span 은 이름 길이만큼만 차지하므로(위 span[for-title] 머리말) 안에 글자를 밀 여백이 없다.
94
+ * 그래서 text-align 이 아무 일도 하지 않는다 — 숫자 칸의 값은 오른쪽인데 머리글만 왼쪽에
95
+ * 남았다. [재봤음] 「수량」 머리 x=391 · 값 오른쪽 끝 x=402. 2026-09-02
96
+ *
97
+ * 칸이 밀면 이름과 표식이 **함께** 그 방향으로 간다. 그래서 오른쪽 정렬 칸에서도 표식이 이름
98
+ * 옆에 붙어 있다.
99
+ *
100
+ * 거터의 기본은 가운데(체크박스 · 더러움 표식), 보통 칸의 기본은 왼쪽이다.
101
+ */
102
+ const fallback = column.type == 'gutter' ? 'center' : 'flex-start';
103
+ const justify = `justify-content:${ALIGN_JUSTIFY[(align || ((_a = column.record) === null || _a === void 0 ? void 0 : _a.align))] || fallback};`;
75
104
  return html `
76
105
  <div
77
106
  ?gutter=${column.type == 'gutter'}
@@ -79,8 +108,8 @@ let DataGridHeader = class DataGridHeader extends LitElement {
79
108
  column
80
109
  class=${ifDefined(clazz)}
81
110
  style=${group
82
- ? `--group-start:${start};--group-size:${size};${((_a = column.header) === null || _a === void 0 ? void 0 : _a.style) || ''}`
83
- : `${((_b = column.header) === null || _b === void 0 ? void 0 : _b.style) || ''}`}
111
+ ? `--group-start:${start};--group-size:${size};${justify}${((_b = column.header) === null || _b === void 0 ? void 0 : _b.style) || ''}`
112
+ : `${justify}${((_c = column.header) === null || _c === void 0 ? void 0 : _c.style) || ''}`}
84
113
  >
85
114
  <span
86
115
  for-title
@@ -90,7 +119,7 @@ let DataGridHeader = class DataGridHeader extends LitElement {
90
119
  >${this._renderHeader(column)}
91
120
  </span>
92
121
 
93
- ${((_c = column.record) === null || _c === void 0 ? void 0 : _c.editable) ? html `<md-icon editable-mark title=${i18next.t('text.grid-column-editable', { defaultValue: 'editable' })}>edit</md-icon>` : nothing}
122
+ ${((_d = column.record) === null || _d === void 0 ? void 0 : _d.editable) ? html `<md-icon editable-mark title=${i18next.t('text.grid-column-editable', { defaultValue: 'editable' })}>edit</md-icon>` : nothing}
94
123
  ${!group && column.sortable
95
124
  ? html `
96
125
  <span sorter @click=${(e) => this._changeSort(column)}>
@@ -419,6 +448,16 @@ DataGridHeader.styles = [
419
448
 
420
449
  text-overflow: ellipsis;
421
450
  font: var(--grid-header-font);
451
+ /*
452
+ * 글꼴은 따로 받는다 — 기본은 물려받는다(본문과 같은 글꼴).
453
+ *
454
+ * font 축약형은 글꼴 이름을 반드시 요구해서, 토큰 하나로 쓰면 굵기 · 크기와 글꼴이 묶인다.
455
+ * 그 탓에 머리글이 고정폭으로 그려졌는데, **고정폭에는 한글 글자가 없다.** 대체 글꼴로 떨어지므로
456
+ * 「ISA-95 계층 단」 한 줄 안에서 라틴과 한글이 서로 다른 글꼴이 됐다.
457
+ *
458
+ * 테마가 글꼴까지 정하고 싶으면 --grid-header-font-family 를 준다.
459
+ */
460
+ font-family: var(--grid-header-font-family, inherit);
422
461
  color: var(--grid-header-color);
423
462
  }
424
463
 
@@ -435,6 +474,10 @@ DataGridHeader.styles = [
435
474
  */
436
475
  div[gutter] {
437
476
  padding: var(--grid-gutter-padding);
477
+ /*
478
+ * 기본은 가운데. 거터마다 자기 정렬이 있으면 renderHeaderColumn 이 인라인으로 덮는다 —
479
+ * 순번은 오른쪽이다(몸의 숫자가 오른쪽이므로 머리의 # 도 오른쪽이어야 자릿수가 맞아 보인다).
480
+ */
438
481
  justify-content: center;
439
482
  }
440
483
 
@@ -464,7 +507,21 @@ DataGridHeader.styles = [
464
507
  }
465
508
 
466
509
  span[for-title] {
467
- flex: 1;
510
+ /*
511
+ * 이름이 자기 길이만큼만 차지한다 — 그러면 정렬 표식이 이름 바로 오른쪽에 붙는다.
512
+ *
513
+ * 고치는 표에서는 1 로 되돌린다(data-grid.ts 의 editable-grid 한 벌). 거기서는 칸 끝에 폭 조절
514
+ * 손잡이가 서 있어서, 표식이 그 옆에 모여 있는 편이 낫다.
515
+ *
516
+ * 늘어남만 토큰으로 받고 **줄어듦은 항상 1 이다.** 긴 이름이 줄어들 수 있어야 말줄임으로
517
+ * 잘린다 — 줄어들지 못하면 칸을 넘어가 그냥 잘린다.
518
+ *
519
+ * 축약형(flex)에 var 을 쓰면 「0 1 auto」 가 「none」 으로 해석되는 일이 있었다(실측 0 0 auto).
520
+ * 낱개 속성으로 적으면 그 함정이 없다.
521
+ */
522
+ flex-grow: var(--grid-header-title-grow, 0);
523
+ flex-shrink: 1;
524
+ flex-basis: auto;
468
525
  /* 표식 무리와 이름 사이를 벌린다 — 붙어 있으면 이름의 일부처럼 읽힌다. */
469
526
  margin-right: 6px;
470
527
  /* 작은 대문자 라벨로 쓸 때 자간이 필요하다. 테마가 정하지 않으면 0 이다. */
@@ -1 +1 @@
1
- {"version":3,"file":"data-grid-header.js","sourceRoot":"","sources":["../../../src/data-grid/data-grid-header.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/popup/ox-popup.js'\nimport '@material/web/icon/icon.js'\n\nimport i18next from 'i18next'\nimport { css, html, LitElement, PropertyValues, nothing, TemplateResult } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\nimport throttle from 'lodash-es/throttle.js'\n\nimport { OxPopup } from '@operato/popup'\nimport { TooltipReactiveController, closestElement } from '@operato/utils'\n\nimport { ZERO_COLUMNS, ZERO_DATA } from '../configure/zero-config.js'\nimport { FilterStyles } from '../filters/filter-styles.js'\nimport { getFilterRenderer } from '../filters/registry.js'\nimport { ColumnConfig, FilterConfigObject, FilterValue, GristData, SortersConfig } from '../types.js'\n\n@customElement('ox-grid-header')\nexport class DataGridHeader extends LitElement {\n static styles = [\n FilterStyles,\n css`\n :host {\n position: relative;\n display: grid;\n grid-template-columns: var(--grid-template-columns);\n\n border-top: var(--grid-header-top-border);\n\n /*\n * 가로는 감춘다 — 머리를 사람이 직접 끌지는 않는다. 몸을 따라 프로그램이 옮긴다.\n *\n * 세로는 몸과 같은 만큼 자리를 비운다. 몸만 스크롤바에 자리를 내주면 갈 수 있는 거리가\n * 달라져서, 오른쪽 끝에서 몸이 그 폭만큼 더 간다(몸의 scrollbar-gutter 주석 참조).\n * 머리에는 세로로 넘칠 것이 없으므로 손잡이는 그려지지 않고 자리만 남는다.\n */\n overflow-x: hidden;\n overflow-y: scroll;\n scrollbar-gutter: stable;\n\n font-variation-settings: 'FILL' 1;\n\n user-select: none;\n }\n\n :host([raised]) [fixed] {\n /* 고정 컬럼이 살짝 올라와 있는 느낌을 표현 */\n box-shadow: 3px 0 3px rgba(0, 0, 0, 0.1);\n }\n\n div[column] {\n display: flex;\n\n white-space: nowrap;\n overflow: hidden;\n background-color: var(--grid-header-background-color);\n border-bottom: var(--grid-header-bottom-border);\n padding: var(--grid-header-padding);\n\n text-overflow: ellipsis;\n font: var(--grid-header-font);\n color: var(--grid-header-color);\n }\n\n /*\n * 거터 칸(순번 · 선택 · 더러움 표식)은 몸과 **같은 자리**에 있어야 한다. 머리의 체크박스와 각 줄의\n * 체크박스가 한 줄로 서지 않으면 표가 어긋나 보인다.\n *\n * 전에는 두 가지가 어긋나 있었다.\n * · text-align: center 로 가운데를 맞추려 했지만 이 칸은 display: flex 다 —\n * flex 안에서 text-align 은 항목을 옮기지 못한다. 그래서 왼쪽에 붙었다\n * · 여백을 몸(--grid-gutter-padding)과 **다른 토큰**(--spacing-small)에서 읽었다\n *\n * 그래서 정렬은 flex 로 하고, 여백은 몸과 같은 토큰을 본다.\n */\n div[gutter] {\n padding: var(--grid-gutter-padding);\n justify-content: center;\n }\n\n /*\n * 거터 칸의 내용물은 span[for-title] 안에 들어간다 — 열 제목이 쓰는 그 span 이다. 그래서 제목용\n * 규칙 둘을 함께 물려받는데, 거터에는 제목도 정렬 표식도 없으므로 둘 다 체크박스를 밀기만 한다.\n *\n * flex: 1 칸을 다 채워서, 칸의 justify-content 가 나눌 여백이 남지 않는다\n * margin-right 제목과 표식 사이를 벌리려던 값이라, 내용물이 그만큼 왼쪽으로 간다\n *\n * 둘을 거두면 span 이 내용물 크기로 줄고, 칸이 그것을 가운데로 놓는다. 입력의 기본 여백도 없애야\n * 몸의 체크박스와 정확히 같은 자리에 선다 — 몸은 여백 없이 가운데에 있다.\n */\n div[gutter] span[for-title] {\n flex: none;\n margin-right: 0;\n }\n\n div[gutter] input {\n margin: 0;\n }\n\n span {\n display: block;\n white-space: nowrap;\n overflow: hidden;\n }\n\n span[for-title] {\n flex: 1;\n /* 표식 무리와 이름 사이를 벌린다 — 붙어 있으면 이름의 일부처럼 읽힌다. */\n margin-right: 6px;\n /* 작은 대문자 라벨로 쓸 때 자간이 필요하다. 테마가 정하지 않으면 0 이다. */\n letter-spacing: var(--grid-header-letter-spacing, normal);\n text-overflow: ellipsis;\n line-height: 1.6;\n text-transform: var(--grid-header-text-transform, capitalize);\n align-self: center;\n }\n\n span[for-title] * {\n vertical-align: middle;\n }\n\n span[for-title] md-icon {\n font-size: 1.2em;\n }\n\n span[sorter],\n span[filter] {\n display: flex;\n align-self: center;\n\n padding: 0;\n border: 0;\n }\n\n span[sorter] md-icon {\n font-size: var(--grid-header-sorter-size);\n }\n\n /*\n * 머리의 표식은 **알림이지 버튼이 아니다.** 머리에서 읽어야 할 것은 열 이름이다.\n *\n * ── 연필이 지저분해 보이던 이유 셋 ──────────────────────────────────\n * 크기가 글자만 했고(1.2em), 획이 본문과 같은 굵기였고, 열 이름 바로 옆에 붙어 있었다.\n * 편집용 표에서는 거의 모든 열이 고칠 수 있어서 그 셋이 열 수만큼 반복됐다.\n *\n * 셋을 각각 낮춘다.\n *\n * 크기 14px — 정렬 표식과 같게 맞춘다. 전에는 연필 12px, 화살표 18px 로 따로 놀았다\n * 획 가변 글꼴의 굵기 축을 200 으로. 채운 글리프가 아니라 가는 선이 된다\n * 자리 정렬 표식과 한 무리로 오른쪽에 모은다. 이름과 표식 사이가 갈린다\n *\n * 글리프는 연필(edit)이다. text_fields · edit_square 와 나란히 놓고 견주었고 사용자가 골랐다 —\n * 「고칠 수 있다」는 뜻이 가장 바로 오는 것이 연필이다.\n *\n * 연필이 지저분해 보였던 것은 글리프 탓이 아니라 크기(15px)와 획 굵기 탓이었다. 14px 에\n * 굵기 200 으로 두면 가는 선이 되어 이름을 방해하지 않는다.\n *\n * ── 정렬 표식 ──────────────────────────────────────────────────────\n * 정렬할 수 있다는 것은 아주 흐리게, 지금 정렬 중인 것만 한 단계 진하게 둔다.\n *\n * 색은 토큰으로 받되 currentColor 를 섞은 폴백을 둔다 — 테마가 값을 정하지 않아도 흐려지고\n * 라이트·다크 어느 쪽에서도 배경 대비가 유지된다.\n */\n md-icon[editable-mark] {\n align-self: center;\n font-size: var(--grid-header-mark-size, 14px);\n /* 가변 글꼴의 굵기·명암 축. 정적 글꼴이면 조용히 무시된다. */\n font-variation-settings: 'wght' 200, 'GRAD' -25, 'opsz' 20;\n color: var(--grid-header-editable-color, color-mix(in srgb, currentColor 34%, transparent));\n }\n\n md-icon[sortable-mark] {\n color: var(--grid-header-sortable-color, color-mix(in srgb, currentColor 18%, transparent));\n }\n\n span[sorter] md-icon:not([sortable-mark]),\n span[sorter] sub {\n color: var(--grid-header-sorted-color, color-mix(in srgb, currentColor 52%, transparent));\n }\n\n span[filter] > md-icon {\n font-size: var(--fontsize-default);\n line-height: 20px;\n }\n\n /*\n * 열 폭 조절 손잡이 — **세로 선을 그리는 것이 이것이다.**\n *\n * 표 안의 세로 선은 이 손잡이의 오른쪽 테두리다(칸 자체는 위아래 테두리만 갖는다). 그래서 이\n * 손잡이를 감추면 열 폭 조절과 세로 격자가 함께 사라진다 — 그 둘은 원래 한 물건이다.\n *\n * 고치지 않는 목록에서는 열 폭을 끌어 옮길 일이 없고, 세로 선이 없으면 표가 격자가 아니라\n * 줄로 읽힌다. 그럴 때 테마가 이렇게 정한다.\n *\n * --grid-header-splitter-display: none\n *\n * 값을 정하지 않으면 예전 그대로다 — 편집용 표는 손잡이가 있어야 한다.\n */\n span[splitter] {\n display: var(--grid-header-splitter-display, flex);\n cursor: col-resize;\n border-right: var(--grid-header-splitter-border);\n margin-right: 0;\n }\n\n /*\n * 손잡이가 있는 칸은 오른쪽 여백을 두지 않는다.\n *\n * 손잡이는 flex 항목이라 칸의 padding 안쪽에 놓인다. 좌우 여백이 2px 이던 동안에는 그 차이가\n * 안 보였지만, 여백을 10px 로 올리자 손잡이가 열 경계에서 10px 당겨졌다 — 세로 선이 경계가\n * 아닌 자리에 그려진 것이다.\n *\n * 그래서 손잡이가 있을 때만 오른쪽 여백을 거둔다. 손잡이가 없는 칸(거터 · 폭을 못 바꾸는 열)은\n * 여백을 그대로 둬야 글자가 경계에 닿지 않는다.\n *\n * 세로 길이는 손대지 않는다 — flex 가 늘려 주는 그대로, 칸의 위아래 여백만큼 들어간 짧은 선이다.\n */\n div[column]:has(span[splitter]) {\n padding-right: 0;\n }\n\n span[splitter]:hover {\n border-right: var(--grid-header-splitter-border-hover);\n }\n\n [filter-title] {\n color: var(--grid-header-filter-title-color);\n font: var(--grid-header-filter-title-font);\n text-transform: capitalize;\n }\n\n [filter-title] * {\n vertical-align: middle;\n }\n\n [filter-title] md-icon {\n opacity: 0.7;\n color: var(--grid-header-filter-title-icon-color);\n }\n\n [filter] input[type='checkbox'] {\n margin-left: var(--spacing-medium);\n margin-bottom: var(--spacing-small);\n }\n\n [fixed] {\n position: sticky;\n z-index: 2;\n }\n\n .span-both {\n grid-row: 1 / span 2; /* 1단과 2단에 걸쳐 표시 */\n }\n\n .group-header {\n grid-row: 1; /* 1행에 배치 */\n grid-column: var(--group-start) / span var(--group-size); /* 2열부터 시작하여 2열에 걸쳐 표시 */\n }\n\n @media print {\n :host {\n grid-template-columns: var(--grid-template-print-columns);\n }\n }\n\n @media (max-width: 768px) {\n /* 모바일에서는 그리드에서 고정된 열 해제 */\n [fixed] {\n position: static;\n z-index: 0;\n box-shadow: none !important;\n }\n }\n `\n ]\n\n @property({ type: Array }) columns: ColumnConfig[] = ZERO_COLUMNS\n @property({ type: Object }) data: GristData = ZERO_DATA\n @property({ type: Array }) sorters: SortersConfig = []\n @property({ type: Array }) filters: FilterValue[] = []\n @property({ type: Boolean, attribute: 'filtering-feature' }) filteringFeature: boolean = false\n\n @state() private row1: {\n index: number\n column: ColumnConfig\n clazz?: string\n start?: number\n size?: number\n align?: string\n group?: string\n }[] = []\n\n @state() private row2: {\n index: number\n column: ColumnConfig\n }[] = []\n\n private _lastAccVal?: number\n private _throttledNotifier?: any\n\n private tooltipController?: TooltipReactiveController = new TooltipReactiveController(this)\n\n connectedCallback() {\n super.connectedCallback()\n\n const grid = closestElement('ox-grist', this)\n\n this.addEventListener('scroll', function () {\n this.scrollLeft == 0 ? this.removeAttribute('raised') : this.setAttribute('raised', '')\n })\n\n if (this.filteringFeature) {\n this?.addEventListener('filter-change', (e: Event) => {\n const { name, operator, value } = (e as CustomEvent).detail\n const filters = this.filters instanceof Array ? [...this.filters] : []\n\n if (value == null) {\n const index = filters.findIndex(filter => filter.name === name)\n if (index === -1) {\n return\n }\n\n filters.splice(index, 1)\n } else {\n const index = filters.findIndex(filter => filter.name === name)\n if (index === -1) {\n filters.push({ name, operator, value })\n } else {\n filters.splice(index, 1, { name, operator, value })\n }\n }\n\n grid?.dispatchEvent(\n new CustomEvent('fetch-params-change', {\n detail: {\n filters,\n from: 'data-grid-header'\n }\n })\n )\n })\n }\n }\n\n render() {\n const clazz = this.row2.length > 0 ? 'span-both' : undefined\n\n return html`\n ${this.row1.map(({ column, clazz, start, size, align, index, group }) =>\n this.renderHeaderColumn({ column, clazz, start, size, align, index, group })\n )}\n\n <div column class=${ifDefined(clazz)}></div>\n\n ${this.row2.map(({ column, index }) => this.renderHeaderColumn({ column, index }))}\n `\n }\n\n renderHeaderColumn({ column, clazz, start, size, align, index, group }: any): TemplateResult {\n if (column.hidden) {\n return html`${nothing}`\n }\n\n return html`\n <div\n ?gutter=${column.type == 'gutter'}\n ?fixed=${column.fixed}\n column\n class=${ifDefined(clazz)}\n style=${group\n ? `--group-start:${start};--group-size:${size};${column.header?.style || ''}`\n : `${column.header?.style || ''}`}\n >\n <span\n for-title\n data-reactive-tooltip\n style=\"text-align:${align || column.record.align || 'left'};\"\n @click=${(e: MouseEvent) => this._changeSort(column)}\n >${this._renderHeader(column)}\n </span>\n\n ${column.record?.editable ? html`<md-icon editable-mark title=${i18next.t('text.grid-column-editable', { defaultValue: 'editable' })}>edit</md-icon>` : nothing}\n ${!group && column.sortable\n ? html`\n <span sorter @click=${(e: MouseEvent) => this._changeSort(column)}>\n ${this._renderSortHeader(column)}\n </span>\n `\n : nothing}\n ${!group &&\n this.filteringFeature &&\n column.filter &&\n (column.filter as FilterConfigObject).operator !== 'search'\n ? html` <span filter> ${this._renderFilterHeader(column)} </span> `\n : nothing}\n ${column.resizable !== false\n ? html`\n <span splitter draggable=\"false\" @pointerdown=${(e: PointerEvent) => this._pointerdown(e, index)}\n >&nbsp;</span\n >\n `\n : nothing}\n </div>\n `\n }\n\n notifyFixedLeftChange() {\n const fixedHeaders = Array.from(this.renderRoot.querySelectorAll('div[fixed]')) as HTMLElement[]\n const fixedLefts = [] as number[]\n var left = 0\n fixedHeaders.forEach((header: HTMLElement) => {\n header.style.left = left + 'px'\n fixedLefts.push(left)\n\n const width = header.offsetWidth\n left += width\n })\n\n this.dispatchEvent(\n new CustomEvent('fixed-lefts-change', {\n detail: fixedLefts\n })\n )\n }\n\n updated(changes: PropertyValues) {\n var isColumnWidthChangePossible = false\n\n if (changes.has('columns')) {\n this.row2 = this.columns.reduce((row2, column, index) => {\n if (column.hidden || !column.header?.group) {\n return row2\n }\n return row2.concat({\n index,\n column\n } as any)\n }, [] as any[])\n\n const clazz = this.row2.length > 0 ? 'span-both' : undefined\n\n var columnNo = 0\n\n this.row1 = this.columns.reduce((row1, column, index) => {\n if (column.hidden) {\n return row1\n }\n\n columnNo++\n if (!column.header?.group) {\n return row1.concat({\n index,\n column,\n clazz\n } as any)\n }\n const { group, groupStyle } = column.header\n const last = row1[row1.length - 1] as any\n\n if (!last || group !== last.group) {\n return row1.concat({\n index,\n column: {\n ...column,\n header: {\n renderer: () => group,\n style: groupStyle\n }\n },\n group,\n align: 'center',\n clazz: 'group-header',\n start: columnNo,\n size: 1\n } as any)\n }\n\n last.size++\n\n return row1\n }, [] as any[])\n\n isColumnWidthChangePossible = true\n }\n\n if (changes.has('data')) {\n isColumnWidthChangePossible = true\n }\n\n if (isColumnWidthChangePossible) {\n // requestAnimationFrame(() => this.notifyFixedLeftChange())\n this.notifyFixedLeftChange()\n }\n }\n\n _renderHeader(column: ColumnConfig) {\n var { renderer } = column.header || {}\n var title = renderer.call(this, column)\n\n return html`${column?.record?.mandatory ? '*' : ''} ${title} `\n }\n\n _renderSortHeader(column: ColumnConfig) {\n var sorters = this.sorters || []\n\n var sorter = sorters.find(sorter => column.type !== 'gutter' && column.name == sorter.name)\n if (!sorter) {\n return html`<md-icon sortable-mark>unfold_more</md-icon>`\n }\n\n if (sorters.length > 1) {\n var rank = sorters.indexOf(sorter) + 1\n return sorter.desc\n ? html` <md-icon>keyboard_arrow_down</md-icon><sub>${rank}</sub> `\n : html` <md-icon>keyboard_arrow_up</md-icon><sub>${rank}</sub> `\n } else {\n return sorter.desc ? html` <md-icon>keyboard_arrow_down</md-icon> ` : html` <md-icon>keyboard_arrow_up</md-icon> `\n }\n }\n\n _renderFilterHeader(column: ColumnConfig) {\n const name = column.name\n const filter = column.filter as FilterConfigObject\n const type = filter.type\n const value = this.filters.find(filter => filter.name === name)?.value\n const idx = filter!.operator === 'between' ? 1 : 0\n const renderer = getFilterRenderer(type)[idx]\n\n return html`\n <md-icon\n @click=${(e: Event) => {\n const parent = (e.target as HTMLElement).closest('[column]') as HTMLElement\n const popup = parent.querySelector('ox-popup, ox-popup-list') as OxPopup | null\n // const popup = (e.target as HTMLElement).nextSibling as OxPopupList | null\n\n // absolute position인 popup의 위치 부모는 grist 이므로,\n // data-grid-header 의 포지션 부모(grist)의 위치로부터 계산해야함.\n // this의 position을 relative로 하지 못하는 이유 : ox-popup-list가 grid body에 덮히기 때문.\n // const top = parent.offsetTop + parent.offsetHeight\n // const right = this.clientWidth - (parent.offsetLeft + parent.offsetWidth - this.scrollLeft)\n\n popup?.open({\n right: 0,\n top: parent.offsetHeight,\n fixed: true\n })\n }}\n >filter_alt</md-icon\n >\n\n ${!renderer\n ? html``\n : type !== 'select'\n ? html` <ox-popup\n ><div filter-title><md-icon>filter_alt</md-icon> filter by <strong>${column.name}</strong></div>\n ${renderer(column, value, this)}</ox-popup\n >`\n : filter!.operator === 'in'\n ? html`<ox-popup-list\n multiple\n attr-selected=\"checked\"\n .value=${value}\n with-search\n @select=${(e: CustomEvent) =>\n e.target?.dispatchEvent(\n new CustomEvent('filter-change', {\n bubbles: true,\n composed: true,\n detail: {\n name,\n operator: filter!.operator,\n value: !e.detail\n ? undefined\n : e.detail instanceof Array && e.detail.length === 0\n ? undefined\n : e.detail\n }\n })\n )}\n ><div filter-title slot=\"header\">\n <md-icon>filter_alt</md-icon> filter by <strong>${column.name}</strong>\n </div>\n ${renderer(column, value, this)}</ox-popup-list\n >`\n : html`<ox-popup-list\n .value=${value}\n with-search\n @select=${(e: CustomEvent) =>\n e.target?.dispatchEvent(\n new CustomEvent('filter-change', {\n bubbles: true,\n composed: true,\n detail: {\n name,\n operator: filter!.operator,\n value: e.detail ? e.detail : undefined\n }\n })\n )}\n ><div filter-title slot=\"header\">\n <md-icon>filter_alt</md-icon> filter by <strong>${column.name}</strong>\n </div>\n ${renderer(column, value, this)}</ox-popup-list\n >`}\n `\n }\n\n _changeSort(column: ColumnConfig) {\n if (!column.sortable) {\n return\n }\n\n var sorters = [...this.sorters]\n\n var idx = sorters.findIndex(sorter => sorter.name == column.name)\n if (idx !== -1) {\n let sorter = sorters[idx]\n if (sorter.desc) {\n sorters.splice(idx, 1)\n } else {\n sorters.splice(idx, 1, {\n ...sorter,\n desc: true\n })\n }\n } else {\n var sorter = {\n name: column.name,\n desc: false\n }\n\n sorters.push(sorter)\n }\n\n this.sorters = sorters\n\n this.dispatchEvent(\n new CustomEvent('fetch-params-change', {\n bubbles: true,\n composed: true,\n detail: {\n sorters: this.sorters,\n from: 'data-grid-header'\n }\n })\n )\n }\n\n _accumalate(x: number) {\n this._lastAccVal = (this._lastAccVal ?? 0) + x\n return this._lastAccVal\n }\n\n _notifyWidthChange(idx: number, width: number) {\n if (!this._throttledNotifier) {\n this._throttledNotifier = throttle((idx: number, width: number) => {\n this.dispatchEvent(\n new CustomEvent('column-width-change', {\n bubbles: true,\n composed: true,\n detail: {\n idx,\n width\n }\n })\n )\n\n this.notifyFixedLeftChange()\n\n this._lastAccVal = 0\n }, 100)\n }\n\n this._throttledNotifier(idx, width)\n }\n\n _pointerdown(e: PointerEvent, idx: number) {\n e.stopPropagation()\n e.preventDefault()\n ;(e.target as HTMLElement).setPointerCapture(e.pointerId)\n\n var pointermoveHandler = ((e: PointerEvent) => {\n e.stopPropagation()\n e.preventDefault()\n let column = this.columns[idx]\n\n let width = Math.max(0, Number(column.width || 100) + this._accumalate(e.movementX))\n if (width == 0) {\n /* CLARIFY-ME 왜 마지막 이벤트의 offsetX로 음수 값이 오는가 */\n return\n }\n\n this._notifyWidthChange(idx, width)\n }).bind(this)\n\n var pointerupHandler = ((e: PointerEvent) => {\n ;(e.target as HTMLElement).releasePointerCapture(e.pointerId)\n\n document.removeEventListener('pointermove', pointermoveHandler)\n document.removeEventListener('pointerup', pointerupHandler)\n\n pointermoveHandler(e)\n }).bind(this)\n\n document.addEventListener('pointermove', pointermoveHandler)\n document.addEventListener('pointerup', pointerupHandler)\n }\n}\n"]}
1
+ {"version":3,"file":"data-grid-header.js","sourceRoot":"","sources":["../../../src/data-grid/data-grid-header.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/popup/ox-popup.js'\nimport '@material/web/icon/icon.js'\n\nimport i18next from 'i18next'\nimport { css, html, LitElement, PropertyValues, nothing, TemplateResult } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\nimport throttle from 'lodash-es/throttle.js'\n\nimport { OxPopup } from '@operato/popup'\nimport { TooltipReactiveController, closestElement } from '@operato/utils'\n\nimport { ZERO_COLUMNS, ZERO_DATA } from '../configure/zero-config.js'\nimport { FilterStyles } from '../filters/filter-styles.js'\nimport { getFilterRenderer } from '../filters/registry.js'\nimport { ColumnConfig, FilterConfigObject, FilterValue, GristData, SortersConfig } from '../types.js'\n\n/** 칸의 정렬 선언(record.align)을 flex 의 말로 옮긴다. */\nconst ALIGN_JUSTIFY = {\n left: 'flex-start',\n center: 'center',\n right: 'flex-end'\n} as const\n\n@customElement('ox-grid-header')\nexport class DataGridHeader extends LitElement {\n static styles = [\n FilterStyles,\n css`\n :host {\n position: relative;\n display: grid;\n grid-template-columns: var(--grid-template-columns);\n\n border-top: var(--grid-header-top-border);\n\n /*\n * 가로는 감춘다 — 머리를 사람이 직접 끌지는 않는다. 몸을 따라 프로그램이 옮긴다.\n *\n * 세로는 몸과 같은 만큼 자리를 비운다. 몸만 스크롤바에 자리를 내주면 갈 수 있는 거리가\n * 달라져서, 오른쪽 끝에서 몸이 그 폭만큼 더 간다(몸의 scrollbar-gutter 주석 참조).\n * 머리에는 세로로 넘칠 것이 없으므로 손잡이는 그려지지 않고 자리만 남는다.\n */\n overflow-x: hidden;\n overflow-y: scroll;\n scrollbar-gutter: stable;\n\n font-variation-settings: 'FILL' 1;\n\n user-select: none;\n }\n\n :host([raised]) [fixed] {\n /* 고정 컬럼이 살짝 올라와 있는 느낌을 표현 */\n box-shadow: 3px 0 3px rgba(0, 0, 0, 0.1);\n }\n\n div[column] {\n display: flex;\n\n white-space: nowrap;\n overflow: hidden;\n background-color: var(--grid-header-background-color);\n border-bottom: var(--grid-header-bottom-border);\n padding: var(--grid-header-padding);\n\n text-overflow: ellipsis;\n font: var(--grid-header-font);\n /*\n * 글꼴은 따로 받는다 — 기본은 물려받는다(본문과 같은 글꼴).\n *\n * font 축약형은 글꼴 이름을 반드시 요구해서, 토큰 하나로 쓰면 굵기 · 크기와 글꼴이 묶인다.\n * 그 탓에 머리글이 고정폭으로 그려졌는데, **고정폭에는 한글 글자가 없다.** 대체 글꼴로 떨어지므로\n * 「ISA-95 계층 단」 한 줄 안에서 라틴과 한글이 서로 다른 글꼴이 됐다.\n *\n * 테마가 글꼴까지 정하고 싶으면 --grid-header-font-family 를 준다.\n */\n font-family: var(--grid-header-font-family, inherit);\n color: var(--grid-header-color);\n }\n\n /*\n * 거터 칸(순번 · 선택 · 더러움 표식)은 몸과 **같은 자리**에 있어야 한다. 머리의 체크박스와 각 줄의\n * 체크박스가 한 줄로 서지 않으면 표가 어긋나 보인다.\n *\n * 전에는 두 가지가 어긋나 있었다.\n * · text-align: center 로 가운데를 맞추려 했지만 이 칸은 display: flex 다 —\n * flex 안에서 text-align 은 항목을 옮기지 못한다. 그래서 왼쪽에 붙었다\n * · 여백을 몸(--grid-gutter-padding)과 **다른 토큰**(--spacing-small)에서 읽었다\n *\n * 그래서 정렬은 flex 로 하고, 여백은 몸과 같은 토큰을 본다.\n */\n div[gutter] {\n padding: var(--grid-gutter-padding);\n /*\n * 기본은 가운데. 거터마다 자기 정렬이 있으면 renderHeaderColumn 이 인라인으로 덮는다 —\n * 순번은 오른쪽이다(몸의 숫자가 오른쪽이므로 머리의 # 도 오른쪽이어야 자릿수가 맞아 보인다).\n */\n justify-content: center;\n }\n\n /*\n * 거터 칸의 내용물은 span[for-title] 안에 들어간다 — 열 제목이 쓰는 그 span 이다. 그래서 제목용\n * 규칙 둘을 함께 물려받는데, 거터에는 제목도 정렬 표식도 없으므로 둘 다 체크박스를 밀기만 한다.\n *\n * flex: 1 칸을 다 채워서, 칸의 justify-content 가 나눌 여백이 남지 않는다\n * margin-right 제목과 표식 사이를 벌리려던 값이라, 내용물이 그만큼 왼쪽으로 간다\n *\n * 둘을 거두면 span 이 내용물 크기로 줄고, 칸이 그것을 가운데로 놓는다. 입력의 기본 여백도 없애야\n * 몸의 체크박스와 정확히 같은 자리에 선다 — 몸은 여백 없이 가운데에 있다.\n */\n div[gutter] span[for-title] {\n flex: none;\n margin-right: 0;\n }\n\n div[gutter] input {\n margin: 0;\n }\n\n span {\n display: block;\n white-space: nowrap;\n overflow: hidden;\n }\n\n span[for-title] {\n /*\n * 이름이 자기 길이만큼만 차지한다 — 그러면 정렬 표식이 이름 바로 오른쪽에 붙는다.\n *\n * 고치는 표에서는 1 로 되돌린다(data-grid.ts 의 editable-grid 한 벌). 거기서는 칸 끝에 폭 조절\n * 손잡이가 서 있어서, 표식이 그 옆에 모여 있는 편이 낫다.\n *\n * 늘어남만 토큰으로 받고 **줄어듦은 항상 1 이다.** 긴 이름이 줄어들 수 있어야 말줄임으로\n * 잘린다 — 줄어들지 못하면 칸을 넘어가 그냥 잘린다.\n *\n * 축약형(flex)에 var 을 쓰면 「0 1 auto」 가 「none」 으로 해석되는 일이 있었다(실측 0 0 auto).\n * 낱개 속성으로 적으면 그 함정이 없다.\n */\n flex-grow: var(--grid-header-title-grow, 0);\n flex-shrink: 1;\n flex-basis: auto;\n /* 표식 무리와 이름 사이를 벌린다 — 붙어 있으면 이름의 일부처럼 읽힌다. */\n margin-right: 6px;\n /* 작은 대문자 라벨로 쓸 때 자간이 필요하다. 테마가 정하지 않으면 0 이다. */\n letter-spacing: var(--grid-header-letter-spacing, normal);\n text-overflow: ellipsis;\n line-height: 1.6;\n text-transform: var(--grid-header-text-transform, capitalize);\n align-self: center;\n }\n\n span[for-title] * {\n vertical-align: middle;\n }\n\n span[for-title] md-icon {\n font-size: 1.2em;\n }\n\n span[sorter],\n span[filter] {\n display: flex;\n align-self: center;\n\n padding: 0;\n border: 0;\n }\n\n span[sorter] md-icon {\n font-size: var(--grid-header-sorter-size);\n }\n\n /*\n * 머리의 표식은 **알림이지 버튼이 아니다.** 머리에서 읽어야 할 것은 열 이름이다.\n *\n * ── 연필이 지저분해 보이던 이유 셋 ──────────────────────────────────\n * 크기가 글자만 했고(1.2em), 획이 본문과 같은 굵기였고, 열 이름 바로 옆에 붙어 있었다.\n * 편집용 표에서는 거의 모든 열이 고칠 수 있어서 그 셋이 열 수만큼 반복됐다.\n *\n * 셋을 각각 낮춘다.\n *\n * 크기 14px — 정렬 표식과 같게 맞춘다. 전에는 연필 12px, 화살표 18px 로 따로 놀았다\n * 획 가변 글꼴의 굵기 축을 200 으로. 채운 글리프가 아니라 가는 선이 된다\n * 자리 정렬 표식과 한 무리로 오른쪽에 모은다. 이름과 표식 사이가 갈린다\n *\n * 글리프는 연필(edit)이다. text_fields · edit_square 와 나란히 놓고 견주었고 사용자가 골랐다 —\n * 「고칠 수 있다」는 뜻이 가장 바로 오는 것이 연필이다.\n *\n * 연필이 지저분해 보였던 것은 글리프 탓이 아니라 크기(15px)와 획 굵기 탓이었다. 14px 에\n * 굵기 200 으로 두면 가는 선이 되어 이름을 방해하지 않는다.\n *\n * ── 정렬 표식 ──────────────────────────────────────────────────────\n * 정렬할 수 있다는 것은 아주 흐리게, 지금 정렬 중인 것만 한 단계 진하게 둔다.\n *\n * 색은 토큰으로 받되 currentColor 를 섞은 폴백을 둔다 — 테마가 값을 정하지 않아도 흐려지고\n * 라이트·다크 어느 쪽에서도 배경 대비가 유지된다.\n */\n md-icon[editable-mark] {\n align-self: center;\n font-size: var(--grid-header-mark-size, 14px);\n /* 가변 글꼴의 굵기·명암 축. 정적 글꼴이면 조용히 무시된다. */\n font-variation-settings: 'wght' 200, 'GRAD' -25, 'opsz' 20;\n color: var(--grid-header-editable-color, color-mix(in srgb, currentColor 34%, transparent));\n }\n\n md-icon[sortable-mark] {\n color: var(--grid-header-sortable-color, color-mix(in srgb, currentColor 18%, transparent));\n }\n\n span[sorter] md-icon:not([sortable-mark]),\n span[sorter] sub {\n color: var(--grid-header-sorted-color, color-mix(in srgb, currentColor 52%, transparent));\n }\n\n span[filter] > md-icon {\n font-size: var(--fontsize-default);\n line-height: 20px;\n }\n\n /*\n * 열 폭 조절 손잡이 — **세로 선을 그리는 것이 이것이다.**\n *\n * 표 안의 세로 선은 이 손잡이의 오른쪽 테두리다(칸 자체는 위아래 테두리만 갖는다). 그래서 이\n * 손잡이를 감추면 열 폭 조절과 세로 격자가 함께 사라진다 — 그 둘은 원래 한 물건이다.\n *\n * 고치지 않는 목록에서는 열 폭을 끌어 옮길 일이 없고, 세로 선이 없으면 표가 격자가 아니라\n * 줄로 읽힌다. 그럴 때 테마가 이렇게 정한다.\n *\n * --grid-header-splitter-display: none\n *\n * 값을 정하지 않으면 예전 그대로다 — 편집용 표는 손잡이가 있어야 한다.\n */\n span[splitter] {\n display: var(--grid-header-splitter-display, flex);\n cursor: col-resize;\n border-right: var(--grid-header-splitter-border);\n margin-right: 0;\n }\n\n /*\n * 손잡이가 있는 칸은 오른쪽 여백을 두지 않는다.\n *\n * 손잡이는 flex 항목이라 칸의 padding 안쪽에 놓인다. 좌우 여백이 2px 이던 동안에는 그 차이가\n * 안 보였지만, 여백을 10px 로 올리자 손잡이가 열 경계에서 10px 당겨졌다 — 세로 선이 경계가\n * 아닌 자리에 그려진 것이다.\n *\n * 그래서 손잡이가 있을 때만 오른쪽 여백을 거둔다. 손잡이가 없는 칸(거터 · 폭을 못 바꾸는 열)은\n * 여백을 그대로 둬야 글자가 경계에 닿지 않는다.\n *\n * 세로 길이는 손대지 않는다 — flex 가 늘려 주는 그대로, 칸의 위아래 여백만큼 들어간 짧은 선이다.\n */\n div[column]:has(span[splitter]) {\n padding-right: 0;\n }\n\n span[splitter]:hover {\n border-right: var(--grid-header-splitter-border-hover);\n }\n\n [filter-title] {\n color: var(--grid-header-filter-title-color);\n font: var(--grid-header-filter-title-font);\n text-transform: capitalize;\n }\n\n [filter-title] * {\n vertical-align: middle;\n }\n\n [filter-title] md-icon {\n opacity: 0.7;\n color: var(--grid-header-filter-title-icon-color);\n }\n\n [filter] input[type='checkbox'] {\n margin-left: var(--spacing-medium);\n margin-bottom: var(--spacing-small);\n }\n\n [fixed] {\n position: sticky;\n z-index: 2;\n }\n\n .span-both {\n grid-row: 1 / span 2; /* 1단과 2단에 걸쳐 표시 */\n }\n\n .group-header {\n grid-row: 1; /* 1행에 배치 */\n grid-column: var(--group-start) / span var(--group-size); /* 2열부터 시작하여 2열에 걸쳐 표시 */\n }\n\n @media print {\n :host {\n grid-template-columns: var(--grid-template-print-columns);\n }\n }\n\n @media (max-width: 768px) {\n /* 모바일에서는 그리드에서 고정된 열 해제 */\n [fixed] {\n position: static;\n z-index: 0;\n box-shadow: none !important;\n }\n }\n `\n ]\n\n @property({ type: Array }) columns: ColumnConfig[] = ZERO_COLUMNS\n @property({ type: Object }) data: GristData = ZERO_DATA\n @property({ type: Array }) sorters: SortersConfig = []\n @property({ type: Array }) filters: FilterValue[] = []\n @property({ type: Boolean, attribute: 'filtering-feature' }) filteringFeature: boolean = false\n\n @state() private row1: {\n index: number\n column: ColumnConfig\n clazz?: string\n start?: number\n size?: number\n align?: string\n group?: string\n }[] = []\n\n @state() private row2: {\n index: number\n column: ColumnConfig\n }[] = []\n\n private _lastAccVal?: number\n private _throttledNotifier?: any\n\n private tooltipController?: TooltipReactiveController = new TooltipReactiveController(this)\n\n connectedCallback() {\n super.connectedCallback()\n\n const grid = closestElement('ox-grist', this)\n\n this.addEventListener('scroll', function () {\n this.scrollLeft == 0 ? this.removeAttribute('raised') : this.setAttribute('raised', '')\n })\n\n if (this.filteringFeature) {\n this?.addEventListener('filter-change', (e: Event) => {\n const { name, operator, value } = (e as CustomEvent).detail\n const filters = this.filters instanceof Array ? [...this.filters] : []\n\n if (value == null) {\n const index = filters.findIndex(filter => filter.name === name)\n if (index === -1) {\n return\n }\n\n filters.splice(index, 1)\n } else {\n const index = filters.findIndex(filter => filter.name === name)\n if (index === -1) {\n filters.push({ name, operator, value })\n } else {\n filters.splice(index, 1, { name, operator, value })\n }\n }\n\n grid?.dispatchEvent(\n new CustomEvent('fetch-params-change', {\n detail: {\n filters,\n from: 'data-grid-header'\n }\n })\n )\n })\n }\n }\n\n render() {\n const clazz = this.row2.length > 0 ? 'span-both' : undefined\n\n return html`\n ${this.row1.map(({ column, clazz, start, size, align, index, group }) =>\n this.renderHeaderColumn({ column, clazz, start, size, align, index, group })\n )}\n\n <div column class=${ifDefined(clazz)}></div>\n\n ${this.row2.map(({ column, index }) => this.renderHeaderColumn({ column, index }))}\n `\n }\n\n renderHeaderColumn({ column, clazz, start, size, align, index, group }: any): TemplateResult {\n if (column.hidden) {\n return html`${nothing}`\n }\n\n /*\n * 거터 머리는 flex 로 정렬한다.\n *\n * 아래 span 의 `text-align` 은 거터에서 듣지 않는다 — 그 span 이 내용물 크기로 줄어 있어서\n * (위 div[gutter] 머리말 참조) 글자를 밀 여백이 span 안에 없다. 그래서 칸이 밀어야 한다.\n *\n * 값은 그 거터가 이미 선언한 것을 본다. 순번은 right, 선택과 더러움 표식은 center 다. 여기에 따로\n * 적으면 거터를 하나 더할 때 두 곳을 맞춰야 한다.\n */\n /*\n * 정렬은 **칸이 flex 로 민다.** 아래 span 의 text-align 에 기대지 않는다.\n *\n * 그 span 은 이름 길이만큼만 차지하므로(위 span[for-title] 머리말) 안에 글자를 밀 여백이 없다.\n * 그래서 text-align 이 아무 일도 하지 않는다 — 숫자 칸의 값은 오른쪽인데 머리글만 왼쪽에\n * 남았다. [재봤음] 「수량」 머리 x=391 · 값 오른쪽 끝 x=402. 2026-09-02\n *\n * 칸이 밀면 이름과 표식이 **함께** 그 방향으로 간다. 그래서 오른쪽 정렬 칸에서도 표식이 이름\n * 옆에 붙어 있다.\n *\n * 거터의 기본은 가운데(체크박스 · 더러움 표식), 보통 칸의 기본은 왼쪽이다.\n */\n const fallback = column.type == 'gutter' ? 'center' : 'flex-start'\n const justify = `justify-content:${ALIGN_JUSTIFY[(align || column.record?.align) as keyof typeof ALIGN_JUSTIFY] || fallback};`\n\n return html`\n <div\n ?gutter=${column.type == 'gutter'}\n ?fixed=${column.fixed}\n column\n class=${ifDefined(clazz)}\n style=${group\n ? `--group-start:${start};--group-size:${size};${justify}${column.header?.style || ''}`\n : `${justify}${column.header?.style || ''}`}\n >\n <span\n for-title\n data-reactive-tooltip\n style=\"text-align:${align || column.record.align || 'left'};\"\n @click=${(e: MouseEvent) => this._changeSort(column)}\n >${this._renderHeader(column)}\n </span>\n\n ${column.record?.editable ? html`<md-icon editable-mark title=${i18next.t('text.grid-column-editable', { defaultValue: 'editable' })}>edit</md-icon>` : nothing}\n ${!group && column.sortable\n ? html`\n <span sorter @click=${(e: MouseEvent) => this._changeSort(column)}>\n ${this._renderSortHeader(column)}\n </span>\n `\n : nothing}\n ${!group &&\n this.filteringFeature &&\n column.filter &&\n (column.filter as FilterConfigObject).operator !== 'search'\n ? html` <span filter> ${this._renderFilterHeader(column)} </span> `\n : nothing}\n ${column.resizable !== false\n ? html`\n <span splitter draggable=\"false\" @pointerdown=${(e: PointerEvent) => this._pointerdown(e, index)}\n >&nbsp;</span\n >\n `\n : nothing}\n </div>\n `\n }\n\n notifyFixedLeftChange() {\n const fixedHeaders = Array.from(this.renderRoot.querySelectorAll('div[fixed]')) as HTMLElement[]\n const fixedLefts = [] as number[]\n var left = 0\n fixedHeaders.forEach((header: HTMLElement) => {\n header.style.left = left + 'px'\n fixedLefts.push(left)\n\n const width = header.offsetWidth\n left += width\n })\n\n this.dispatchEvent(\n new CustomEvent('fixed-lefts-change', {\n detail: fixedLefts\n })\n )\n }\n\n updated(changes: PropertyValues) {\n var isColumnWidthChangePossible = false\n\n if (changes.has('columns')) {\n this.row2 = this.columns.reduce((row2, column, index) => {\n if (column.hidden || !column.header?.group) {\n return row2\n }\n return row2.concat({\n index,\n column\n } as any)\n }, [] as any[])\n\n const clazz = this.row2.length > 0 ? 'span-both' : undefined\n\n var columnNo = 0\n\n this.row1 = this.columns.reduce((row1, column, index) => {\n if (column.hidden) {\n return row1\n }\n\n columnNo++\n if (!column.header?.group) {\n return row1.concat({\n index,\n column,\n clazz\n } as any)\n }\n const { group, groupStyle } = column.header\n const last = row1[row1.length - 1] as any\n\n if (!last || group !== last.group) {\n return row1.concat({\n index,\n column: {\n ...column,\n header: {\n renderer: () => group,\n style: groupStyle\n }\n },\n group,\n align: 'center',\n clazz: 'group-header',\n start: columnNo,\n size: 1\n } as any)\n }\n\n last.size++\n\n return row1\n }, [] as any[])\n\n isColumnWidthChangePossible = true\n }\n\n if (changes.has('data')) {\n isColumnWidthChangePossible = true\n }\n\n if (isColumnWidthChangePossible) {\n // requestAnimationFrame(() => this.notifyFixedLeftChange())\n this.notifyFixedLeftChange()\n }\n }\n\n _renderHeader(column: ColumnConfig) {\n var { renderer } = column.header || {}\n var title = renderer.call(this, column)\n\n return html`${column?.record?.mandatory ? '*' : ''} ${title} `\n }\n\n _renderSortHeader(column: ColumnConfig) {\n var sorters = this.sorters || []\n\n var sorter = sorters.find(sorter => column.type !== 'gutter' && column.name == sorter.name)\n if (!sorter) {\n return html`<md-icon sortable-mark>unfold_more</md-icon>`\n }\n\n if (sorters.length > 1) {\n var rank = sorters.indexOf(sorter) + 1\n return sorter.desc\n ? html` <md-icon>keyboard_arrow_down</md-icon><sub>${rank}</sub> `\n : html` <md-icon>keyboard_arrow_up</md-icon><sub>${rank}</sub> `\n } else {\n return sorter.desc ? html` <md-icon>keyboard_arrow_down</md-icon> ` : html` <md-icon>keyboard_arrow_up</md-icon> `\n }\n }\n\n _renderFilterHeader(column: ColumnConfig) {\n const name = column.name\n const filter = column.filter as FilterConfigObject\n const type = filter.type\n const value = this.filters.find(filter => filter.name === name)?.value\n const idx = filter!.operator === 'between' ? 1 : 0\n const renderer = getFilterRenderer(type)[idx]\n\n return html`\n <md-icon\n @click=${(e: Event) => {\n const parent = (e.target as HTMLElement).closest('[column]') as HTMLElement\n const popup = parent.querySelector('ox-popup, ox-popup-list') as OxPopup | null\n // const popup = (e.target as HTMLElement).nextSibling as OxPopupList | null\n\n // absolute position인 popup의 위치 부모는 grist 이므로,\n // data-grid-header 의 포지션 부모(grist)의 위치로부터 계산해야함.\n // this의 position을 relative로 하지 못하는 이유 : ox-popup-list가 grid body에 덮히기 때문.\n // const top = parent.offsetTop + parent.offsetHeight\n // const right = this.clientWidth - (parent.offsetLeft + parent.offsetWidth - this.scrollLeft)\n\n popup?.open({\n right: 0,\n top: parent.offsetHeight,\n fixed: true\n })\n }}\n >filter_alt</md-icon\n >\n\n ${!renderer\n ? html``\n : type !== 'select'\n ? html` <ox-popup\n ><div filter-title><md-icon>filter_alt</md-icon> filter by <strong>${column.name}</strong></div>\n ${renderer(column, value, this)}</ox-popup\n >`\n : filter!.operator === 'in'\n ? html`<ox-popup-list\n multiple\n attr-selected=\"checked\"\n .value=${value}\n with-search\n @select=${(e: CustomEvent) =>\n e.target?.dispatchEvent(\n new CustomEvent('filter-change', {\n bubbles: true,\n composed: true,\n detail: {\n name,\n operator: filter!.operator,\n value: !e.detail\n ? undefined\n : e.detail instanceof Array && e.detail.length === 0\n ? undefined\n : e.detail\n }\n })\n )}\n ><div filter-title slot=\"header\">\n <md-icon>filter_alt</md-icon> filter by <strong>${column.name}</strong>\n </div>\n ${renderer(column, value, this)}</ox-popup-list\n >`\n : html`<ox-popup-list\n .value=${value}\n with-search\n @select=${(e: CustomEvent) =>\n e.target?.dispatchEvent(\n new CustomEvent('filter-change', {\n bubbles: true,\n composed: true,\n detail: {\n name,\n operator: filter!.operator,\n value: e.detail ? e.detail : undefined\n }\n })\n )}\n ><div filter-title slot=\"header\">\n <md-icon>filter_alt</md-icon> filter by <strong>${column.name}</strong>\n </div>\n ${renderer(column, value, this)}</ox-popup-list\n >`}\n `\n }\n\n _changeSort(column: ColumnConfig) {\n if (!column.sortable) {\n return\n }\n\n var sorters = [...this.sorters]\n\n var idx = sorters.findIndex(sorter => sorter.name == column.name)\n if (idx !== -1) {\n let sorter = sorters[idx]\n if (sorter.desc) {\n sorters.splice(idx, 1)\n } else {\n sorters.splice(idx, 1, {\n ...sorter,\n desc: true\n })\n }\n } else {\n var sorter = {\n name: column.name,\n desc: false\n }\n\n sorters.push(sorter)\n }\n\n this.sorters = sorters\n\n this.dispatchEvent(\n new CustomEvent('fetch-params-change', {\n bubbles: true,\n composed: true,\n detail: {\n sorters: this.sorters,\n from: 'data-grid-header'\n }\n })\n )\n }\n\n _accumalate(x: number) {\n this._lastAccVal = (this._lastAccVal ?? 0) + x\n return this._lastAccVal\n }\n\n _notifyWidthChange(idx: number, width: number) {\n if (!this._throttledNotifier) {\n this._throttledNotifier = throttle((idx: number, width: number) => {\n this.dispatchEvent(\n new CustomEvent('column-width-change', {\n bubbles: true,\n composed: true,\n detail: {\n idx,\n width\n }\n })\n )\n\n this.notifyFixedLeftChange()\n\n this._lastAccVal = 0\n }, 100)\n }\n\n this._throttledNotifier(idx, width)\n }\n\n _pointerdown(e: PointerEvent, idx: number) {\n e.stopPropagation()\n e.preventDefault()\n ;(e.target as HTMLElement).setPointerCapture(e.pointerId)\n\n var pointermoveHandler = ((e: PointerEvent) => {\n e.stopPropagation()\n e.preventDefault()\n let column = this.columns[idx]\n\n let width = Math.max(0, Number(column.width || 100) + this._accumalate(e.movementX))\n if (width == 0) {\n /* CLARIFY-ME 왜 마지막 이벤트의 offsetX로 음수 값이 오는가 */\n return\n }\n\n this._notifyWidthChange(idx, width)\n }).bind(this)\n\n var pointerupHandler = ((e: PointerEvent) => {\n ;(e.target as HTMLElement).releasePointerCapture(e.pointerId)\n\n document.removeEventListener('pointermove', pointermoveHandler)\n document.removeEventListener('pointerup', pointerupHandler)\n\n pointermoveHandler(e)\n }).bind(this)\n\n document.addEventListener('pointermove', pointermoveHandler)\n document.addEventListener('pointerup', pointerupHandler)\n }\n}\n"]}
@@ -4,7 +4,7 @@ import '../empty-note.js';
4
4
  import './data-grid-header.js';
5
5
  import './data-grid-body.js';
6
6
  import './data-grid-footer.js';
7
- import { css, html } from 'lit';
7
+ import { css, html, nothing } from 'lit';
8
8
  import { customElement, property, query, state } from 'lit/decorators.js';
9
9
  import { styles as MDTypeScaleStyles } from '@material/web/typography/md-typescale-styles.js';
10
10
  import { ScrollbarStyles } from '@operato/styles';
@@ -157,14 +157,11 @@ let DataGrid = class DataGrid extends DataManipulator {
157
157
  this.style.setProperty('--grid-template-print-columns', widths.replace(/px/gi, 'fr'));
158
158
  }
159
159
  render() {
160
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
160
161
  var { pagination = {}, columns = [], filters } = this.config;
161
162
  var paginatable = !pagination.infinite;
162
163
  var data = this.data;
163
164
  return html `
164
- <div setting>
165
- <slot name="setting"></slot>
166
- </div>
167
-
168
165
  <ox-grid-header
169
166
  class="md-typescale-label-medium-prominent"
170
167
  .columns=${columns}
@@ -181,6 +178,19 @@ let DataGrid = class DataGrid extends DataManipulator {
181
178
  >
182
179
  </ox-grid-header>
183
180
 
181
+ <!--
182
+ 헤더 **다음**에 둔다. CSS 로 「헤더에 올렸을 때만」을 표현하려면 형제 선택자가 필요하고, 형제
183
+ 선택자는 뒤쪽 형제만 고를 수 있다.
184
+
185
+ :host(:has(ox-grid-header:hover)) 로는 안 된다 — :host() 의 인수는 바깥 트리에서 평가되므로
186
+ 섀도 트리 안의 ox-grid-header 를 보지 못한다. 실제로 그렇게 써 봤고 hover 에 반응하지 않았다.
187
+
188
+ 순서를 바꿔도 보이는 자리는 같다 — 아래 스타일에서 호스트의 오른쪽 위에 절대 좌표로 붙인다.
189
+ -->
190
+ <div setting>
191
+ <slot name="setting"></slot>
192
+ </div>
193
+
184
194
  <ox-grid-body
185
195
  class="md-typescale-body-medium"
186
196
  .config=${this.config}
@@ -189,12 +199,38 @@ let DataGrid = class DataGrid extends DataManipulator {
189
199
  .focused=${this.focused}
190
200
  .fixedLefts=${this.fixedLefts}
191
201
  >
192
- ${this.empty ? html ` <ox-empty-note title=${i18next.t('text.grid-no-records', { defaultValue: 'NO RECORDS' })}></ox-empty-note> ` : html ``}
202
+ ${this.empty
203
+ ? html `
204
+ <!--
205
+ 아직 아무것도 없을 때 **화면이 자기 말을 넣을 수 있다.**
206
+
207
+ 전에는 「NO RECORDS」가 박혀 있었다. 그 문장은 다음에 무엇을 할지 알려 주지 않는다 —
208
+ 비어 있는 화면이야말로 「여기서 무엇을 만들 수 있고 그것이 무엇에 쓰이나」를 말해야 하는
209
+ 자리다. 처음 오는 사람이 가장 먼저 보는 화면이기도 하다.
210
+
211
+ 화면이 config.emptyNote 로 말하고, 말하지 않으면 예전 문장이 그대로 나온다.
212
+ -->
213
+ <ox-empty-note
214
+ icon=${(_c = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.emptyNote) === null || _b === void 0 ? void 0 : _b.icon) !== null && _c !== void 0 ? _c : nothing}
215
+ title=${(_f = (_e = (_d = this.config) === null || _d === void 0 ? void 0 : _d.emptyNote) === null || _e === void 0 ? void 0 : _e.title) !== null && _f !== void 0 ? _f : i18next.t('text.grid-no-records', { defaultValue: 'NO RECORDS' })}
216
+ description=${(_j = (_h = (_g = this.config) === null || _g === void 0 ? void 0 : _g.emptyNote) === null || _h === void 0 ? void 0 : _h.description) !== null && _j !== void 0 ? _j : nothing}
217
+ ></ox-empty-note>
218
+ `
219
+ : html ``}
193
220
  </ox-grid-body>
194
221
  ${paginatable
195
222
  ? html `
223
+ <!--
224
+ 푸터에는 본문 타이프스케일을 씌우지 않는다.
225
+
226
+ 그 클래스는 font 축약형으로 0.875rem 를 넣는데, **바깥 트리의 규칙이라 푸터의
227
+ :host { font-size } 를 이긴다**(그림자 캐스케이드에서 호스트 요소는 바깥 트리 규칙이
228
+ 우선한다). 그래서 푸터가 자기 크기를 못 정하고 본문과 같은 14px 로 남아 있었다.
229
+ [재봤음] 리터럴 :host { font-size: 7px } 도 안 먹었다. 2026-09-02
230
+
231
+ 푸터는 본문이 아니다. 크기는 --grid-footer-font-size 가 정한다.
232
+ -->
196
233
  <ox-grid-footer
197
- class="md-typescale-body-medium"
198
234
  .data=${data}
199
235
  .pagination=${this.pagination}
200
236
  ></ox-grid-footer>
@@ -225,12 +261,22 @@ DataGrid.styles = [
225
261
  :host([editable-grid]) {
226
262
  --grid-record-focused-cell-border: 1px dashed var(--ui-faint, #8a959c);
227
263
  --grid-header-splitter-display: flex;
264
+ /*
265
+ * 열 이름이 칸을 다 차지하게 두어 정렬 표식을 칸 오른쪽 끝으로 민다. 거기에는 폭 조절 손잡이가
266
+ * 서 있으므로 표식이 그 옆에 모인다.
267
+ *
268
+ * 읽기 전용 표에는 손잡이가 없어서, 표식이 칸 끝에 홀로 떠 이름과 멀어진다. 그래서 기본은
269
+ * 이름에 붙는 쪽이다(data-grid-header.ts).
270
+ */
271
+ --grid-header-title-grow: 1;
228
272
  }
229
273
 
230
274
  :host {
231
275
  display: flex;
232
276
  flex-direction: column;
233
277
 
278
+ /* div[setting] 의 절대 좌표 기준. */
279
+ position: relative;
234
280
  overflow: hidden;
235
281
 
236
282
  border-width: var(--grid-container-border-width);
@@ -259,9 +305,64 @@ DataGrid.styles = [
259
305
  transform: translate(-50%, -50%);
260
306
  }
261
307
 
308
+ /*
309
+ * 컬럼 설정 단추는 **헤더에 마우스를 올릴 때만** 보인다.
310
+ *
311
+ * 늘 보이면 목록 화면마다 오른쪽 위에 눈에 걸리는 것이 하나 생긴다. 자주 쓰는 것도 아니다.
312
+ *
313
+ * 감춰 있는 동안에는 pointer-events 도 끈다 — 안 보이는데 눌리는 자리가 있으면, 헤더의 마지막
314
+ * 컬럼을 누르려던 사람이 엉뚱한 팝업을 만난다.
315
+ *
316
+ * 세 갈래로 켠다.
317
+ * 헤더에 올렸을 때 :has(ox-grid-header:hover)
318
+ * 단추 자체에 올렸을 때 단추가 헤더 위에 떠 있으므로, 커서가 단추로 옮겨오면 헤더는 더 이상
319
+ * hover 가 아니다. 이 갈래가 없으면 커서 아래에서 사라진다
320
+ * 키보드 초점 focus-within
321
+ */
262
322
  div[setting] {
263
- position: relative;
323
+ /*
324
+ * 크기 없이 호스트의 오른쪽 위에 붙는다. 안에 들어오는 단추가 [slot='setting'] 규칙으로
325
+ * top: -3px · right: 0 을 스스로 잡으므로, 이 div 는 기준점 노릇만 한다.
326
+ */
327
+ position: absolute;
328
+ top: 0;
329
+ right: 0;
330
+ width: 0;
331
+ height: 0;
264
332
  z-index: 5;
333
+ opacity: 0;
334
+ pointer-events: none;
335
+ transition: opacity 0.12s ease-out;
336
+ }
337
+
338
+ /*
339
+ * 단추 자체에 올렸을 때도 켜 둔다 — 단추가 헤더 위에 떠 있어서, 커서가 단추로 옮겨오면 헤더는
340
+ * 더 이상 hover 가 아니다. 이 갈래가 없으면 커서 아래에서 사라진다.
341
+ */
342
+ ox-grid-header:hover + div[setting],
343
+ div[setting]:hover,
344
+ div[setting]:focus-within {
345
+ opacity: 1;
346
+ pointer-events: auto;
347
+ }
348
+
349
+ /*
350
+ * 손가락으로 쓰는 장치 — hover 가 없으므로 감추면 닿을 방법이 없다. 늘 두고 평소에는 흐리게,
351
+ * 누르는 동안 선명하게 한다.
352
+ *
353
+ * 화면 폭이 아니라 입력 장치로 가른다. 창을 좁힌 데스크톱은 여기에 걸리지 않고, 큰 태블릿은
354
+ * 폭이 넓어도 걸린다.
355
+ */
356
+ @media (pointer: coarse) {
357
+ div[setting] {
358
+ opacity: 0.35;
359
+ pointer-events: auto;
360
+ }
361
+
362
+ div[setting]:active,
363
+ div[setting]:focus-within {
364
+ opacity: 1;
365
+ }
265
366
  }
266
367
 
267
368
  @media print {