@iyulab/data-components 0.5.0 → 0.6.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 CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.6.0] - 2026-06-11
4
+
5
+ ### Added
6
+ - `USimpleSheet`: `theme` 속성 1급 지원 (`'light' | 'dark'`, attribute 리플렉트) — per-element 테마 지정 가능, `:host-context` 미지원 브라우저(Firefox/Safari)에서도 동작 (ISSUE-20260610-usimplesheet-darkmode-inconsistent)
7
+ - `USimpleSheet`: 조상 `data-theme="dark"` 컨텍스트에서도 다크 모드 적용 — Theme 유틸 없이 `data-theme`만 설정하는 앱에서 도구별 다크 적용이 비일관하던 문제 해소
8
+
9
+ ### Changed
10
+ - 다크 모드 CSS를 단일 소스에서 3가지 컨텍스트(`:host([theme="dark"])` / `:host-context([theme="dark"])` / `:host-context([data-theme="dark"])`) 개별 규칙으로 생성 — 셀렉터 리스트 결합 시 `:host-context` 미지원 브라우저가 리스트 전체를 무효화하는 문제 회피
11
+
3
12
  ## [0.5.0] - 2026-06-10
4
13
 
5
14
  ### Added
@@ -1 +1 @@
1
- export declare const styles: import('lit').CSSResult;
1
+ export declare const styles: import('lit').CSSResult[];
@@ -1,6 +1,6 @@
1
- import { css } from "lit";
1
+ import { css, unsafeCSS } from "lit";
2
2
  //#region src/components/data-view/UDataView.styles.ts
3
- var styles = css`
3
+ var baseStyles = css`
4
4
  :host {
5
5
  display: block;
6
6
  width: 100%;
@@ -19,8 +19,8 @@ var styles = css`
19
19
  align-items: center;
20
20
  justify-content: space-between;
21
21
  padding: 0.75rem;
22
- background: var(--u-bg-color);
23
- border: 1px solid var(--u-border-color);
22
+ background: var(--u-bg-color, #fff);
23
+ border: 1px solid var(--u-border-color, #e2e8f0);
24
24
  border-radius: 8px;
25
25
  }
26
26
 
@@ -30,13 +30,13 @@ var styles = css`
30
30
  }
31
31
 
