@simplysm/solid 13.0.71 → 13.0.74

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 (215) hide show
  1. package/README.md +209 -202
  2. package/dist/components/data/calendar/Calendar.d.ts.map +1 -1
  3. package/dist/components/data/calendar/Calendar.js +3 -11
  4. package/dist/components/data/calendar/Calendar.js.map +2 -2
  5. package/dist/components/data/sheet/DataSheet.d.ts.map +1 -1
  6. package/dist/components/data/sheet/DataSheet.js +13 -16
  7. package/dist/components/data/sheet/DataSheet.js.map +2 -2
  8. package/dist/components/data/sheet/DataSheet.styles.d.ts.map +1 -1
  9. package/dist/components/data/sheet/DataSheet.styles.js +1 -1
  10. package/dist/components/data/sheet/DataSheet.styles.js.map +1 -1
  11. package/dist/components/data/sheet/DataSheetConfigDialog.d.ts.map +1 -1
  12. package/dist/components/data/sheet/DataSheetConfigDialog.js +27 -9
  13. package/dist/components/data/sheet/DataSheetConfigDialog.js.map +2 -2
  14. package/dist/components/disclosure/Dialog.d.ts +1 -1
  15. package/dist/components/disclosure/Dialog.d.ts.map +1 -1
  16. package/dist/components/disclosure/Dialog.js +5 -5
  17. package/dist/components/disclosure/Dialog.js.map +2 -2
  18. package/dist/components/disclosure/dialogZIndex.d.ts +1 -1
  19. package/dist/components/features/crud-detail/CrudDetail.js +23 -23
  20. package/dist/components/features/crud-detail/CrudDetail.js.map +2 -2
  21. package/dist/components/features/crud-sheet/CrudSheet.js +49 -49
  22. package/dist/components/features/crud-sheet/CrudSheet.js.map +2 -2
  23. package/dist/components/features/crud-sheet/types.d.ts +4 -4
  24. package/dist/components/features/crud-sheet/types.d.ts.map +1 -1
  25. package/dist/components/features/data-select-button/DataSelectButton.d.ts +25 -7
  26. package/dist/components/features/data-select-button/DataSelectButton.d.ts.map +1 -1
  27. package/dist/components/features/data-select-button/DataSelectButton.js +27 -12
  28. package/dist/components/features/data-select-button/DataSelectButton.js.map +2 -2
  29. package/dist/components/features/permission-table/PermissionTable.js +4 -4
  30. package/dist/components/features/permission-table/PermissionTable.js.map +2 -2
  31. package/dist/components/features/shared-data/SharedDataSelect.d.ts +22 -10
  32. package/dist/components/features/shared-data/SharedDataSelect.d.ts.map +1 -1
  33. package/dist/components/features/shared-data/SharedDataSelect.js +113 -29
  34. package/dist/components/features/shared-data/SharedDataSelect.js.map +2 -2
  35. package/dist/components/features/shared-data/SharedDataSelectButton.d.ts +3 -3
  36. package/dist/components/features/shared-data/SharedDataSelectButton.d.ts.map +1 -1
  37. package/dist/components/features/shared-data/SharedDataSelectButton.js.map +1 -1
  38. package/dist/components/features/shared-data/SharedDataSelectList.js +5 -4
  39. package/dist/components/features/shared-data/SharedDataSelectList.js.map +2 -2
  40. package/dist/components/feedback/notification/NotificationBanner.js +3 -3
  41. package/dist/components/feedback/notification/NotificationBanner.js.map +2 -2
  42. package/dist/components/feedback/notification/NotificationBell.d.ts.map +1 -1
  43. package/dist/components/feedback/notification/NotificationBell.js +12 -5
  44. package/dist/components/feedback/notification/NotificationBell.js.map +2 -2
  45. package/dist/components/feedback/notification/NotificationProvider.d.ts.map +1 -1
  46. package/dist/components/feedback/notification/NotificationProvider.js +3 -1
  47. package/dist/components/feedback/notification/NotificationProvider.js.map +2 -2
  48. package/dist/components/form-control/ThemeToggle.d.ts.map +1 -1
  49. package/dist/components/form-control/ThemeToggle.js +9 -6
  50. package/dist/components/form-control/ThemeToggle.js.map +2 -2
  51. package/dist/components/form-control/checkbox/Checkbox.d.ts.map +1 -1
  52. package/dist/components/form-control/checkbox/Checkbox.js +3 -1
  53. package/dist/components/form-control/checkbox/Checkbox.js.map +2 -2
  54. package/dist/components/form-control/checkbox/CheckboxGroup.js +1 -1
  55. package/dist/components/form-control/checkbox/CheckboxGroup.js.map +2 -2
  56. package/dist/components/form-control/checkbox/Radio.d.ts.map +1 -1
  57. package/dist/components/form-control/checkbox/Radio.js +3 -1
  58. package/dist/components/form-control/checkbox/Radio.js.map +2 -2
  59. package/dist/components/form-control/checkbox/RadioGroup.js +1 -1
  60. package/dist/components/form-control/checkbox/RadioGroup.js.map +2 -2
  61. package/dist/components/form-control/color-picker/ColorPicker.d.ts.map +1 -1
  62. package/dist/components/form-control/color-picker/ColorPicker.js +3 -1
  63. package/dist/components/form-control/color-picker/ColorPicker.js.map +2 -2
  64. package/dist/components/form-control/combobox/Combobox.d.ts.map +1 -1
  65. package/dist/components/form-control/combobox/Combobox.js +9 -5
  66. package/dist/components/form-control/combobox/Combobox.js.map +2 -2
  67. package/dist/components/form-control/date-range-picker/DateRangePicker.js +9 -9
  68. package/dist/components/form-control/date-range-picker/DateRangePicker.js.map +2 -2
  69. package/dist/components/form-control/editor/EditorToolbar.js +3 -3
  70. package/dist/components/form-control/editor/EditorToolbar.js.map +2 -2
  71. package/dist/components/form-control/field/DatePicker.d.ts.map +1 -1
  72. package/dist/components/form-control/field/DatePicker.js +9 -3
  73. package/dist/components/form-control/field/DatePicker.js.map +2 -2
  74. package/dist/components/form-control/field/DateTimePicker.d.ts.map +1 -1
  75. package/dist/components/form-control/field/DateTimePicker.js +9 -3
  76. package/dist/components/form-control/field/DateTimePicker.js.map +2 -2
  77. package/dist/components/form-control/field/NumberInput.d.ts.map +1 -1
  78. package/dist/components/form-control/field/NumberInput.js +9 -3
  79. package/dist/components/form-control/field/NumberInput.js.map +2 -2
  80. package/dist/components/form-control/field/TextInput.d.ts.map +1 -1
  81. package/dist/components/form-control/field/TextInput.js +10 -4
  82. package/dist/components/form-control/field/TextInput.js.map +2 -2
  83. package/dist/components/form-control/field/Textarea.d.ts.map +1 -1
  84. package/dist/components/form-control/field/Textarea.js +9 -3
  85. package/dist/components/form-control/field/Textarea.js.map +2 -2
  86. package/dist/components/form-control/field/TimePicker.d.ts.map +1 -1
  87. package/dist/components/form-control/field/TimePicker.js +9 -3
  88. package/dist/components/form-control/field/TimePicker.js.map +2 -2
  89. package/dist/components/form-control/numpad/Numpad.d.ts.map +1 -1
  90. package/dist/components/form-control/numpad/Numpad.js +5 -1
  91. package/dist/components/form-control/numpad/Numpad.js.map +2 -2
  92. package/dist/components/form-control/select/Select.js +7 -7
  93. package/dist/components/form-control/select/Select.js.map +2 -2
  94. package/dist/components/form-control/state-preset/StatePreset.d.ts.map +1 -1
  95. package/dist/components/form-control/state-preset/StatePreset.js +42 -20
  96. package/dist/components/form-control/state-preset/StatePreset.js.map +2 -2
  97. package/dist/components/layout/sidebar/SidebarContainer.js +3 -3
  98. package/dist/components/layout/sidebar/SidebarContainer.js.map +2 -2
  99. package/dist/components/layout/sidebar/SidebarMenu.d.ts.map +1 -1
  100. package/dist/components/layout/sidebar/SidebarMenu.js +5 -2
  101. package/dist/components/layout/sidebar/SidebarMenu.js.map +2 -2
  102. package/dist/components/layout/topbar/Topbar.js +3 -4
  103. package/dist/components/layout/topbar/Topbar.js.map +2 -2
  104. package/dist/components/layout/topbar/TopbarMenu.js +3 -3
  105. package/dist/components/layout/topbar/TopbarMenu.js.map +2 -2
  106. package/dist/hooks/createSelectionGroup.d.ts +2 -2
  107. package/dist/hooks/createSelectionGroup.d.ts.map +1 -1
  108. package/dist/hooks/createSelectionGroup.js +5 -2
  109. package/dist/hooks/createSelectionGroup.js.map +2 -2
  110. package/dist/providers/i18n/I18nContext.d.ts +0 -4
  111. package/dist/providers/i18n/I18nContext.d.ts.map +1 -1
  112. package/dist/providers/i18n/I18nContext.js +1 -5
  113. package/dist/providers/i18n/I18nContext.js.map +2 -2
  114. package/dist/providers/i18n/locales/en.d.ts +38 -0
  115. package/dist/providers/i18n/locales/en.d.ts.map +1 -1
  116. package/dist/providers/i18n/locales/en.js +39 -1
  117. package/dist/providers/i18n/locales/en.js.map +1 -1
  118. package/dist/providers/i18n/locales/ko.d.ts +38 -0
  119. package/dist/providers/i18n/locales/ko.d.ts.map +1 -1
  120. package/dist/providers/i18n/locales/ko.js +39 -1
  121. package/dist/providers/i18n/locales/ko.js.map +1 -1
  122. package/package.json +6 -6
  123. package/src/components/data/calendar/Calendar.tsx +3 -4
  124. package/src/components/data/sheet/DataSheet.styles.ts +1 -1
  125. package/src/components/data/sheet/DataSheet.tsx +14 -15
  126. package/src/components/data/sheet/DataSheetConfigDialog.tsx +12 -10
  127. package/src/components/data/sheet/types.ts +1 -1
  128. package/src/components/disclosure/Dialog.tsx +10 -10
  129. package/src/components/disclosure/dialogZIndex.ts +1 -1
  130. package/src/components/features/crud-detail/CrudDetail.tsx +25 -25
  131. package/src/components/features/crud-sheet/CrudSheet.tsx +53 -53
  132. package/src/components/features/crud-sheet/types.ts +4 -4
  133. package/src/components/features/data-select-button/DataSelectButton.tsx +51 -21
  134. package/src/components/features/permission-table/PermissionTable.tsx +3 -3
  135. package/src/components/features/shared-data/SharedDataSelect.tsx +172 -33
  136. package/src/components/features/shared-data/SharedDataSelectButton.tsx +3 -2
  137. package/src/components/features/shared-data/SharedDataSelectList.tsx +4 -4
  138. package/src/components/feedback/notification/NotificationBanner.tsx +3 -3
  139. package/src/components/feedback/notification/NotificationBell.tsx +6 -4
  140. package/src/components/feedback/notification/NotificationProvider.tsx +3 -1
  141. package/src/components/form-control/ThemeToggle.tsx +10 -6
  142. package/src/components/form-control/checkbox/Checkbox.tsx +4 -1
  143. package/src/components/form-control/checkbox/CheckboxGroup.tsx +1 -1
  144. package/src/components/form-control/checkbox/Radio.tsx +4 -1
  145. package/src/components/form-control/checkbox/RadioGroup.tsx +1 -1
  146. package/src/components/form-control/color-picker/ColorPicker.tsx +4 -1
  147. package/src/components/form-control/combobox/Combobox.tsx +6 -3
  148. package/src/components/form-control/date-range-picker/DateRangePicker.tsx +8 -8
  149. package/src/components/form-control/editor/EditorToolbar.tsx +23 -23
  150. package/src/components/form-control/field/DatePicker.tsx +6 -3
  151. package/src/components/form-control/field/DateTimePicker.tsx +6 -3
  152. package/src/components/form-control/field/NumberInput.tsx +6 -3
  153. package/src/components/form-control/field/TextInput.tsx +7 -4
  154. package/src/components/form-control/field/Textarea.tsx +6 -3
  155. package/src/components/form-control/field/TimePicker.tsx +6 -3
  156. package/src/components/form-control/numpad/Numpad.tsx +3 -1
  157. package/src/components/form-control/select/Select.tsx +7 -7
  158. package/src/components/form-control/state-preset/StatePreset.tsx +14 -12
  159. package/src/components/layout/sidebar/SidebarContainer.tsx +3 -3
  160. package/src/components/layout/sidebar/SidebarMenu.tsx +3 -1
  161. package/src/components/layout/topbar/Topbar.tsx +3 -3
  162. package/src/components/layout/topbar/TopbarMenu.tsx +3 -3
  163. package/src/hooks/createSelectionGroup.tsx +8 -4
  164. package/src/providers/i18n/I18nContext.tsx +0 -7
  165. package/src/providers/i18n/locales/en.ts +38 -0
  166. package/src/providers/i18n/locales/ko.ts +38 -0
  167. package/tailwind.config.ts +2 -2
  168. package/tests/components/data/kanban/Kanban.selection.spec.tsx +34 -24
  169. package/tests/components/disclosure/Dialog.spec.tsx +28 -28
  170. package/tests/components/disclosure/DialogProvider.spec.tsx +51 -25
  171. package/tests/components/features/address/AddressSearch.spec.tsx +12 -4
  172. package/tests/components/features/crud-detail/CrudDetail.spec.tsx +1 -0
  173. package/tests/components/features/crud-sheet/CrudSheet.spec.tsx +30 -6
  174. package/tests/components/features/data-select-button/DataSelectButton.spec.tsx +77 -56
  175. package/tests/components/features/permission-table/PermissionTable.spec.tsx +12 -8
  176. package/tests/components/features/shared-data/SharedDataSelect.spec.tsx +172 -0
  177. package/tests/components/features/shared-data/SharedDataSelectList.spec.tsx +14 -2
  178. package/tests/components/feedback/notification/LiveRegion.spec.tsx +20 -9
  179. package/tests/components/feedback/notification/NotificationBanner.spec.tsx +64 -46
  180. package/tests/components/feedback/notification/NotificationBell.spec.tsx +70 -51
  181. package/tests/components/feedback/notification/NotificationContext.spec.tsx +105 -78
  182. package/tests/components/form-control/checkbox/Checkbox.spec.tsx +25 -20
  183. package/tests/components/form-control/checkbox/CheckboxGroup.spec.tsx +53 -30
  184. package/tests/components/form-control/checkbox/Radio.spec.tsx +25 -20
  185. package/tests/components/form-control/checkbox/RadioGroup.spec.tsx +53 -30
  186. package/tests/components/form-control/color-picker/ColorPicker.spec.tsx +24 -15
  187. package/tests/components/form-control/combobox/Combobox.spec.tsx +92 -59
  188. package/tests/components/form-control/date-range-picker/DateRangePicker.spec.tsx +2 -2
  189. package/tests/components/form-control/field/DatePicker.spec.tsx +50 -44
  190. package/tests/components/form-control/field/DateTimePicker.spec.tsx +51 -45
  191. package/tests/components/form-control/field/NumberInput.spec.tsx +53 -47
  192. package/tests/components/form-control/field/TextInput.spec.tsx +50 -44
  193. package/tests/components/form-control/field/Textarea.spec.tsx +35 -29
  194. package/tests/components/form-control/field/TimePicker.spec.tsx +43 -37
  195. package/tests/components/form-control/numpad/Numpad.spec.tsx +175 -25
  196. package/tests/components/form-control/select/Select.spec.tsx +5 -0
  197. package/tests/components/form-control/select/SelectItem.spec.tsx +1 -0
  198. package/tests/components/layout/sidebar/Sidebar.spec.tsx +79 -35
  199. package/tests/components/layout/sidebar/SidebarContainer.spec.tsx +1 -0
  200. package/tests/components/layout/sidebar/SidebarMenu.spec.tsx +28 -17
  201. package/tests/components/layout/topbar/TopbarActions.spec.tsx +41 -23
  202. package/tests/components/layout/topbar/createTopbarActions.spec.tsx +1 -0
  203. package/tests/hooks/usePrint.spec.tsx +1 -1
  204. package/tests/hooks/useRouterLink.spec.tsx +2 -0
  205. package/tests/hooks/useSyncConfig.spec.tsx +1 -0
  206. package/tests/providers/ErrorLoggerProvider.spec.tsx +1 -0
  207. package/tests/providers/PwaUpdateProvider.spec.tsx +16 -6
  208. package/tests/providers/ServiceClientContext.spec.tsx +40 -25
  209. package/tests/providers/i18n/I18nContext.spec.tsx +3 -4
  210. package/tests/providers/shared-data/SharedDataProvider.spec.tsx +2 -0
  211. package/dist/hooks/usePrint.d.ts +0 -3
  212. package/dist/hooks/usePrint.d.ts.map +0 -1
  213. package/dist/hooks/usePrint.js +0 -5
  214. package/dist/hooks/usePrint.js.map +0 -6
  215. package/src/hooks/usePrint.ts +0 -2
