@simplysm/solid 13.0.69 → 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 (495) hide show
  1. package/README.md +168 -195
  2. package/dist/components/data/calendar/Calendar.d.ts.map +1 -1
  3. package/dist/components/data/calendar/Calendar.js +15 -2
  4. package/dist/components/data/calendar/Calendar.js.map +2 -2
  5. package/dist/components/data/kanban/KanbanContext.js +2 -2
  6. package/dist/components/data/kanban/KanbanContext.js.map +1 -1
  7. package/dist/components/data/list/List.d.ts +8 -8
  8. package/dist/components/data/list/ListContext.d.ts +1 -1
  9. package/dist/components/data/list/ListItem.d.ts +15 -15
  10. package/dist/components/data/sheet/DataSheet.d.ts.map +1 -1
  11. package/dist/components/data/sheet/DataSheet.js +6 -4
  12. package/dist/components/data/sheet/DataSheet.js.map +2 -2
  13. package/dist/components/data/sheet/DataSheetConfigDialog.js +8 -8
  14. package/dist/components/data/sheet/DataSheetConfigDialog.js.map +1 -1
  15. package/dist/components/data/sheet/types.d.ts +4 -4
  16. package/dist/components/data/sheet/types.d.ts.map +1 -1
  17. package/dist/components/disclosure/Collapse.d.ts +4 -4
  18. package/dist/components/disclosure/Dialog.d.ts +24 -24
  19. package/dist/components/disclosure/Dialog.d.ts.map +1 -1
  20. package/dist/components/disclosure/Dialog.js +7 -2
  21. package/dist/components/disclosure/Dialog.js.map +2 -2
  22. package/dist/components/disclosure/DialogContext.d.ts +25 -25
  23. package/dist/components/disclosure/DialogContext.d.ts.map +1 -1
  24. package/dist/components/disclosure/DialogContext.js +1 -1
  25. package/dist/components/disclosure/DialogContext.js.map +1 -1
  26. package/dist/components/disclosure/DialogInstanceContext.d.ts +7 -7
  27. package/dist/components/disclosure/DialogInstanceContext.d.ts.map +1 -1
  28. package/dist/components/disclosure/DialogProvider.d.ts +3 -3
  29. package/dist/components/disclosure/Dropdown.d.ts +26 -24
  30. package/dist/components/disclosure/Dropdown.d.ts.map +1 -1
  31. package/dist/components/disclosure/Dropdown.js +24 -8
  32. package/dist/components/disclosure/Dropdown.js.map +2 -2
  33. package/dist/components/disclosure/Tabs.js +1 -1
  34. package/dist/components/disclosure/Tabs.js.map +1 -1
  35. package/dist/components/disclosure/dialogZIndex.d.ts +9 -7
  36. package/dist/components/disclosure/dialogZIndex.d.ts.map +1 -1
  37. package/dist/components/disclosure/dialogZIndex.js +4 -0
  38. package/dist/components/disclosure/dialogZIndex.js.map +1 -1
  39. package/dist/components/features/crud-detail/CrudDetail.d.ts.map +1 -1
  40. package/dist/components/features/crud-detail/CrudDetail.js +34 -22
  41. package/dist/components/features/crud-detail/CrudDetail.js.map +2 -2
  42. package/dist/components/features/crud-sheet/CrudSheet.d.ts.map +1 -1
  43. package/dist/components/features/crud-sheet/CrudSheet.js +48 -33
  44. package/dist/components/features/crud-sheet/CrudSheet.js.map +2 -2
  45. package/dist/components/features/crudRegistry.d.ts +16 -0
  46. package/dist/components/features/crudRegistry.d.ts.map +1 -0
  47. package/dist/components/features/crudRegistry.js +37 -0
  48. package/dist/components/features/crudRegistry.js.map +6 -0
  49. package/dist/components/features/data-select-button/DataSelectButton.d.ts +14 -14
  50. package/dist/components/features/data-select-button/DataSelectButton.d.ts.map +1 -1
  51. package/dist/components/features/data-select-button/DataSelectButton.js +27 -9
  52. package/dist/components/features/data-select-button/DataSelectButton.js.map +2 -2
  53. package/dist/components/features/permission-table/PermissionTable.d.ts +3 -3
  54. package/dist/components/features/permission-table/PermissionTable.d.ts.map +1 -1
  55. package/dist/components/features/permission-table/PermissionTable.js +74 -85
  56. package/dist/components/features/permission-table/PermissionTable.js.map +2 -2
  57. package/dist/components/features/shared-data/SharedDataSelect.d.ts +12 -12
  58. package/dist/components/features/shared-data/SharedDataSelect.d.ts.map +1 -1
  59. package/dist/components/features/shared-data/SharedDataSelect.js +10 -6
  60. package/dist/components/features/shared-data/SharedDataSelect.js.map +2 -2
  61. package/dist/components/features/shared-data/SharedDataSelectButton.d.ts +10 -10
  62. package/dist/components/features/shared-data/SharedDataSelectButton.d.ts.map +1 -1
  63. package/dist/components/features/shared-data/SharedDataSelectList.d.ts +23 -15
  64. package/dist/components/features/shared-data/SharedDataSelectList.d.ts.map +1 -1
  65. package/dist/components/features/shared-data/SharedDataSelectList.js +191 -65
  66. package/dist/components/features/shared-data/SharedDataSelectList.js.map +2 -2
  67. package/dist/components/features/shared-data/SharedDataSelectListContext.d.ts +15 -0
  68. package/dist/components/features/shared-data/SharedDataSelectListContext.d.ts.map +1 -0
  69. package/dist/components/features/shared-data/SharedDataSelectListContext.js +27 -0
  70. package/dist/components/features/shared-data/SharedDataSelectListContext.js.map +6 -0
  71. package/dist/components/feedback/Progress.d.ts +1 -1
  72. package/dist/components/feedback/Progress.d.ts.map +1 -1
  73. package/dist/components/feedback/busy/BusyContainer.d.ts +2 -2
  74. package/dist/components/feedback/busy/BusyContainer.d.ts.map +1 -1
  75. package/dist/components/feedback/busy/BusyContext.d.ts +11 -11
  76. package/dist/components/feedback/busy/BusyContext.d.ts.map +1 -1
  77. package/dist/components/feedback/busy/BusyContext.js +1 -1
  78. package/dist/components/feedback/busy/BusyContext.js.map +1 -1
  79. package/dist/components/feedback/busy/BusyProvider.d.ts +6 -6
  80. package/dist/components/feedback/busy/BusyProvider.d.ts.map +1 -1
  81. package/dist/components/feedback/notification/NotificationBanner.d.ts.map +1 -1
  82. package/dist/components/feedback/notification/NotificationBanner.js +7 -3
  83. package/dist/components/feedback/notification/NotificationBanner.js.map +2 -2
  84. package/dist/components/feedback/notification/NotificationBell.js +2 -2
  85. package/dist/components/feedback/notification/NotificationBell.js.map +1 -1
  86. package/dist/components/feedback/notification/NotificationContext.d.ts +22 -22
  87. package/dist/components/feedback/notification/NotificationContext.d.ts.map +1 -1
  88. package/dist/components/feedback/notification/NotificationContext.js +1 -1
  89. package/dist/components/feedback/notification/NotificationContext.js.map +1 -1
  90. package/dist/components/feedback/notification/NotificationProvider.d.ts +5 -5
  91. package/dist/components/feedback/notification/NotificationProvider.js +1 -1
  92. package/dist/components/feedback/notification/NotificationProvider.js.map +1 -1
  93. package/dist/components/feedback/print/PrintContext.js +1 -1
  94. package/dist/components/feedback/print/PrintContext.js.map +1 -1
  95. package/dist/components/form-control/DropdownTrigger.styles.d.ts +1 -1
  96. package/dist/components/form-control/DropdownTrigger.styles.d.ts.map +1 -1
  97. package/dist/components/form-control/ThemeToggle.d.ts +7 -7
  98. package/dist/components/form-control/ThemeToggle.d.ts.map +1 -1
  99. package/dist/components/form-control/ThemeToggle.js +3 -3
  100. package/dist/components/form-control/checkbox/Checkbox.js +1 -1
  101. package/dist/components/form-control/checkbox/CheckboxGroup.js +1 -1
  102. package/dist/components/form-control/checkbox/Radio.js +1 -1
  103. package/dist/components/form-control/checkbox/RadioGroup.js +1 -1
  104. package/dist/components/form-control/color-picker/ColorPicker.d.ts +12 -12
  105. package/dist/components/form-control/color-picker/ColorPicker.d.ts.map +1 -1
  106. package/dist/components/form-control/color-picker/ColorPicker.js +2 -2
  107. package/dist/components/form-control/combobox/Combobox.d.ts +22 -22
  108. package/dist/components/form-control/combobox/Combobox.d.ts.map +1 -1
  109. package/dist/components/form-control/combobox/Combobox.js +2 -2
  110. package/dist/components/form-control/combobox/ComboboxContext.d.ts +4 -4
  111. package/dist/components/form-control/combobox/ComboboxContext.d.ts.map +1 -1
  112. package/dist/components/form-control/combobox/ComboboxContext.js +1 -1
  113. package/dist/components/form-control/combobox/ComboboxContext.js.map +1 -1
  114. package/dist/components/form-control/combobox/ComboboxItem.d.ts +3 -3
  115. package/dist/components/form-control/combobox/ComboboxItem.d.ts.map +1 -1
  116. package/dist/components/form-control/date-range-picker/DateRangePicker.d.ts +14 -14
  117. package/dist/components/form-control/date-range-picker/DateRangePicker.d.ts.map +1 -1
  118. package/dist/components/form-control/date-range-picker/DateRangePicker.js +20 -9
  119. package/dist/components/form-control/date-range-picker/DateRangePicker.js.map +2 -2
  120. package/dist/components/form-control/editor/EditorToolbar.d.ts.map +1 -1
  121. package/dist/components/form-control/editor/EditorToolbar.js +65 -20
  122. package/dist/components/form-control/editor/EditorToolbar.js.map +2 -2
  123. package/dist/components/form-control/editor/RichTextEditor.d.ts +6 -6
  124. package/dist/components/form-control/editor/RichTextEditor.d.ts.map +1 -1
  125. package/dist/components/form-control/editor/RichTextEditor.js +1 -1
  126. package/dist/components/form-control/editor/editor.css +5 -5
  127. package/dist/components/form-control/field/DatePicker.d.ts +22 -22
  128. package/dist/components/form-control/field/DatePicker.d.ts.map +1 -1
  129. package/dist/components/form-control/field/DatePicker.js +4 -4
  130. package/dist/components/form-control/field/DatePicker.js.map +1 -1
  131. package/dist/components/form-control/field/DateTimePicker.d.ts +21 -21
  132. package/dist/components/form-control/field/DateTimePicker.d.ts.map +1 -1
  133. package/dist/components/form-control/field/DateTimePicker.js +4 -4
  134. package/dist/components/form-control/field/DateTimePicker.js.map +1 -1
  135. package/dist/components/form-control/field/FieldPlaceholder.d.ts +1 -1
  136. package/dist/components/form-control/field/FieldPlaceholder.d.ts.map +1 -1
  137. package/dist/components/form-control/field/NumberInput.d.ts +23 -23
  138. package/dist/components/form-control/field/NumberInput.d.ts.map +1 -1
  139. package/dist/components/form-control/field/NumberInput.js +4 -4
  140. package/dist/components/form-control/field/NumberInput.js.map +1 -1
  141. package/dist/components/form-control/field/TextInput.d.ts +25 -25
  142. package/dist/components/form-control/field/TextInput.d.ts.map +1 -1
  143. package/dist/components/form-control/field/TextInput.js +5 -5
  144. package/dist/components/form-control/field/TextInput.js.map +1 -1
  145. package/dist/components/form-control/field/Textarea.d.ts +19 -19
  146. package/dist/components/form-control/field/Textarea.d.ts.map +1 -1
  147. package/dist/components/form-control/field/Textarea.js +4 -4
  148. package/dist/components/form-control/field/Textarea.js.map +1 -1
  149. package/dist/components/form-control/field/TimePicker.d.ts +20 -20
  150. package/dist/components/form-control/field/TimePicker.d.ts.map +1 -1
  151. package/dist/components/form-control/field/TimePicker.js +4 -4
  152. package/dist/components/form-control/field/TimePicker.js.map +1 -1
  153. package/dist/components/form-control/numpad/Numpad.d.ts +11 -11
  154. package/dist/components/form-control/numpad/Numpad.d.ts.map +1 -1
  155. package/dist/components/form-control/select/Select.d.ts +26 -26
  156. package/dist/components/form-control/select/Select.d.ts.map +1 -1
  157. package/dist/components/form-control/select/Select.js +34 -23
  158. package/dist/components/form-control/select/Select.js.map +2 -2
  159. package/dist/components/form-control/select/SelectContext.d.ts +7 -7
  160. package/dist/components/form-control/select/SelectContext.d.ts.map +1 -1
  161. package/dist/components/form-control/select/SelectContext.js +1 -1
  162. package/dist/components/form-control/select/SelectContext.js.map +1 -1
  163. package/dist/components/form-control/select/SelectItem.d.ts +4 -4
  164. package/dist/components/form-control/select/SelectItem.d.ts.map +1 -1
  165. package/dist/components/form-control/state-preset/StatePreset.js +8 -8
  166. package/dist/components/form-control/state-preset/StatePreset.js.map +1 -1
  167. package/dist/components/layout/FormTable.js +4 -4
  168. package/dist/components/layout/sidebar/Sidebar.d.ts +5 -5
  169. package/dist/components/layout/sidebar/SidebarContainer.d.ts +11 -11
  170. package/dist/components/layout/sidebar/SidebarContainer.d.ts.map +1 -1
  171. package/dist/components/layout/sidebar/SidebarContainer.js +6 -1
  172. package/dist/components/layout/sidebar/SidebarContainer.js.map +2 -2
  173. package/dist/components/layout/sidebar/SidebarContext.d.ts +7 -7
  174. package/dist/components/layout/sidebar/SidebarContext.js +1 -1
  175. package/dist/components/layout/sidebar/SidebarContext.js.map +1 -1
  176. package/dist/components/layout/sidebar/SidebarMenu.d.ts +11 -11
  177. package/dist/components/layout/sidebar/SidebarUser.d.ts +14 -14
  178. package/dist/components/layout/topbar/Topbar.d.ts +6 -6
  179. package/dist/components/layout/topbar/Topbar.d.ts.map +1 -1
  180. package/dist/components/layout/topbar/Topbar.js +11 -6
  181. package/dist/components/layout/topbar/Topbar.js.map +2 -2
  182. package/dist/components/layout/topbar/TopbarContainer.d.ts +6 -6
  183. package/dist/components/layout/topbar/TopbarContext.js +2 -2
  184. package/dist/components/layout/topbar/TopbarContext.js.map +1 -1
  185. package/dist/components/layout/topbar/TopbarMenu.d.ts +11 -11
  186. package/dist/components/layout/topbar/TopbarMenu.d.ts.map +1 -1
  187. package/dist/components/layout/topbar/TopbarMenu.js +5 -1
  188. package/dist/components/layout/topbar/TopbarMenu.js.map +2 -2
  189. package/dist/components/layout/topbar/TopbarUser.d.ts +9 -9
  190. package/dist/directives/ripple.d.ts +5 -5
  191. package/dist/helpers/createAppStructure.d.ts.map +1 -1
  192. package/dist/helpers/createAppStructure.js +7 -3
  193. package/dist/helpers/createAppStructure.js.map +1 -1
  194. package/dist/helpers/createHmrSafeContext.d.ts +3 -0
  195. package/dist/helpers/createHmrSafeContext.d.ts.map +1 -0
  196. package/dist/helpers/createHmrSafeContext.js +10 -0
  197. package/dist/helpers/createHmrSafeContext.js.map +6 -0
  198. package/dist/helpers/createSlotComponent.d.ts +3 -3
  199. package/dist/helpers/mergeStyles.d.ts +8 -8
  200. package/dist/hooks/createControllableSignal.d.ts +10 -10
  201. package/dist/hooks/createControllableStore.d.ts +6 -6
  202. package/dist/hooks/createIMEHandler.d.ts +7 -7
  203. package/dist/hooks/createMountTransition.d.ts +4 -4
  204. package/dist/hooks/createSelectionGroup.d.ts.map +1 -1
  205. package/dist/hooks/createSelectionGroup.js +4 -3
  206. package/dist/hooks/createSelectionGroup.js.map +2 -2
  207. package/dist/hooks/createSlotSignal.d.ts +2 -2
  208. package/dist/hooks/useLocalStorage.d.ts +11 -11
  209. package/dist/hooks/useLogger.d.ts +1 -1
  210. package/dist/hooks/useLogger.d.ts.map +1 -1
  211. package/dist/hooks/useLogger.js +1 -1
  212. package/dist/hooks/useLogger.js.map +1 -1
  213. package/dist/hooks/useRouterLink.d.ts +10 -10
  214. package/dist/hooks/useRouterLink.d.ts.map +1 -1
  215. package/dist/index.d.ts +2 -1
  216. package/dist/index.d.ts.map +1 -1
  217. package/dist/index.js +2 -1
  218. package/dist/index.js.map +1 -1
  219. package/dist/providers/ClipboardProvider.d.ts +5 -5
  220. package/dist/providers/ConfigContext.d.ts +6 -6
  221. package/dist/providers/ConfigContext.js +2 -2
  222. package/dist/providers/ConfigContext.js.map +1 -1
  223. package/dist/providers/ErrorLoggerProvider.d.ts +3 -3
  224. package/dist/providers/LoggerContext.d.ts +13 -13
  225. package/dist/providers/PwaUpdateProvider.d.ts +4 -4
  226. package/dist/providers/PwaUpdateProvider.js +2 -2
  227. package/dist/providers/PwaUpdateProvider.js.map +1 -1
  228. package/dist/providers/ServiceClientContext.d.ts +8 -8
  229. package/dist/providers/ServiceClientContext.d.ts.map +1 -1
  230. package/dist/providers/ServiceClientContext.js +1 -1
  231. package/dist/providers/ServiceClientContext.js.map +1 -1
  232. package/dist/providers/ServiceClientProvider.d.ts +6 -6
  233. package/dist/providers/ServiceClientProvider.js +7 -7
  234. package/dist/providers/ServiceClientProvider.js.map +1 -1
  235. package/dist/providers/SyncStorageContext.d.ts +14 -14
  236. package/dist/providers/SystemProvider.d.ts.map +1 -1
  237. package/dist/providers/SystemProvider.js +21 -16
  238. package/dist/providers/SystemProvider.js.map +2 -2
  239. package/dist/providers/ThemeContext.d.ts +20 -20
  240. package/dist/providers/ThemeContext.d.ts.map +1 -1
  241. package/dist/providers/ThemeContext.js +1 -1
  242. package/dist/providers/ThemeContext.js.map +1 -1
  243. package/dist/providers/i18n/I18nContext.d.ts +44 -0
  244. package/dist/providers/i18n/I18nContext.d.ts.map +1 -0
  245. package/dist/providers/i18n/I18nContext.js +73 -0
  246. package/dist/providers/i18n/I18nContext.js.map +6 -0
  247. package/dist/providers/i18n/I18nContext.types.d.ts +28 -0
  248. package/dist/providers/i18n/I18nContext.types.d.ts.map +1 -0
  249. package/dist/providers/i18n/I18nContext.types.js +1 -0
  250. package/dist/providers/i18n/I18nContext.types.js.map +6 -0
  251. package/dist/providers/i18n/i18nUtils.d.ts +18 -0
  252. package/dist/providers/i18n/i18nUtils.d.ts.map +1 -0
  253. package/dist/providers/i18n/i18nUtils.js +25 -0
  254. package/dist/providers/i18n/i18nUtils.js.map +6 -0
  255. package/dist/providers/i18n/locales/en.d.ts +163 -0
  256. package/dist/providers/i18n/locales/en.d.ts.map +1 -0
  257. package/dist/providers/i18n/locales/en.js +165 -0
  258. package/dist/providers/i18n/locales/en.js.map +6 -0
  259. package/dist/providers/i18n/locales/ko.d.ts +163 -0
  260. package/dist/providers/i18n/locales/ko.d.ts.map +1 -0
  261. package/dist/providers/i18n/locales/ko.js +165 -0
  262. package/dist/providers/i18n/locales/ko.js.map +6 -0
  263. package/dist/providers/shared-data/SharedDataChangeEvent.d.ts +4 -4
  264. package/dist/providers/shared-data/SharedDataContext.d.ts +28 -28
  265. package/dist/providers/shared-data/SharedDataContext.d.ts.map +1 -1
  266. package/dist/providers/shared-data/SharedDataContext.js +1 -1
  267. package/dist/providers/shared-data/SharedDataContext.js.map +1 -1
  268. package/dist/providers/shared-data/SharedDataProvider.d.ts +9 -9
  269. package/dist/providers/shared-data/SharedDataProvider.js +4 -4
  270. package/dist/providers/shared-data/SharedDataProvider.js.map +1 -1
  271. package/package.json +9 -8
  272. package/src/components/data/calendar/Calendar.tsx +10 -4
  273. package/src/components/data/kanban/Kanban.tsx +14 -14
  274. package/src/components/data/kanban/KanbanContext.ts +3 -3
  275. package/src/components/data/list/List.tsx +10 -10
  276. package/src/components/data/list/ListContext.ts +1 -1
  277. package/src/components/data/list/ListItem.styles.ts +8 -8
  278. package/src/components/data/list/ListItem.tsx +15 -15
  279. package/src/components/data/sheet/DataSheet.styles.ts +22 -22
  280. package/src/components/data/sheet/DataSheet.tsx +52 -48
  281. package/src/components/data/sheet/DataSheetColumn.tsx +1 -1
  282. package/src/components/data/sheet/DataSheetConfigDialog.tsx +9 -9
  283. package/src/components/data/sheet/sheetUtils.ts +7 -7
  284. package/src/components/data/sheet/types.ts +16 -16
  285. package/src/components/disclosure/Collapse.tsx +11 -11
  286. package/src/components/disclosure/Dialog.tsx +60 -57
  287. package/src/components/disclosure/DialogContext.ts +26 -26
  288. package/src/components/disclosure/DialogInstanceContext.ts +7 -7
  289. package/src/components/disclosure/DialogProvider.tsx +5 -5
  290. package/src/components/disclosure/Dropdown.tsx +89 -75
  291. package/src/components/disclosure/Tabs.tsx +1 -1
  292. package/src/components/disclosure/dialogZIndex.ts +16 -11
  293. package/src/components/display/Echarts.tsx +4 -4
  294. package/src/components/features/address/AddressSearch.tsx +2 -2
  295. package/src/components/features/crud-detail/CrudDetail.tsx +34 -21
  296. package/src/components/features/crud-detail/CrudDetailAfter.tsx +1 -1
  297. package/src/components/features/crud-detail/CrudDetailBefore.tsx +1 -1
  298. package/src/components/features/crud-detail/CrudDetailTools.tsx +1 -1
  299. package/src/components/features/crud-sheet/CrudSheet.tsx +52 -40
  300. package/src/components/features/crud-sheet/CrudSheetColumn.tsx +1 -1
  301. package/src/components/features/crud-sheet/CrudSheetFilter.tsx +1 -1
  302. package/src/components/features/crud-sheet/CrudSheetHeader.tsx +1 -1
  303. package/src/components/features/crud-sheet/CrudSheetTools.tsx +1 -1
  304. package/src/components/features/crudRegistry.ts +60 -0
  305. package/src/components/features/data-select-button/DataSelectButton.tsx +34 -32
  306. package/src/components/features/permission-table/PermissionTable.tsx +70 -64
  307. package/src/components/features/shared-data/SharedDataSelect.tsx +24 -22
  308. package/src/components/features/shared-data/SharedDataSelectButton.tsx +10 -10
  309. package/src/components/features/shared-data/SharedDataSelectList.tsx +231 -59
  310. package/src/components/features/shared-data/SharedDataSelectListContext.ts +39 -0
  311. package/src/components/feedback/Progress.tsx +1 -1
  312. package/src/components/feedback/busy/BusyContainer.tsx +6 -6
  313. package/src/components/feedback/busy/BusyContext.ts +12 -12
  314. package/src/components/feedback/busy/BusyProvider.tsx +6 -6
  315. package/src/components/feedback/notification/NotificationBanner.tsx +3 -1
  316. package/src/components/feedback/notification/NotificationBell.tsx +4 -4
  317. package/src/components/feedback/notification/NotificationContext.ts +28 -28
  318. package/src/components/feedback/notification/NotificationProvider.tsx +9 -9
  319. package/src/components/feedback/print/PrintContext.ts +1 -1
  320. package/src/components/form-control/Button.tsx +1 -1
  321. package/src/components/form-control/DropdownTrigger.styles.ts +1 -1
  322. package/src/components/form-control/Invalid.tsx +5 -5
  323. package/src/components/form-control/ThemeToggle.tsx +10 -10
  324. package/src/components/form-control/checkbox/Checkbox.styles.ts +8 -8
  325. package/src/components/form-control/checkbox/Checkbox.tsx +2 -2
  326. package/src/components/form-control/checkbox/CheckboxGroup.tsx +1 -1
  327. package/src/components/form-control/checkbox/Radio.tsx +2 -2
  328. package/src/components/form-control/checkbox/RadioGroup.tsx +1 -1
  329. package/src/components/form-control/color-picker/ColorPicker.tsx +17 -17
  330. package/src/components/form-control/combobox/Combobox.tsx +55 -55
  331. package/src/components/form-control/combobox/ComboboxContext.ts +5 -5
  332. package/src/components/form-control/combobox/ComboboxItem.tsx +3 -3
  333. package/src/components/form-control/date-range-picker/DateRangePicker.tsx +40 -26
  334. package/src/components/form-control/editor/EditorToolbar.tsx +52 -50
  335. package/src/components/form-control/editor/RichTextEditor.tsx +16 -16
  336. package/src/components/form-control/editor/editor.css +5 -5
  337. package/src/components/form-control/field/DatePicker.tsx +39 -39
  338. package/src/components/form-control/field/DateTimePicker.tsx +38 -38
  339. package/src/components/form-control/field/Field.styles.ts +11 -11
  340. package/src/components/form-control/field/FieldPlaceholder.tsx +1 -1
  341. package/src/components/form-control/field/NumberInput.tsx +63 -63
  342. package/src/components/form-control/field/TextInput.tsx +48 -48
  343. package/src/components/form-control/field/Textarea.tsx +32 -32
  344. package/src/components/form-control/field/TimePicker.tsx +37 -37
  345. package/src/components/form-control/numpad/Numpad.tsx +26 -26
  346. package/src/components/form-control/select/Select.tsx +82 -86
  347. package/src/components/form-control/select/SelectContext.ts +8 -8
  348. package/src/components/form-control/select/SelectItem.tsx +5 -5
  349. package/src/components/form-control/state-preset/StatePreset.tsx +13 -13
  350. package/src/components/layout/FormTable.tsx +4 -4
  351. package/src/components/layout/sidebar/Sidebar.tsx +8 -8
  352. package/src/components/layout/sidebar/SidebarContainer.tsx +19 -17
  353. package/src/components/layout/sidebar/SidebarContext.ts +8 -8
  354. package/src/components/layout/sidebar/SidebarMenu.tsx +19 -19
  355. package/src/components/layout/sidebar/SidebarUser.tsx +14 -14
  356. package/src/components/layout/topbar/Topbar.tsx +15 -13
  357. package/src/components/layout/topbar/TopbarContainer.tsx +6 -6
  358. package/src/components/layout/topbar/TopbarContext.ts +2 -2
  359. package/src/components/layout/topbar/TopbarMenu.tsx +18 -16
  360. package/src/components/layout/topbar/TopbarUser.tsx +9 -9
  361. package/src/directives/ripple.ts +8 -8
  362. package/src/helpers/createAppStructure.ts +15 -8
  363. package/src/helpers/createHmrSafeContext.ts +8 -0
  364. package/src/helpers/createSlotComponent.ts +4 -4
  365. package/src/helpers/mergeStyles.ts +11 -11
  366. package/src/hooks/createControllableSignal.ts +11 -11
  367. package/src/hooks/createControllableStore.ts +8 -8
  368. package/src/hooks/createIMEHandler.ts +7 -7
  369. package/src/hooks/createMountTransition.ts +4 -4
  370. package/src/hooks/createSelectionGroup.tsx +5 -3
  371. package/src/hooks/createSlotSignal.ts +2 -2
  372. package/src/hooks/useLocalStorage.ts +13 -13
  373. package/src/hooks/useLogger.ts +2 -2
  374. package/src/hooks/useRouterLink.ts +15 -15
  375. package/src/index.ts +4 -3
  376. package/src/providers/ClipboardProvider.tsx +19 -19
  377. package/src/providers/ConfigContext.tsx +8 -8
  378. package/src/providers/ErrorLoggerProvider.tsx +3 -3
  379. package/src/providers/LoggerContext.tsx +13 -13
  380. package/src/providers/PwaUpdateProvider.tsx +6 -6
  381. package/src/providers/ServiceClientContext.ts +9 -9
  382. package/src/providers/ServiceClientProvider.tsx +15 -15
  383. package/src/providers/SyncStorageContext.tsx +15 -15
  384. package/src/providers/SystemProvider.tsx +15 -12
  385. package/src/providers/ThemeContext.tsx +26 -26
  386. package/src/providers/i18n/I18nContext.tsx +129 -0
  387. package/src/providers/i18n/I18nContext.types.ts +30 -0
  388. package/src/providers/i18n/i18nUtils.ts +38 -0
  389. package/src/providers/i18n/locales/en.ts +161 -0
  390. package/src/providers/i18n/locales/ko.ts +161 -0
  391. package/src/providers/shared-data/SharedDataChangeEvent.ts +4 -4
  392. package/src/providers/shared-data/SharedDataContext.ts +29 -29
  393. package/src/providers/shared-data/SharedDataProvider.tsx +21 -21
  394. package/src/styles/patterns.styles.ts +6 -6
  395. package/src/styles/tokens.styles.ts +5 -5
  396. package/tailwind.config.ts +1 -1
  397. package/tailwind.css +4 -4
  398. package/tests/components/data/List.spec.tsx +689 -0
  399. package/tests/components/data/Pagination.spec.tsx +336 -0
  400. package/tests/components/data/Table.spec.tsx +55 -0
  401. package/tests/components/data/kanban/Kanban.selection.spec.tsx +213 -0
  402. package/tests/components/data/sheet/DataSheet.spec.tsx +645 -0
  403. package/tests/components/disclosure/Collapse.spec.tsx +173 -0
  404. package/tests/components/disclosure/Dialog.spec.tsx +438 -0
  405. package/tests/components/disclosure/DialogProvider.spec.tsx +142 -0
  406. package/tests/components/disclosure/Dropdown.spec.tsx +333 -0
  407. package/tests/components/disclosure/Tabs.spec.tsx +220 -0
  408. package/tests/components/disclosure/dialogZIndex.spec.ts +45 -0
  409. package/tests/components/display/Alert.spec.tsx +47 -0
  410. package/tests/components/display/Barcode.spec.tsx +61 -0
  411. package/tests/components/display/Card.spec.tsx +41 -0
  412. package/tests/components/display/Link.spec.tsx +62 -0
  413. package/tests/components/display/Tag.spec.tsx +47 -0
  414. package/tests/components/features/address/AddressSearch.spec.tsx +45 -0
  415. package/tests/components/features/crud-detail/CrudDetail.spec.tsx +537 -0
  416. package/tests/components/features/crud-sheet/CrudSheet.spec.tsx +491 -0
  417. package/tests/components/features/crudRegistry.spec.ts +119 -0
  418. package/tests/components/features/data-select-button/DataSelectButton.spec.tsx +482 -0
  419. package/tests/components/features/permission-table/PermissionTable.spec.tsx +288 -0
  420. package/tests/components/features/shared-data/SharedDataSelectList.spec.tsx +448 -0
  421. package/tests/components/feedback/busy/BusyContainer.spec.tsx +80 -0
  422. package/tests/components/feedback/notification/LiveRegion.spec.tsx +52 -0
  423. package/tests/components/feedback/notification/NotificationBanner.spec.tsx +187 -0
  424. package/tests/components/feedback/notification/NotificationBell.spec.tsx +226 -0
  425. package/tests/components/feedback/notification/NotificationContext.spec.tsx +362 -0
  426. package/tests/components/feedback/print/Print.spec.tsx +45 -0
  427. package/tests/components/form-control/Button.spec.tsx +119 -0
  428. package/tests/components/form-control/Invalid.spec.tsx +131 -0
  429. package/tests/components/form-control/checkbox/Checkbox.spec.tsx +137 -0
  430. package/tests/components/form-control/checkbox/CheckboxGroup.spec.tsx +108 -0
  431. package/tests/components/form-control/checkbox/Radio.spec.tsx +138 -0
  432. package/tests/components/form-control/checkbox/RadioGroup.spec.tsx +108 -0
  433. package/tests/components/form-control/color-picker/ColorPicker.spec.tsx +94 -0
  434. package/tests/components/form-control/combobox/Combobox.spec.tsx +253 -0
  435. package/tests/components/form-control/combobox/ComboboxItem.spec.tsx +88 -0
  436. package/tests/components/form-control/date-range-picker/DateRangePicker.spec.tsx +208 -0
  437. package/tests/components/form-control/field/DatePicker.spec.tsx +381 -0
  438. package/tests/components/form-control/field/DateTimePicker.spec.tsx +383 -0
  439. package/tests/components/form-control/field/NumberInput.spec.tsx +371 -0
  440. package/tests/components/form-control/field/TextInput.spec.tsx +341 -0
  441. package/tests/components/form-control/field/Textarea.spec.tsx +224 -0
  442. package/tests/components/form-control/field/TimePicker.spec.tsx +315 -0
  443. package/tests/components/form-control/numpad/Numpad.spec.tsx +248 -0
  444. package/tests/components/form-control/select/Select.spec.tsx +676 -0
  445. package/tests/components/form-control/select/SelectItem.spec.tsx +174 -0
  446. package/tests/components/layout/FormGroup.spec.tsx +104 -0
  447. package/tests/components/layout/FormTable.spec.tsx +43 -0
  448. package/tests/components/layout/sidebar/Sidebar.spec.tsx +192 -0
  449. package/tests/components/layout/sidebar/SidebarContainer.spec.tsx +261 -0
  450. package/tests/components/layout/sidebar/SidebarMenu.spec.tsx +219 -0
  451. package/tests/components/layout/sidebar/SidebarUser.spec.tsx +133 -0
  452. package/tests/components/layout/topbar/TopbarActions.spec.tsx +77 -0
  453. package/tests/components/layout/topbar/TopbarContainer.spec.tsx +38 -0
  454. package/tests/components/layout/topbar/createTopbarActions.spec.tsx +66 -0
  455. package/tests/directives/ripple.spec.tsx +130 -0
  456. package/tests/helpers/createAppStructure.spec.tsx +843 -0
  457. package/tests/helpers/mergeStyles.spec.ts +172 -0
  458. package/tests/hooks/createControllableSignal.spec.ts +194 -0
  459. package/tests/hooks/createIMEHandler.spec.ts +80 -0
  460. package/tests/hooks/createMountTransition.spec.ts +86 -0
  461. package/tests/hooks/useLocalStorage.spec.tsx +223 -0
  462. package/tests/hooks/useLogger.spec.tsx +116 -0
  463. package/tests/hooks/usePrint.spec.tsx +134 -0
  464. package/tests/hooks/useRouterLink.spec.tsx +183 -0
  465. package/tests/hooks/useSyncConfig.spec.tsx +304 -0
  466. package/tests/providers/ClipboardProvider.spec.tsx +20 -0
  467. package/tests/providers/ConfigContext.spec.tsx +42 -0
  468. package/tests/providers/ErrorLoggerProvider.spec.tsx +73 -0
  469. package/tests/providers/LoggerContext.spec.tsx +76 -0
  470. package/tests/providers/PwaUpdateProvider.spec.tsx +22 -0
  471. package/tests/providers/ServiceClientContext.spec.tsx +88 -0
  472. package/tests/providers/SyncStorageContext.spec.tsx +77 -0
  473. package/tests/providers/i18n/I18nContext.spec.tsx +110 -0
  474. package/tests/providers/shared-data/SharedDataProvider.spec.tsx +401 -0
  475. package/tests/vitest-env.d.ts +1 -0
  476. package/dist/components/form-control/select-list/SelectList.d.ts +0 -54
  477. package/dist/components/form-control/select-list/SelectList.d.ts.map +0 -1
  478. package/dist/components/form-control/select-list/SelectList.js +0 -280
  479. package/dist/components/form-control/select-list/SelectList.js.map +0 -6
  480. package/dist/components/form-control/select-list/SelectListContext.d.ts +0 -13
  481. package/dist/components/form-control/select-list/SelectListContext.d.ts.map +0 -1
  482. package/dist/components/form-control/select-list/SelectListContext.js +0 -14
  483. package/dist/components/form-control/select-list/SelectListContext.js.map +0 -6
  484. package/docs/data-components.md +0 -782
  485. package/docs/disclosure.md +0 -254
  486. package/docs/display.md +0 -153
  487. package/docs/feedback.md +0 -238
  488. package/docs/form-controls.md +0 -1068
  489. package/docs/helpers.md +0 -54
  490. package/docs/hooks.md +0 -588
  491. package/docs/layout.md +0 -384
  492. package/docs/providers.md +0 -211
  493. package/docs/styling.md +0 -184
  494. package/src/components/form-control/select-list/SelectList.tsx +0 -385
  495. package/src/components/form-control/select-list/SelectListContext.ts +0 -23
