@simplysm/solid 13.0.70 → 13.0.71

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 (98) hide show
  1. package/README.md +1 -1
  2. package/dist/components/disclosure/Dropdown.d.ts +6 -4
  3. package/dist/components/disclosure/Dropdown.d.ts.map +1 -1
  4. package/dist/components/disclosure/Dropdown.js +24 -8
  5. package/dist/components/disclosure/Dropdown.js.map +2 -2
  6. package/dist/components/disclosure/dialogZIndex.d.ts +2 -0
  7. package/dist/components/disclosure/dialogZIndex.d.ts.map +1 -1
  8. package/dist/components/disclosure/dialogZIndex.js +4 -0
  9. package/dist/components/disclosure/dialogZIndex.js.map +1 -1
  10. package/dist/components/features/crud-detail/CrudDetail.d.ts.map +1 -1
  11. package/dist/components/features/crud-detail/CrudDetail.js +16 -7
  12. package/dist/components/features/crud-detail/CrudDetail.js.map +2 -2
  13. package/dist/components/features/crud-sheet/CrudSheet.d.ts.map +1 -1
  14. package/dist/components/features/crud-sheet/CrudSheet.js +14 -5
  15. package/dist/components/features/crud-sheet/CrudSheet.js.map +2 -2
  16. package/dist/components/features/crudRegistry.d.ts +16 -0
  17. package/dist/components/features/crudRegistry.d.ts.map +1 -0
  18. package/dist/components/features/crudRegistry.js +37 -0
  19. package/dist/components/features/crudRegistry.js.map +6 -0
  20. package/dist/components/features/permission-table/PermissionTable.d.ts.map +1 -1
  21. package/dist/components/features/permission-table/PermissionTable.js +71 -86
  22. package/dist/components/features/permission-table/PermissionTable.js.map +2 -2
  23. package/dist/components/features/shared-data/SharedDataSelect.js +2 -4
  24. package/dist/components/features/shared-data/SharedDataSelect.js.map +2 -2
  25. package/dist/components/features/shared-data/SharedDataSelectList.d.ts +2 -4
  26. package/dist/components/features/shared-data/SharedDataSelectList.d.ts.map +1 -1
  27. package/dist/components/features/shared-data/SharedDataSelectList.js +11 -46
  28. package/dist/components/features/shared-data/SharedDataSelectList.js.map +2 -2
  29. package/dist/components/form-control/select/Select.d.ts.map +1 -1
  30. package/dist/components/form-control/select/Select.js +1 -1
  31. package/dist/components/form-control/select/Select.js.map +1 -1
  32. package/dist/helpers/createAppStructure.d.ts.map +1 -1
  33. package/dist/helpers/createAppStructure.js +3 -2
  34. package/dist/helpers/createAppStructure.js.map +1 -1
  35. package/dist/helpers/createHmrSafeContext.d.ts +3 -0
  36. package/dist/helpers/createHmrSafeContext.d.ts.map +1 -0
  37. package/dist/helpers/createHmrSafeContext.js +10 -0
  38. package/dist/helpers/createHmrSafeContext.js.map +6 -0
  39. package/dist/hooks/createSelectionGroup.d.ts.map +1 -1
  40. package/dist/hooks/createSelectionGroup.js +3 -2
  41. package/dist/hooks/createSelectionGroup.js.map +2 -2
  42. package/package.json +6 -5
  43. package/src/components/disclosure/Dropdown.tsx +31 -17
  44. package/src/components/disclosure/dialogZIndex.ts +5 -0
  45. package/src/components/features/crud-detail/CrudDetail.tsx +16 -5
  46. package/src/components/features/crud-sheet/CrudSheet.tsx +13 -3
  47. package/src/components/features/crudRegistry.ts +60 -0
  48. package/src/components/features/permission-table/PermissionTable.tsx +49 -46
  49. package/src/components/features/shared-data/SharedDataSelect.tsx +2 -2
  50. package/src/components/features/shared-data/SharedDataSelectList.tsx +11 -36
  51. package/src/components/form-control/select/Select.tsx +1 -5
  52. package/src/helpers/createAppStructure.ts +3 -2
  53. package/src/helpers/createHmrSafeContext.ts +8 -0
  54. package/src/hooks/createSelectionGroup.tsx +4 -2
  55. package/tests/components/data/List.spec.tsx +52 -52
  56. package/tests/components/data/Pagination.spec.tsx +43 -43
  57. package/tests/components/data/Table.spec.tsx +4 -4
  58. package/tests/components/data/kanban/Kanban.selection.spec.tsx +21 -21
  59. package/tests/components/data/sheet/DataSheet.spec.tsx +50 -50
  60. package/tests/components/disclosure/Collapse.spec.tsx +24 -24
  61. package/tests/components/disclosure/Dialog.spec.tsx +33 -33
  62. package/tests/components/disclosure/DialogProvider.spec.tsx +9 -9
  63. package/tests/components/disclosure/Dropdown.spec.tsx +134 -14
  64. package/tests/components/disclosure/Tabs.spec.tsx +21 -21
  65. package/tests/components/disclosure/dialogZIndex.spec.ts +45 -0
  66. package/tests/components/display/Alert.spec.tsx +4 -4
  67. package/tests/components/display/Barcode.spec.tsx +7 -7
  68. package/tests/components/display/Card.spec.tsx +3 -3
  69. package/tests/components/display/Link.spec.tsx +5 -5
  70. package/tests/components/display/Tag.spec.tsx +4 -4
  71. package/tests/components/features/address/AddressSearch.spec.tsx +3 -3
  72. package/tests/components/features/crudRegistry.spec.ts +119 -0
  73. package/tests/components/features/data-select-button/DataSelectButton.spec.tsx +8 -8
  74. package/tests/components/features/permission-table/PermissionTable.spec.tsx +43 -43
  75. package/tests/components/features/shared-data/SharedDataSelectList.spec.tsx +2 -17
  76. package/tests/components/feedback/busy/BusyContainer.spec.tsx +7 -7
  77. package/tests/components/feedback/notification/NotificationBell.spec.tsx +9 -9
  78. package/tests/components/feedback/print/Print.spec.tsx +4 -4
  79. package/tests/components/form-control/Button.spec.tsx +18 -18
  80. package/tests/components/form-control/checkbox/Checkbox.spec.tsx +20 -20
  81. package/tests/components/form-control/checkbox/CheckboxGroup.spec.tsx +12 -12
  82. package/tests/components/form-control/checkbox/Radio.spec.tsx +21 -21
  83. package/tests/components/form-control/checkbox/RadioGroup.spec.tsx +12 -12
  84. package/tests/components/form-control/color-picker/ColorPicker.spec.tsx +10 -10
  85. package/tests/components/form-control/combobox/Combobox.spec.tsx +16 -16
  86. package/tests/components/form-control/combobox/ComboboxItem.spec.tsx +7 -7
  87. package/tests/components/form-control/date-range-picker/DateRangePicker.spec.tsx +24 -24
  88. package/tests/components/form-control/field/DatePicker.spec.tsx +50 -50
  89. package/tests/components/form-control/field/DateTimePicker.spec.tsx +47 -47
  90. package/tests/components/form-control/field/NumberInput.spec.tsx +54 -54
  91. package/tests/components/form-control/field/TextInput.spec.tsx +49 -49
  92. package/tests/components/form-control/field/Textarea.spec.tsx +33 -33
  93. package/tests/components/form-control/field/TimePicker.spec.tsx +42 -42
  94. package/tests/components/form-control/numpad/Numpad.spec.tsx +40 -40
  95. package/tests/components/form-control/select/Select.spec.tsx +9 -9
  96. package/tests/components/form-control/select/SelectItem.spec.tsx +10 -10
  97. package/tests/helpers/createAppStructure.spec.tsx +57 -57
  98. package/tests/helpers/mergeStyles.spec.ts +31 -31