@@ -1,10 +1,8 @@
1
- import { afterEach, describe, it, expect, vi } from "vitest";
1
+ import { afterEach, beforeEach, describe, it, expect, vi } from "vitest";
2
2
  import { render, cleanup } from "@solidjs/testing-library";
3
3
  import { createSignal, type JSX } from "solid-js";
4
- import { DataSelectButton, type DataSelectModalResult } from "@simplysm/solid";
4
+ import { DataSelectButton, type InjectedSelectProps } from "@simplysm/solid";
5
5
  import { DialogProvider } from "../../../../src/components/disclosure/DialogProvider";
6
- import { useDialogInstance } from "../../../../src/components/disclosure/DialogInstanceContext";
7
- import { Dialog } from "../../../../src/components/disclosure/Dialog";
8
6
  import { I18nProvider } from "../../../../src/providers/i18n/I18nContext";
9
7
  import { ConfigProvider } from "../../../../src/providers/ConfigContext";
10
8
 
@@ -28,24 +26,17 @@ function createTestLoad() {
28
26
  return loadFn;
29
27
  }
30
28
 
31
- // modal component for tests (returns specific keys)
32
- function TestModal(selectedKeys: number[]): () => JSX.Element {
33
- return () => {
34
- const instance = useDialogInstance<DataSelectModalResult<number>>();
35
- return (
36
- <Dialog open onOpenChange={() => undefined}>
37
- <Dialog.Header>테스트 모달</Dialog.Header>
38
- <div data-testid="modal-content">
39
- <button data-testid="modal-confirm" onClick={() => instance?.close({ selectedKeys })}>
40
- 확인
41
- </button>
42
- <button data-testid="modal-cancel" onClick={() => instance?.close(undefined)}>
43
- 취소
44
- </button>
45
- </div>
46
- </Dialog>
47
- );
48
- };
29
+ // Dialog component for tests receives InjectedSelectProps automatically
30
+ function TestDialogComponent(props: { confirmKeys: number[] } & InjectedSelectProps) {
31
+ return (
32
+ <div data-testid="dialog-content">
33
+ <div data-testid="select-mode">{props.selectMode}</div>
34
+ <div data-testid="selected-keys">{JSON.stringify([...props.selectedKeys])}</div>
35
+ <button data-testid="dialog-confirm" onClick={() => props.onSelect({ keys: props.confirmKeys })}>
36
+ confirm
37
+ </button>
38
+ </div>
39
+ );
49
40
  }
50
41
 
51
42
  // helper to wrap with DialogProvider
@@ -58,6 +49,10 @@ function renderWithDialog(ui: () => JSX.Element) {
58
49
  }
59
50
 
60
51
  describe("DataSelectButton", () => {
52
+ beforeEach(() => {
53
+ localStorage.setItem("test.i18n-locale", JSON.stringify("en"));
54
+ });
55
+
61
56
  afterEach(() => {
62
57
  cleanup();
63
58
  });
@@ -67,7 +62,7 @@ describe("DataSelectButton", () => {
67
62
  const { container } = renderWithDialog(() => (
68
63
  <DataSelectButton
69
64
  load={load}
70
- modal={TestModal([])}
65
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [] } }}
71
66
  renderItem={(item: TestItem) => <span>{item.name}</span>}
72
67
  />
73
68
  ));
@@ -84,7 +79,7 @@ describe("DataSelectButton", () => {
84
79
  <DataSelectButton
85
80
  value={1}
86
81
  load={load}
87
- modal={TestModal([])}
82
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [] } }}
88
83
  renderItem={(item: TestItem) => <span>{item.name}</span>}
89
84
  />
90
85
  ));