@@ -2,12 +2,15 @@ import {
2
2
  children,
3
3
  createMemo,
4
4
  createSignal,
5
+ createUniqueId,
5
6
  type JSX,
7
+ onCleanup,
6
8
  onMount,
7
9
  Show,
8
10
  splitProps,
9
11
  useContext,
10
12
  } from "solid-js";
13
+ import { registerCrud, unregisterCrud, activateCrud, isActiveCrud } from "../crudRegistry";
11
14
  import { reconcile, unwrap } from "solid-js/store";
12
15
  import { createControllableStore } from "../../../hooks/createControllableStore";
13
16
  import { objClone, objEqual } from "@simplysm/core-common";
@@ -19,6 +22,7 @@ import { createTopbarActions, TopbarContext } from "../../layout/topbar/TopbarCo
19
22
  import { useDialogInstance } from "../../disclosure/DialogInstanceContext";
20
23
  import { Dialog } from "../../disclosure/Dialog";
21
24
  import { createEventListener } from "@solid-primitives/event-listener";
25
+ import { useI18nOptional } from "../../../providers/i18n/I18nContext";
22
26
  import clsx from "clsx";
23
27
  import {
24
28
  IconCheck,
@@ -60,6 +64,7 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
60
64
  ]);
61
65
 
62
66
  const noti = useNotification();