32
32
  .view-toggles u-button[active] {
33
- background: var(--u-blue-600);
34
- color: var(--u-neutral-0);
33
+ background: var(--u-blue-600, #1E88E5);
34
+ color: var(--u-neutral-0, #fff);
35
35
  }
36
36
 
37
37
  .info {
38
38
  font-size: 0.875rem;
39
- color: var(--u-txt-color-weak);
39
+ color: var(--u-txt-color-weak, #64748b);
40
40
  font-weight: 500;
41
41
  }
42
42
 
@@ -56,8 +56,8 @@ var styles = css`
56
56
 
57
57
  /* Card Styles */
58
58
  .card {
59
- background: var(--u-bg-color);
60
- border: 1px solid var(--u-border-color);
59
+ background: var(--u-bg-color, #fff);
60
+ border: 1px solid var(--u-border-color, #e2e8f0);
61
61
  border-radius: 8px;
62
62
  padding: 1.25rem;
63
63
  cursor: pointer;
@@ -65,15 +65,15 @@ var styles = css`
65
65
  }
66
66
 
67
67
  .card:hover {
68
- border-color: var(--u-blue-600);
69
- box-shadow: 0 4px 12px var(--u-shadow-color-weak);
68
+ border-color: var(--u-blue-600, #1E88E5);
69
+ box-shadow: 0 4px 12px var(--u-shadow-color-weak, rgba(0, 0, 0, 0.08));
70
70
  transform: translateY(-2px);
71
71
  }
72
72
 
73
73
  .card.selected {
74
- border-color: var(--u-blue-600);
75
- background: var(--u-bg-color-active);
76
- box-shadow: 0 0 0 3px var(--u-blue-200);
74
+ border-color: var(--u-blue-600, #1E88E5);
75
+ background: var(--u-bg-color-active, #EEEEEE);
76
+ box-shadow: 0 0 0 3px var(--u-blue-200, #90CAF9);
77
77
  }
78
78
 
79
79
  .card-content {
@@ -91,14 +91,14 @@ var styles = css`
91
91
  .card-field .label {
92
92
  font-size: 0.875rem;
93
93
  font-weight: 600;
94
- color: var(--u-txt-color-weak);
94
+ color: var(--u-txt-color-weak, #64748b);
95
95
  min-width: 80px;
96
96
  flex-shrink: 0;
97
97
  }
98
98
 
99
99
  .card-field .value {
100
100
  font-size: 0.9375rem;
101
- color: var(--u-txt-color);
101
+ color: var(--u-txt-color, #0f172a);
102
102
  word-break: break-word;
103
103
  }
104
104
 
@@ -116,18 +116,18 @@ var styles = css`
116
116
  /* Table */
117
117
  .table-wrapper {
118
118
  overflow-x: auto;
119
- border: 1px solid var(--u-border-color);
119
+ border: 1px solid var(--u-border-color, #e2e8f0);
120
120
  border-radius: 8px;
121
121
  }
122
122
 
123
123
  table {
124
124
  width: 100%;
125
125
  border-collapse: collapse;
126
- background: var(--u-bg-color);
126
+ background: var(--u-bg-color, #fff);
127
127
  }
128
128
 
129
129
  thead {
130
- background: var(--u-neutral-50);
130
+ background: var(--u-neutral-50, #f8fafc);
131
131
  position: sticky;
132
132
  top: 0;
133
133
  z-index: 10;
@@ -138,8 +138,8 @@ var styles = css`
138
138
  text-align: left;
139
139
  font-size: 0.875rem;
140
140
  font-weight: 600;
141
- color: var(--u-txt-color-weak);
142
- border-bottom: 2px solid var(--u-border-color);
141
+ color: var(--u-txt-color-weak, #64748b);
142
+ border-bottom: 2px solid var(--u-border-color, #e2e8f0);
143
143
  white-space: nowrap;
144
144
  }
145
145
 
@@ -149,21 +149,21 @@ var styles = css`
149
149
  }
150
150
 
151
151
  tbody tr:hover {
152
- background: var(--u-bg-color-hover);
152
+ background: var(--u-bg-color-hover, #F5F5F5);
153
153
  }
154
154
 
155
155
  tbody tr.selected {
156
- background: var(--u-bg-color-active);
156
+ background: var(--u-bg-color-active, #EEEEEE);
157
157
  }
158
158
 
159
159
  tbody tr:not(:last-child) {
160
- border-bottom: 1px solid var(--u-border-color-weak);
160
+ border-bottom: 1px solid var(--u-border-color-weak, #f1f5f9);
161
161
  }
162
162
 
163
163
  td {
164
164
  padding: 0.875rem 1rem;
165
165
  font-size: 0.9375rem;
166
- color: var(--u-txt-color);
166
+ color: var(--u-txt-color, #0f172a);
167
167
  }
168
168
 
169
169
  /* Empty State */
@@ -172,9 +172,91 @@ var styles = css`
172
172
  align-items: center;
173
173
  justify-content: center;
174
174
  min-height: 300px;
175
- color: var(--u-txt-color-weak);
175
+ color: var(--u-txt-color-weak, #64748b);
176
176
  font-size: 1rem;
177
177
  }
178
178
  `;
179
+ var DARK_PREFIXES = [
180
+ ":host([theme=\"dark\"])",
181
+ ":host-context([theme=\"dark\"])",
182
+ ":host-context([data-theme=\"dark\"])"
183
+ ];
184
+ var darkRules = (host) => `
185
+ ${host} .toolbar {
186
+ background: var(--u-bg-color, #121212);
187
+ border-color: var(--u-border-color, #3D3D3D);
188
+ }
189
+
190
+ ${host} .view-toggles u-button[active] {
191
+ background: var(--u-blue-600, #87B8F5);
192
+ color: var(--u-neutral-0, #000);
193
+ }
194
+
195
+ ${host} .info {
196
+ color: var(--u-txt-color-weak, #8A8A8A);
197
+ }
198
+
199
+ ${host} .card {
200
+ background: var(--u-bg-color, #121212);
201
+ border-color: var(--u-border-color, #3D3D3D);
202
+ }
203
+
204
+ ${host} .card:hover {
205
+ border-color: var(--u-blue-600, #87B8F5);
206
+ box-shadow: 0 4px 12px var(--u-shadow-color-weak, rgba(0, 0, 0, 0.25));
207
+ }
208
+
209
+ ${host} .card.selected {
210
+ border-color: var(--u-blue-600, #87B8F5);
211
+ background: var(--u-bg-color-active, #3D3D3D);
212
+ box-shadow: 0 0 0 3px var(--u-blue-200, #2B4F7E);
213
+ }
214
+
215
+ ${host} .card-field .label {
216
+ color: var(--u-txt-color-weak, #8A8A8A);
217
+ }
218
+
219
+ ${host} .card-field .value {
220
+ color: var(--u-txt-color, #D4D4D4);
221
+ }
222
+
223
+ ${host} .table-wrapper {
224
+ border-color: var(--u-border-color, #3D3D3D);
225
+ }
226
+
227
+ ${host} table {
228
+ background: var(--u-bg-color, #121212);
229
+ }
230
+
231
+ ${host} thead {
232
+ background: var(--u-neutral-50, #0A0A0A);
233
+ }
234
+
235
+ ${host} th {
236
+ color: var(--u-txt-color-weak, #8A8A8A);
237
+ border-bottom-color: var(--u-border-color, #3D3D3D);
238
+ }
239
+
240
+ ${host} tbody tr:hover {
241
+ background: var(--u-bg-color-hover, #2A2A2A);
242
+ }
243
+
244
+ ${host} tbody tr.selected {
245
+ background: var(--u-bg-color-active, #3D3D3D);
246
+ }
247
+
248
+ ${host} tbody tr:not(:last-child) {
249
+ border-bottom-color: var(--u-border-color-weak, #2A2A2A);
250
+ }
251
+
252
+ ${host} td {
253
+ color: var(--u-txt-color, #D4D4D4);
254
+ }
255
+
256
+ ${host} .empty {
257
+ color: var(--u-txt-color-weak, #8A8A8A);
258
+ }
259
+ `;
260
+ var styles = [baseStyles, unsafeCSS(DARK_PREFIXES.map(darkRules).join("\n"))];
179
261
  //#endregion
180
262
  export { styles };
@@ -48,6 +48,11 @@ export declare class USimpleSheet extends UElement {
48
48
  cols: number;
49
49
  /** 읽기 전용 모드 */
50
50
  readonly: boolean;
51
+ /**
52
+ * 명시 테마. 'dark'이면 다크 스타일을 적용합니다.
53
+ * 미설정 시 조상 컨텍스트의 theme/data-theme 속성에 따릅니다 (:host-context, Chromium 한정).
54
+ */
55
+ theme?: 'light' | 'dark';
51
56
  private _sel;
52
57
  private _editing;
53
58
  private _editVal;
@@ -924,6 +924,10 @@ __decorate([property({ type: Array }), __decorateMetadata("design:type", Array)]
924
924
  __decorate([property({ type: Number }), __decorateMetadata("design:type", Object)], USimpleSheet.prototype, "rows", void 0);
925
925
  __decorate([property({ type: Number }), __decorateMetadata("design:type", Object)], USimpleSheet.prototype, "cols", void 0);
926
926
  __decorate([property({ type: Boolean }), __decorateMetadata("design:type", Object)], USimpleSheet.prototype, "readonly", void 0);
927
+ __decorate([property({
928
+ type: String,
929
+ reflect: true
930
+ }), __decorateMetadata("design:type", String)], USimpleSheet.prototype, "theme", void 0);
927
931
  __decorate([state(), __decorateMetadata("design:type", Object)], USimpleSheet.prototype, "_sel", void 0);
928
932
  __decorate([state(), __decorateMetadata("design:type", Object)], USimpleSheet.prototype, "_editing", void 0);
929
933
  __decorate([state(), __decorateMetadata("design:type", Object)], USimpleSheet.prototype, "_editVal", void 0);
@@ -1 +1 @@
1
- export declare const styles: import('lit').CSSResult;
1
+ export declare const styles: import('lit').CSSResult[];
@@ -1,6 +1,6 @@
1
- import { css } from "lit";
1
+ import { css, unsafeCSS } from "lit";
2
2
  //#region src/components/simple-sheet/USimpleSheet.styles.ts
3
- var styles = css`
3
+ var baseStyles = css`
4
4
  :host {
5
5
  display: block;
6
6
  width: 100%;
@@ -281,126 +281,130 @@ var styles = css`
281
281
  cursor: default;
282
282
  }
283
283
 
284
- /* ── Dark mode ──
285
- 외부에서 --u-* CSS 변수가 제공되면 그 값을 사용하고,
286
- 제공되지 않으면 자체 dark fallback 값을 적용한다. */
287
-
288
- :host-context([theme="dark"]) .sheet-container {
284
+ `;
285
+ var DARK_PREFIXES = [
286
+ ":host([theme=\"dark\"])",
287
+ ":host-context([theme=\"dark\"])",
288
+ ":host-context([data-theme=\"dark\"])"
289
+ ];
290
+ var darkRules = (host) => `
291
+ ${host} .sheet-container {
289
292
  background: var(--u-bg-color, #121212);
290
293
  border-color: var(--u-border-color, #3D3D3D);
291
294
  }
292
295
 
293
- :host-context([theme="dark"]) .sheet-container:focus-within {
296
+ ${host} .sheet-container:focus-within {
294
297
  border-color: var(--u-blue-500, #6ba3e3);
295
298
  box-shadow: 0 0 0 2px var(--u-blue-100, #1e3a5f);
296
299
  }
297
300
 
298
- :host-context([theme="dark"]) .corner {
301
+ ${host} .corner {
299
302
  background: var(--u-neutral-100, #121212);
300
303
  border-color: var(--u-border-color, #3D3D3D);
301
304
  }
302
305
 
303
- :host-context([theme="dark"]) .corner:hover {
306
+ ${host} .corner:hover {
304
307
  background: var(--u-neutral-200, #1E1E1E);
305
308
  }
306
309
 
307
- :host-context([theme="dark"]) .col-header {
310
+ ${host} .col-header {
308
311
  background: var(--u-neutral-100, #121212);
309
312
  color: var(--u-txt-color-weak, #8A8A8A);
310
313
  border-color: var(--u-border-color, #3D3D3D);
311
314
  }
312
315
 
313
- :host-context([theme="dark"]) .col-header.col-selected {
316
+ ${host} .col-header.col-selected {
314
317
  background: var(--u-blue-100, #1e3a5f);
315
318
  color: var(--u-blue-800, #c2deff);
316
319
  }
317
320
 
318
- :host-context([theme="dark"]) .row-num {
321
+ ${host} .row-num {
319
322
  background: var(--u-neutral-50, #0A0A0A);
320
323
  color: var(--u-txt-color-weak, #8A8A8A);
321
324
  border-right-color: var(--u-border-color, #3D3D3D);
322
325
  border-bottom-color: var(--u-border-color-weak, #2A2A2A);
323
326
  }
324
327
 
325
- :host-context([theme="dark"]) .row-num.row-selected {
328
+ ${host} .row-num.row-selected {
326
329
  background: var(--u-blue-100, #1e3a5f);
327
330
  color: var(--u-blue-800, #c2deff);
328
331
  }
329
332
 
330
- :host-context([theme="dark"]) .cell {
333
+ ${host} .cell {
331
334
  color: var(--u-txt-color, #D4D4D4);
332
335
  border-right-color: var(--u-border-color-weak, #2A2A2A);
333
336
  border-bottom-color: var(--u-border-color-weak, #2A2A2A);
334
337
  }
335
338
 
336
- :host-context([theme="dark"]) .cell.cell-readonly {
339
+ ${host} .cell.cell-readonly {
337
340
  background: var(--u-neutral-100, #1E1E1E);
338
341
  color: var(--u-txt-color-weak, #8A8A8A);
339
342
  }
340
343
 
341
- :host-context([theme="dark"]) .cell.cell-readonly.selected {
344
+ ${host} .cell.cell-readonly.selected {
342
345
  background: var(--u-neutral-200, #2A2A2A);
343
346
  }
344
347
 
345
- :host-context([theme="dark"]) .cell.cell-readonly.anchor {
348
+ ${host} .cell.cell-readonly.anchor {
346
349
  background: var(--u-neutral-100, #1E1E1E);
347
350
  }
348
351
 
349
- :host-context([theme="dark"]) .cell.cell-computed {
352
+ ${host} .cell.cell-computed {
350
353
  background: var(--u-blue-100, #1e3a5f);
351
354
  color: var(--u-txt-color, #D4D4D4);
352
355
  }
353
356
 
354
- :host-context([theme="dark"]) .cell.cell-computed.selected {
357
+ ${host} .cell.cell-computed.selected {
355
358
  background: var(--u-blue-200, #2a4a6f);
356
359
  }
357
360
 
358
- :host-context([theme="dark"]) .cell.cell-computed.anchor {
361
+ ${host} .cell.cell-computed.anchor {
359
362
  background: var(--u-blue-100, #1e3a5f);
360
363
  }
361
364
 
362
- :host-context([theme="dark"]) .cell.selected {
365
+ ${host} .cell.selected {
363
366
  background: var(--u-blue-0, #0a1e3d);
364
367
  }
365
368
 
366
- :host-context([theme="dark"]) .cell.anchor {
369
+ ${host} .cell.anchor {
367
370
  background: var(--u-bg-color, #121212);
368
371
  outline-color: var(--u-blue-500, #6ba3e3);
369
372
  }
370
373
 
371
- :host-context([theme="dark"]) .resize-handle:hover::after {
374
+ ${host} .resize-handle:hover::after {
372
375
  background: var(--u-blue-500, #6ba3e3);
373
376
  }
374
377
 
375
- :host-context([theme="dark"]) .cell-input {
378
+ ${host} .cell-input {
376
379
  background: var(--u-bg-color, #121212);
377
380
  color: var(--u-txt-color, #D4D4D4);
378
381
  outline-color: var(--u-blue-500, #6ba3e3);
379
382
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
380
383
  }
381
384
 
382
- :host-context([theme="dark"]) .cell-dropdown {
385
+ ${host} .cell-dropdown {
383
386
  background: var(--u-bg-color, #121212);
384
387
  border-color: var(--u-border-color, #3D3D3D);
385
388
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
386
389
  }
387
390
 
388
- :host-context([theme="dark"]) .dropdown-item {
391
+ ${host} .dropdown-item {
389
392
  color: var(--u-txt-color, #D4D4D4);
390
393
  }
391
394
 
392
- :host-context([theme="dark"]) .dropdown-item:hover {
395
+ ${host} .dropdown-item:hover {
393
396
  background: var(--u-neutral-100, #1E1E1E);
394
397
  }
395
398
 
396
- :host-context([theme="dark"]) .dropdown-item.highlighted {
399
+ ${host} .dropdown-item.highlighted {
397
400
  background: var(--u-blue-100, #1e3a5f);
398
401
  color: var(--u-blue-800, #c2deff);
399
402
  }
400
403
 
401
- :host-context([theme="dark"]) .dropdown-empty {
404
+ ${host} .dropdown-empty {
402
405
  color: var(--u-txt-color-weak, #8A8A8A);
403
406
  }
404
407
  `;
408
+ var styles = [baseStyles, unsafeCSS(DARK_PREFIXES.map(darkRules).join("\n"))];
405
409
  //#endregion
406
410
  export { styles };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@iyulab/data-components",
3
3
  "description": "iyulab data visualization components",
4
- "version": "0.5.0",
4
+ "version": "0.6.1",
5
5
  "keywords": [
6
6
  "iyulab",
7
7
  "web-components",
@@ -51,7 +51,9 @@
51
51
  ],
52
52
  "scripts": {
53
53
  "start": "vite",
54
- "build": "eslint && vite build"
54
+ "build": "eslint && vite build",
55
+ "test": "vitest run",
56
+ "test:watch": "vitest"
55
57
  },
56
58
  "dependencies": {
57
59
  "@iyulab/components": "^1.0.6",
@@ -72,15 +74,17 @@
72
74
  "devDependencies": {
73
75
  "@eslint/js": "^9.39.4",
74
76
  "@lit/react": "^1.0.8",
75
- "@types/react": "^19.2.14",
76
77
  "@types/node": "^25.8.0",
78
+ "@types/react": "^19.2.14",
77
79
  "eslint": "^9.39.4",
78
80
  "glob": "^13.0.6",
79
81
  "globals": "^17.6.0",
82
+ "happy-dom": "^20.10.2",
80
83
  "react": "^19.2.6",
81
84
  "typescript": "^5.9.3",
82
85
  "typescript-eslint": "^8.59.3",
83
86
  "vite": "^8.0.13",
84
- "vite-plugin-dts": "^5.0.0"
87
+ "vite-plugin-dts": "^5.0.0",
88
+ "vitest": "^4.1.8"
85
89
  }
86
90
  }