@simplysm/solid 13.0.70 → 13.0.72

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.
Files changed (106) hide show
  1. package/README.md +1 -1
  2. package/dist/components/data/sheet/DataSheet.d.ts.map +1 -1
  3. package/dist/components/data/sheet/DataSheet.js +3 -6
  4. package/dist/components/data/sheet/DataSheet.js.map +1 -1
  5. package/dist/components/data/sheet/DataSheet.styles.d.ts.map +1 -1
  6. package/dist/components/data/sheet/DataSheet.styles.js +1 -1
  7. package/dist/components/data/sheet/DataSheet.styles.js.map +1 -1
  8. package/dist/components/disclosure/Dropdown.d.ts +6 -4
  9. package/dist/components/disclosure/Dropdown.d.ts.map +1 -1
  10. package/dist/components/disclosure/Dropdown.js +24 -8
  11. package/dist/components/disclosure/Dropdown.js.map +2 -2
  12. package/dist/components/disclosure/dialogZIndex.d.ts +2 -0
  13. package/dist/components/disclosure/dialogZIndex.d.ts.map +1 -1
  14. package/dist/components/disclosure/dialogZIndex.js +4 -0
  15. package/dist/components/disclosure/dialogZIndex.js.map +1 -1
  16. package/dist/components/features/crud-detail/CrudDetail.d.ts.map +1 -1
  17. package/dist/components/features/crud-detail/CrudDetail.js +16 -7
  18. package/dist/components/features/crud-detail/CrudDetail.js.map +2 -2
  19. package/dist/components/features/crud-sheet/CrudSheet.d.ts.map +1 -1
  20. package/dist/components/features/crud-sheet/CrudSheet.js +14 -5
  21. package/dist/components/features/crud-sheet/CrudSheet.js.map +2 -2
  22. package/dist/components/features/crudRegistry.d.ts +16 -0
  23. package/dist/components/features/crudRegistry.d.ts.map +1 -0
  24. package/dist/components/features/crudRegistry.js +37 -0
  25. package/dist/components/features/crudRegistry.js.map +6 -0
  26. package/dist/components/features/permission-table/PermissionTable.d.ts.map +1 -1
  27. package/dist/components/features/permission-table/PermissionTable.js +71 -86
  28. package/dist/components/features/permission-table/PermissionTable.js.map +2 -2
  29. package/dist/components/features/shared-data/SharedDataSelect.js +2 -4
  30. package/dist/components/features/shared-data/SharedDataSelect.js.map +2 -2
  31. package/dist/components/features/shared-data/SharedDataSelectList.d.ts +2 -4
  32. package/dist/components/features/shared-data/SharedDataSelectList.d.ts.map +1 -1
  33. package/dist/components/features/shared-data/SharedDataSelectList.js +11 -46
  34. package/dist/components/features/shared-data/SharedDataSelectList.js.map +2 -2
  35. package/dist/components/form-control/select/Select.d.ts.map +1 -1
  36. package/dist/components/form-control/select/Select.js +1 -1
  37. package/dist/components/form-control/select/Select.js.map +1 -1
  38. package/dist/helpers/createAppStructure.d.ts.map +1 -1
  39. package/dist/helpers/createAppStructure.js +3 -2
  40. package/dist/helpers/createAppStructure.js.map +1 -1
  41. package/dist/helpers/createHmrSafeContext.d.ts +3 -0
  42. package/dist/helpers/createHmrSafeContext.d.ts.map +1 -0
  43. package/dist/helpers/createHmrSafeContext.js +10 -0
  44. package/dist/helpers/createHmrSafeContext.js.map +6 -0
  45. package/dist/hooks/createSelectionGroup.d.ts.map +1 -1
  46. package/dist/hooks/createSelectionGroup.js +3 -2
  47. package/dist/hooks/createSelectionGroup.js.map +2 -2
  48. package/package.json +6 -5
  49. package/src/components/data/sheet/DataSheet.styles.ts +1 -1
  50. package/src/components/data/sheet/DataSheet.tsx +3 -4
  51. package/src/components/disclosure/Dropdown.tsx +31 -17
  52. package/src/components/disclosure/dialogZIndex.ts +5 -0
  53. package/src/components/features/crud-detail/CrudDetail.tsx +16 -5
  54. package/src/components/features/crud-sheet/CrudSheet.tsx +13 -3
  55. package/src/components/features/crudRegistry.ts +60 -0
  56. package/src/components/features/permission-table/PermissionTable.tsx +49 -46
  57. package/src/components/features/shared-data/SharedDataSelect.tsx +2 -2
  58. package/src/components/features/shared-data/SharedDataSelectList.tsx +11 -36
  59. package/src/components/form-control/select/Select.tsx +1 -5
  60. package/src/helpers/createAppStructure.ts +3 -2
  61. package/src/helpers/createHmrSafeContext.ts +8 -0
  62. package/src/hooks/createSelectionGroup.tsx +4 -2
  63. package/tests/components/data/List.spec.tsx +52 -52
  64. package/tests/components/data/Pagination.spec.tsx +43 -43
  65. package/tests/components/data/Table.spec.tsx +4 -4
  66. package/tests/components/data/kanban/Kanban.selection.spec.tsx +21 -21
  67. package/tests/components/data/sheet/DataSheet.spec.tsx +50 -50
  68. package/tests/components/disclosure/Collapse.spec.tsx +24 -24
  69. package/tests/components/disclosure/Dialog.spec.tsx +33 -33
  70. package/tests/components/disclosure/DialogProvider.spec.tsx +9 -9
  71. package/tests/components/disclosure/Dropdown.spec.tsx +134 -14
  72. package/tests/components/disclosure/Tabs.spec.tsx +21 -21
  73. package/tests/components/disclosure/dialogZIndex.spec.ts +45 -0
  74. package/tests/components/display/Alert.spec.tsx +4 -4
  75. package/tests/components/display/Barcode.spec.tsx +7 -7
  76. package/tests/components/display/Card.spec.tsx +3 -3
  77. package/tests/components/display/Link.spec.tsx +5 -5
  78. package/tests/components/display/Tag.spec.tsx +4 -4
  79. package/tests/components/features/address/AddressSearch.spec.tsx +3 -3
  80. package/tests/components/features/crudRegistry.spec.ts +119 -0
  81. package/tests/components/features/data-select-button/DataSelectButton.spec.tsx +8 -8
  82. package/tests/components/features/permission-table/PermissionTable.spec.tsx +43 -43
  83. package/tests/components/features/shared-data/SharedDataSelectList.spec.tsx +2 -17
  84. package/tests/components/feedback/busy/BusyContainer.spec.tsx +7 -7
  85. package/tests/components/feedback/notification/NotificationBell.spec.tsx +9 -9
  86. package/tests/components/feedback/print/Print.spec.tsx +4 -4
  87. package/tests/components/form-control/Button.spec.tsx +18 -18
  88. package/tests/components/form-control/checkbox/Checkbox.spec.tsx +20 -20
  89. package/tests/components/form-control/checkbox/CheckboxGroup.spec.tsx +12 -12
  90. package/tests/components/form-control/checkbox/Radio.spec.tsx +21 -21
  91. package/tests/components/form-control/checkbox/RadioGroup.spec.tsx +12 -12
  92. package/tests/components/form-control/color-picker/ColorPicker.spec.tsx +10 -10
  93. package/tests/components/form-control/combobox/Combobox.spec.tsx +16 -16
  94. package/tests/components/form-control/combobox/ComboboxItem.spec.tsx +7 -7
  95. package/tests/components/form-control/date-range-picker/DateRangePicker.spec.tsx +24 -24
  96. package/tests/components/form-control/field/DatePicker.spec.tsx +50 -50
  97. package/tests/components/form-control/field/DateTimePicker.spec.tsx +47 -47
  98. package/tests/components/form-control/field/NumberInput.spec.tsx +54 -54
  99. package/tests/components/form-control/field/TextInput.spec.tsx +49 -49
  100. package/tests/components/form-control/field/Textarea.spec.tsx +33 -33
  101. package/tests/components/form-control/field/TimePicker.spec.tsx +42 -42
  102. package/tests/components/form-control/numpad/Numpad.spec.tsx +40 -40
  103. package/tests/components/form-control/select/Select.spec.tsx +9 -9
  104. package/tests/components/form-control/select/SelectItem.spec.tsx +10 -10
  105. package/tests/helpers/createAppStructure.spec.tsx +57 -57
  106. package/tests/helpers/mergeStyles.spec.ts +31 -31
