@iyulab/data-components 0.1.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.
@@ -0,0 +1,283 @@
1
+ import { css } from 'lit';
2
+
3
+ const styles = css`
4
+ :host {
5
+ display: block;
6
+ width: 100%;
7
+ }
8
+
9
+ .u-data-view-container {
10
+ width: 100%;
11
+ }
12
+
13
+ .layout-selector {
14
+ display: flex;
15
+ justify-content: flex-end;
16
+ margin-bottom: 1rem;
17
+
18
+ u-icon-button {
19
+ margin-left: 0.5rem;
20
+
21
+ &[current] {
22
+ color: var(--u-blue-600);
23
+ }
24
+ }
25
+ }
26
+
27
+ .u-data-view {
28
+ &.grid {
29
+ display: grid;
30
+ gap: var(--item-margin);
31
+ grid-template-columns: repeat(auto-fill, minmax(var(--min-item-width), 1fr));
32
+ }
33
+
34
+ &.list {
35
+ display: flex;
36
+ flex-direction: column;
37
+ gap: var(--item-margin);
38
+ }
39
+ }
40
+
41
+ .default-item {
42
+ background-color: #fff;
43
+ border: 1px solid #ccc;
44
+ border-radius: 8px;
45
+ padding: 1rem;
46
+ cursor: pointer;
47
+ transition: all 0.3s ease;
48
+
49
+ &:hover {
50
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
51
+ }
52
+
53
+ &.selected {
54
+ border: 2px solid #007bff;
55
+ box-shadow: 0 0 15px rgba(0, 123, 255, 0.3);
56
+ }
57
+ }
58
+
59
+ .u-data-view.list .default-item {
60
+ display: flex;
61
+ align-items: flex-start;
62
+ }
63
+
64
+ .u-data-view.list .default-item .default-image,
65
+ .u-data-view.list .default-item .placeholder-image {
66
+ width: 128px;
67
+ height: 128px;
68
+ min-width: 128px;
69
+ margin-right: 1rem;
70
+ margin-bottom: 0;
71
+ object-fit: cover;
72
+ }
73
+
74
+ .u-data-view.list .default-item .default-fields {
75
+ flex: 1;
76
+ }
77
+
78
+ .default-image {
79
+ width: 100%;
80
+ height: 128px;
81
+ object-fit: cover;
82
+ margin-bottom: 1rem;
83
+ border-radius: 4px;
84
+
85
+ &.list-image {
86
+ width: 128px;
87
+ height: 128px;
88
+ }
89
+
90
+ &.table-image {
91
+ width: 64px;
92
+ height: 64px;
93
+ margin-bottom: 0;
94
+ }
95
+
96
+ &.placeholder-image {
97
+ display: flex;
98
+ align-items: center;
99
+ justify-content: center;
100
+ font-size: 2rem;
101
+ font-weight: bold;
102
+ text-transform: uppercase;
103
+ }
104
+ }
105
+
106
+ .default-fields {
107
+ .field {
108
+ margin-bottom: 0.5rem;
109
+ display: flex;
110
+ align-items: center;
111
+
112
+ .field-title {
113
+ color: var(--u-neutral-600);
114
+ margin-right: 0.5rem;
115
+ flex: 0 0 30%;
116
+ }
117
+
118
+ .field-value {
119
+ font-weight: bold;
120
+ flex: 1;
121
+ }
122
+ }
123
+ }
124
+
125
+ .default-table {
126
+ width: 100%;
127
+ border-collapse: separate;
128
+ border-spacing: 0;
129
+
130
+ th, td {
131
+ padding: 0.5em;
132
+ border: none;
133
+ border-bottom: 1px solid #eee;
134
+ }
135
+
136
+ th {
137
+ background-color: #f8f9fa;
138
+ font-weight: bold;
139
+ text-align: left;
140
+ }
141
+
142
+ .image-cell {
143
+ width: 64px;
144
+ height: 64px;
145
+ padding: 0;
146
+ position: relative;
147
+
148
+ img, .placeholder-image {
149
+ position: absolute;
150
+ top: 0;
151
+ left: 0;
152
+ width: 100%;
153
+ height: 100%;
154
+ object-fit: cover;
155
+ }
156
+
157
+ .placeholder-image {
158
+ font-size: 1.5rem;
159
+ }
160
+ }
161
+
162
+ tr {
163
+ transition: all 0.3s ease;
164
+
165
+ &:hover {
166
+ background-color: rgba(0, 123, 255, 0.05);
167
+ }
168
+
169
+ &.selected {
170
+ background-color: rgba(0, 123, 255, 0.1);
171
+ box-shadow: 0 0 0 2px #007bff;
172
+ position: relative;
173
+ z-index: 1;
174
+
175
+ td:first-child {
176
+ border-top-left-radius: 8px;
177
+ border-bottom-left-radius: 8px;
178
+ }
179
+
180
+ td:last-child {
181
+ border-top-right-radius: 8px;
182
+ border-bottom-right-radius: 8px;
183
+ }
184
+ }
185
+ }
186
+ }
187
+
188
+ u-skeleton {
189
+ display: block;
190
+ width: 100%;
191
+ height: 1em;
192
+ background-color: #e0e0e0;
193
+ border-radius: 4px;
194
+ overflow: hidden;
195
+ position: relative;
196
+
197
+ &::after {
198
+ content: "";
199
+ position: absolute;
200
+ top: 0;
201
+ left: 0;
202
+ width: 100%;
203
+ height: 100%;
204
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
205
+ animation: skeleton-loading 1.5s infinite;
206
+ }
207
+ }
208
+
209
+ @keyframes skeleton-loading {
210
+ 0% {
211
+ transform: translateX(-100%);
212
+ }
213
+ 100% {
214
+ transform: translateX(100%);
215
+ }
216
+ }
217
+
218
+ .skeleton-item {
219
+ &.grid .skeleton-image,
220
+ &.list .skeleton-image {
221
+ width: 100%;
222
+ height: 128px;
223
+ margin-bottom: 1rem;
224
+ }
225
+
226
+ &.list {
227
+ display: flex;
228
+ align-items: flex-start;
229
+
230
+ .skeleton-image {
231
+ width: 128px;
232
+ height: 128px;
233
+ margin-right: 1rem;
234
+ margin-bottom: 0;
235
+ }
236
+
237
+ .skeleton-fields {
238
+ flex: 1;
239
+ }
240
+ }
241
+
242
+ .skeleton-field {
243
+ display: flex;
244
+ align-items: center;
245
+ margin-bottom: 0.5rem;
246
+
247
+ .skeleton-label {
248
+ width: 30%;
249
+ height: 1em;
250
+ margin-right: 0.5rem;
251
+ }
252
+
253
+ .skeleton-value {
254
+ width: 70%;
255
+ height: 1em;
256
+ }
257
+ }
258
+ }
259
+
260
+ .skeleton-table {
261
+ width: 100%;
262
+
263
+ .skeleton-row {
264
+ display: flex;
265
+ border-bottom: 1px solid #eee;
266
+ padding: 0.5em 0;
267
+
268
+ .skeleton-cell {
269
+ flex: 1;
270
+ height: 1em;
271
+ margin-right: 0.5em;
272
+
273
+ &:first-child {
274
+ width: 64px;
275
+ height: 64px;
276
+ flex: none;
277
+ }
278
+ }
279
+ }
280
+ }
281
+ `;
282
+
283
+ export { styles };
@@ -0,0 +1,3 @@
1
+ export { UDataGrid } from './data-grid/UDataGrid';
2
+ export type { UDataGridColumn, UDataGridProps } from './data-grid/UDataGrid.types';
3
+ export * from './data-view/UDataView';
@@ -0,0 +1,2 @@
1
+ export * from './components';
2
+ export * from './utils';
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { initShadowDomProtection, registerProtectedStylesheet } from './utils/shadowDomProtection.js';
2
+ export { initDevExtremeCssInjection, injectCssToShadowDoms } from './utils/devExtremeCssInjection.js';
3
+ export { UDataGrid } from './components/data-grid/UDataGrid.js';
4
+ import './components/data-view/UDataView.js';
5
+ export { UDataView } from './components/data-view/UDataView.component.js';
package/dist/init.d.ts ADDED
File without changes
@@ -0,0 +1,3 @@
1
+ const devExtremeOverridesCssText = "/* ================================================================\r\n DevExtreme Custom Styles for Shadow DOM\r\n - 이 스타일들은 Shadow DOM에 주입되어 DataGrid 등에 적용됨\r\n - dx.light.css와 함께 adoptedStyleSheets로 주입됨\r\n ================================================================ */\r\n\r\n/* Prevent DevExtreme from using 100vw which ignores sidebar */\r\n.dx-widget {\r\n max-width: 100% !important;\r\n}\r\n\r\n/* DevExtreme DataGrid 스타일 보정 */\r\n.dx-datagrid {\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\r\n background-color: #fff;\r\n border: 1px solid #ddd;\r\n border-radius: 4px;\r\n}\r\n\r\n.dx-datagrid .dx-header-row {\r\n background-color: #f8f9fa;\r\n border-bottom: 2px solid #dee2e6;\r\n}\r\n\r\n.dx-datagrid .dx-header-row .dx-header-cell {\r\n border-right: 1px solid #dee2e6;\r\n padding: 12px 8px;\r\n font-weight: 600;\r\n color: #495057;\r\n}\r\n\r\n.dx-datagrid .dx-data-row {\r\n border-bottom: 1px solid #dee2e6;\r\n}\r\n\r\n.dx-datagrid .dx-data-row .dx-cell {\r\n border-right: 1px solid #f1f3f4;\r\n padding: 10px 8px;\r\n}\r\n\r\n.dx-datagrid .dx-data-row:hover {\r\n background-color: #f8f9fa;\r\n}\r\n\r\n.dx-datagrid .dx-data-row.dx-row-alt {\r\n background-color: #fbfbfb;\r\n}\r\n\r\n.dx-datagrid .dx-data-row.dx-row-alt:hover {\r\n background-color: #f5f5f5;\r\n}\r\n\r\n/* 그룹 패널 스타일 */\r\n.dx-datagrid .dx-group-panel {\r\n background-color: #e9ecef;\r\n border-bottom: 1px solid #dee2e6;\r\n padding: 10px 15px;\r\n min-height: 40px;\r\n}\r\n\r\n.dx-datagrid .dx-group-panel-message {\r\n color: #6c757d;\r\n font-style: italic;\r\n}\r\n\r\n/* 필터 행 스타일 */\r\n.dx-datagrid .dx-filter-row {\r\n background-color: #fff;\r\n}\r\n\r\n.dx-datagrid .dx-filter-row .dx-cell {\r\n border-bottom: 1px solid #dee2e6;\r\n padding: 5px 8px;\r\n}\r\n\r\n/* 페이징 스타일 */\r\n.dx-datagrid .dx-pager {\r\n background-color: #f8f9fa;\r\n border-top: 1px solid #dee2e6;\r\n padding: 10px;\r\n}\r\n\r\n/* 도구 모음 스타일 */\r\n.dx-datagrid .dx-toolbar {\r\n background-color: #f8f9fa;\r\n border-bottom: 1px solid #dee2e6;\r\n padding: 8px 12px;\r\n}\r\n\r\n/* 로딩 패널 스타일 */\r\n.dx-loadpanel {\r\n background-color: rgba(255, 255, 255, 0.9);\r\n}\r\n\r\n.dx-loadpanel .dx-loadpanel-content {\r\n border: 1px solid #dee2e6;\r\n border-radius: 4px;\r\n background-color: #fff;\r\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\r\n}\r\n\r\n/* 선택 체크박스 스타일 */\r\n.dx-datagrid .dx-select-checkbox {\r\n margin: 0 auto;\r\n}\r\n\r\n/* 고정된 컬럼 스타일 */\r\n.dx-datagrid .dx-col-fixed {\r\n background-color: #fff;\r\n box-shadow: 2px 0 4px rgba(0, 0, 0, 0.1);\r\n}\r\n\r\n/* 상태별 컬럼 너비 조정 */\r\n.dx-datagrid .dx-command-select {\r\n width: 50px !important;\r\n min-width: 50px !important;\r\n}\r\n\r\n/* 반응형 디자인 */\r\n@media (max-width: 768px) {\r\n .dx-datagrid .dx-cell {\r\n padding: 8px 4px;\r\n font-size: 14px;\r\n }\r\n\r\n .dx-datagrid .dx-header-cell {\r\n padding: 10px 4px;\r\n font-size: 14px;\r\n }\r\n}\r\n\r\n/* DevExtreme 아이콘 폰트 문제 해결 */\r\n.dx-icon {\r\n font-family: 'DXIcons', 'Helvetica Neue', 'Segoe UI', sans-serif !important;\r\n}\r\n\r\n/* 버튼 스타일 개선 */\r\n.dx-button {\r\n border-radius: 4px;\r\n}\r\n\r\n.dx-button.dx-button-normal {\r\n background-color: #007bff;\r\n border-color: #007bff;\r\n color: #fff;\r\n}\r\n\r\n.dx-button.dx-button-normal:hover {\r\n background-color: #0056b3;\r\n border-color: #0056b3;\r\n}\r\n\r\n/* 입력 필드 스타일 */\r\n.dx-texteditor {\r\n border-radius: 4px;\r\n}\r\n\r\n.dx-texteditor .dx-texteditor-input {\r\n padding: 8px 12px;\r\n}\r\n\r\n/* 셀렉트박스 스타일 */\r\n.dx-selectbox {\r\n border-radius: 4px;\r\n}\r\n\r\n/* 날짜 피커 스타일 */\r\n.dx-datebox {\r\n border-radius: 4px;\r\n}\r\n";
2
+
3
+ export { devExtremeOverridesCssText as default };
@@ -0,0 +1,23 @@
1
+ /**
2
+ * DevExtreme CSS Shadow DOM Injection
3
+ *
4
+ * DevExtreme components render inside Shadow DOM but their CSS is loaded
5
+ * in the Light DOM. Due to Shadow DOM encapsulation, Light DOM CSS doesn't
6
+ * apply to Shadow DOM content.
7
+ *
8
+ * This module:
9
+ * 1. Imports DevExtreme CSS as text (using Vite ?inline query)
10
+ * 2. Creates a CSSStyleSheet from the CSS text
11
+ * 3. Injects the stylesheet into all Shadow DOMs
12
+ * 4. Uses MutationObserver to detect and inject into new Shadow DOMs
13
+ */
14
+ /**
15
+ * Initialize DevExtreme CSS injection
16
+ * Sets up MutationObserver to detect new Shadow DOMs
17
+ */
18
+ export declare function initDevExtremeCssInjection(): void;
19
+ /**
20
+ * Register and inject custom CSS into all Shadow DOMs (existing and future)
21
+ * Sets up automatic injection for new Shadow DOMs via MutationObserver
22
+ */
23
+ export declare function injectCssToShadowDoms(cssText: string): CSSStyleSheet | null;
@@ -0,0 +1,164 @@
1
+ import devExtremeCssText from 'devextreme/dist/css/dx.light.css?inline';
2
+ import devExtremeOverridesCssText from '../styles/devextreme-overrides.css.js';
3
+ import { registerProtectedStylesheet } from './shadowDomProtection.js';
4
+
5
+ let isInitialized = false;
6
+ let devExtremeStyleSheet = null;
7
+ let devExtremeOverridesStyleSheet = null;
8
+ const injectedShadowRoots = /* @__PURE__ */ new WeakSet();
9
+ function injectToShadowRoot(shadowRoot) {
10
+ if (!devExtremeStyleSheet || injectedShadowRoots.has(shadowRoot)) return;
11
+ try {
12
+ const currentSheets = [...shadowRoot.adoptedStyleSheets];
13
+ const sheetsToAdd = [];
14
+ if (!currentSheets.includes(devExtremeStyleSheet)) {
15
+ sheetsToAdd.push(devExtremeStyleSheet);
16
+ }
17
+ if (devExtremeOverridesStyleSheet && !currentSheets.includes(devExtremeOverridesStyleSheet)) {
18
+ sheetsToAdd.push(devExtremeOverridesStyleSheet);
19
+ }
20
+ if (sheetsToAdd.length > 0) {
21
+ shadowRoot.adoptedStyleSheets = [...currentSheets, ...sheetsToAdd];
22
+ injectedShadowRoots.add(shadowRoot);
23
+ if (process.env.NODE_ENV === "development") {
24
+ console.log("[data-components] DevExtreme CSS injected into Shadow DOM");
25
+ }
26
+ }
27
+ } catch (e) {
28
+ console.warn("[data-components] Failed to inject DevExtreme CSS:", e);
29
+ }
30
+ }
31
+ function injectToExistingShadowRoots() {
32
+ document.querySelectorAll("*").forEach((el) => {
33
+ if (el.shadowRoot) {
34
+ injectToShadowRoot(el.shadowRoot);
35
+ }
36
+ });
37
+ }
38
+ function initDevExtremeCssInjection() {
39
+ if (isInitialized) return;
40
+ if (typeof window === "undefined") return;
41
+ try {
42
+ devExtremeStyleSheet = new CSSStyleSheet();
43
+ devExtremeStyleSheet.replaceSync(devExtremeCssText || "");
44
+ if (process.env.NODE_ENV === "development") {
45
+ console.log("[data-components] DevExtreme base CSS stylesheet created");
46
+ console.log("[data-components] Base CSS length:", devExtremeCssText?.length || 0);
47
+ }
48
+ } catch (e) {
49
+ console.warn("[data-components] Failed to create DevExtreme base CSSStyleSheet:", e);
50
+ return;
51
+ }
52
+ try {
53
+ if (devExtremeOverridesCssText && devExtremeOverridesCssText.length > 0) {
54
+ devExtremeOverridesStyleSheet = new CSSStyleSheet();
55
+ devExtremeOverridesStyleSheet.replaceSync(devExtremeOverridesCssText);
56
+ registerProtectedStylesheet(devExtremeOverridesStyleSheet);
57
+ if (process.env.NODE_ENV === "development") {
58
+ console.log("[data-components] DevExtreme overrides CSS stylesheet created");
59
+ console.log("[data-components] Overrides CSS length:", devExtremeOverridesCssText.length);
60
+ }
61
+ }
62
+ } catch (e) {
63
+ console.warn("[data-components] Failed to create DevExtreme overrides CSSStyleSheet:", e);
64
+ }
65
+ const observer = new MutationObserver((mutations) => {
66
+ mutations.forEach((mutation) => {
67
+ mutation.addedNodes.forEach((node) => {
68
+ if (node instanceof Element) {
69
+ if (node.shadowRoot) {
70
+ injectToShadowRoot(node.shadowRoot);
71
+ }
72
+ node.querySelectorAll("*").forEach((el) => {
73
+ if (el.shadowRoot) {
74
+ injectToShadowRoot(el.shadowRoot);
75
+ }
76
+ });
77
+ }
78
+ });
79
+ });
80
+ });
81
+ const startObserving = () => {
82
+ injectToExistingShadowRoots();
83
+ observer.observe(document.body, { childList: true, subtree: true });
84
+ setTimeout(injectToExistingShadowRoots, 1e3);
85
+ setTimeout(injectToExistingShadowRoots, 3e3);
86
+ };
87
+ if (document.readyState === "loading") {
88
+ document.addEventListener("DOMContentLoaded", startObserving);
89
+ } else {
90
+ startObserving();
91
+ }
92
+ isInitialized = true;
93
+ }
94
+ const customStylesheets = [];
95
+ function injectCustomStylesToShadowRoot(shadowRoot) {
96
+ if (customStylesheets.length === 0) return;
97
+ try {
98
+ const currentSheets = [...shadowRoot.adoptedStyleSheets];
99
+ const newSheets = customStylesheets.filter((sheet) => !currentSheets.includes(sheet));
100
+ if (newSheets.length > 0) {
101
+ shadowRoot.adoptedStyleSheets = [...currentSheets, ...newSheets];
102
+ }
103
+ } catch (e) {
104
+ console.warn("[data-components] Failed to inject custom styles:", e);
105
+ }
106
+ }
107
+ function injectCssToShadowDoms(cssText) {
108
+ if (typeof window === "undefined") return null;
109
+ try {
110
+ const stylesheet = new CSSStyleSheet();
111
+ stylesheet.replaceSync(cssText || "");
112
+ registerProtectedStylesheet(stylesheet);
113
+ customStylesheets.push(stylesheet);
114
+ document.querySelectorAll("*").forEach((el) => {
115
+ if (el.shadowRoot) {
116
+ const currentSheets = [...el.shadowRoot.adoptedStyleSheets];
117
+ if (!currentSheets.includes(stylesheet)) {
118
+ el.shadowRoot.adoptedStyleSheets = [...currentSheets, stylesheet];
119
+ }
120
+ }
121
+ });
122
+ setupCustomStylesObserver();
123
+ if (process.env.NODE_ENV === "development") {
124
+ console.log("[data-components] Custom CSS registered for Shadow DOM injection");
125
+ }
126
+ return stylesheet;
127
+ } catch (e) {
128
+ console.warn("[data-components] Failed to inject custom CSS:", e);
129
+ return null;
130
+ }
131
+ }
132
+ let customStylesObserverInitialized = false;
133
+ function setupCustomStylesObserver() {
134
+ if (customStylesObserverInitialized) return;
135
+ if (typeof window === "undefined") return;
136
+ const observer = new MutationObserver((mutations) => {
137
+ mutations.forEach((mutation) => {
138
+ mutation.addedNodes.forEach((node) => {
139
+ if (node instanceof Element) {
140
+ if (node.shadowRoot) {
141
+ injectCustomStylesToShadowRoot(node.shadowRoot);
142
+ }
143
+ node.querySelectorAll("*").forEach((el) => {
144
+ if (el.shadowRoot) {
145
+ injectCustomStylesToShadowRoot(el.shadowRoot);
146
+ }
147
+ });
148
+ }
149
+ });
150
+ });
151
+ });
152
+ const startObserving = () => {
153
+ observer.observe(document.body, { childList: true, subtree: true });
154
+ };
155
+ if (document.readyState === "loading") {
156
+ document.addEventListener("DOMContentLoaded", startObserving);
157
+ } else {
158
+ startObserving();
159
+ }
160
+ customStylesObserverInitialized = true;
161
+ }
162
+ initDevExtremeCssInjection();
163
+
164
+ export { initDevExtremeCssInjection, injectCssToShadowDoms };
@@ -0,0 +1,2 @@
1
+ export { initShadowDomProtection, registerProtectedStylesheet } from './shadowDomProtection';
2
+ export { initDevExtremeCssInjection, injectCssToShadowDoms } from './devExtremeCssInjection';
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Shadow DOM Style Protection
3
+ *
4
+ * Protects Lit component styles from being overwritten by Vite HMR.
5
+ * When DevExtreme or other libraries load CSS, Vite HMR may clear/replace
6
+ * Shadow DOM's adoptedStyleSheets, causing Lit component styles to be lost.
7
+ *
8
+ * This module intercepts adoptedStyleSheets setter to:
9
+ * 1. Detect and save Lit styles (identified by :host selector)
10
+ * 2. Block HMR reset attempts that would clear Lit styles
11
+ * 3. Merge Lit styles with other styles (like DevExtreme)
12
+ * 4. Protect registered custom stylesheets from being lost during re-renders
13
+ */
14
+ /**
15
+ * Register a custom stylesheet to be protected
16
+ * Protected stylesheets will always be preserved when adoptedStyleSheets changes
17
+ */
18
+ export declare function registerProtectedStylesheet(stylesheet: CSSStyleSheet): void;
19
+ /**
20
+ * Initialize Shadow DOM style protection
21
+ * Should be called before any Lit components are loaded
22
+ */
23
+ export declare function initShadowDomProtection(): void;
@@ -0,0 +1,82 @@
1
+ let isInitialized = false;
2
+ const protectedCustomStylesheets = /* @__PURE__ */ new Set();
3
+ function registerProtectedStylesheet(stylesheet) {
4
+ protectedCustomStylesheets.add(stylesheet);
5
+ }
6
+ function isProtectedCustomStylesheet(sheet) {
7
+ return protectedCustomStylesheets.has(sheet);
8
+ }
9
+ function isLitStyleSheet(sheet) {
10
+ try {
11
+ if (!sheet.cssRules || sheet.cssRules.length === 0) return false;
12
+ const firstRule = sheet.cssRules[0];
13
+ return firstRule.cssText.startsWith(":host");
14
+ } catch {
15
+ return false;
16
+ }
17
+ }
18
+ function isEmptyOrHMRReset(sheets) {
19
+ if (!sheets || sheets.length === 0) return true;
20
+ return sheets.every((sheet) => {
21
+ try {
22
+ return !sheet.cssRules || sheet.cssRules.length === 0;
23
+ } catch {
24
+ return true;
25
+ }
26
+ });
27
+ }
28
+ function initShadowDomProtection() {
29
+ if (isInitialized) return;
30
+ if (typeof window === "undefined") return;
31
+ const originalDescriptor = Object.getOwnPropertyDescriptor(
32
+ ShadowRoot.prototype,
33
+ "adoptedStyleSheets"
34
+ );
35
+ if (!originalDescriptor) {
36
+ console.warn("[data-components] adoptedStyleSheets descriptor not found");
37
+ return;
38
+ }
39
+ const protectedLitStylesMap = /* @__PURE__ */ new WeakMap();
40
+ Object.defineProperty(ShadowRoot.prototype, "adoptedStyleSheets", {
41
+ get() {
42
+ return originalDescriptor.get?.call(this) ?? [];
43
+ },
44
+ set(sheets) {
45
+ const savedLitStyles = protectedLitStylesMap.get(this) || [];
46
+ const newLitStyles = sheets?.filter(isLitStyleSheet) || [];
47
+ const newNonLitStyles = sheets?.filter((s) => !isLitStyleSheet(s)) || [];
48
+ if (newLitStyles.length > 0) {
49
+ protectedLitStylesMap.set(this, [...newLitStyles]);
50
+ }
51
+ const protectedSheets = Array.from(protectedCustomStylesheets);
52
+ if (isEmptyOrHMRReset(sheets) && (savedLitStyles.length > 0 || protectedSheets.length > 0)) {
53
+ const preserved = [...savedLitStyles, ...protectedSheets.filter((s) => !savedLitStyles.includes(s))];
54
+ originalDescriptor.set?.call(this, preserved);
55
+ return;
56
+ }
57
+ if (savedLitStyles.length > 0 && newLitStyles.length === 0 && newNonLitStyles.length > 0) {
58
+ const nonProtectedNewStyles = newNonLitStyles.filter((s) => !isProtectedCustomStylesheet(s));
59
+ const mergedSheets = [
60
+ ...savedLitStyles,
61
+ ...protectedSheets.filter((s) => !savedLitStyles.includes(s)),
62
+ ...nonProtectedNewStyles.filter((s) => !protectedSheets.includes(s))
63
+ ];
64
+ originalDescriptor.set?.call(this, mergedSheets);
65
+ return;
66
+ }
67
+ const finalSheets = sheets ? [...sheets] : [];
68
+ protectedSheets.forEach((ps) => {
69
+ if (!finalSheets.includes(ps)) {
70
+ finalSheets.push(ps);
71
+ }
72
+ });
73
+ originalDescriptor.set?.call(this, finalSheets);
74
+ },
75
+ configurable: true,
76
+ enumerable: true
77
+ });
78
+ isInitialized = true;
79
+ }
80
+ initShadowDomProtection();
81
+
82
+ export { initShadowDomProtection, registerProtectedStylesheet };
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "@iyulab/data-components",
3
+ "description": "iyulab data visualization components",
4
+ "version": "0.1.0",
5
+ "keywords": [
6
+ "iyulab",
7
+ "web-components",
8
+ "lit-element"
9
+ ],
10
+ "license": "MIT",
11
+ "author": "iyulab",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/iyulab/node-data-components.git"
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "LICENSE",
19
+ "README.md",
20
+ "CHANGELOG.md",
21
+ "package.json"
22
+ ],
23
+ "type": "module",
24
+ "types": "./dist/index.d.ts",
25
+ "exports": {
26
+ ".": {
27
+ "types": "./src/index.d.ts",
28
+ "import": "./src/index.js"
29
+ },
30
+ "./dist/*": {
31
+ "types": "./src/*.d.ts",
32
+ "import": "./src/*"
33
+ },
34
+ "./init": {
35
+ "types": "./src/init.d.ts",
36
+ "import": "./src/init.js"
37
+ }
38
+ },
39
+ "sideEffects": [
40
+ "./dist/utilities/shadowDomProtection.js",
41
+ "./dist/utilities/devExtremeCssInjection.js",
42
+ "./dist/components/data-grid/UDataGrid.js",
43
+ "./dist/components/data-view/UDataView.js",
44
+ "./dist/components/simple-sheet/USimpleSheet.js",
45
+ "./dist/init.js"
46
+ ],
47
+ "scripts": {
48
+ "start": "vite",
49
+ "build": "eslint && vite build"
50
+ },
51
+ "dependencies": {
52
+ "@iyulab/components": "^0.4.0",
53
+ "devextreme": "^25.2.4",
54
+ "devextreme-react": "^25.2.4",
55
+ "lit": "^3.3.2",
56
+ "react": "^19.2.4",
57
+ "react-dom": "^19.2.4"
58
+ },
59
+ "devDependencies": {
60
+ "@eslint/js": "^9.39.3",
61
+ "@lit/react": "^1.0.8",
62
+ "@types/node": "^25.3.2",
63
+ "@types/react": "^19.2.14",
64
+ "@types/react-dom": "^19.2.3",
65
+ "@vitejs/plugin-react": "^5.1.4",
66
+ "eslint": "^9.39.3",
67
+ "eslint-plugin-react-hooks": "^7.0.1",
68
+ "eslint-plugin-react-refresh": "^0.5.2",
69
+ "globals": "^17.3.0",
70
+ "typescript": "~5.9.3",
71
+ "typescript-eslint": "^8.56.1",
72
+ "vite": "^7.3.1",
73
+ "vite-plugin-dts": "^4.5.4"
74
+ }
75
+ }