67
+ const i18n = useI18nOptional();
63
68
  const topbarCtx = useContext(TopbarContext);
64
69
  const dialogInstance = useDialogInstance<boolean>();
65
70
 
@@ -80,6 +85,8 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
80
85
 
81
86
  let formRef: HTMLFormElement | undefined;
82
87
 
88
+ const crudId = createUniqueId();
89
+
83
90
  // -- Load --
84
91
  async function doLoad() {
85
92
  setBusyCount((c) => c + 1);
@@ -89,7 +96,7 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
89
96
  originalData = objClone(result.data);
90
97
  setInfo(result.info);
91
98
  } catch (err) {
92
- noti.error(err, "조회실패");
99
+ noti.error(err, i18n?.t("crudDetail.lookupFailed") ?? "Lookup failed");
93
100
  }
94
101
  setBusyCount((c) => c - 1);
95
102
  setReady(true);
@@ -98,6 +105,10 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
98
105
  onMount(() => {
99
106
  void doLoad();
100
107
  });
108
+ onCleanup(() => unregisterCrud(crudId));
109
+
110
+ createEventListener(() => formRef, "pointerdown", () => activateCrud(crudId));
111
+ createEventListener(() => formRef, "focusin", () => activateCrud(crudId));
101
112
 
102
113
  // -- Change Detection --