@@ -3,7 +3,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
3
3
  import { createSignal } from "solid-js";
4
4
  import { Dropdown } from "../../../src/components/disclosure/Dropdown";
5
5
 
6
- describe("Dropdown 컴포넌트", () => {
6
+ describe("Dropdown", () => {
7
7
  beforeEach(() => {
8
8
  vi.stubGlobal("innerWidth", 1024);
9
9
  vi.stubGlobal("innerHeight", 768);
@@ -15,8 +15,8 @@ describe("Dropdown 컴포넌트", () => {
15
15
  vi.unstubAllGlobals();
16
16
  });
17
17
 
18
- describe("Trigger/Content 구조", () => {
19
- it("Trigger 클릭 Content가 렌더링된다", async () => {
18
+ describe("Trigger/Content structure", () => {
19
+ it("renders Content on Trigger click", async () => {
20
20
  render(() => (
21
21
  <Dropdown>
22
22
  <Dropdown.Trigger>
@@ -38,7 +38,7 @@ describe("Dropdown 컴포넌트", () => {
38
38
  });
39
39
  });
40
40
 
41
- it("Trigger 재클릭 닫힌다", () => {
41
+ it("closes on second Trigger click", () => {
42
42
  const [open, setOpen] = createSignal(false);
43
43
  const handleOpenChange = vi.fn((v: boolean) => setOpen(v));
44
44
 
@@ -61,7 +61,7 @@ describe("Dropdown 컴포넌트", () => {
61
61
  expect(handleOpenChange).toHaveBeenCalledWith(false);
62
62
  });
63
63
 
64
- it("disabled Trigger 클릭이 무시된다", () => {
64
+ it("ignores Trigger click when disabled", () => {
65
65
  const [open, setOpen] = createSignal(false);
66
66
  const handleOpenChange = vi.fn((v: boolean) => setOpen(v));
67
67
 
@@ -81,8 +81,8 @@ describe("Dropdown 컴포넌트", () => {
81
81
  });
82
82
  });
83
83
 
84
- describe("Controlled 모드", () => {
85
- it("open prop으로 제어된다", async () => {
84
+ describe("controlled mode", () => {
85
+ it("is controlled by open prop", async () => {
86
86
  const [open, setOpen] = createSignal(false);
87
87
 
88
88
  render(() => (
@@ -106,8 +106,8 @@ describe("Dropdown 컴포넌트", () => {
106
106
  });
107
107
  });
108
108
 
109
- describe("Context menu (Trigger 없음)", () => {
110
- it("position prop으로 위치가 설정된다", async () => {
109
+ describe("Context menu (no Trigger)", () => {
110
+ it("sets position via position prop", async () => {
111
111
  render(() => (
112
112
  <Dropdown position={{ x: 300, y: 200 }} open={true}>
113
113
  <Dropdown.Content>
@@ -124,8 +124,8 @@ describe("Dropdown 컴포넌트", () => {
124
124
  });
125
125
  });
126
126
 
127
- describe("닫힘 감지", () => {
128
- it("외부 pointerdown 닫힌다", async () => {
127
+ describe("close detection", () => {
128
+ it("closes on outside pointerdown", async () => {
129
129
  const handleOpenChange = vi.fn();
130
130
 
131
131
  render(() => (
@@ -150,7 +150,7 @@ describe("Dropdown 컴포넌트", () => {
150
150
  expect(handleOpenChange).toHaveBeenCalledWith(false);
151
151
  });
152
152
 
153
- it("Escape 키로 닫힌다", async () => {
153
+ it("closes on Escape key", async () => {
154
154
  const handleOpenChange = vi.fn();
155
155
 
156
156
  render(() => (
@@ -174,7 +174,7 @@ describe("Dropdown 컴포넌트", () => {
174
174
  });
175
175
 
176
176
  describe("maxHeight", () => {
177
- it("기본값 300px", async () => {
177
+ it("defaults to 300px", async () => {
178
178
  render(() => (
179
179
  <Dropdown open={true}>
180
180
  <Dropdown.Trigger>
@@ -192,7 +192,7 @@ describe("Dropdown 컴포넌트", () => {
192
192
  });
193
193
  });
194
194
 
195
- it("커스텀 적용", async () => {
195
+ it("applies custom value", async () => {
196
196
  render(() => (
197
197
  <Dropdown open={true} maxHeight={500}>
198
198
  <Dropdown.Trigger>
@@ -210,4 +210,124 @@ describe("Dropdown 컴포넌트", () => {
210
210
  });
211
211
  });
212
212
  });
213
+
214
+ describe("keyboardNav tabbable navigation", () => {
215
+ it("ArrowDown from trigger focuses first tabbable in popup (input, not list item)", async () => {
216
+ const [open, setOpen] = createSignal(true);
217
+
218
+ render(() => (
219
+ <Dropdown open={open()} onOpenChange={setOpen} keyboardNav>
220
+ <Dropdown.Trigger>
221
+ <button data-testid="trigger">trigger</button>
222
+ </Dropdown.Trigger>
223
+ <Dropdown.Content>
224
+ <input data-testid="search" />
225
+ <button data-testid="action-btn" type="button">action</button>
226
+ <button data-list-item data-testid="item1" type="button">item1</button>
227
+ </Dropdown.Content>
228
+ </Dropdown>
229
+ ));
230
+
231
+ await waitFor(() => {
232
+ expect(document.querySelector("[data-dropdown]")).not.toBeNull();
233
+ });
234
+
235
+ const triggerWrapper = document.querySelector("[data-dropdown-trigger]") as HTMLElement;
236
+ triggerWrapper.focus();
237
+
238
+ fireEvent.keyDown(triggerWrapper, { key: "ArrowDown" });
239
+
240
+ const search = document.querySelector('[data-testid="search"]') as HTMLElement;
241
+ expect(document.activeElement).toBe(search);
242
+ });
243
+
244
+ it("ArrowDown from input focuses next tabbable (button)", async () => {
245
+ const [open, setOpen] = createSignal(true);
246
+
247
+ render(() => (
248
+ <Dropdown open={open()} onOpenChange={setOpen} keyboardNav>
249
+ <Dropdown.Trigger>
250
+ <button data-testid="trigger">trigger</button>
251
+ </Dropdown.Trigger>
252
+ <Dropdown.Content>
253
+ <input data-testid="search" />
254
+ <button data-testid="action-btn" type="button">action</button>
255
+ <button data-list-item data-testid="item1" type="button">item1</button>
256
+ </Dropdown.Content>
257
+ </Dropdown>
258
+ ));
259
+
260
+ await waitFor(() => {
261
+ expect(document.querySelector("[data-dropdown]")).not.toBeNull();
262
+ });
263
+
264
+ const search = document.querySelector('[data-testid="search"]') as HTMLElement;
265
+ search.focus();
266
+
267
+ const popup = document.querySelector("[data-dropdown]") as HTMLElement;
268
+ fireEvent.keyDown(popup, { key: "ArrowDown" });
269
+
270
+ const actionBtn = document.querySelector('[data-testid="action-btn"]') as HTMLElement;
271
+ expect(document.activeElement).toBe(actionBtn);
272
+ });
273
+
274
+ it("ArrowUp from input focuses trigger (no prev tabbable, dir=down)", async () => {
275
+ const [open, setOpen] = createSignal(true);
276
+
277
+ render(() => (
278
+ <Dropdown open={open()} onOpenChange={setOpen} keyboardNav>
279
+ <Dropdown.Trigger>
280
+ <button data-testid="trigger">trigger</button>
281
+ </Dropdown.Trigger>
282
+ <Dropdown.Content>
283
+ <input data-testid="search" />
284
+ <button data-list-item data-testid="item1" type="button">item1</button>
285
+ </Dropdown.Content>
286
+ </Dropdown>
287
+ ));
288
+
289
+ await waitFor(() => {
290
+ expect(document.querySelector("[data-dropdown]")).not.toBeNull();
291
+ });
292
+
293
+ const search = document.querySelector('[data-testid="search"]') as HTMLElement;
294
+ search.focus();
295
+
296
+ const popup = document.querySelector("[data-dropdown]") as HTMLElement;
297
+ fireEvent.keyDown(popup, { key: "ArrowUp" });
298
+
299
+ const triggerWrapper = document.querySelector("[data-dropdown-trigger]") as HTMLElement;
300
+ expect(document.activeElement).toBe(triggerWrapper);
301
+ });
302
+
303
+ it("ArrowUp from action button focuses prev tabbable (input)", async () => {
304
+ const [open, setOpen] = createSignal(true);
305
+
306
+ render(() => (
307
+ <Dropdown open={open()} onOpenChange={setOpen} keyboardNav>
308
+ <Dropdown.Trigger>
309
+ <button data-testid="trigger">trigger</button>
310
+ </Dropdown.Trigger>
311
+ <Dropdown.Content>
312
+ <input data-testid="search" />
313
+ <button data-testid="action-btn" type="button">action</button>
314
+ <button data-list-item data-testid="item1" type="button">item1</button>
315
+ </Dropdown.Content>
316
+ </Dropdown>
317
+ ));
318
+
319
+ await waitFor(() => {
320
+ expect(document.querySelector("[data-dropdown]")).not.toBeNull();
321
+ });
322
+
323
+ const actionBtn = document.querySelector('[data-testid="action-btn"]') as HTMLElement;
324
+ actionBtn.focus();
325
+
326
+ const popup = document.querySelector("[data-dropdown]") as HTMLElement;
327
+ fireEvent.keyDown(popup, { key: "ArrowUp" });
328
+
329
+ const search = document.querySelector('[data-testid="search"]') as HTMLElement;
330
+ expect(document.activeElement).toBe(search);
331
+ });
332
+ });
213
333
  });
@@ -3,9 +3,9 @@ import { describe, it, expect, vi } from "vitest";
3
3
  import { createSignal } from "solid-js";
4
4
  import { Tabs } from "../../../src/components/disclosure/Tabs";
5
5
 
6
- describe("Tabs 컴포넌트", () => {
6
+ describe("Tabs", () => {
7
7
  describe("basic rendering", () => {
8
- it("tablist role로 렌더링된다", () => {
8
+ it("renders with tablist role", () => {
9
9
  const { getByRole } = render(() => (
10
10
  <Tabs>
11
11
  <Tabs.Tab value="a">A</Tabs.Tab>
@@ -14,7 +14,7 @@ describe("Tabs 컴포넌트", () => {
14
14
  expect(getByRole("tablist")).toBeTruthy();
15
15
  });
16
16
 
17
- it("Tabs.Tab tab role로 렌더링된다", () => {
17
+ it("renders Tabs.Tab with tab role", () => {
18
18
  const { getByRole } = render(() => (
19
19
  <Tabs>
20
20
  <Tabs.Tab value="a">A</Tabs.Tab>
@@ -23,7 +23,7 @@ describe("Tabs 컴포넌트", () => {
23
23
  expect(getByRole("tab")).toBeTruthy();
24
24
  });
25
25
 
26
- it("children이 표시된다", () => {
26
+ it("renders children", () => {
27
27
  const { getByText } = render(() => (
28
28
  <Tabs>
29
29
  <Tabs.Tab value="a">탭 A</Tabs.Tab>
@@ -35,8 +35,8 @@ describe("Tabs 컴포넌트", () => {
35
35
  });
36
36
  });
37
37
 
38
- describe("선택 동작", () => {
39
- it("클릭하면 aria-selected true 된다", () => {
38
+ describe("selection behavior", () => {
39
+ it("sets aria-selected to true on click", () => {
40
40
  const { getAllByRole } = render(() => (
41
41
  <Tabs>
42
42
  <Tabs.Tab value="a">A</Tabs.Tab>
@@ -50,7 +50,7 @@ describe("Tabs 컴포넌트", () => {
50
50
  expect(tabs[1].getAttribute("aria-selected")).toBe("false");
51
51
  });
52
52
 
53
- it("다른 클릭 선택이 변경된다", () => {
53
+ it("changes selection on different tab click", () => {
54
54
  const { getAllByRole } = render(() => (
55
55
  <Tabs value="a">
56
56
  <Tabs.Tab value="a">A</Tabs.Tab>
@@ -64,7 +64,7 @@ describe("Tabs 컴포넌트", () => {
64
64
  expect(tabs[0].getAttribute("aria-selected")).toBe("false");
65
65
  });
66
66
 
67
- it("disabled 탭은 클릭해도 선택되지 않는다", () => {
67
+ it("does not select disabled tab on click", () => {
68
68
  const handleChange = vi.fn();
69
69
  const { getAllByRole } = render(() => (
70
70
  <Tabs onValueChange={handleChange}>
@@ -80,8 +80,8 @@ describe("Tabs 컴포넌트", () => {
80
80
  });
81
81
  });
82
82
 
83
- describe("키보드 동작", () => {
84
- it("Space 키로 선택된다", () => {
83
+ describe("keyboard behavior", () => {
84
+ it("selects tab with Space key", () => {
85
85
  const { getAllByRole } = render(() => (
86
86
  <Tabs>
87
87
  <Tabs.Tab value="a">A</Tabs.Tab>
@@ -93,7 +93,7 @@ describe("Tabs 컴포넌트", () => {
93
93
  expect(getAllByRole("tab")[0].getAttribute("aria-selected")).toBe("true");
94
94
  });
95
95
 
96
- it("Enter 키로 선택된다", () => {
96
+ it("selects tab with Enter key", () => {
97
97
  const { getAllByRole } = render(() => (
98
98
  <Tabs>
99
99
  <Tabs.Tab value="a">A</Tabs.Tab>
@@ -106,8 +106,8 @@ describe("Tabs 컴포넌트", () => {
106
106
  });
107
107
  });
108
108
 
109
- describe("controlled 패턴", () => {
110
- it("value prop 선택 상태로 반영된다", () => {
109
+ describe("controlled pattern", () => {
110
+ it("reflects value prop as selected state", () => {
111
111
  const { getAllByRole } = render(() => (
112
112
  <Tabs value="b">
113
113
  <Tabs.Tab value="a">A</Tabs.Tab>
@@ -119,7 +119,7 @@ describe("Tabs 컴포넌트", () => {
119
119
  expect(getAllByRole("tab")[1].getAttribute("aria-selected")).toBe("true");
120
120
  });
121
121
 
122
- it("onValueChange 클릭 시 호출된다", () => {
122
+ it("calls onValueChange on click", () => {
123
123
  const handleChange = vi.fn();
124
124
  const { getAllByRole } = render(() => (
125
125
  <Tabs value="a" onValueChange={handleChange}>
@@ -132,7 +132,7 @@ describe("Tabs 컴포넌트", () => {
132
132
  expect(handleChange).toHaveBeenCalledWith("b");
133
133
  });
134
134
 
135
- it("외부 상태 변경 업데이트된다", () => {
135
+ it("updates when external state changes", () => {
136
136
  const [value, setValue] = createSignal("a");
137
137
  const { getAllByRole } = render(() => (
138
138
  <Tabs value={value()} onValueChange={setValue}>
@@ -149,8 +149,8 @@ describe("Tabs 컴포넌트", () => {
149
149
  });
150
150
  });
151
151
 
152
- describe("사이즈", () => {
153
- it("size prop에 따라 스타일이 달라진다", () => {
152
+ describe("size", () => {
153
+ it("applies different styles per size prop", () => {
154
154
  const { getAllByRole: getDefault } = render(() => (
155
155
  <Tabs>
156
156
  <Tabs.Tab value="a">A</Tabs.Tab>
@@ -167,7 +167,7 @@ describe("Tabs 컴포넌트", () => {
167
167
  });
168
168
 
169
169
  describe("accessibility", () => {
170
- it("disabled 탭에 aria-disabled 설정된다", () => {
170
+ it("sets aria-disabled on disabled tab", () => {
171
171
  const { getAllByRole } = render(() => (
172
172
  <Tabs>
173
173
  <Tabs.Tab value="a">A</Tabs.Tab>
@@ -180,7 +180,7 @@ describe("Tabs 컴포넌트", () => {
180
180
  expect(getAllByRole("tab")[1].getAttribute("aria-disabled")).toBe("true");
181
181
  });
182
182
 
183
- it("disabled 탭의 tabIndex -1이다", () => {
183
+ it("sets tabIndex to -1 on disabled tab", () => {
184
184
  const { getAllByRole } = render(() => (
185
185
  <Tabs>
186
186
  <Tabs.Tab value="a">A</Tabs.Tab>
@@ -195,7 +195,7 @@ describe("Tabs 컴포넌트", () => {
195
195
  });
196
196
 
197
197
  describe("class merging", () => {
198
- it("Tabs에 사용자 정의 class 병합된다", () => {
198
+ it("merges custom class on Tabs", () => {
199
199
  const { getByRole } = render(() => (
200
200
  // eslint-disable-next-line tailwindcss/no-custom-classname
201
201
  <Tabs class="my-tab-class">
@@ -205,7 +205,7 @@ describe("Tabs 컴포넌트", () => {
205
205
  expect(getByRole("tablist").classList.contains("my-tab-class")).toBe(true);
206
206
  });
207
207
 
208
- it("Tabs.Tab에 사용자 정의 class 병합된다", () => {
208
+ it("merges custom class on Tabs.Tab", () => {
209
209
  const { getByRole } = render(() => (
210
210
  <Tabs>
211
211
  {/* eslint-disable-next-line tailwindcss/no-custom-classname */}
@@ -0,0 +1,45 @@
1
+ import { describe, it, expect, beforeEach } from "vitest";
2
+ import {
3
+ registerDialog,
4
+ unregisterDialog,
5
+ getTopmostDialog,
6
+ } from "../../../src/components/disclosure/dialogZIndex";
7
+
8
+ describe("getTopmostDialog", () => {
9
+ let el1: HTMLElement;
10
+ let el2: HTMLElement;
11
+
12
+ beforeEach(() => {
13
+ el1 = document.createElement("div");
14
+ el2 = document.createElement("div");
15
+ // Clean up any leftover registrations
16
+ unregisterDialog(el1);
17
+ unregisterDialog(el2);
18
+ });
19
+
20
+ it("returns null when no dialogs are registered", () => {
21
+ expect(getTopmostDialog()).toBeNull();
22
+ });
23
+
24
+ it("returns the only registered dialog", () => {
25
+ registerDialog(el1);
26
+ expect(getTopmostDialog()).toBe(el1);
27
+ unregisterDialog(el1);
28
+ });
29
+
30
+ it("returns the last registered dialog when multiple are open", () => {
31
+ registerDialog(el1);
32
+ registerDialog(el2);
33
+ expect(getTopmostDialog()).toBe(el2);
34
+ unregisterDialog(el2);
35
+ unregisterDialog(el1);
36
+ });
37
+
38
+ it("returns previous dialog after topmost is unregistered", () => {
39
+ registerDialog(el1);
40
+ registerDialog(el2);
41
+ unregisterDialog(el2);
42
+ expect(getTopmostDialog()).toBe(el1);
43
+ unregisterDialog(el1);
44
+ });
45
+ });
@@ -2,9 +2,9 @@ import { render } from "@solidjs/testing-library";
2
2
  import { describe, it, expect } from "vitest";
3
3
  import { Alert } from "../../../src/components/display/Alert";
4
4
 
5
- describe("Alert 컴포넌트", () => {
5
+ describe("Alert", () => {
6
6
  describe("basic rendering", () => {
7
- it("children이 Alert 내부에 표시된다", () => {
7
+ it("renders children", () => {
8
8
  const { getByText } = render(() => <Alert>This is a note</Alert>);
9
9
  expect(getByText("This is a note")).toBeTruthy();
10
10
  });
@@ -16,8 +16,8 @@ describe("Alert 컴포넌트", () => {
16
16
  });
17
17
  });
18
18
 
19
- describe("theme 속성", () => {
20
- it("theme prop에 따라 스타일이 달라진다", () => {
19
+ describe("theme prop", () => {
20
+ it("applies different styles per theme", () => {
21
21
  const { container: defaultContainer } = render(() => <Alert>Content</Alert>);
22
22
  const { container: themedContainer } = render(() => <Alert theme="danger">Content</Alert>);
23
23
 
@@ -3,28 +3,28 @@ import { describe, it, expect } from "vitest";
3
3
  import { createSignal } from "solid-js";
4
4
  import { Barcode } from "../../../src/components/display/Barcode";
5
5
 
6
- describe("Barcode 컴포넌트", () => {
6
+ describe("Barcode", () => {
7
7
  describe("basic rendering", () => {
8
- it("data-barcode 속성으로 렌더링된다", () => {
8
+ it("renders with data-barcode attribute", () => {
9
9
  const { container } = render(() => <Barcode type="qrcode" value="test" />);
10
10
  expect(container.querySelector("[data-barcode]")).toBeTruthy();
11
11
  });
12
12
 
13
- it("value 있으면 SVG가 렌더링된다", () => {
13
+ it("renders SVG when value is provided", () => {
14
14
  const { container } = render(() => <Barcode type="qrcode" value="hello" />);
15
15
  const el = container.querySelector("[data-barcode]")!;
16
16
  expect(el.querySelector("svg")).toBeTruthy();
17
17
  });
18
18
 
19
- it("value 없으면 내용이 비어있다", () => {
19
+ it("renders empty when value is absent", () => {
20
20
  const { container } = render(() => <Barcode type="qrcode" />);
21
21
  const el = container.querySelector("[data-barcode]")!;
22
22
  expect(el.innerHTML).toBe("");
23
23
  });
24
24
  });
25
25
 
26
- describe("반응성", () => {
27
- it("value 변경 SVG가 업데이트된다", () => {
26
+ describe("reactivity", () => {
27
+ it("updates SVG when value changes", () => {
28
28
  const [value, setValue] = createSignal("first");
29
29
  const { container } = render(() => <Barcode type="qrcode" value={value()} />);
30
30
  const el = container.querySelector("[data-barcode]")!;
@@ -38,7 +38,7 @@ describe("Barcode 컴포넌트", () => {
38
38
  expect(firstSvg).not.toBe(secondSvg);
39
39
  });
40
40
 
41
- it("value 문자열로 변경되면 SVG가 제거된다", () => {
41
+ it("removes SVG when value changes to empty string", () => {
42
42
  const [value, setValue] = createSignal("hello");
43
43
  const { container } = render(() => <Barcode type="qrcode" value={value()} />);
44
44
  const el = container.querySelector("[data-barcode]")!;
@@ -2,9 +2,9 @@ import { render } from "@solidjs/testing-library";
2
2
  import { describe, it, expect } from "vitest";
3
3
  import { Card } from "../../../src/components/display/Card";
4
4
 
5
- describe("Card 컴포넌트", () => {
5
+ describe("Card", () => {
6
6
  describe("basic rendering", () => {
7
- it("children이 Card 내부에 표시된다", () => {
7
+ it("renders children", () => {
8
8
  const { getByText } = render(() => <Card>Card Content</Card>);
9
9
  expect(getByText("Card Content")).toBeTruthy();
10
10
  });
@@ -32,7 +32,7 @@ describe("Card 컴포넌트", () => {
32
32
  expect(card.getAttribute("data-testid")).toBe("test-card");
33
33
  });
34
34
 
35
- it("id 속성이 전달된다", () => {
35
+ it("passes id attribute", () => {
36
36
  const { container } = render(() => <Card id="my-card">Content</Card>);
37
37
  const card = container.firstChild as HTMLElement;
38
38
  expect(card.id).toBe("my-card");
@@ -2,9 +2,9 @@ import { render } from "@solidjs/testing-library";
2
2
  import { describe, it, expect } from "vitest";
3
3
  import { Link } from "../../../src/components/display/Link";
4
4
 
5
- describe("Link 컴포넌트", () => {
5
+ describe("Link", () => {
6
6
  describe("basic rendering", () => {
7
- it("children이 Link 내부에 표시된다", () => {
7
+ it("renders children", () => {
8
8
  const { getByText } = render(() => <Link href="https://example.com">링크</Link>);
9
9
  expect(getByText("링크")).toBeTruthy();
10
10
  });
@@ -16,14 +16,14 @@ describe("Link 컴포넌트", () => {
16
16
  });
17
17
  });
18
18
 
19
- describe("href 속성", () => {
20
- it("href a 요소에 전달된다", () => {
19
+ describe("href prop", () => {
20
+ it("passes href to anchor element", () => {
21
21
  const { container } = render(() => <Link href="https://example.com">링크</Link>);
22
22
  const link = container.firstChild as HTMLAnchorElement;
23
23
  expect(link.getAttribute("href")).toBe("https://example.com");
24
24
  });
25
25
 
26
- it("target 속성이 전달된다", () => {
26
+ it("passes target attribute", () => {
27
27
  const { container } = render(() => (
28
28
  <Link href="https://example.com" target="_blank">
29
29
  링크
@@ -2,9 +2,9 @@ import { render } from "@solidjs/testing-library";
2
2
  import { describe, it, expect } from "vitest";
3
3
  import { Tag } from "../../../src/components/display/Tag";
4
4
 
5
- describe("Tag 컴포넌트", () => {
5
+ describe("Tag", () => {
6
6
  describe("basic rendering", () => {
7
- it("children이 Tag 내부에 표시된다", () => {
7
+ it("renders children", () => {
8
8
  const { getByText } = render(() => <Tag>New</Tag>);
9
9
  expect(getByText("New")).toBeTruthy();
10
10
  });
@@ -16,8 +16,8 @@ describe("Tag 컴포넌트", () => {
16
16
  });
17
17
  });
18
18
 
19
- describe("theme 속성", () => {
20
- it("theme prop에 따라 스타일이 달라진다", () => {
19
+ describe("theme prop", () => {
20
+ it("applies different styles per theme", () => {
21
21
  const { container: defaultContainer } = render(() => <Tag>Tag</Tag>);
22
22
  const { container: themedContainer } = render(() => <Tag theme="danger">Tag</Tag>);
23
23
 
@@ -22,7 +22,7 @@ function TestApp() {
22
22
  }
23
23
 
24
24
  describe("AddressSearchContent", () => {
25
- it("마운트 Daum Postcode 위젯이 content 영역에 렌더된다", async () => {
25
+ it("mounts and renders Daum Postcode widget inside content area", async () => {
26
26
  const { getByTestId } = render(() => (
27
27
  <DialogProvider>
28
28
  <TestApp />
@@ -31,12 +31,12 @@ describe("AddressSearchContent", () => {
31
31
 
32
32
  getByTestId("open-btn").click();
33
33
 
34
- // Daum Postcode 스크립트 로드 + 위젯 embed 대기
34
+ // wait for Daum Postcode script load + widget embed
35
35
  await waitFor(
36
36
  () => {
37
37
  const content = document.querySelector("[data-address-content]");
38
38
  expect(content).not.toBeNull();
39
- // Daum Postcode 위젯이 embed되면 content 내부에 자식 요소가 생긴다
39
+ // once the Daum Postcode widget is embedded, content has child elements
40
40
  expect(content!.children.length).toBeGreaterThan(0);
41
41
  },
42
42
  { timeout: 10000 },