@@ -101,7 +96,7 @@ describe("DataSelectButton", () => {
101
96
  value={[1, 3]}
102
97
  multiple
103
98
  load={load}
104
- modal={TestModal([])}
99
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [] } }}
105
100
  renderItem={(item: TestItem) => <span>{item.name}</span>}
106
101
  />
107
102
  ));
@@ -122,7 +117,7 @@ describe("DataSelectButton", () => {
122
117
  value={value()}
123
118
  onValueChange={setValue}
124
119
  load={load}
125
- modal={TestModal([])}
120
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [] } }}
126
121
  renderItem={(item: TestItem) => <span>{item.name}</span>}
127
122
  />
128
123
  ));
@@ -142,7 +137,7 @@ describe("DataSelectButton", () => {
142
137
  <DataSelectButton
143
138
  value={1}
144
139
  load={load}
145
- modal={TestModal([])}
140
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [] } }}
146
141
  renderItem={(item: TestItem) => <span>{item.name}</span>}
147
142
  />
148
143
  ));
@@ -159,7 +154,7 @@ describe("DataSelectButton", () => {
159
154
  value={1}
160
155
  required
161
156
  load={load}
162
- modal={TestModal([])}
157
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [] } }}
163
158
  renderItem={(item: TestItem) => <span>{item.name}</span>}