103
114
  function hasChanges(): boolean {
@@ -108,7 +119,7 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
108
119
  // -- Refresh --
109
120
  async function handleRefresh() {
110
121
  if (hasChanges()) {
111
- if (!confirm("변경사항을 무시하시겠습니까?")) return;
122
+ if (!confirm(i18n?.t("crudDetail.discardChanges") ?? "Discard changes?")) return;
112
123
  }
113
124
  await doLoad();
114
125
  }
@@ -120,7 +131,7 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
120
131
 
121
132
  const currentInfo = info();
122
133
  if (currentInfo && !currentInfo.isNew && !hasChanges()) {
123
- noti.info("안내", "변경사항이 없습니다.");
134
+ noti.info(i18n?.t("crudDetail.notice") ?? "Notice", i18n?.t("crudDetail.noChanges") ?? "No changes to save.");
124
135
  return;
125
136
  }
126
137
 
@@ -128,7 +139,7 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
128
139
  try {
129
140
  const result = await local.submit(objClone(unwrap(data)));
130
141
  if (result) {
131
- noti.success("저장 완료", "저장되었습니다.");
142
+ noti.success(i18n?.t("crudDetail.saveCompleted") ?? "Save completed", i18n?.t("crudDetail.saveSuccess") ?? "Saved successfully.");
132
143
  if (dialogInstance) {
133
144
  dialogInstance.close(true);
134
145
  } else {
@@ -136,7 +147,7 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
136
147
  }
137
148
  }
138
149
  } catch (err) {
139
- noti.error(err, "저장 실패");
150
+ noti.error(err, i18n?.t("crudDetail.saveFailed") ?? "Save failed");
140
151
  }
141
152
  setBusyCount((c) => c - 1);
142
153
  }