@@ -3,21 +3,21 @@ import { describe, it, expect, vi } from "vitest";
3
3
  import { createSignal } from "solid-js";
4
4
  import { Pagination } from "../../../src/components/data/Pagination";
5
5
 
6
- describe("Pagination 컴포넌트", () => {
6
+ describe("Pagination component", () => {
7
7
  describe("basic rendering", () => {
8
- it("nav 요소로 렌더링된다", () => {
8
+ it("renders as nav element", () => {
9
9
  const { container } = render(() => <Pagination page={1} totalPageCount={5} />);
10
10
 
11
11
  expect(container.querySelector("nav")).toBeTruthy();
12
12
  });
13
13
 
14
- it("data-pagination 속성이 적용된다", () => {
14
+ it("applies data-pagination attribute", () => {
15
15
  const { container } = render(() => <Pagination page={1} totalPageCount={5} />);
16
16
 
17
17
  expect(container.querySelector("[data-pagination]")).toBeTruthy();
18
18
  });
19
19
 
20
- it("4개의 네비게이션 버튼과 페이지 버튼이 렌더링된다", () => {
20
+ it("renders 4 navigation buttons and page buttons", () => {
21
21
  const { container } = render(() => <Pagination page={1} totalPageCount={5} />);
22
22
 
23
23
  const buttons = container.querySelectorAll("[data-button]");
@@ -25,7 +25,7 @@ describe("Pagination 컴포넌트", () => {
25
25
  expect(buttons.length).toBe(9);
26
26
  });
27
27
 
28
- it("페이지 번호가 1-based로 표시된다", () => {
28
+ it("displays page numbers as 1-based", () => {
29
29
  const { getByText } = render(() => <Pagination page={1} totalPageCount={3} />);
30
30
 
31
31
  expect(getByText("1")).toBeTruthy();
@@ -33,7 +33,7 @@ describe("Pagination 컴포넌트", () => {
33
33
  expect(getByText("3")).toBeTruthy();
34
34
  });
35
35
 
36
- it("custom class nav 요소에 전달된다", () => {
36
+ it("passes custom class to nav element", () => {
37
37
  const { container } = render(() => (
38
38
  // eslint-disable-next-line tailwindcss/no-custom-classname
39
39
  <Pagination page={1} totalPageCount={5} class="my-custom" />
@@ -44,8 +44,8 @@ describe("Pagination 컴포넌트", () => {
44
44
  });
45
45
  });
46
46
 
47
- describe("displayPageCount 기본값", () => {
48
- it("displayPageCount 기본값은 10이다", () => {
47
+ describe("displayPageCount default", () => {
48
+ it("default displayPageCount is 10", () => {
49
49
  const { container } = render(() => <Pagination page={1} totalPageCount={25} />);
50
50
 
51
51
  const buttons = container.querySelectorAll("[data-button]");
@@ -53,7 +53,7 @@ describe("Pagination 컴포넌트", () => {
53
53
  expect(buttons.length).toBe(14);
54
54
  });
55
55
 
56
- it("displayPageCount=5 설정하면 5개의 페이지 버튼이 표시된다", () => {
56
+ it("displays 5 page buttons when displayPageCount=5", () => {
57
57
  const { container } = render(() => (
58
58
  <Pagination page={1} totalPageCount={25} displayPageCount={5} />
59
59
  ));
@@ -64,12 +64,12 @@ describe("Pagination 컴포넌트", () => {
64
64
  });
65
65
  });
66
66
 
67
- describe("현재 페이지 표시", () => {
68
- it("현재 페이지 버튼은 다른 variant를 가진다", () => {
67
+ describe("current page display", () => {
68
+ it("current page button has a different variant", () => {
69
69
  const { container } = render(() => <Pagination page={3} totalPageCount={5} />);
70
70
 
71
71
  const buttons = container.querySelectorAll("[data-button]");
72
- // buttons[0]=<<, [1]=<, [2]=page1, [3]=page2, [4]=page3(현재), [5]=page4, [6]=page5, [7]=>, [8]=>>
72
+ // buttons[0]=<<, [1]=<, [2]=page1, [3]=page2, [4]=page3(current), [5]=page4, [6]=page5, [7]=>, [8]=>>
73
73
  const currentButton = buttons[4]; // page 3 (1-based page=3)
74
74
  const otherButton = buttons[2]; // page 1
75
75
 
@@ -77,8 +77,8 @@ describe("Pagination 컴포넌트", () => {
77
77
  });
78
78
  });
79
79
 
80
- describe("페이지 그룹 계산", () => {
81
- it("page=1, displayPageCount=5일 때 페이지 1~5가 표시된다", () => {
80
+ describe("page group calculation", () => {
81
+ it("displays pages 1-5 when page=1, displayPageCount=5", () => {
82
82
  const { getByText, queryByText } = render(() => (
83
83
  <Pagination page={1} totalPageCount={20} displayPageCount={5} />
84
84
  ));
@@ -91,7 +91,7 @@ describe("Pagination 컴포넌트", () => {
91
91
  expect(queryByText("6")).toBeFalsy();
92
92
  });
93
93
 
94
- it("page=6, displayPageCount=5일 때 페이지 6~10이 표시된다", () => {
94
+ it("displays pages 6-10 when page=6, displayPageCount=5", () => {
95
95
  const { getByText, queryByText } = render(() => (
96
96
  <Pagination page={6} totalPageCount={20} displayPageCount={5} />
97
97
  ));
@@ -105,7 +105,7 @@ describe("Pagination 컴포넌트", () => {
105
105
  expect(queryByText("11")).toBeFalsy();
106
106
  });
107
107
 
108
- it("page=13, displayPageCount=10일 때 페이지 11~20이 표시된다", () => {
108
+ it("displays pages 11-20 when page=13, displayPageCount=10", () => {
109
109
  const { getByText, queryByText } = render(() => (
110
110
  <Pagination page={13} totalPageCount={25} displayPageCount={10} />
111
111
  ));
@@ -116,7 +116,7 @@ describe("Pagination 컴포넌트", () => {
116
116
  expect(queryByText("21")).toBeFalsy();
117
117
  });
118
118
 
119
- it("마지막 그룹에서 totalPageCount보다 적은 페이지만 표시된다", () => {
119
+ it("displays only remaining pages in the last group below totalPageCount", () => {
120
120
  const { container, getByText, queryByText } = render(() => (
121
121
  <Pagination page={8} totalPageCount={8} displayPageCount={5} />
122
122
  ));
@@ -133,8 +133,8 @@ describe("Pagination 컴포넌트", () => {
133
133
  });
134
134
  });
135
135
 
136
- describe("네비게이션 버튼 비활성화", () => {
137
- it(" 번째 그룹일 first/prev 버튼이 비활성화된다", () => {
136
+ describe("navigation button disabled state", () => {
137
+ it("disables first/prev buttons in the first group", () => {
138
138
  const { container } = render(() => (
139
139
  <Pagination page={1} totalPageCount={20} displayPageCount={5} />
140
140
  ));
@@ -147,7 +147,7 @@ describe("Pagination 컴포넌트", () => {
147
147
  expect(prevBtn.hasAttribute("disabled")).toBe(true);
148
148
  });
149
149
 
150
- it("마지막 그룹일 때 next/last 버튼이 비활성화된다", () => {
150
+ it("disables next/last buttons in the last group", () => {
151
151
  const { container } = render(() => (
152
152
  <Pagination page={19} totalPageCount={20} displayPageCount={5} />
153
153
  ));
@@ -160,7 +160,7 @@ describe("Pagination 컴포넌트", () => {
160
160
  expect(lastBtn.hasAttribute("disabled")).toBe(true);
161
161
  });
162
162
 
163
- it("중간 그룹일 모든 네비게이션 버튼이 활성화된다", () => {
163
+ it("all navigation buttons are enabled in a middle group", () => {
164
164
  const { container } = render(() => (
165
165
  <Pagination page={6} totalPageCount={20} displayPageCount={5} />
166
166
  ));
@@ -178,8 +178,8 @@ describe("Pagination 컴포넌트", () => {
178
178
  });
179
179
  });
180
180
 
181
- describe("페이지 클릭", () => {
182
- it("페이지 버튼 클릭 onPageChange가 호출된다", () => {
181
+ describe("page click", () => {
182
+ it("calls onPageChange when a page button is clicked", () => {
183
183
  const onPageChange = vi.fn();
184
184
  const { getByText } = render(() => (
185
185
  <Pagination page={1} totalPageCount={5} onPageChange={onPageChange} />
@@ -190,7 +190,7 @@ describe("Pagination 컴포넌트", () => {
190
190
  expect(onPageChange).toHaveBeenCalledWith(3); // 1-based
191
191
  });
192
192
 
193
- it("현재 페이지 클릭 시에도 onPageChange가 호출된다", () => {
193
+ it("calls onPageChange even when clicking the current page", () => {
194
194
  const onPageChange = vi.fn();
195
195
  const { getByText } = render(() => (
196
196
  <Pagination page={1} totalPageCount={5} onPageChange={onPageChange} />
@@ -202,8 +202,8 @@ describe("Pagination 컴포넌트", () => {
202
202
  });
203
203
  });
204
204
 
205
- describe("first 버튼 (<<)", () => {
206
- it("first 버튼 클릭 시 page 1으로 이동한다", () => {
205
+ describe("first button (<<)", () => {
206
+ it("navigates to page 1 when first button is clicked", () => {
207
207
  const onPageChange = vi.fn();
208
208
  const { container } = render(() => (
209
209
  <Pagination
@@ -221,8 +221,8 @@ describe("Pagination 컴포넌트", () => {
221
221
  });
222
222
  });
223
223
 
224
- describe("last 버튼 (>>)", () => {
225
- it("last 버튼 클릭 마지막 페이지로 이동한다", () => {
224
+ describe("last button (>>)", () => {
225
+ it("navigates to last page when last button is clicked", () => {
226
226
  const onPageChange = vi.fn();
227
227
  const { container } = render(() => (
228
228
  <Pagination page={1} totalPageCount={20} displayPageCount={5} onPageChange={onPageChange} />
@@ -235,8 +235,8 @@ describe("Pagination 컴포넌트", () => {
235
235
  });
236
236
  });
237
237
 
238
- describe("prev 그룹 버튼 (<)", () => {
239
- it("prev 버튼 클릭 이전 그룹의 마지막 페이지로 이동한다", () => {
238
+ describe("prev group button (<)", () => {
239
+ it("navigates to last page of previous group when prev button is clicked", () => {
240
240
  const onPageChange = vi.fn();
241
241
  const { container } = render(() => (
242
242
  <Pagination page={8} totalPageCount={20} displayPageCount={5} onPageChange={onPageChange} />
@@ -251,8 +251,8 @@ describe("Pagination 컴포넌트", () => {
251
251
  });
252
252
  });
253
253
 
254
- describe("next 그룹 버튼 (>)", () => {
255
- it("next 버튼 클릭 다음 그룹의 페이지로 이동한다", () => {
254
+ describe("next group button (>)", () => {
255
+ it("navigates to first page of next group when next button is clicked", () => {
256
256
  const onPageChange = vi.fn();
257
257
  const { container } = render(() => (
258
258
  <Pagination page={4} totalPageCount={20} displayPageCount={5} onPageChange={onPageChange} />
@@ -268,7 +268,7 @@ describe("Pagination 컴포넌트", () => {
268
268
  });
269
269
 
270
270
  describe("size prop", () => {
271
- it("size prop 전달되면 스타일이 달라진다", () => {
271
+ it("applies different styles when size prop is provided", () => {
272
272
  const { container: defaultContainer } = render(() => (
273
273
  <Pagination page={1} totalPageCount={5} />
274
274
  ));
@@ -283,34 +283,34 @@ describe("Pagination 컴포넌트", () => {
283
283
  const smNav = smContainer.querySelector("nav");
284
284
  const lgNav = lgContainer.querySelector("nav");
285
285
 
286
- // sm lg default와 다른 클래스를 가져야 한다
286
+ // sm and lg should have different classes from default
287
287
  expect(smNav?.className).not.toBe(defaultNav?.className);
288
288
  expect(lgNav?.className).not.toBe(defaultNav?.className);
289
289
  });
290
290
  });
291
291
 
292
- describe("반응형 동작", () => {
293
- it("page가 시그널로 변경되면 UI가 업데이트된다", () => {
292
+ describe("reactive behavior", () => {
293
+ it("updates UI when page signal changes", () => {
294
294
  const [page, setPage] = createSignal(1);
295
295
 
296
296
  const { container, getByText } = render(() => (
297
297
  <Pagination page={page()} totalPageCount={20} displayPageCount={5} onPageChange={setPage} />
298
298
  ));
299
299
 
300
- // 초기 상태: 페이지 1~5 표시
300
+ // initial state: pages 1-5 are displayed
301
301
  expect(getByText("1")).toBeTruthy();
302
302
 
303
- // next 그룹으로 이동 (> 클릭 → page 6)
303
+ // navigate to next group (> click → page 6)
304
304
  const buttons = container.querySelectorAll("[data-button]");
305
- fireEvent.click(buttons[buttons.length - 2]); // > 클릭 → page 6
305
+ fireEvent.click(buttons[buttons.length - 2]); // > click → page 6
306
306
 
307
- // 페이지가 변경되면 6~10 그룹이 표시되어야 한다
307
+ // after page change, group 6-10 should be displayed
308
308
  expect(getByText("6")).toBeTruthy();
309
309
  });
310
310
  });
311
311
 
312
- describe("엣지 케이스", () => {
313
- it("totalPageCount=1일 네비게이션 버튼이 모두 비활성화된다", () => {
312
+ describe("edge cases", () => {
313
+ it("all navigation buttons are disabled when totalPageCount=1", () => {
314
314
  const { container } = render(() => <Pagination page={1} totalPageCount={1} />);
315
315
 
316
316
  const buttons = container.querySelectorAll("[data-button]");
@@ -325,7 +325,7 @@ describe("Pagination 컴포넌트", () => {
325
325
  expect(lastBtn.hasAttribute("disabled")).toBe(true);
326
326
  });
327
327
 
328
- it("totalPageCount=0일 페이지 버튼이 표시되지 않는다", () => {
328
+ it("no page buttons displayed when totalPageCount=0", () => {
329
329
  const { container } = render(() => <Pagination page={1} totalPageCount={0} />);
330
330
 
331
331
  const buttons = container.querySelectorAll("[data-button]");
@@ -2,9 +2,9 @@ import { render } from "@solidjs/testing-library";
2
2
  import { describe, it, expect } from "vitest";
3
3
  import { Table } from "../../../src/components/data/Table";
4
4
 
5
- describe("Table 컴포넌트", () => {
5
+ describe("Table component", () => {
6
6
  describe("basic rendering", () => {
7
- it("children Table 내부에 표시된다", () => {
7
+ it("renders children inside Table", () => {
8
8
  const { container } = render(() => (
9
9
  <Table>
10
10
  <tbody>
@@ -24,8 +24,8 @@ describe("Table 컴포넌트", () => {
24
24
  });
25
25
  });
26
26
 
27
- describe("inset 속성", () => {
28
- it("inset prop에 따라 스타일이 달라진다", () => {
27
+ describe("inset prop", () => {
28
+ it("applies different styles based on inset prop", () => {
29
29
  const { container: defaultContainer } = render(() => <Table>Content</Table>);
30
30
  const { container: insetContainer } = render(() => <Table inset>Content</Table>);
31
31
 
@@ -2,7 +2,7 @@ import { render, fireEvent } from "@solidjs/testing-library";
2
2
  import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
3
3
  import { Kanban } from "../../../../src/components/data/kanban/Kanban";
4
4
 
5
- describe("Kanban 선택 시스템", () => {
5
+ describe("Kanban selection system", () => {
6
6
  function renderKanban(options?: {
7
7
  selectedValues?: unknown[];
8
8
  onSelectedValuesChange?: (v: unknown[]) => void;
@@ -36,8 +36,8 @@ describe("Kanban 선택 시스템", () => {
36
36
  ));
37
37
  }
38
38
 
39
- describe("Shift+Click 선택", () => {
40
- it("Shift+Click으로 카드가 선택된다", () => {
39
+ describe("Shift+Click selection", () => {
40
+ it("selects a card with Shift+Click", () => {
41
41
  const handleChange = vi.fn();
42
42
  const { getByText } = renderKanban({
43
43
  selectedValues: [],
@@ -48,7 +48,7 @@ describe("Kanban 선택 시스템", () => {
48
48
  expect(handleChange).toHaveBeenCalledWith([1]);
49
49
  });
50
50
 
51
- it("이미 선택된 카드를 Shift+Click하면 선택 해제된다", () => {
51
+ it("deselects an already selected card with Shift+Click", () => {
52
52
  const handleChange = vi.fn();
53
53
  const { getByText } = renderKanban({
54
54
  selectedValues: [1],
@@ -59,7 +59,7 @@ describe("Kanban 선택 시스템", () => {
59
59
  expect(handleChange).toHaveBeenCalledWith([]);
60
60
  });
61
61
 
62
- it("Shift 없는 클릭은 선택을 변경하지 않는다", () => {
62
+ it("click without Shift does not change selection", () => {
63
63
  const handleChange = vi.fn();
64
64
  const { getByText } = renderKanban({
65
65
  selectedValues: [],
@@ -70,7 +70,7 @@ describe("Kanban 선택 시스템", () => {
70
70
  expect(handleChange).not.toHaveBeenCalled();
71
71
  });
72
72
 
73
- it("selectable=false 카드는 Shift+Click해도 선택되지 않는다", () => {
73
+ it("does not select card with selectable=false on Shift+Click", () => {
74
74
  const handleChange = vi.fn();
75
75
  const { getByText } = renderKanban({
76
76
  selectedValues: [],
@@ -84,8 +84,8 @@ describe("Kanban 선택 시스템", () => {
84
84
  });
85
85
  });
86
86
 
87
- describe("선택 시각 피드백", () => {
88
- it("선택된 카드에 ring + shadow 클래스가 적용된다", () => {
87
+ describe("selection visual feedback", () => {
88
+ it("applies ring + shadow classes to selected card", () => {
89
89
  const { getByText } = renderKanban({ selectedValues: [1] });
90
90
  const card1Content = getByText("Card 1").closest("[data-card]") as HTMLElement;
91
91
  expect(card1Content.classList.contains("ring-2")).toBe(true);
@@ -93,21 +93,21 @@ describe("Kanban 선택 시스템", () => {
93
93
  expect(card1Content.classList.contains("shadow-md")).toBe(true);
94
94
  });
95
95
 
96
- it("선택되지 않은 카드에는 ring 클래스가 없다", () => {
96
+ it("unselected card has no ring class", () => {
97
97
  const { getByText } = renderKanban({ selectedValues: [1] });
98
98
  const card2Content = getByText("Card 2").closest("[data-card]") as HTMLElement;
99
99
  expect(card2Content.classList.contains("ring-2")).toBe(false);
100
100
  });
101
101
  });
102
102
 
103
- describe("레인별 전체 선택 체크박스", () => {
104
- it("selectable 카드가 있는 레인에 전체 선택 체크박스가 표시된다", () => {
103
+ describe("per-lane select-all checkbox", () => {
104
+ it("displays select-all checkbox in lanes that have selectable cards", () => {
105
105
  const { container } = renderKanban({ selectedValues: [] });
106
106
  const checkboxes = container.querySelectorAll("[role='checkbox']");
107
107
  expect(checkboxes.length).toBe(2);
108
108
  });
109
109
 
110
- it("전체 선택 체크박스 클릭 레인 모든 selectable 카드가 선택된다", () => {
110
+ it("selects all selectable cards in lane when select-all checkbox is clicked", () => {
111
111
  const handleChange = vi.fn();
112
112
  const { container } = renderKanban({
113
113
  selectedValues: [],
@@ -119,7 +119,7 @@ describe("Kanban 선택 시스템", () => {
119
119
  expect(handleChange).toHaveBeenCalledWith([1, 2]);
120
120
  });
121
121
 
122
- it("전체 선택 상태에서 체크박스 클릭 레인 카드만 선택 해제된다", () => {
122
+ it("deselects only cards in the lane when clicking checkbox in fully-selected state", () => {
123
123
  const handleChange = vi.fn();
124
124
  const { container } = renderKanban({
125
125
  selectedValues: [1, 2, 4],
@@ -131,14 +131,14 @@ describe("Kanban 선택 시스템", () => {
131
131
  expect(handleChange).toHaveBeenCalledWith([4]);
132
132
  });
133
133
 
134
- it("모든 selectable 카드가 선택되면 체크박스가 체크 상태이다", () => {
134
+ it("checkbox is checked when all selectable cards are selected", () => {
135
135
  const { container } = renderKanban({ selectedValues: [1, 2] });
136
136
  const firstLane = container.querySelector("[data-kanban-lane]") as HTMLElement;
137
137
  const checkbox = firstLane.querySelector("[role='checkbox']") as HTMLElement;
138
138
  expect(checkbox.getAttribute("aria-checked")).toBe("true");
139
139
  });
140
140
 
141
- it("일부만 선택되면 체크박스가 미체크 상태이다", () => {
141
+ it("checkbox is unchecked when only some cards are selected", () => {
142
142
  const { container } = renderKanban({ selectedValues: [1] });
143
143
  const firstLane = container.querySelector("[data-kanban-lane]") as HTMLElement;
144
144
  const checkbox = firstLane.querySelector("[role='checkbox']") as HTMLElement;
@@ -146,7 +146,7 @@ describe("Kanban 선택 시스템", () => {
146
146
  });
147
147
  });
148
148
 
149
- describe("Long press 단독 선택", () => {
149
+ describe("long press exclusive selection", () => {
150
150
  beforeEach(() => {
151
151
  vi.useFakeTimers();
152
152
  });
@@ -155,7 +155,7 @@ describe("Kanban 선택 시스템", () => {
155
155
  vi.useRealTimers();
156
156
  });
157
157
 
158
- it("500ms 이상 누르면 해당 카드만 단독 선택된다", () => {
158
+ it("exclusively selects that card when pressed for 500ms or more", () => {
159
159
  const handleChange = vi.fn();
160
160
  const { getByText } = renderKanban({
161
161
  selectedValues: [2, 4],
@@ -169,7 +169,7 @@ describe("Kanban 선택 시스템", () => {
169
169
  expect(handleChange).toHaveBeenCalledWith([1]);
170
170
  });
171
171
 
172
- it("500ms 미만으로 누르면 선택이 변경되지 않는다", () => {
172
+ it("does not change selection when pressed for less than 500ms", () => {
173
173
  const handleChange = vi.fn();
174
174
  const { getByText } = renderKanban({
175
175
  selectedValues: [],
@@ -184,7 +184,7 @@ describe("Kanban 선택 시스템", () => {
184
184
  expect(handleChange).not.toHaveBeenCalled();
185
185
  });
186
186
 
187
- it("selectable=false 카드는 long press해도 선택되지 않는다", () => {
187
+ it("does not select card with selectable=false on long press", () => {
188
188
  const handleChange = vi.fn();
189
189
  const { getByText } = renderKanban({
190
190
  selectedValues: [],
@@ -201,8 +201,8 @@ describe("Kanban 선택 시스템", () => {
201
201
  });
202
202
  });
203
203
 
204
- describe("Uncontrolled 모드", () => {
205
- it("onSelectedValuesChange 없이도 Shift+Click 선택이 동작한다", () => {
204
+ describe("uncontrolled mode", () => {
205
+ it("Shift+Click selection works without onSelectedValuesChange", () => {
206
206
  const { getByText } = renderKanban();
207
207
  const card1 = getByText("Card 1").closest("[data-kanban-card]") as HTMLElement;
208
208
  fireEvent.click(card1, { shiftKey: true });