164
159
  />
165
160
  ));
@@ -178,7 +173,7 @@ describe("DataSelectButton", () => {
178
173
  value={1}
179
174
  onValueChange={onValueChange}
180
175
  load={load}
181
- modal={TestModal([])}
176
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [] } }}
182
177
  renderItem={(item: TestItem) => <span>{item.name}</span>}
183
178
  />
184
179
  ));
@@ -202,7 +197,7 @@ describe("DataSelectButton", () => {
202
197
  multiple
203
198
  onValueChange={onValueChange}
204
199
  load={load}
205
- modal={TestModal([])}
200
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [] } }}
206
201
  renderItem={(item: TestItem) => <span>{item.name}</span>}
207
202
  />
208
203
  ));
@@ -222,7 +217,7 @@ describe("DataSelectButton", () => {
222
217
  <DataSelectButton
223
218
  disabled
224
219
  load={load}
225
- modal={TestModal([])}
220
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [] } }}
226
221
  renderItem={(item: TestItem) => <span>{item.name}</span>}
227
222
  />
228
223
  ));
@@ -236,7 +231,7 @@ describe("DataSelectButton", () => {
236
231
  const { container } = renderWithDialog(() => (
237
232
  <DataSelectButton
238
233
  load={load}
239
- modal={TestModal([])}
234
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [] } }}
240
235
  renderItem={(item: TestItem) => <span>{item.name}</span>}
241
236
  />
242
237
  ));