@@ -160,7 +171,7 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
160
171
  try {
161
172
  const result = await local.toggleDelete(del);
162
173
  if (result) {
163
- noti.success(del ? "삭제 완료" : "복구 완료", del ? "삭제되었습니다." : "복구되었습니다.");
174
+ noti.success(del ? (i18n?.t("crudDetail.deleteCompleted") ?? "Delete completed") : (i18n?.t("crudDetail.restoreCompleted") ?? "Restore completed"), del ? (i18n?.t("crudDetail.deleteSuccess") ?? "Deleted successfully.") : (i18n?.t("crudDetail.restoreSuccess") ?? "Restored successfully."));
164
175
  if (dialogInstance) {
165
176
  dialogInstance.close(true);
166
177
  } else {
@@ -168,20 +179,22 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
168
179
  }
169
180
  }
170
181
  } catch (err) {
171
- noti.error(err, del ? "삭제 실패" : "복구 실패");
182
+ noti.error(err, del ? (i18n?.t("crudDetail.deleteFailed") ?? "Delete failed") : (i18n?.t("crudDetail.restoreFailed") ?? "Restore failed"));
172
183
  }
173
184
  setBusyCount((c) => c - 1);
174
185
  }
175
186
 
176
187
  // -- Keyboard Shortcuts --
177
188
  createEventListener(document, "keydown", (e: KeyboardEvent) => {
178
- if (!formRef?.contains(document.activeElement)) return;
189
+ if (!isActiveCrud(crudId)) return;
179
190
  if (e.ctrlKey && e.key === "s") {
180
191
  e.preventDefault();
181
- formRef.requestSubmit();
192
+ e.stopImmediatePropagation();
193
+ formRef?.requestSubmit();
182
194
  }
183
195
  if (e.ctrlKey && e.altKey && e.key === "l") {
184
196
  e.preventDefault();
197
+ e.stopImmediatePropagation();
185
198
  void handleRefresh();
186
199
  }
187
200
  });
@@ -198,7 +211,7 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
198
211
  onClick={() => formRef?.requestSubmit()}
199
212
  >
200
213
  <Icon icon={IconDeviceFloppy} class="mr-1" />
