@iyulab/data-components 0.1.8 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -2
- package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/decorate.js +9 -0
- package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/decorateMetadata.js +6 -0
- package/dist/components/data-grid/UDataGrid.js +144 -172
- package/dist/components/data-view/UDataView.d.ts +44 -3
- package/dist/components/data-view/UDataView.js +172 -4
- package/dist/components/data-view/UDataView.styles.js +4 -83
- package/dist/components/simple-sheet/USimpleSheet.d.ts +167 -3
- package/dist/components/simple-sheet/USimpleSheet.js +934 -4
- package/dist/components/simple-sheet/USimpleSheet.styles.js +4 -4
- package/dist/components/u-rich-table/URichTable.d.ts +75 -0
- package/dist/components/u-rich-table/URichTable.js +618 -0
- package/dist/components/u-rich-table/styles.d.ts +1 -0
- package/dist/components/u-rich-table/styles.js +433 -0
- package/dist/components/u-rich-table/types.d.ts +67 -0
- package/dist/components/u-rich-table/utils/clipboard.d.ts +9 -0
- package/dist/components/u-rich-table/utils/clipboard.js +31 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -5
- package/package.json +20 -33
- package/dist/components/data-view/UDataView.component.d.ts +0 -47
- package/dist/components/data-view/UDataView.component.js +0 -226
- package/dist/components/simple-sheet/USimpleSheet.component.d.ts +0 -158
- package/dist/components/simple-sheet/USimpleSheet.component.js +0 -1014
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.1] - 2026-04-01
|
|
4
|
+
### Changed
|
|
5
|
+
- 컴포넌트 파일 구조 리팩토링: `.component.ts` 파일을 기존 `.ts`로 병합 (UDataView, USimpleSheet, URichTable)
|
|
6
|
+
- UDataView: 다크모드 하드코딩 스타일 제거 — CSS 변수 기반으로 전환
|
|
7
|
+
- 의존성 업데이트: devextreme 25.2.5, vite 8.0.3, typescript-eslint 8.57.2 등
|
|
8
|
+
|
|
9
|
+
## [0.3.0] - 2026-03-26
|
|
10
|
+
### Added
|
|
11
|
+
- URichTable: 코어 컴포넌트 추가 — 렌더링, 정렬, 필터, 편집, 페이지네이션
|
|
12
|
+
- URichTable: 엑셀 스타일 클립보드(복사/붙여넣기) + 키보드 네비게이션
|
|
13
|
+
- URichTable: 다크모드 지원 (`:host-context([theme="dark"])`)
|
|
14
|
+
- USimpleSheet: `setSelection()`, `selectAll()` 공개 API 추가
|
|
15
|
+
|
|
3
16
|
## [0.1.8] - 2026-03-08
|
|
4
17
|
### Added
|
|
5
18
|
- USimpleSheet: `format` 속성 — Intl.NumberFormatOptions(통화, 퍼센트 등) 또는 콜백 함수로 표시 포맷 지정
|
|
@@ -13,5 +26,30 @@
|
|
|
13
26
|
- 에러 발생 시 빈 문자열 표시
|
|
14
27
|
- 붙여넣기/Fill 시 compute 열 건너뛰기
|
|
15
28
|
|
|
16
|
-
## [0.1.6]
|
|
17
|
-
|
|
29
|
+
## [0.1.6] - 2026-03-08
|
|
30
|
+
### Added
|
|
31
|
+
- USimpleSheet: 드롭다운 셀렉터 기능 (`options`/`strict` 속성)
|
|
32
|
+
- 드롭다운 상태 관리, 필터링, 키보드 네비게이션
|
|
33
|
+
- 다크모드 지원
|
|
34
|
+
### Fixed
|
|
35
|
+
- USimpleSheet: 문자 입력 시 이중 입력 방지 (`preventDefault` 추가)
|
|
36
|
+
- USimpleSheet: strict 모드에서 `_isDropdownClick` 리셋 및 안전한 스크롤 처리
|
|
37
|
+
|
|
38
|
+
## [0.1.4] - 2026-03-07
|
|
39
|
+
### Changed
|
|
40
|
+
- UDataView, USimpleSheet: 다크모드 스타일 업데이트
|
|
41
|
+
|
|
42
|
+
## [0.1.3] - 2026-03-07
|
|
43
|
+
### Fixed
|
|
44
|
+
- Vite 빌드에 컴포넌트 엔트리 포인트 추가 (sub-path exports 수정)
|
|
45
|
+
|
|
46
|
+
## [0.1.2] - 2026-03-07
|
|
47
|
+
### Added
|
|
48
|
+
- 컴포넌트별 독립 임포트를 위한 sub-path exports 추가
|
|
49
|
+
|
|
50
|
+
## [0.1.1] - 2026-03-06
|
|
51
|
+
### Changed
|
|
52
|
+
- 재배포를 위한 버전 범프
|
|
53
|
+
|
|
54
|
+
## [0.1.0] - 2026-03-06
|
|
55
|
+
- 초기 라이브러리 릴리스
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region \0@oxc-project+runtime@0.122.0/helpers/decorate.js
|
|
2
|
+
function __decorate(decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
}
|
|
8
|
+
//#endregion
|
|
9
|
+
export { __decorate };
|
|
@@ -1,174 +1,146 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
function UDataGrid({
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
/* @__PURE__ */ jsx(Item, { name: "columnChooserButton" }),
|
|
145
|
-
showSearchPanel && /* @__PURE__ */ jsx(Item, { name: "searchPanel" })
|
|
146
|
-
] }),
|
|
147
|
-
columns.map((col, index) => /* @__PURE__ */ jsx(
|
|
148
|
-
Column,
|
|
149
|
-
{
|
|
150
|
-
dataField: col.dataField,
|
|
151
|
-
caption: col.caption,
|
|
152
|
-
width: col.width,
|
|
153
|
-
minWidth: col.minWidth,
|
|
154
|
-
dataType: col.dataType,
|
|
155
|
-
format: col.format,
|
|
156
|
-
alignment: col.alignment,
|
|
157
|
-
fixed: col.fixed,
|
|
158
|
-
fixedPosition: col.fixedPosition,
|
|
159
|
-
allowHiding: col.allowHiding,
|
|
160
|
-
allowSorting: col.allowSorting,
|
|
161
|
-
allowFiltering: col.allowFiltering,
|
|
162
|
-
allowGrouping: col.allowGrouping,
|
|
163
|
-
sortOrder: col.sortOrder,
|
|
164
|
-
cellRender: col.cellRender,
|
|
165
|
-
visible: col.visible
|
|
166
|
-
},
|
|
167
|
-
col.dataField || `column-${index}`
|
|
168
|
-
))
|
|
169
|
-
]
|
|
170
|
-
}
|
|
171
|
-
) });
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import "devextreme/data/odata/store";
|
|
3
|
+
import DataGrid, { Column, ColumnChooser, Export, FilterRow, GroupPanel, Grouping, HeaderFilter, Item, LoadPanel, Paging, SearchPanel, Selection, Toolbar } from "devextreme-react/data-grid";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/data-grid/UDataGrid.tsx
|
|
6
|
+
function UDataGrid({ dataSourceUrl, keyField, selectFields, columns, pageSize = 25, showBorders = true, allowColumnReordering = true, allowColumnResizing = true, showGroupPanel = true, showSearchPanel = true, showFilterRow = true, showHeaderFilter = true, allowExport = true, exportFileName, isDevelopment = false, onDataLoaded, onDataLoadError, onExporting, onRowClick, beforeSend }) {
|
|
7
|
+
const defaultBeforeSend = (operation, ajaxOptions) => {
|
|
8
|
+
try {
|
|
9
|
+
if (!ajaxOptions) {
|
|
10
|
+
console.warn("ajaxOptions가 undefined입니다");
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
if (!ajaxOptions.headers || typeof ajaxOptions.headers !== "object") ajaxOptions.headers = {};
|
|
14
|
+
ajaxOptions.headers["Accept"] = "application/json";
|
|
15
|
+
ajaxOptions.headers["Content-Type"] = "application/json";
|
|
16
|
+
if (isDevelopment) {
|
|
17
|
+
ajaxOptions.crossDomain = true;
|
|
18
|
+
ajaxOptions.headers["Access-Control-Allow-Origin"] = "*";
|
|
19
|
+
}
|
|
20
|
+
console.log(`U-DataGrid ${operation} 요청:`, {
|
|
21
|
+
url: ajaxOptions.url,
|
|
22
|
+
headers: ajaxOptions.headers,
|
|
23
|
+
method: ajaxOptions.type || "GET"
|
|
24
|
+
});
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.error("beforeSend 처리 중 오류:", error);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const defaultOnLoadError = (error) => {
|
|
30
|
+
console.error("U-DataGrid 데이터 로딩 오류:", error);
|
|
31
|
+
let errorMessage = "데이터를 불러오는 중 오류가 발생했습니다.";
|
|
32
|
+
try {
|
|
33
|
+
if (error && typeof error === "object") {
|
|
34
|
+
if (error.status === 404) errorMessage = "API 엔드포인트를 찾을 수 없습니다. 서버가 실행중인지 확인해주세요.";
|
|
35
|
+
else if (error.status === 0) errorMessage = "CORS 오류 또는 네트워크 연결 문제입니다. 서버 설정을 확인해주세요.";
|
|
36
|
+
else if (error.status >= 500) errorMessage = "서버 내부 오류입니다. 서버 로그를 확인해주세요.";
|
|
37
|
+
else if (error.message) errorMessage = error.message;
|
|
38
|
+
else if (typeof error === "string") errorMessage = error;
|
|
39
|
+
}
|
|
40
|
+
} catch (parseError) {
|
|
41
|
+
console.error("오류 메시지 파싱 중 문제:", parseError);
|
|
42
|
+
}
|
|
43
|
+
alert(`${errorMessage}\n\n요청 URL: ${dataSourceUrl}`);
|
|
44
|
+
};
|
|
45
|
+
const dataSource = useMemo(() => {
|
|
46
|
+
return {
|
|
47
|
+
store: {
|
|
48
|
+
type: "odata",
|
|
49
|
+
version: 4,
|
|
50
|
+
url: dataSourceUrl,
|
|
51
|
+
key: keyField,
|
|
52
|
+
beforeSend: beforeSend || defaultBeforeSend,
|
|
53
|
+
onLoading: () => {
|
|
54
|
+
console.log("U-DataGrid 데이터 로딩 시작...");
|
|
55
|
+
},
|
|
56
|
+
onLoaded: (data) => {
|
|
57
|
+
console.log("U-DataGrid 데이터 로딩 완료:", data);
|
|
58
|
+
onDataLoaded?.(data);
|
|
59
|
+
},
|
|
60
|
+
onLoadError: onDataLoadError || defaultOnLoadError
|
|
61
|
+
},
|
|
62
|
+
select: selectFields
|
|
63
|
+
};
|
|
64
|
+
}, [
|
|
65
|
+
dataSourceUrl,
|
|
66
|
+
keyField,
|
|
67
|
+
selectFields,
|
|
68
|
+
beforeSend,
|
|
69
|
+
onDataLoaded,
|
|
70
|
+
onDataLoadError
|
|
71
|
+
]);
|
|
72
|
+
const handleExporting = (e) => {
|
|
73
|
+
if (exportFileName) e.fileName = exportFileName;
|
|
74
|
+
else e.fileName = `DataGrid_Export_${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`;
|
|
75
|
+
onExporting?.(e);
|
|
76
|
+
};
|
|
77
|
+
return /* @__PURE__ */ jsx("div", {
|
|
78
|
+
style: {
|
|
79
|
+
width: "100%",
|
|
80
|
+
height: "100%",
|
|
81
|
+
position: "relative",
|
|
82
|
+
contain: "layout style",
|
|
83
|
+
isolation: "isolate",
|
|
84
|
+
overflow: "hidden"
|
|
85
|
+
},
|
|
86
|
+
children: /* @__PURE__ */ jsxs(DataGrid, {
|
|
87
|
+
dataSource,
|
|
88
|
+
showBorders,
|
|
89
|
+
allowColumnReordering,
|
|
90
|
+
allowColumnResizing,
|
|
91
|
+
columnAutoWidth: false,
|
|
92
|
+
showColumnLines: true,
|
|
93
|
+
showRowLines: true,
|
|
94
|
+
rowAlternationEnabled: true,
|
|
95
|
+
hoverStateEnabled: true,
|
|
96
|
+
height: "100%",
|
|
97
|
+
width: "100%",
|
|
98
|
+
wordWrapEnabled: true,
|
|
99
|
+
columnResizingMode: "widget",
|
|
100
|
+
remoteOperations: true,
|
|
101
|
+
onExporting: handleExporting,
|
|
102
|
+
onRowClick,
|
|
103
|
+
children: [
|
|
104
|
+
/* @__PURE__ */ jsx(LoadPanel, { enabled: true }),
|
|
105
|
+
/* @__PURE__ */ jsx(Selection, { mode: "multiple" }),
|
|
106
|
+
showFilterRow && /* @__PURE__ */ jsx(FilterRow, { visible: true }),
|
|
107
|
+
showHeaderFilter && /* @__PURE__ */ jsx(HeaderFilter, { visible: true }),
|
|
108
|
+
showSearchPanel && /* @__PURE__ */ jsx(SearchPanel, {
|
|
109
|
+
visible: true,
|
|
110
|
+
placeholder: "검색..."
|
|
111
|
+
}),
|
|
112
|
+
/* @__PURE__ */ jsx(Grouping, { autoExpandAll: false }),
|
|
113
|
+
showGroupPanel && /* @__PURE__ */ jsx(GroupPanel, { visible: true }),
|
|
114
|
+
/* @__PURE__ */ jsx(ColumnChooser, { enabled: true }),
|
|
115
|
+
/* @__PURE__ */ jsx(Paging, { defaultPageSize: pageSize }),
|
|
116
|
+
allowExport && /* @__PURE__ */ jsx(Export, { enabled: true }),
|
|
117
|
+
/* @__PURE__ */ jsxs(Toolbar, { children: [
|
|
118
|
+
showGroupPanel && /* @__PURE__ */ jsx(Item, { name: "groupPanel" }),
|
|
119
|
+
allowExport && /* @__PURE__ */ jsx(Item, { name: "exportButton" }),
|
|
120
|
+
/* @__PURE__ */ jsx(Item, { name: "columnChooserButton" }),
|
|
121
|
+
showSearchPanel && /* @__PURE__ */ jsx(Item, { name: "searchPanel" })
|
|
122
|
+
] }),
|
|
123
|
+
columns.map((col, index) => /* @__PURE__ */ jsx(Column, {
|
|
124
|
+
dataField: col.dataField,
|
|
125
|
+
caption: col.caption,
|
|
126
|
+
width: col.width,
|
|
127
|
+
minWidth: col.minWidth,
|
|
128
|
+
dataType: col.dataType,
|
|
129
|
+
format: col.format,
|
|
130
|
+
alignment: col.alignment,
|
|
131
|
+
fixed: col.fixed,
|
|
132
|
+
fixedPosition: col.fixedPosition,
|
|
133
|
+
allowHiding: col.allowHiding,
|
|
134
|
+
allowSorting: col.allowSorting,
|
|
135
|
+
allowFiltering: col.allowFiltering,
|
|
136
|
+
allowGrouping: col.allowGrouping,
|
|
137
|
+
sortOrder: col.sortOrder,
|
|
138
|
+
cellRender: col.cellRender,
|
|
139
|
+
visible: col.visible
|
|
140
|
+
}, col.dataField || `column-${index}`))
|
|
141
|
+
]
|
|
142
|
+
})
|
|
143
|
+
});
|
|
172
144
|
}
|
|
173
|
-
|
|
145
|
+
//#endregion
|
|
174
146
|
export { UDataGrid };
|
|
@@ -1,8 +1,49 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TemplateResult } from 'lit';
|
|
2
|
+
import { UElement } from '@iyulab/components/dist/components/UElement.js';
|
|
3
|
+
export type ViewMode = 'grid' | 'list' | 'table';
|
|
4
|
+
export interface DataColumn {
|
|
5
|
+
key: string;
|
|
6
|
+
label?: string;
|
|
7
|
+
width?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Data View Component
|
|
11
|
+
* 데이터를 3가지 레이아웃(grid, list, table)으로 표시하는 컴포넌트
|
|
12
|
+
*/
|
|
13
|
+
export declare class UDataView extends UElement {
|
|
14
|
+
static styles: import('lit').CSSResultGroup[];
|
|
15
|
+
/** 표시할 데이터 배열 */
|
|
16
|
+
items: any[];
|
|
17
|
+
/** 현재 뷰 모드 */
|
|
18
|
+
mode: ViewMode;
|
|
19
|
+
/** 표시할 컬럼 설정 (미지정시 자동 감지) */
|
|
20
|
+
columns?: DataColumn[];
|
|
21
|
+
/** 그리드 모드 최소 폭 */
|
|
22
|
+
gridMinWidth: string;
|
|
23
|
+
/** 아이템 간격 */
|
|
24
|
+
gap: string;
|
|
25
|
+
/** 커스텀 렌더 함수 (grid/list 카드용) */
|
|
26
|
+
renderCard?: (item: any, index: number) => TemplateResult;
|
|
27
|
+
/** 커스텀 셀 렌더 함수 (table용) */
|
|
28
|
+
renderCell?: (item: any, column: DataColumn, index: number) => TemplateResult | string;
|
|
29
|
+
private selectedIndex;
|
|
30
|
+
render(): TemplateResult<1>;
|
|
31
|
+
private renderToolbar;
|
|
32
|
+
private renderViewButton;
|
|
33
|
+
private renderContent;
|
|
34
|
+
private renderGrid;
|
|
35
|
+
private renderList;
|
|
36
|
+
private renderTable;
|
|
37
|
+
private renderGridItem;
|
|
38
|
+
private renderListItem;
|
|
39
|
+
private renderDefaultCard;
|
|
40
|
+
private getCellContent;
|
|
41
|
+
private getColumns;
|
|
42
|
+
private formatLabel;
|
|
43
|
+
private formatValue;
|
|
44
|
+
}
|
|
2
45
|
declare global {
|
|
3
46
|
interface HTMLElementTagNameMap {
|
|
4
47
|
"u-data-view": UDataView;
|
|
5
48
|
}
|
|
6
49
|
}
|
|
7
|
-
export { UDataView };
|
|
8
|
-
export type { Column, ViewMode } from './UDataView.component.js';
|
|
@@ -1,5 +1,173 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { styles } from "./UDataView.styles.js";
|
|
2
|
+
import { __decorateMetadata } from "../../_virtual/_@oxc-project_runtime@0.122.0/helpers/decorateMetadata.js";
|
|
3
|
+
import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.122.0/helpers/decorate.js";
|
|
4
|
+
import { html } from "lit";
|
|
5
|
+
import { customElement, property, state } from "lit/decorators.js";
|
|
6
|
+
import "@iyulab/components/dist/components/icon/UIcon.js";
|
|
7
|
+
import "@iyulab/components/dist/components/button/UButton.js";
|
|
8
|
+
import { UElement } from "@iyulab/components/dist/components/UElement.js";
|
|
9
|
+
//#region src/components/data-view/UDataView.ts
|
|
10
|
+
var UDataView = class UDataView extends UElement {
|
|
11
|
+
constructor(..._args) {
|
|
12
|
+
super(..._args);
|
|
13
|
+
this.items = [];
|
|
14
|
+
this.mode = "grid";
|
|
15
|
+
this.gridMinWidth = "200px";
|
|
16
|
+
this.gap = "1rem";
|
|
17
|
+
this.selectedIndex = null;
|
|
18
|
+
}
|
|
19
|
+
static {
|
|
20
|
+
this.styles = [super.styles, styles];
|
|
21
|
+
}
|
|
22
|
+
render() {
|
|
23
|
+
return html`
|
|
24
|
+
<div class="data-view">
|
|
25
|
+
${this.renderToolbar()}
|
|
26
|
+
${this.renderContent()}
|
|
27
|
+
</div>
|
|
28
|
+
`;
|
|
29
|
+
}
|
|
30
|
+
renderToolbar() {
|
|
31
|
+
return html`
|
|
32
|
+
<div class="toolbar">
|
|
33
|
+
<div class="view-toggles">
|
|
34
|
+
${this.renderViewButton("grid", "grid-3x3-gap", "Grid")}
|
|
35
|
+
${this.renderViewButton("list", "list-ul", "List")}
|
|
36
|
+
${this.renderViewButton("table", "table", "Table")}
|
|
37
|
+
</div>
|
|
38
|
+
<div class="info">
|
|
39
|
+
${this.items.length} items
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
`;
|
|
43
|
+
}
|
|
44
|
+
renderViewButton(mode, icon, label) {
|
|
45
|
+
return html`
|
|
46
|
+
<u-button
|
|
47
|
+
?active=${this.mode === mode}
|
|
48
|
+
title=${label}
|
|
49
|
+
>
|
|
50
|
+
<u-icon lib="bootstrap" name=${icon}></u-icon>
|
|
51
|
+
</u-button>
|
|
52
|
+
`;
|
|
53
|
+
}
|
|
54
|
+
renderContent() {
|
|
55
|
+
if (!this.items?.length) return html`<div class="empty">No data available</div>`;
|
|
56
|
+
switch (this.mode) {
|
|
57
|
+
case "grid": return this.renderGrid();
|
|
58
|
+
case "list": return this.renderList();
|
|
59
|
+
case "table": return this.renderTable();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
renderGrid() {
|
|
63
|
+
return html`
|
|
64
|
+
<div class="grid" style="--min-width: ${this.gridMinWidth}; --gap: ${this.gap};">
|
|
65
|
+
${this.items.map((item, index) => this.renderGridItem(item, index))}
|
|
66
|
+
</div>
|
|
67
|
+
`;
|
|
68
|
+
}
|
|
69
|
+
renderList() {
|
|
70
|
+
return html`
|
|
71
|
+
<div class="list" style="--gap: ${this.gap};">
|
|
72
|
+
${this.items.map((item, index) => this.renderListItem(item, index))}
|
|
73
|
+
</div>
|
|
74
|
+
`;
|
|
75
|
+
}
|
|
76
|
+
renderTable() {
|
|
77
|
+
const cols = this.getColumns();
|
|
78
|
+
return html`
|
|
79
|
+
<div class="table-wrapper">
|
|
80
|
+
<table>
|
|
81
|
+
<thead>
|
|
82
|
+
<tr>
|
|
83
|
+
${cols.map((col) => html`
|
|
84
|
+
<th style=${col.width ? `width: ${col.width}` : ""}>
|
|
85
|
+
${col.label || this.formatLabel(col.key)}
|
|
86
|
+
</th>
|
|
87
|
+
`)}
|
|
88
|
+
</tr>
|
|
89
|
+
</thead>
|
|
90
|
+
<tbody>
|
|
91
|
+
${this.items.map((item, index) => html`
|
|
92
|
+
<tr
|
|
93
|
+
class=${this.selectedIndex === index ? "selected" : ""}
|
|
94
|
+
>
|
|
95
|
+
${cols.map((col) => html`
|
|
96
|
+
<td>${this.getCellContent(item, col, index)}</td>
|
|
97
|
+
`)}
|
|
98
|
+
</tr>
|
|
99
|
+
`)}
|
|
100
|
+
</tbody>
|
|
101
|
+
</table>
|
|
102
|
+
</div>
|
|
103
|
+
`;
|
|
104
|
+
}
|
|
105
|
+
renderGridItem(item, index) {
|
|
106
|
+
const content = this.renderCard ? this.renderCard(item, index) : this.renderDefaultCard(item);
|
|
107
|
+
return html`
|
|
108
|
+
<div
|
|
109
|
+
class="card ${this.selectedIndex === index ? "selected" : ""}"
|
|
110
|
+
>
|
|
111
|
+
${content}
|
|
112
|
+
</div>
|
|
113
|
+
`;
|
|
114
|
+
}
|
|
115
|
+
renderListItem(item, index) {
|
|
116
|
+
const content = this.renderCard ? this.renderCard(item, index) : this.renderDefaultCard(item);
|
|
117
|
+
return html`
|
|
118
|
+
<div
|
|
119
|
+
class="card list-card ${this.selectedIndex === index ? "selected" : ""}"
|
|
120
|
+
>
|
|
121
|
+
${content}
|
|
122
|
+
</div>
|
|
123
|
+
`;
|
|
124
|
+
}
|
|
125
|
+
renderDefaultCard(item) {
|
|
126
|
+
return html`
|
|
127
|
+
<div class="card-content">
|
|
128
|
+
${this.getColumns().slice(0, 5).map((col) => {
|
|
129
|
+
const value = item[col.key];
|
|
130
|
+
return html`
|
|
131
|
+
<div class="card-field">
|
|
132
|
+
<span class="label">${col.label || this.formatLabel(col.key)}:</span>
|
|
133
|
+
<span class="value">${this.formatValue(value)}</span>
|
|
134
|
+
</div>
|
|
135
|
+
`;
|
|
136
|
+
})}
|
|
137
|
+
</div>
|
|
138
|
+
`;
|
|
139
|
+
}
|
|
140
|
+
getCellContent(item, column, index) {
|
|
141
|
+
if (this.renderCell) return this.renderCell(item, column, index);
|
|
142
|
+
return this.formatValue(item[column.key]);
|
|
143
|
+
}
|
|
144
|
+
getColumns() {
|
|
145
|
+
if (this.columns?.length) return this.columns;
|
|
146
|
+
if (this.items.length > 0) {
|
|
147
|
+
const firstItem = this.items[0];
|
|
148
|
+
return Object.keys(firstItem).map((key) => ({ key }));
|
|
149
|
+
}
|
|
150
|
+
return [];
|
|
151
|
+
}
|
|
152
|
+
formatLabel(key) {
|
|
153
|
+
return key.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase()).trim();
|
|
154
|
+
}
|
|
155
|
+
formatValue(value) {
|
|
156
|
+
if (value == null) return "—";
|
|
157
|
+
if (typeof value === "boolean") return value ? "✓" : "✗";
|
|
158
|
+
if (value instanceof Date) return value.toLocaleString();
|
|
159
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
160
|
+
return String(value);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
__decorate([property({ type: Array }), __decorateMetadata("design:type", Array)], UDataView.prototype, "items", void 0);
|
|
164
|
+
__decorate([property({ type: String }), __decorateMetadata("design:type", Object)], UDataView.prototype, "mode", void 0);
|
|
165
|
+
__decorate([property({ type: Array }), __decorateMetadata("design:type", Array)], UDataView.prototype, "columns", void 0);
|
|
166
|
+
__decorate([property({ type: String }), __decorateMetadata("design:type", Object)], UDataView.prototype, "gridMinWidth", void 0);
|
|
167
|
+
__decorate([property({ type: String }), __decorateMetadata("design:type", Object)], UDataView.prototype, "gap", void 0);
|
|
168
|
+
__decorate([property({ attribute: false }), __decorateMetadata("design:type", Function)], UDataView.prototype, "renderCard", void 0);
|
|
169
|
+
__decorate([property({ attribute: false }), __decorateMetadata("design:type", Function)], UDataView.prototype, "renderCell", void 0);
|
|
170
|
+
__decorate([state(), __decorateMetadata("design:type", Object)], UDataView.prototype, "selectedIndex", void 0);
|
|
171
|
+
UDataView = __decorate([customElement("u-data-view")], UDataView);
|
|
172
|
+
//#endregion
|
|
5
173
|
export { UDataView };
|