@@ -245,7 +240,7 @@ describe("DataSelectButton", () => {
245
240
  expect(searchBtn).not.toBeNull();
246
241
  });
247
242
 
248
- it("opens modal on search button click and applies result for single select", async () => {
243
+ it("opens dialog on search button click and applies result for single select", async () => {
249
244
  const load = createTestLoad();
250
245
  const onValueChange = vi.fn();
251
246
 
@@ -253,7 +248,7 @@ describe("DataSelectButton", () => {
253
248
  <DataSelectButton
254
249
  onValueChange={onValueChange}
255
250
  load={load}
256
- modal={TestModal([2])}
251
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [2] } }}
257
252
  renderItem={(item: TestItem) => <span>{item.name}</span>}
258
253
  />
259
254
  ));
@@ -261,10 +256,10 @@ describe("DataSelectButton", () => {
261
256
  const searchBtn = container.querySelector("[data-search-button]") as HTMLButtonElement;
262
257
  searchBtn.click();
263
258
 
264
- // once modal opens, find and click confirm button
259
+ // once dialog opens, find and click confirm button
265
260
  await vi.waitFor(() => {
266
261
  const confirmBtn = document.querySelector(
267
- "[data-testid='modal-confirm']",
262
+ "[data-testid='dialog-confirm']",
268
263
  ) as HTMLButtonElement;
269
264
  expect(confirmBtn).not.toBeNull();
270
265
  confirmBtn.click();
@@ -275,7 +270,7 @@ describe("DataSelectButton", () => {
275
270
  });
276
271
  });
277
272
 
278
- it("opens modal and applies result for multiple select", async () => {
273
+ it("opens dialog and applies result for multiple select", async () => {
279
274
  const load = createTestLoad();
280
275
  const onValueChange = vi.fn();
281
276
 
@@ -284,7 +279,7 @@ describe("DataSelectButton", () => {
284
279
  multiple
285
280
  onValueChange={onValueChange}
286
281
  load={load}
287
- modal={TestModal([1, 3])}
282
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [1, 3] } }}
288
283
  renderItem={(item: TestItem) => <span>{item.name}</span>}
289
284
  />
290
285
  ));
@@ -294,7 +289,7 @@ describe("DataSelectButton", () => {
294
289
 
295
290
  await vi.waitFor(() => {
296
291
  const confirmBtn = document.querySelector(
297
- "[data-testid='modal-confirm']",
292
+ "[data-testid='dialog-confirm']",
298
293
  ) as HTMLButtonElement;
299
294
  expect(confirmBtn).not.toBeNull();
300
295
  confirmBtn.click();
@@ -305,7 +300,7 @@ describe("DataSelectButton", () => {
305
300
  });
306
301
  });
307
302
 
308
- it("does not change value when modal is cancelled", async () => {
303
+ it("does not change value when dialog is cancelled", async () => {
309
304
  const load = createTestLoad();
310
305
  const onValueChange = vi.fn();
311
306
 
@@ -314,7 +309,7 @@ describe("DataSelectButton", () => {
314
309
  value={1}
315
310
  onValueChange={onValueChange}
316
311
  load={load}
317
- modal={TestModal([2])}
312
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [2] } }}
318
313
  renderItem={(item: TestItem) => <span>{item.name}</span>}
319
314
  />
320
315
  ));
@@ -323,13 +318,14 @@ describe("DataSelectButton", () => {
323
318
  searchBtn.click();
324
319
 
325
320
  await vi.waitFor(() => {
326
- const cancelBtn = document.querySelector("[data-testid='modal-cancel']") as HTMLButtonElement;
327
- expect(cancelBtn).not.toBeNull();
328
- cancelBtn.click();
321
+ const dialogContent = document.querySelector("[data-testid='dialog-content']");
322
+ expect(dialogContent).not.toBeNull();
329
323
  });
330
324
 
331
- // value should not change
332
- await new Promise((r) => setTimeout(r, 100));
325
+ // Close via ESC key
326
+ document.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape", bubbles: true }));
327
+
328
+ await new Promise((r) => setTimeout(r, 300));
333
329
  expect(onValueChange).not.toHaveBeenCalled();
334
330
  });
335
331
 
@@ -339,7 +335,7 @@ describe("DataSelectButton", () => {
339
335
  <DataSelectButton
340
336
  required
341
337
  load={load}
342
- modal={TestModal([])}
338
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [] } }}
343
339
  renderItem={(item: TestItem) => <span>{item.name}</span>}
344
340
  />
345
341
  ));
@@ -356,7 +352,7 @@ describe("DataSelectButton", () => {
356
352
  <DataSelectButton
357
353
  value={1}
358
354
  load={load}
359
- modal={TestModal([])}
355
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [] } }}
360
356
  renderItem={(item: TestItem) => <span>{item.name}</span>}
361
357
  validate={(v) => (v === 1 ? "1은 선택할 수 없습니다" : undefined)}
362
358
  />
@@ -375,7 +371,7 @@ describe("DataSelectButton", () => {
375
371
  <DataSelectButton
376
372
  disabled
377
373
  load={load}
378
- modal={TestModal([])}
374
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [] } }}
379
375
  renderItem={(item: TestItem) => <span>{item.name}</span>}
380
376
  />
381
377
  ));