201
- 저장
214
+ {i18n?.t("crudDetail.save") ?? "Save"}
202
215
  </Button>
203
216
  </Show>
204
217
  <Show
@@ -214,13 +227,13 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
214
227
  onClick={() => void handleToggleDelete()}
215
228
  >
216
229
  <Icon icon={info()!.isDeleted ? IconTrashOff : IconTrash} class="mr-1" />
217
- {info()!.isDeleted ? "복구" : "삭제"}
230
+ {info()!.isDeleted ? (i18n?.t("crudDetail.restore") ?? "Restore") : (i18n?.t("crudDetail.delete") ?? "Delete")}
218
231
  </Button>
219
232
  )}
220
233
  </Show>
221
234
  <Button size="lg" variant="ghost" theme="info" onClick={() => void handleRefresh()}>
222
235
  <Icon icon={IconRefresh} class="mr-1" />
223
- 새로고침
236
+ {i18n?.t("crudDetail.refresh") ?? "Refresh"}
224
237
  </Button>
225
238
  </>
226
239
  ));
@@ -271,11 +284,11 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
271
284
  <BusyContainer
272
285
  ready={ready()}
273
286
  busy={busyCount() > 0}
274
- class={clsx("flex h-full flex-col", local.class)}
287
+ class={clsx("flex h-full flex-col gap-2", local.class)}
275
288
  >
276
289
  {/* Toolbar */}
277
290
  <Show when={(!isModal && !topbarCtx) || defs().tools}>
278
- <div class="flex gap-2 p-2 pb-0">
291
+ <div class="flex gap-2 pb-0">
279
292
  <Show when={!topbarCtx && !isModal}>
280
293
  <Show when={canEdit() && local.submit}>
281
294
  <Button
@@ -285,7 +298,7 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
285
298
  onClick={() => formRef?.requestSubmit()}
286
299
  >
287
300
  <Icon icon={IconDeviceFloppy} class="mr-1" />
288
- 저장
301
+ {i18n?.t("crudDetail.save") ?? "Save"}
289
302
  </Button>
290
303
  </Show>
291
304
  <Show
@@ -305,13 +318,13 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
305
318
  onClick={() => void handleToggleDelete()}
306
319
  >
307
320
  <Icon icon={info()!.isDeleted ? IconTrashOff : IconTrash} class="mr-1" />
308
- {info()!.isDeleted ? "복구" : "삭제"}
321
+ {info()!.isDeleted ? (i18n?.t("crudDetail.restore") ?? "Restore") : (i18n?.t("crudDetail.delete") ?? "Delete")}
309
322
  </Button>
310
323
  )}
311
324
  </Show>
312
325
  <Button size="sm" theme="info" variant="ghost" onClick={() => void handleRefresh()}>
313
326
  <Icon icon={IconRefresh} class="mr-1" />
314
- 새로고침
327
+ {i18n?.t("crudDetail.refresh") ?? "Refresh"}
315
328
  </Button>
316
329
  </Show>
317
330
  <Show when={defs().tools}>{(toolsDef) => toolsDef().children}</Show>
@@ -322,7 +335,7 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
322
335
  <Show when={defs().before}>{(beforeDef) => beforeDef().children}</Show>
323
336
 
324
337
  {/* Form */}
325
- <form ref={formRef} class="flex-1 overflow-auto p-4" onSubmit={handleFormSubmit}>
338
+ <form ref={(el) => { formRef = el; registerCrud(crudId, el); }} class="flex-1 overflow-auto" onSubmit={handleFormSubmit}>
326
339
  {formContent()}
327
340
  </form>
328
341
 
@@ -330,7 +343,7 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
330
343
  <Show when={info()?.lastModifiedAt}>
331
344
  {(_) => (
332
345
  <div class="px-2 pb-1 text-xs text-base-400">
333
- 최종 수정: {info()!.lastModifiedAt!.toFormatString("yyyy-MM-dd HH:mm")}
346
+ {i18n?.t("crudDetail.lastModified") ?? "Last modified"}: {info()!.lastModifiedAt!.toFormatString("yyyy-MM-dd HH:mm")}
334
347
  <Show when={info()?.lastModifiedBy}> ({info()!.lastModifiedBy})</Show>
335
348
  </div>
336
349
  )}
@@ -349,7 +362,7 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
349
362
  {(_) => (
350
363
  <Button variant={"solid"} theme="danger" onClick={() => void handleToggleDelete()}>
351
364
  <Icon icon={info()!.isDeleted ? IconTrashOff : IconTrash} class="mr-1" />
352
- {info()!.isDeleted ? "복구" : "삭제"}
365
+ {info()!.isDeleted ? (i18n?.t("crudDetail.restore") ?? "Restore") : (i18n?.t("crudDetail.delete") ?? "Delete")}
353
366
  </Button>
354
367
  )}
355
368
  </Show>
@@ -361,7 +374,7 @@ const CrudDetailBase = <TData extends object>(props: CrudDetailProps<TData>) =>
361
374
  class={"gap-1"}
362
375
  >
363
376
  <Icon icon={IconCheck} />
364
- 확인
377
+ {i18n?.t("crudDetail.confirm") ?? "Confirm"}
365
378
  </Button>
366
379
  </Show>
367
380
  </div>
@@ -9,7 +9,7 @@ export function isCrudDetailAfterDef(value: unknown): value is CrudDetailAfterDe
9
9
  );
10
10
  }
11
11
 
12
- /* eslint-disable solid/reactivity -- plain object 반환 패턴으로 reactive context 불필요 */
12
+ /* eslint-disable solid/reactivity -- plain object return pattern does not require reactive context */
13
13
  export function CrudDetailAfter(props: { children: JSX.Element }): JSX.Element {
14
14
  return {
15
15
  __type: "crud-detail-after",
@@ -9,7 +9,7 @@ export function isCrudDetailBeforeDef(value: unknown): value is CrudDetailBefore
9
9
  );
10
10
  }
11
11
 
12
- /* eslint-disable solid/reactivity -- plain object 반환 패턴으로 reactive context 불필요 */
12
+ /* eslint-disable solid/reactivity -- plain object return pattern does not require reactive context */
13
13
  export function CrudDetailBefore(props: { children: JSX.Element }): JSX.Element {
14
14
  return {
15
15
  __type: "crud-detail-before",
@@ -9,7 +9,7 @@ export function isCrudDetailToolsDef(value: unknown): value is CrudDetailToolsDe
9
9
  );
10
10
  }
11
11
 
12
- /* eslint-disable solid/reactivity -- plain object 반환 패턴으로 reactive context 불필요 */
12
+ /* eslint-disable solid/reactivity -- plain object return pattern does not require reactive context */
13
13
  export function CrudDetailTools(props: { children: JSX.Element }): JSX.Element {
14
14
  return {
15
15
  __type: "crud-detail-tools",
@@ -3,8 +3,10 @@ import {
3
3
  createEffect,
4
4
  createMemo,
5
5
  createSignal,
6
+ createUniqueId,
6
7
  For,
7
8
  type JSX,
9
+ onCleanup,
8
10
  Show,
9
11
  splitProps,
10
12
  useContext,
@@ -19,6 +21,7 @@ import { DataSheet } from "../../data/sheet/DataSheet";
19
21
  import { DataSheetColumn } from "../../data/sheet/DataSheetColumn";
20
22
  import { BusyContainer } from "../../feedback/busy/BusyContainer";
21
23
  import { useNotification } from "../../feedback/notification/NotificationContext";
24
+ import { useI18nOptional } from "../../../providers/i18n/I18nContext";
22
25
  import { Button } from "../../form-control/Button";
23
26
  import { Icon } from "../../display/Icon";
24
27
  import { FormGroup } from "../../layout/FormGroup";
@@ -40,6 +43,7 @@ import {
40
43
  IconTrashOff,
41
44
  IconUpload,
42
45
  } from "@tabler/icons-solidjs";
46
+ import { registerCrud, unregisterCrud, activateCrud, isActiveCrud } from "../crudRegistry";
43
47
  import { CrudSheetColumn, isCrudSheetColumnDef } from "./CrudSheetColumn";
44
48
  import { CrudSheetFilter, isCrudSheetFilterDef } from "./CrudSheetFilter";
45
49
  import { CrudSheetTools, isCrudSheetToolsDef } from "./CrudSheetTools";
@@ -91,6 +95,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
91
95
  ]);
92
96
 
93
97
  const noti = useNotification();
98
+ const i18n = useI18nOptional();
94
99
  const topbarCtx = useContext(TopbarContext);
95
100
  const dialogInstance = useDialogInstance();
96
101
  const isModal = dialogInstance !== undefined;
@@ -116,7 +121,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
116
121
  });
117
122
  let originalItems: TItem[] = [];
118
123
 
119
- // eslint-disable-next-line solid/reactivity -- filterInitial 초기값으로만 사용
124
+ // eslint-disable-next-line solid/reactivity -- filterInitial is used only for initial value
120
125
  const [filter, setFilter] = createStore<TFilter>((local.filterInitial ?? {}) as TFilter);