@@ -391,7 +387,7 @@ describe("DataSelectButton", () => {
391
387
  <DataSelectButton
392
388
  required
393
389
  load={load}
394
- modal={TestModal([])}
390
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [] } }}
395
391
  renderItem={(item: TestItem) => <span>{item.name}</span>}
396
392
  />
397
393
  ));
@@ -400,7 +396,7 @@ describe("DataSelectButton", () => {
400
396
  expect(trigger.getAttribute("aria-required")).toBe("true");
401
397
  });
402
398
 
403
- it("opens modal on Enter key press", async () => {
399
+ it("opens dialog on Enter key press", async () => {
404
400
  const load = createTestLoad();
405
401
  const onValueChange = vi.fn();
406
402
 
@@ -408,7 +404,7 @@ describe("DataSelectButton", () => {
408
404
  <DataSelectButton
409
405
  onValueChange={onValueChange}
410
406
  load={load}
411
- modal={TestModal([3])}
407
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [3] } }}
412
408
  renderItem={(item: TestItem) => <span>{item.name}</span>}
413
409
  />
414
410
  ));
@@ -418,7 +414,7 @@ describe("DataSelectButton", () => {
418
414
 
419
415
  await vi.waitFor(() => {
420
416
  const confirmBtn = document.querySelector(
421
- "[data-testid='modal-confirm']",
417
+ "[data-testid='dialog-confirm']",
422
418
  ) as HTMLButtonElement;
423
419
  expect(confirmBtn).not.toBeNull();
424
420
  confirmBtn.click();
@@ -439,7 +435,7 @@ describe("DataSelectButton", () => {
439
435
  <DataSelectButton
440
436
  value={2}
441
437
  load={asyncLoad}
442
- modal={TestModal([])}
438
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [] } }}
443
439
  renderItem={(item: TestItem) => <span>{item.name}</span>}
444
440
  />
445
441
  ));
@@ -454,7 +450,7 @@ describe("DataSelectButton", () => {
454
450
  const { container } = renderWithDialog(() => (
455
451
  <DataSelectButton
456
452
  load={load}
457
- modal={TestModal([])}
453
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [] } }}
458
454
  renderItem={(item: TestItem) => <span>{item.name}</span>}
459
455
  />
460
456
  ));
@@ -470,7 +466,7 @@ describe("DataSelectButton", () => {
470
466
  value={1}
471
467
  disabled
472
468
  load={load}
473
- modal={TestModal([])}
469
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [] } }}
474
470
  renderItem={(item: TestItem) => <span>{item.name}</span>}
475
471
  />
476
472
  ));
@@ -479,4 +475,29 @@ describe("DataSelectButton", () => {
479
475
  const clearBtn = container.querySelector("[data-clear-button]");
480
476
  expect(clearBtn).toBeNull();
481
477
  });
478
+
479
+ it("injects selectMode and selectedKeys into dialog component", async () => {
480
+ const load = createTestLoad();
481
+
482
+ const { container } = renderWithDialog(() => (
483
+ <DataSelectButton
484
+ value={1}
485
+ multiple
486
+ load={load}
487
+ dialog={{ component: TestDialogComponent, props: { confirmKeys: [] } }}
488
+ renderItem={(item: TestItem) => <span>{item.name}</span>}
489
+ />
490
+ ));
491
+
492
+ const searchBtn = container.querySelector("[data-search-button]") as HTMLButtonElement;
493
+ searchBtn.click();
494
+
495
+ await vi.waitFor(() => {
496
+ const selectMode = document.querySelector("[data-testid='select-mode']");
497
+ expect(selectMode?.textContent).toBe("multiple");
498
+
499
+ const selectedKeys = document.querySelector("[data-testid='selected-keys']");
500
+ expect(selectedKeys?.textContent).toBe("[1]");
501
+ });
502
+ });
482
503
  });
@@ -1,5 +1,5 @@
1
1
  import { render, fireEvent } from "@solidjs/testing-library";
2
- import { describe, it, expect, vi } from "vitest";
2
+ import { describe, it, expect, vi, beforeEach } from "vitest";
3
3
  import { createSignal } from "solid-js";
4
4
  import {
5
5
  PermissionTable,
@@ -171,35 +171,39 @@ describe("changePermCheck", () => {
171
171
  // =====================
172
172
 
173
173
  describe("PermissionTable component", () => {
174
+ beforeEach(() => {
175
+ localStorage.setItem("test.i18n-locale", JSON.stringify("en"));
176
+ });
177
+
174
178
  describe("basic rendering", () => {
175
179
  it("renders as DataSheet (div with data-sheet attribute)", () => {
176
- const { container } = render(() => <PermissionTable items={sampleItems} />);
180
+ const { container } = render(() => <ConfigProvider clientName="test"><I18nProvider><PermissionTable items={sampleItems} /></I18nProvider></ConfigProvider>);
177
181
  const wrapper = container.querySelector("[data-sheet]");
178
182
  expect(wrapper).toBeTruthy();
179
183
  expect(wrapper!.tagName).toBe("DIV");
180
184
  });
181
185
 
182
186
  it("renders a table inside DataSheet", () => {
183
- const { container } = render(() => <PermissionTable items={sampleItems} />);
187
+ const { container } = render(() => <ConfigProvider clientName="test"><I18nProvider><PermissionTable items={sampleItems} /></I18nProvider></ConfigProvider>);
184
188
  const table = container.querySelector("[data-sheet] table");
185
189
  expect(table).toBeTruthy();
186
190
  });
187
191
 
188
192
  it("displays perm type columns in header", () => {
189
- const { getByText } = render(() => <PermissionTable items={sampleItems} />);
193
+ const { getByText } = render(() => <ConfigProvider clientName="test"><I18nProvider><PermissionTable items={sampleItems} /></I18nProvider></ConfigProvider>);
190
194
  expect(getByText("use")).toBeTruthy();
191
195
  expect(getByText("edit")).toBeTruthy();
192
196
  expect(getByText("approve")).toBeTruthy();
193
197
  });
194
198
 
195
199
  it("displays item titles", () => {
196
- const { getByText } = render(() => <PermissionTable items={sampleItems} />);
200
+ const { getByText } = render(() => <ConfigProvider clientName="test"><I18nProvider><PermissionTable items={sampleItems} /></I18nProvider></ConfigProvider>);
197
201
  expect(getByText("사용자 관리")).toBeTruthy();
198
202
  expect(getByText("시스템")).toBeTruthy();
199
203
  });
200
204
 
201
205
  it("child items are expanded by default", () => {
202
- const { getByText } = render(() => <PermissionTable items={sampleItems} />);
206
+ const { getByText } = render(() => <ConfigProvider clientName="test"><I18nProvider><PermissionTable items={sampleItems} /></I18nProvider></ConfigProvider>);
203
207
  expect(getByText("권한 설정")).toBeTruthy();
204
208
  expect(getByText("사용자 목록")).toBeTruthy();
205
209
  });
@@ -240,7 +244,7 @@ describe("PermissionTable component", () => {
240
244
 
241
245
  describe("expand/collapse", () => {
242
246
  it("rows with children have an expand/collapse toggle", () => {
243
- const { getByText } = render(() => <PermissionTable items={sampleItems} />);
247
+ const { getByText } = render(() => <ConfigProvider clientName="test"><I18nProvider><PermissionTable items={sampleItems} /></I18nProvider></ConfigProvider>);
244
248
  // find the row containing "사용자 관리" and check for expand toggle button
245
249
  const titleEl = getByText("사용자 관리");
246
250
  const row = titleEl.closest("tr")!;
@@ -249,7 +253,7 @@ describe("PermissionTable component", () => {
249
253
  });
250
254
 
251
255
  it("clicking collapse button removes children from the DOM", () => {
252
- const { getByText, queryByText } = render(() => <PermissionTable items={sampleItems} />);
256
+ const { getByText, queryByText } = render(() => <ConfigProvider clientName="test"><I18nProvider><PermissionTable items={sampleItems} /></I18nProvider></ConfigProvider>);
253
257
 
254
258
  // initially: children are visible (all expanded by default)
255
259
  expect(getByText("권한 설정")).toBeTruthy();
@@ -0,0 +1,172 @@
1
+ import { afterEach, beforeEach, describe, it, expect, vi } from "vitest";
2
+ import { render, cleanup } from "@solidjs/testing-library";
3
+ import { createSignal, type Accessor } from "solid-js";
4
+ import {
5
+ SharedDataSelect,
6
+ type InjectedSelectProps,
7
+ } from "@simplysm/solid";
8
+ import { type SharedDataAccessor } from "../../../../src/providers/shared-data/SharedDataContext";
9
+ import { DialogProvider } from "../../../../src/components/disclosure/DialogProvider";
10
+ import { I18nProvider } from "../../../../src/providers/i18n/I18nContext";
11
+ import { ConfigProvider } from "../../../../src/providers/ConfigContext";
12
+
13
+ interface TestItem {
14
+ id: number;
15
+ name: string;
16
+ }
17
+
18
+ const testItems: TestItem[] = [
19
+ { id: 1, name: "Apple" },
20
+ { id: 2, name: "Banana" },
21
+ { id: 3, name: "Cherry" },
22
+ ];
23
+
24
+ function createMockAccessor(itemsSignal: Accessor<TestItem[]>): SharedDataAccessor<TestItem> {
25
+ return {
26
+ items: itemsSignal,
27
+ get: (key) => itemsSignal().find((item) => item.id === key),
28
+ emit: vi.fn(async () => {}),
29
+ getKey: (item) => item.id,
30
+ getSearchText: (item) => item.name,
31
+ };
32
+ }
33
+
34
+ function TestDialogComponent(props: { confirmKeys: number[] } & InjectedSelectProps) {
35
+ return (
36
+ <div data-testid="dialog-content">
37
+ <div data-testid="select-mode">{props.selectMode}</div>
38
+ <div data-testid="selected-keys">{JSON.stringify([...props.selectedKeys])}</div>
39
+ <button
40
+ data-testid="dialog-confirm"
41
+ onClick={() => props.onSelect({ keys: props.confirmKeys })}
42
+ >
43
+ confirm
44
+ </button>
45
+ </div>
46
+ );
47
+ }
48
+
49
+ function renderWithDialog(ui: () => import("solid-js").JSX.Element) {
50
+ return render(() => (
51
+ <ConfigProvider clientName="test"><I18nProvider>
52
+ <DialogProvider>{ui()}</DialogProvider>
53
+ </I18nProvider></ConfigProvider>
54
+ ));
55
+ }
56
+
57
+ describe("SharedDataSelect", () => {
58
+ beforeEach(() => {
59
+ localStorage.setItem("test.i18n-locale", JSON.stringify("en"));
60
+ });
61
+
62
+ afterEach(() => {
63
+ cleanup();
64
+ });
65
+
66
+ it("renders items via ItemTemplate", () => {
67
+ const [items] = createSignal(testItems);
68
+ const accessor = createMockAccessor(items);
69
+
70
+ const { getByText } = renderWithDialog(() => (
71
+ <SharedDataSelect data={accessor} value={1} onValueChange={() => {}}>
72
+ <SharedDataSelect.ItemTemplate>
73
+ {(item: TestItem) => <span>{item.name}</span>}
74
+ </SharedDataSelect.ItemTemplate>
75
+ </SharedDataSelect>
76
+ ));
77
+
78
+ // Select should render with items from accessor
79
+ expect(getByText("Apple")).toBeTruthy();
80
+ });
81
+
82
+ it("renders custom Action button", () => {
83
+ const [items] = createSignal(testItems);
84
+ const accessor = createMockAccessor(items);
85
+ const onClick = vi.fn();
86
+
87
+ const { container } = renderWithDialog(() => (
88
+ <SharedDataSelect data={accessor} value={1} onValueChange={() => {}}>
89
+ <SharedDataSelect.ItemTemplate>
90
+ {(item: TestItem) => <span>{item.name}</span>}
91
+ </SharedDataSelect.ItemTemplate>
92
+ <SharedDataSelect.Action onClick={onClick}>
93
+ <span data-testid="custom-action">Edit</span>
94
+ </SharedDataSelect.Action>
95
+ </SharedDataSelect>
96
+ ));
97
+
98
+ const actionBtn = container.querySelector("[data-testid='custom-action']");
99
+ expect(actionBtn).not.toBeNull();
100
+ });
101
+
102
+ it("opens dialog and applies selection result", async () => {
103
+ const [items] = createSignal(testItems);
104
+ const accessor = createMockAccessor(items);
105
+ const onValueChange = vi.fn();
106
+
107
+ const { container } = renderWithDialog(() => (
108
+ <SharedDataSelect
109
+ data={accessor}
110
+ value={1}
111
+ onValueChange={onValueChange}
112
+ dialog={{
113
+ component: TestDialogComponent,
114
+ props: { confirmKeys: [2] },
115
+ option: { header: "Select Item" },
116
+ }}
117
+ >
118
+ <SharedDataSelect.ItemTemplate>
119
+ {(item: TestItem) => <span>{item.name}</span>}
120
+ </SharedDataSelect.ItemTemplate>
121
+ </SharedDataSelect>
122
+ ));
123
+
124
+ // Click search action button to open dialog
125
+ const searchBtn = container.querySelector("[data-select-action]") as HTMLButtonElement;
126
+ expect(searchBtn).not.toBeNull();
127
+ searchBtn.click();
128
+
129
+ // Confirm in dialog
130
+ await vi.waitFor(() => {
131
+ const confirmBtn = document.querySelector("[data-testid='dialog-confirm']") as HTMLButtonElement;
132
+ expect(confirmBtn).not.toBeNull();
133
+ confirmBtn.click();
134
+ });
135
+
136
+ await vi.waitFor(() => {
137
+ expect(onValueChange).toHaveBeenCalledWith(2);
138
+ });
139
+ });
140
+
141
+ it("passes selectedKeys to dialog component", async () => {
142
+ const [items] = createSignal(testItems);
143
+ const accessor = createMockAccessor(items);
144
+
145
+ const { container } = renderWithDialog(() => (
146
+ <SharedDataSelect
147
+ data={accessor}
148
+ value={3}
149
+ onValueChange={() => {}}
150
+ dialog={{
151
+ component: TestDialogComponent,
152
+ props: { confirmKeys: [] },
153
+ }}
154
+ >
155
+ <SharedDataSelect.ItemTemplate>
156
+ {(item: TestItem) => <span>{item.name}</span>}
157
+ </SharedDataSelect.ItemTemplate>
158
+ </SharedDataSelect>
159
+ ));
160
+
161
+ const searchBtn = container.querySelector("[data-select-action]") as HTMLButtonElement;
162
+ searchBtn.click();
163
+
164
+ await vi.waitFor(() => {
165
+ const selectedKeys = document.querySelector("[data-testid='selected-keys']");
166
+ expect(selectedKeys?.textContent).toBe("[3]");
167
+
168
+ const selectMode = document.querySelector("[data-testid='select-mode']");
169
+ expect(selectMode?.textContent).toBe("single");
170
+ });
171
+ });
172
+ });
@@ -1,8 +1,10 @@
1
- import { afterEach, describe, it, expect, vi } from "vitest";
1
+ import { afterEach, beforeEach, describe, it, expect, vi } from "vitest";
2
2
  import { render, screen, fireEvent, cleanup } from "@solidjs/testing-library";
3
3
  import { createSignal } from "solid-js";
4
4
  import { SharedDataSelectList } from "@simplysm/solid";
5
5
  import { DialogProvider } from "../../../../src/components/disclosure/DialogProvider";
6
+ import { I18nProvider } from "../../../../src/providers/i18n/I18nContext";
7
+ import { ConfigProvider } from "../../../../src/providers/ConfigContext";
6
8
 
7
9
  // SharedDataAccessor mock factory
8
10
  function createMockAccessor<T>(
@@ -25,10 +27,20 @@ function createMockAccessor<T>(
25
27
 
26
28
  // DialogProvider wrapper
27
29
  function renderWithDialog(ui: () => import("solid-js").JSX.Element) {
28
- return render(() => <DialogProvider>{ui()}</DialogProvider>);
30
+ return render(() => (
31
+ <ConfigProvider clientName="test">
32
+ <I18nProvider>
33
+ <DialogProvider>{ui()}</DialogProvider>
34
+ </I18nProvider>
35
+ </ConfigProvider>
36
+ ));
29
37
  }
30
38
 
31
39
  describe("SharedDataSelectList", () => {
40
+ beforeEach(() => {
41
+ localStorage.setItem("test.i18n-locale", JSON.stringify("en"));
42
+ });
43
+
32
44
  afterEach(() => {
33
45
  cleanup();
34
46
  });