121
126
  const [lastFilter, setLastFilter] = createSignal<TFilter>(objClone(filter));
122
127
 
@@ -132,6 +137,11 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
132
137
 
133
138
  let formRef: HTMLFormElement | undefined;
134
139
 
140
+ const crudId = createUniqueId();
141
+ onCleanup(() => unregisterCrud(crudId));
142
+ createEventListener(() => formRef, "pointerdown", () => activateCrud(crudId));
143
+ createEventListener(() => formRef, "focusin", () => activateCrud(crudId));
144
+
135
145
  createEffect(() => {
136
146
  void doRefresh();
137
147
  });
@@ -158,7 +168,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
158
168
  try {
159
169
  await refresh();
160
170
  } catch (err) {
161
- noti.error(err, "조회 실패");
171
+ noti.error(err, i18n?.t("crudSheet.lookupFailed") ?? "Lookup failed");
162
172
  }
163
173
  setBusyCount((c) => c - 1);
164
174
  setReady(true);
@@ -171,7 +181,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
171
181
  setTotalPageCount(result.pageCount ?? 0);
172
182
  }
173
183
 
174
- /* eslint-disable solid/reactivity -- 이벤트 핸들러에서만 호출, store 즉시 읽기 */
184
+ /* eslint-disable solid/reactivity -- called only in event handlers, immediate store read */
175
185
  function getItemDiffs() {
176
186
  return items.oneWayDiffs(originalItems, (item) => local.getItemKey(item), {
177
187
  excludes: local.inlineEdit?.diffsExcludes,
@@ -182,7 +192,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
182
192
  function checkIgnoreChanges(): boolean {
183
193
  if (!local.inlineEdit) return true;
184
194
  if (getItemDiffs().length === 0) return true;
185
- return confirm("변경사항이 있습니다. 무시하시겠습니까?");
195
+ return confirm(i18n?.t("crudSheet.discardChanges") ?? "You have unsaved changes. Discard them?");
186
196
  }
187
197
 
188
198
  // -- Filter --
@@ -233,18 +243,18 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
233
243
  const diffs = getItemDiffs();
234
244
 
235
245
  if (diffs.length === 0) {
236
- noti.info("안내", "변경사항이 없습니다.");
246
+ noti.info(i18n?.t("crudSheet.notice") ?? "Notice", i18n?.t("crudSheet.noChanges") ?? "No changes to save.");
237
247
  return;
238
248
  }
239
249
 
240
250
  setBusyCount((c) => c + 1);
241
251
  try {
242
252
  await local.inlineEdit.submit(diffs);
243
- noti.success("저장 완료", "저장되었습니다.");
253
+ noti.success(i18n?.t("crudSheet.saveCompleted") ?? "Save completed", i18n?.t("crudSheet.saveSuccess") ?? "Saved successfully.");
244
254
  await refresh();
245
255
  local.onSubmitted?.();
246
256
  } catch (err) {
247
- noti.error(err, "저장 실패");
257
+ noti.error(err, i18n?.t("crudSheet.saveFailed") ?? "Save failed");
248
258
  }
249
259
  setBusyCount((c) => c - 1);
250
260
  }
@@ -264,7 +274,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
264
274
  try {
265
275
  await refresh();
266
276
  } catch (err) {
267
- noti.error(err, "조회 실패");
277
+ noti.error(err, i18n?.t("crudSheet.lookupFailed") ?? "Lookup failed");
268
278
  }
269
279
  setBusyCount((c) => c - 1);
270
280
  }
@@ -277,9 +287,9 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
277
287
  setBusyCount((c) => c + 1);
278
288
  try {
279
289
  await refresh();
280
- noti.success("삭제 완료", "삭제되었습니다.");
290
+ noti.success(i18n?.t("crudSheet.deleteCompleted") ?? "Delete completed", i18n?.t("crudSheet.deleteSuccess") ?? "Deleted successfully.");
281
291
  } catch (err) {
282
- noti.error(err, "삭제 실패");
292
+ noti.error(err, i18n?.t("crudSheet.deleteFailed") ?? "Delete failed");
283
293
  }
284
294
  setBusyCount((c) => c - 1);
285
295
  }
@@ -292,9 +302,9 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
292
302
  setBusyCount((c) => c + 1);
293
303
  try {
294
304
  await refresh();
295
- noti.success("복구 완료", "복구되었습니다.");
305
+ noti.success(i18n?.t("crudSheet.restoreCompleted") ?? "Restore completed", i18n?.t("crudSheet.restoreSuccess") ?? "Restored successfully.");
296
306
  } catch (err) {
297
- noti.error(err, "복구 실패");
307
+ noti.error(err, i18n?.t("crudSheet.restoreFailed") ?? "Restore failed");
298
308
  }
299
309
  setBusyCount((c) => c - 1);
300
310
  }
@@ -308,7 +318,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
308
318
  const result = await local.search(lastFilter(), undefined, sorts());
309
319
  await local.excel.download(result.items);
310
320
  } catch (err) {
311
- noti.error(err, "엑셀 다운로드 실패");
321
+ noti.error(err, i18n?.t("crudSheet.excelDownloadFailed") ?? "Excel download failed");
312
322
  }
313
323
  setBusyCount((c) => c - 1);
314
324
  }
@@ -326,10 +336,10 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
326
336
  setBusyCount((c) => c + 1);
327
337
  try {
328
338
  await local.excel!.upload!(file);
329
- noti.success("완료", "엑셀 업로드가 완료되었습니다.");
339
+ noti.success(i18n?.t("crudSheet.excelCompleted") ?? "Completed", i18n?.t("crudSheet.excelUploadSuccess") ?? "Excel upload completed successfully.");
330
340
  await refresh();
331
341
  } catch (err) {
332
- noti.error(err, "엑셀 업로드 실패");
342
+ noti.error(err, i18n?.t("crudSheet.excelUploadFailed") ?? "Excel upload failed");
333
343
  }
334
344
  setBusyCount((c) => c - 1);
335
345
  };
@@ -338,7 +348,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
338
348
 
339
349
  // -- Select Mode --
340
350
  function handleSelectedItemsChange(newSelectedItems: TItem[]) {
341
- // 현재 페이지 아이템들의 key Set
351
+ // Current page items key Set
342
352
  const currentItems = items as unknown as TItem[];
343
353
  const currentKeys = new Set<string | number>();
344
354
  for (const item of currentItems) {
@@ -346,22 +356,22 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
346
356
  if (key != null) currentKeys.add(key);
347
357
  }
348
358
 
349
- // 새로 선택된 아이템들의 key
359
+ // Newly selected items key
350
360
  const newSelectedKeys = new Set<string | number>();
351
361
  for (const item of newSelectedItems) {
352
362
  const key = local.getItemKey(item);
353
363
  if (key != null) newSelectedKeys.add(key);
354
364
  }
355
365
 
356
- // 다른 페이지 key 보존 + 현재 페이지 key 갱신
366
+ // Preserve other page keys + update current page keys
357
367
  const merged = new Set<string | number>();
358
368
  for (const key of selectedKeys()) {
359
369
  if (!currentKeys.has(key)) {
360
- merged.add(key); // 다른 페이지 key 보존
370
+ merged.add(key); // Preserve other page keys
361
371
  }
362
372
  }
363
373
  for (const key of newSelectedKeys) {
364
- merged.add(key); // 현재 페이지 선택 추가
374
+ merged.add(key); // Add current page selection
365
375
  }
366
376
 
367
377
  setSelectedKeys(merged);
@@ -387,20 +397,22 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
387
397
 
388
398
  // -- Keyboard Shortcuts --
389
399
  createEventListener(document, "keydown", async (e: KeyboardEvent) => {
390
- if (!formRef?.contains(document.activeElement)) return;
400
+ if (!isActiveCrud(crudId)) return;
391
401
  if (e.ctrlKey && e.key === "s" && !isSelectMode()) {
392
402
  e.preventDefault();
393
- formRef.requestSubmit();
403
+ e.stopImmediatePropagation();
404
+ formRef?.requestSubmit();
394
405
  }
395
406
  if (e.ctrlKey && e.altKey && e.key === "l") {
396
407
  e.preventDefault();
408
+ e.stopImmediatePropagation();
397
409
  if (!checkIgnoreChanges()) return;
398
410
  await doRefresh();
399
411
  }
400
412
  });
401
413
 
402
414
  // -- Route Leave Guard --
403
- // eslint-disable-next-line solid/reactivity -- inlineEdit 초기 설정값으로만 사용
415
+ // eslint-disable-next-line solid/reactivity -- inlineEdit is used only for initial value
404
416
  if (!isModal && local.inlineEdit) {
405
417
  try {
406
418
  useBeforeLeave((e) => {
@@ -409,7 +421,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
409
421
  }
410
422
  });
411
423
  } catch {
412
- // Router context 없으면 skip
424
+ // Skip if no Router context
413
425
  }
414
426
  }
415
427
 
@@ -425,12 +437,12 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
425
437
  onClick={() => formRef?.requestSubmit()}
426
438
  >
427
439
  <Icon icon={IconDeviceFloppy} class="mr-1" />
428
- 저장
440
+ {i18n?.t("crudSheet.save") ?? "Save"}
429
441
  </Button>
430
442
  </Show>
431
443
  <Button size="lg" variant="ghost" theme="info" onClick={handleRefresh}>
432
444
  <Icon icon={IconRefresh} class="mr-1" />
433
- 새로고침
445
+ {i18n?.t("crudSheet.refresh") ?? "Refresh"}
434
446
  </Button>
435
447
  </>
436
448
  ));
@@ -491,12 +503,12 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
491
503
  onClick={() => formRef?.requestSubmit()}
492
504
  >
493
505
  <Icon icon={IconDeviceFloppy} class="mr-1" />
494
- 저장
506
+ {i18n?.t("crudSheet.save") ?? "Save"}
495
507
  </Button>
496
508
  </Show>
497
509
  <Button size="sm" theme="info" variant="ghost" onClick={handleRefresh}>
498
510
  <Icon icon={IconRefresh} class="mr-1" />
499
- 새로고침
511
+ {i18n?.t("crudSheet.refresh") ?? "Refresh"}
500
512
  </Button>
501
513
  </div>
502
514
  </Show>
@@ -512,7 +524,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
512
524
  <FormGroup.Item>
513
525
  <Button type="submit" theme="info" variant="solid">
514
526
  <Icon icon={IconSearch} class="mr-1" />
515
- 조회
527
+ {i18n?.t("crudSheet.search") ?? "Search"}
516
528
  </Button>
517
529
  </FormGroup.Item>
518
530
  {filterDef().children(filter, setFilter)}
@@ -528,7 +540,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
528
540
  {/* Inline edit buttons */}
529
541
  <Show when={canEdit() && local.inlineEdit}>
530
542
  <Button size="sm" theme="primary" variant="ghost" onClick={handleAddRow}>
531
- <Icon icon={IconPlus} class="mr-1" />행 추가
543
+ <Icon icon={IconPlus} class="mr-1" />{i18n?.t("crudSheet.addRow") ?? "Add Row"}
532
544
  </Button>
533
545
  </Show>
534
546
 
@@ -541,7 +553,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
541
553
  onClick={() => void handleEditItem()}
542
554
  >
543
555
  <Icon icon={IconPlus} class="mr-1" />
544
- 등록
556
+ {i18n?.t("crudSheet.register") ?? "Register"}
545
557
  </Button>
546
558
  </Show>
547
559
  <Show when={canEdit() && local.modalEdit?.deleteItems}>
@@ -560,7 +572,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
560
572
  }
561
573
  >
562
574
  <Icon icon={IconTrash} class="mr-1" />
563
- 선택 삭제
575
+ {i18n?.t("crudSheet.deleteSelected") ?? "Delete Selected"}
564
576
  </Button>
565
577
  </Show>
566
578
  <Show when={canEdit() && local.modalEdit?.restoreItems}>
@@ -575,7 +587,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
575
587
  }
576
588
  >
577
589
  <Icon icon={IconTrashOff} class="mr-1" />
578
- 선택 복구
590
+ {i18n?.t("crudSheet.restoreSelected") ?? "Restore Selected"}
579
591
  </Button>
580
592
  </Show>
581
593
 
@@ -583,13 +595,13 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
583
595
  <Show when={canEdit() && local.excel?.upload}>
584
596
  <Button size="sm" theme="success" variant="ghost" onClick={handleExcelUpload}>
585
597
  <Icon icon={IconUpload} class="mr-1" />
586
- 엑셀 업로드
598
+ {i18n?.t("crudSheet.excelUpload") ?? "Excel Upload"}
587
599
  </Button>
588
600
  </Show>
589
601
  <Show when={local.excel}>
590
602
  <Button size="sm" theme="success" variant="ghost" onClick={handleExcelDownload}>
591
603
  <Icon icon={IconFileExcel} class="mr-1" />
592
- 엑셀 다운로드
604
+ {i18n?.t("crudSheet.excelDownload") ?? "Excel Download"}
593
605
  </Button>
594
606
  </Show>
595
607
  </Show>
@@ -600,7 +612,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
600
612
  </Show>
601
613
 
602
614
  {/* DataSheet */}
603
- <form ref={formRef} class="flex-1 overflow-hidden p-2 pt-1" onSubmit={handleFormSubmit}>
615
+ <form ref={(el) => { formRef = el; registerCrud(crudId, el); }} class="flex-1 overflow-hidden p-2 pt-1" onSubmit={handleFormSubmit}>
604
616
  <DataSheet
605
617
  class="h-full"
606
618
  items={items}
@@ -709,7 +721,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
709
721
 
710
722
  {/* Auto lastModified columns */}
711
723
  <Show when={local.lastModifiedAtProp}>
712
- <DataSheetColumn<TItem> key={local.lastModifiedAtProp!} header="수정일시" hidden>
724
+ <DataSheetColumn<TItem> key={local.lastModifiedAtProp!} header={i18n?.t("crudSheet.lastModified") ?? "Last Modified"} hidden>
713
725
  {(dsCtx) => (
714
726
  <div class="px-2 py-1 text-center">
715
727
  {(
@@ -723,7 +735,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
723
735
  </Show>
724
736
 
725
737
  <Show when={local.lastModifiedByProp}>
726
- <DataSheetColumn<TItem> key={local.lastModifiedByProp!} header="수정자" hidden>
738
+ <DataSheetColumn<TItem> key={local.lastModifiedByProp!} header={i18n?.t("crudSheet.modifiedBy") ?? "Modified By"} hidden>
727
739
  {(dsCtx) => (
728
740
  <div class="px-2 py-1 text-center">
729
741
  {objGetChainValue(dsCtx.item, local.lastModifiedByProp!, true) as string}
@@ -740,12 +752,12 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
740
752
  <div class="flex-1" />
741
753
  <Show when={selectedItems().length > 0}>
742
754
  <Button size="sm" theme="danger" onClick={handleSelectCancel}>
743
- {local.selectMode === "multiple" ? "모두" : "선택"} 해제
755
+ {local.selectMode === "multiple" ? (i18n?.t("crudSheet.deselectAll") ?? "Deselect All") : (i18n?.t("crudSheet.deselect") ?? "Deselect")}
744
756
  </Button>
745
757
  </Show>
746
758
  <Show when={local.selectMode === "multiple"}>
747
759
  <Button size="sm" theme="primary" onClick={handleSelectConfirm}>
748
- 확인({selectedItems().length})
760
+ {i18n?.t("crudSheet.confirm") ?? "Confirm"} ({selectedItems().length})
749
761
  </Button>
750
762
  </Show>
751
763
  </div>
@@ -10,7 +10,7 @@ export function isCrudSheetColumnDef(value: unknown): value is CrudSheetColumnDe
10
10
  );
11
11
  }
12
12
 
13
- /* eslint-disable solid/reactivity -- plain object 반환 패턴으로 reactive context 불필요 */
13
+ /* eslint-disable solid/reactivity -- plain object return pattern, reactive context not needed */
14
14
  export function CrudSheetColumn<TItem>(props: CrudSheetColumnProps<TItem>): JSX.Element {
15
15
  return {
16
16
  __type: "crud-sheet-column",
@@ -9,7 +9,7 @@ export function isCrudSheetFilterDef(value: unknown): value is CrudSheetFilterDe
9
9
  );
10
10
  }
11
11
 
12
- /* eslint-disable solid/reactivity -- plain object 반환 패턴으로 reactive context 불필요 */
12
+ /* eslint-disable solid/reactivity -- plain object return pattern does not require reactive context */
13
13
  export function CrudSheetFilter<TFilter>(props: {
14
14
  children: (filter: TFilter, setFilter: any) => JSX.Element;
15
15
  }): JSX.Element {
@@ -9,7 +9,7 @@ export function isCrudSheetHeaderDef(value: unknown): value is CrudSheetHeaderDe
9
9
  );
10
10
  }
11
11
 
12
- /* eslint-disable solid/reactivity -- plain object 반환 패턴으로 reactive context 불필요 */
12
+ /* eslint-disable solid/reactivity -- plain object return pattern does not require reactive context */
13
13
  export function CrudSheetHeader(props: { children: JSX.Element }): JSX.Element {
14
14
  return {
15
15
  __type: "crud-sheet-header",
@@ -9,7 +9,7 @@ export function isCrudSheetToolsDef(value: unknown): value is CrudSheetToolsDef<
9
9
  );
10
10
  }
11
11
 
12
- /* eslint-disable solid/reactivity -- plain object 반환 패턴으로 reactive context 불필요 */
12
+ /* eslint-disable solid/reactivity -- plain object return pattern does not require reactive context */
13
13
  export function CrudSheetTools<_TItem>(props: {
14
14
  children: (ctx: any) => JSX.Element;
15
15
  }): JSX.Element {