hakumi_components 0.1.18.pre → 0.1.19.pre

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 (467) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -2
  3. data/README.md +208 -381
  4. data/app/assets/javascripts/hakumi_components.js +40 -34
  5. data/app/assets/stylesheets/hakumi_components.css +1 -1
  6. data/app/components/hakumi_components/admin_panel/component.rb +19 -9
  7. data/app/components/hakumi_components/affix/component.rb +54 -30
  8. data/app/components/hakumi_components/alert/component.html.erb +2 -2
  9. data/app/components/hakumi_components/alert/component.rb +68 -18
  10. data/app/components/hakumi_components/anchor/component.rb +35 -27
  11. data/app/components/hakumi_components/anchor/link/component.html.erb +1 -1
  12. data/app/components/hakumi_components/anchor/link/component.rb +28 -9
  13. data/app/components/hakumi_components/autocomplete/component.html.erb +86 -66
  14. data/app/components/hakumi_components/autocomplete/component.rb +115 -89
  15. data/app/components/hakumi_components/avatar/component.rb +45 -12
  16. data/app/components/hakumi_components/badge/component.rb +99 -45
  17. data/app/components/hakumi_components/base_component.rb +290 -91
  18. data/app/components/hakumi_components/breadcrumb/component.rb +16 -5
  19. data/app/components/hakumi_components/breadcrumb/item/component.html.erb +5 -5
  20. data/app/components/hakumi_components/breadcrumb/item/component.rb +56 -8
  21. data/app/components/hakumi_components/breadcrumb/item/menu_entry.rb +71 -0
  22. data/app/components/hakumi_components/button/component.rb +62 -20
  23. data/app/components/hakumi_components/calendar/component.html.erb +19 -19
  24. data/app/components/hakumi_components/calendar/component.rb +225 -202
  25. data/app/components/hakumi_components/calendar/day_cell.rb +62 -0
  26. data/app/components/hakumi_components/calendar/display_model.rb +237 -0
  27. data/app/components/hakumi_components/calendar/event_entry.rb +54 -0
  28. data/app/components/hakumi_components/calendar/locale_pack.rb +28 -0
  29. data/app/components/hakumi_components/calendar/panel_entry.rb +48 -0
  30. data/app/components/hakumi_components/calendar/week_row.rb +28 -0
  31. data/app/components/hakumi_components/card/component.html.erb +2 -2
  32. data/app/components/hakumi_components/card/component.rb +76 -49
  33. data/app/components/hakumi_components/card/grid/component.html.erb +1 -1
  34. data/app/components/hakumi_components/card/grid/component.rb +23 -17
  35. data/app/components/hakumi_components/card/meta/component.html.erb +8 -8
  36. data/app/components/hakumi_components/card/meta/component.rb +42 -24
  37. data/app/components/hakumi_components/carousel/autoplay_config.rb +27 -0
  38. data/app/components/hakumi_components/carousel/component.rb +85 -67
  39. data/app/components/hakumi_components/carousel/dots_config.rb +36 -0
  40. data/app/components/hakumi_components/cascader/component.html.erb +54 -36
  41. data/app/components/hakumi_components/cascader/component.rb +111 -62
  42. data/app/components/hakumi_components/checkbox/component.html.erb +5 -5
  43. data/app/components/hakumi_components/checkbox/component.rb +40 -6
  44. data/app/components/hakumi_components/checkbox/group/component.html.erb +4 -4
  45. data/app/components/hakumi_components/checkbox/group/component.rb +40 -13
  46. data/app/components/hakumi_components/checkbox/group/option.rb +34 -0
  47. data/app/components/hakumi_components/collapse/component.rb +64 -48
  48. data/app/components/hakumi_components/collapse/panel/component.rb +64 -21
  49. data/app/components/hakumi_components/color_picker/component.html.erb +21 -22
  50. data/app/components/hakumi_components/color_picker/component.rb +159 -49
  51. data/app/components/hakumi_components/color_picker/preset_group.rb +27 -0
  52. data/app/components/hakumi_components/concerns/form_field.rb +169 -68
  53. data/app/components/hakumi_components/concerns/form_field_contract.rb +57 -0
  54. data/app/components/hakumi_components/concerns/form_field_interface.rb +16 -0
  55. data/app/components/hakumi_components/concerns/input_control.rb +111 -0
  56. data/app/components/hakumi_components/concerns/input_control_contract.rb +47 -0
  57. data/app/components/hakumi_components/concerns/input_control_interface.rb +34 -0
  58. data/app/components/hakumi_components/concerns/selection_control.rb +122 -0
  59. data/app/components/hakumi_components/concerns/selection_control_contract.rb +47 -0
  60. data/app/components/hakumi_components/concerns/selection_control_interface.rb +34 -0
  61. data/app/components/hakumi_components/container/component.rb +29 -14
  62. data/app/components/hakumi_components/date_picker/component.html.erb +1 -3
  63. data/app/components/hakumi_components/date_picker/component.rb +130 -16
  64. data/app/components/hakumi_components/date_picker/range_picker.rb +159 -28
  65. data/app/components/hakumi_components/date_picker/shared_rendering.rb +151 -61
  66. data/app/components/hakumi_components/descriptions/component.html.erb +6 -6
  67. data/app/components/hakumi_components/descriptions/component.rb +98 -61
  68. data/app/components/hakumi_components/descriptions/item/component.rb +32 -8
  69. data/app/components/hakumi_components/divider/component.rb +36 -16
  70. data/app/components/hakumi_components/drawer/component.html.erb +2 -2
  71. data/app/components/hakumi_components/drawer/component.rb +112 -29
  72. data/app/components/hakumi_components/dropdown/component.rb +32 -35
  73. data/app/components/hakumi_components/dropdown/divider/component.rb +4 -0
  74. data/app/components/hakumi_components/dropdown/item/component.rb +42 -16
  75. data/app/components/hakumi_components/empty/component.rb +66 -31
  76. data/app/components/hakumi_components/flex/component.rb +39 -21
  77. data/app/components/hakumi_components/float_button/back_top/component.rb +35 -28
  78. data/app/components/hakumi_components/float_button/component.rb +161 -75
  79. data/app/components/hakumi_components/float_button/group/component.rb +85 -98
  80. data/app/components/hakumi_components/float_button/group_cluster/component.rb +46 -54
  81. data/app/components/hakumi_components/float_button/group_spec.rb +259 -0
  82. data/app/components/hakumi_components/float_button/item_spec.rb +115 -0
  83. data/app/components/hakumi_components/float_button/position_config.rb +68 -0
  84. data/app/components/hakumi_components/form/item/component.rb +34 -27
  85. data/app/components/hakumi_components/grid/col/component.rb +88 -17
  86. data/app/components/hakumi_components/grid/row/component.rb +35 -17
  87. data/app/components/hakumi_components/icon/component.rb +49 -49
  88. data/app/components/hakumi_components/image/component.html.erb +7 -7
  89. data/app/components/hakumi_components/image/component.rb +103 -40
  90. data/app/components/hakumi_components/image/preview_group/component.html.erb +1 -1
  91. data/app/components/hakumi_components/image/preview_group/component.rb +41 -36
  92. data/app/components/hakumi_components/image/preview_group/item.rb +48 -0
  93. data/app/components/hakumi_components/input/component.html.erb +1 -1
  94. data/app/components/hakumi_components/input/component.rb +142 -66
  95. data/app/components/hakumi_components/input/password/component.rb +30 -41
  96. data/app/components/hakumi_components/input/text_area/component.html.erb +2 -2
  97. data/app/components/hakumi_components/input/text_area/component.rb +89 -42
  98. data/app/components/hakumi_components/input_number/component.html.erb +5 -5
  99. data/app/components/hakumi_components/input_number/component.rb +137 -55
  100. data/app/components/hakumi_components/layout/component.html.erb +1 -1
  101. data/app/components/hakumi_components/layout/component.rb +23 -16
  102. data/app/components/hakumi_components/layout/content/component.html.erb +1 -1
  103. data/app/components/hakumi_components/layout/content/component.rb +24 -14
  104. data/app/components/hakumi_components/layout/footer/component.html.erb +1 -1
  105. data/app/components/hakumi_components/layout/footer/component.rb +24 -14
  106. data/app/components/hakumi_components/layout/header/component.html.erb +1 -1
  107. data/app/components/hakumi_components/layout/header/component.rb +24 -14
  108. data/app/components/hakumi_components/layout/sider/component.html.erb +1 -1
  109. data/app/components/hakumi_components/layout/sider/component.rb +83 -49
  110. data/app/components/hakumi_components/mentions/coercion.rb +46 -0
  111. data/app/components/hakumi_components/mentions/component.html.erb +6 -6
  112. data/app/components/hakumi_components/mentions/component.rb +131 -67
  113. data/app/components/hakumi_components/mentions/option.rb +30 -0
  114. data/app/components/hakumi_components/menu/component.rb +50 -59
  115. data/app/components/hakumi_components/menu/divider/component.rb +4 -0
  116. data/app/components/hakumi_components/menu/group/component.rb +16 -15
  117. data/app/components/hakumi_components/menu/item/component.rb +42 -19
  118. data/app/components/hakumi_components/menu/sub_menu/component.rb +49 -37
  119. data/app/components/hakumi_components/message/component.rb +62 -27
  120. data/app/components/hakumi_components/modal/component.html.erb +6 -6
  121. data/app/components/hakumi_components/modal/component.rb +93 -40
  122. data/app/components/hakumi_components/modal/confirm/component.html.erb +2 -2
  123. data/app/components/hakumi_components/modal/confirm/component.rb +49 -8
  124. data/app/components/hakumi_components/modal/error/component.rb +8 -39
  125. data/app/components/hakumi_components/modal/info/component.rb +6 -40
  126. data/app/components/hakumi_components/modal/status_component.rb +150 -0
  127. data/app/components/hakumi_components/modal/success/component.rb +6 -40
  128. data/app/components/hakumi_components/modal/warning/component.rb +14 -44
  129. data/app/components/hakumi_components/notification/component.rb +72 -38
  130. data/app/components/hakumi_components/pagination/component.html.erb +7 -11
  131. data/app/components/hakumi_components/pagination/component.rb +105 -72
  132. data/app/components/hakumi_components/pagination/page_item.rb +49 -0
  133. data/app/components/hakumi_components/popconfirm/component.rb +67 -19
  134. data/app/components/hakumi_components/popover/component.html.erb +2 -2
  135. data/app/components/hakumi_components/popover/component.rb +102 -38
  136. data/app/components/hakumi_components/progress/attribute_renderer.rb +354 -0
  137. data/app/components/hakumi_components/progress/circle_geometry.rb +76 -0
  138. data/app/components/hakumi_components/progress/component.html.erb +18 -17
  139. data/app/components/hakumi_components/progress/component.rb +230 -402
  140. data/app/components/hakumi_components/progress/controller_locals_parser.rb +130 -0
  141. data/app/components/hakumi_components/progress/info_tooltip_policy.rb +39 -0
  142. data/app/components/hakumi_components/progress/info_value.rb +75 -0
  143. data/app/components/hakumi_components/progress/status_state.rb +31 -0
  144. data/app/components/hakumi_components/progress/steps_renderer.rb +149 -0
  145. data/app/components/hakumi_components/progress/stroke_gradient_value.rb +90 -0
  146. data/app/components/hakumi_components/qr_code/component.rb +138 -72
  147. data/app/components/hakumi_components/radio/component.html.erb +3 -3
  148. data/app/components/hakumi_components/radio/component.rb +42 -9
  149. data/app/components/hakumi_components/radio/group/component.html.erb +9 -9
  150. data/app/components/hakumi_components/radio/group/component.rb +76 -27
  151. data/app/components/hakumi_components/radio/group/option.rb +43 -0
  152. data/app/components/hakumi_components/rate/component.html.erb +1 -1
  153. data/app/components/hakumi_components/rate/component.rb +55 -9
  154. data/app/components/hakumi_components/result/component.rb +87 -37
  155. data/app/components/hakumi_components/segmented/component.html.erb +1 -1
  156. data/app/components/hakumi_components/segmented/component.rb +81 -118
  157. data/app/components/hakumi_components/segmented/option.rb +191 -0
  158. data/app/components/hakumi_components/select/component.html.erb +19 -19
  159. data/app/components/hakumi_components/select/component.rb +88 -37
  160. data/app/components/hakumi_components/selection_control/coercion.rb +161 -0
  161. data/app/components/hakumi_components/selection_control/entry.rb +22 -0
  162. data/app/components/hakumi_components/selection_control/option.rb +42 -0
  163. data/app/components/hakumi_components/selection_control/option_group.rb +34 -0
  164. data/app/components/hakumi_components/selection_control/tree_node.rb +123 -0
  165. data/app/components/hakumi_components/skeleton/avatar/component.rb +36 -14
  166. data/app/components/hakumi_components/skeleton/avatar_config.rb +79 -0
  167. data/app/components/hakumi_components/skeleton/button/component.rb +32 -14
  168. data/app/components/hakumi_components/skeleton/component.rb +79 -93
  169. data/app/components/hakumi_components/skeleton/image/component.rb +46 -22
  170. data/app/components/hakumi_components/skeleton/input/component.rb +25 -10
  171. data/app/components/hakumi_components/skeleton/node/component.rb +23 -7
  172. data/app/components/hakumi_components/skeleton/paragraph_config.rb +92 -0
  173. data/app/components/hakumi_components/skeleton/title_config.rb +31 -0
  174. data/app/components/hakumi_components/slider/component.html.erb +11 -11
  175. data/app/components/hakumi_components/slider/component.rb +172 -53
  176. data/app/components/hakumi_components/slider/mark.rb +27 -0
  177. data/app/components/hakumi_components/space/compact/component.html.erb +1 -3
  178. data/app/components/hakumi_components/space/compact/component.rb +35 -19
  179. data/app/components/hakumi_components/space/component.html.erb +1 -1
  180. data/app/components/hakumi_components/space/component.rb +75 -39
  181. data/app/components/hakumi_components/spin/component.rb +92 -31
  182. data/app/components/hakumi_components/splitter/component.html.erb +9 -3
  183. data/app/components/hakumi_components/splitter/component.rb +55 -22
  184. data/app/components/hakumi_components/splitter/panel/component.html.erb +1 -3
  185. data/app/components/hakumi_components/splitter/panel/component.rb +64 -39
  186. data/app/components/hakumi_components/statistic/component.rb +143 -59
  187. data/app/components/hakumi_components/steps/component.rb +87 -55
  188. data/app/components/hakumi_components/steps/item/component.rb +59 -20
  189. data/app/components/hakumi_components/switch/component.html.erb +2 -3
  190. data/app/components/hakumi_components/switch/component.rb +62 -36
  191. data/app/components/hakumi_components/table/column/component.rb +80 -23
  192. data/app/components/hakumi_components/table/column_definition.rb +181 -0
  193. data/app/components/hakumi_components/table/column_group/component.rb +32 -21
  194. data/app/components/hakumi_components/table/component.html.erb +22 -31
  195. data/app/components/hakumi_components/table/component.rb +248 -509
  196. data/app/components/hakumi_components/table/concerns/attribute_helpers.rb +22 -0
  197. data/app/components/hakumi_components/table/concerns/cell_rendering.rb +277 -0
  198. data/app/components/hakumi_components/table/concerns/columns.rb +293 -91
  199. data/app/components/hakumi_components/table/concerns/editable.rb +36 -89
  200. data/app/components/hakumi_components/table/concerns/ellipsis.rb +31 -30
  201. data/app/components/hakumi_components/table/concerns/fixed_columns.rb +26 -19
  202. data/app/components/hakumi_components/table/concerns/surface_rendering.rb +365 -0
  203. data/app/components/hakumi_components/table/configs.rb +518 -0
  204. data/app/components/hakumi_components/table/definition_types.rb +40 -0
  205. data/app/components/hakumi_components/table/display_rows.rb +56 -0
  206. data/app/components/hakumi_components/table/ellipsis_config.rb +143 -0
  207. data/app/components/hakumi_components/table/fixed_offset.rb +36 -0
  208. data/app/components/hakumi_components/table/header_cell.rb +23 -0
  209. data/app/components/hakumi_components/table/row_record.rb +60 -0
  210. data/app/components/hakumi_components/table/row_render_state.rb +85 -0
  211. data/app/components/hakumi_components/tabs/component.html.erb +8 -8
  212. data/app/components/hakumi_components/tabs/component.rb +114 -64
  213. data/app/components/hakumi_components/tabs/indicator_config.rb +34 -0
  214. data/app/components/hakumi_components/tabs/item/component.rb +73 -13
  215. data/app/components/hakumi_components/tag/component.rb +142 -47
  216. data/app/components/hakumi_components/tag/group/component.rb +18 -6
  217. data/app/components/hakumi_components/time_picker/component.html.erb +8 -8
  218. data/app/components/hakumi_components/time_picker/component.rb +71 -17
  219. data/app/components/hakumi_components/timeline/component.html.erb +3 -2
  220. data/app/components/hakumi_components/timeline/component.rb +188 -55
  221. data/app/components/hakumi_components/timeline/item/component.html.erb +2 -2
  222. data/app/components/hakumi_components/timeline/item/component.rb +121 -60
  223. data/app/components/hakumi_components/tooltip/component.html.erb +1 -1
  224. data/app/components/hakumi_components/tooltip/component.rb +89 -64
  225. data/app/components/hakumi_components/tour/component.rb +74 -49
  226. data/app/components/hakumi_components/tour/step.rb +86 -0
  227. data/app/components/hakumi_components/transfer/coercion.rb +66 -0
  228. data/app/components/hakumi_components/transfer/component.html.erb +171 -140
  229. data/app/components/hakumi_components/transfer/component.rb +232 -82
  230. data/app/components/hakumi_components/transfer/item.rb +54 -0
  231. data/app/components/hakumi_components/transfer/operations.rb +31 -0
  232. data/app/components/hakumi_components/tree/component.rb +219 -400
  233. data/app/components/hakumi_components/tree/concerns/node_rendering.rb +365 -0
  234. data/app/components/hakumi_components/tree/node.rb +276 -0
  235. data/app/components/hakumi_components/tree_select/component.html.erb +23 -9
  236. data/app/components/hakumi_components/tree_select/component.rb +116 -107
  237. data/app/components/hakumi_components/typography/base_component.rb +69 -36
  238. data/app/components/hakumi_components/typography/link/component.rb +63 -6
  239. data/app/components/hakumi_components/typography/paragraph/component.rb +6 -0
  240. data/app/components/hakumi_components/typography/text/component.rb +4 -0
  241. data/app/components/hakumi_components/typography/title/component.rb +61 -6
  242. data/app/components/hakumi_components/upload/component.html.erb +106 -88
  243. data/app/components/hakumi_components/upload/component.rb +222 -48
  244. data/app/components/hakumi_components/upload/file_entry.rb +53 -0
  245. data/app/controllers/hakumi_components/components_controller.rb +2 -1
  246. data/app/form_builders/hakumi_components/form_builder/contracts.rb +55 -0
  247. data/app/form_builders/hakumi_components/form_builder/field_context.rb +43 -0
  248. data/app/form_builders/hakumi_components/form_builder/model_binding.rb +163 -0
  249. data/app/form_builders/hakumi_components/form_builder.rb +238 -317
  250. data/app/helpers/hakumi_components/form_helper.rb +27 -23
  251. data/app/javascript/hakumi_components/controllers/hakumi/admin_panel_controller.js +5 -7
  252. data/app/javascript/hakumi_components/controllers/hakumi/back_top_controller.js +1 -1
  253. data/app/javascript/hakumi_components/controllers/hakumi/button_controller.js +108 -2
  254. data/app/javascript/hakumi_components/controllers/hakumi/calendar_controller.js +183 -95
  255. data/app/javascript/hakumi_components/controllers/hakumi/color_picker_controller.js +23 -285
  256. data/app/javascript/hakumi_components/controllers/hakumi/date_picker_controller.js +274 -262
  257. data/app/javascript/hakumi_components/controllers/hakumi/float_button_group_controller.js +2 -2
  258. data/app/javascript/hakumi_components/controllers/hakumi/message_controller.js +4 -2
  259. data/app/javascript/hakumi_components/controllers/hakumi/modal_controller.js +119 -125
  260. data/app/javascript/hakumi_components/controllers/hakumi/table/editable.js +291 -0
  261. data/app/javascript/hakumi_components/controllers/hakumi/table_controller.js +166 -366
  262. data/app/javascript/hakumi_components/controllers/hakumi/tabs_controller.js +8 -2
  263. data/app/javascript/hakumi_components/controllers/hakumi/tag_controller.js +27 -25
  264. data/app/javascript/hakumi_components/controllers/hakumi/tag_group_controller.js +19 -18
  265. data/app/javascript/hakumi_components/controllers/hakumi/theme_controller.js +116 -117
  266. data/app/javascript/hakumi_components/controllers/hakumi/transfer_controller.js +17 -1
  267. data/app/javascript/hakumi_components/controllers/hakumi/tree_controller.js +363 -78
  268. data/app/javascript/hakumi_components/controllers/hakumi/typography_controller.js +3 -3
  269. data/app/javascript/hakumi_components/controllers/hakumi/upload_controller.js +320 -204
  270. data/app/javascript/hakumi_components/core/render_component.js +37 -11
  271. data/app/javascript/hakumi_components/utils/color_helper.js +262 -0
  272. data/app/javascript/stylesheets/_base.scss +9 -0
  273. data/app/javascript/stylesheets/_hakumi_components.scss +1 -0
  274. data/app/javascript/stylesheets/components/_breadcrumb.scss +2 -2
  275. data/app/javascript/stylesheets/components/_calendar.scss +13 -13
  276. data/app/javascript/stylesheets/components/_cascader.scss +5 -5
  277. data/app/javascript/stylesheets/components/_checkbox.scss +9 -11
  278. data/app/javascript/stylesheets/components/_color_picker.scss +11 -11
  279. data/app/javascript/stylesheets/components/_date_picker.scss +4 -4
  280. data/app/javascript/stylesheets/components/_descriptions.scss +2 -2
  281. data/app/javascript/stylesheets/components/_drawer.scss +3 -3
  282. data/app/javascript/stylesheets/components/_dropdown.scss +2 -2
  283. data/app/javascript/stylesheets/components/_flex.scss +1 -1
  284. data/app/javascript/stylesheets/components/_float_button.scss +5 -5
  285. data/app/javascript/stylesheets/components/_form_item.scss +92 -0
  286. data/app/javascript/stylesheets/components/_image.scss +15 -15
  287. data/app/javascript/stylesheets/components/_input.scss +23 -113
  288. data/app/javascript/stylesheets/components/_layout.scss +27 -26
  289. data/app/javascript/stylesheets/components/_menu.scss +15 -15
  290. data/app/javascript/stylesheets/components/_modal.scss +13 -13
  291. data/app/javascript/stylesheets/components/_notification.scss +3 -3
  292. data/app/javascript/stylesheets/components/_popover.scss +1 -1
  293. data/app/javascript/stylesheets/components/_segmented.scss +3 -3
  294. data/app/javascript/stylesheets/components/_select.scss +6 -6
  295. data/app/javascript/stylesheets/components/_slider.scss +1 -1
  296. data/app/javascript/stylesheets/components/_spin.scss +2 -2
  297. data/app/javascript/stylesheets/components/_steps.scss +10 -10
  298. data/app/javascript/stylesheets/components/_switch.scss +11 -10
  299. data/app/javascript/stylesheets/components/_table.scss +6 -6
  300. data/app/javascript/stylesheets/components/_tag.scss +2 -2
  301. data/app/javascript/stylesheets/components/_tooltip.scss +4 -4
  302. data/app/javascript/stylesheets/components/_tree_select.scss +3 -3
  303. data/app/javascript/stylesheets/components/_typography.scss +3 -3
  304. data/app/javascript/stylesheets/components/_upload.scss +4 -4
  305. data/app/services/hakumi_components/component_handler.rb +95 -24
  306. data/app/services/hakumi_components/icon/loader.rb +84 -67
  307. data/app/services/hakumi_components/illustrations/loader.rb +35 -27
  308. data/app/views/hakumi/_alert.html.erb +4 -1
  309. data/app/views/hakumi/_drawer.html.erb +1 -1
  310. data/app/views/hakumi/_statistic.html.erb +11 -11
  311. data/lib/generators/hakumi_components/install_generator.rb +14 -1
  312. data/lib/hakumi_components/documentation/models.rb +290 -0
  313. data/lib/hakumi_components/documentation/node.rb +73 -0
  314. data/lib/hakumi_components/documentation.rb +139 -62
  315. data/lib/hakumi_components/engine.rb +17 -11
  316. data/lib/hakumi_components/file_size_checker.rb +215 -0
  317. data/lib/hakumi_components/locales/en.yml +115 -0
  318. data/lib/hakumi_components/rails/attribute_introspection.rb +39 -107
  319. data/lib/hakumi_components/rails/model_reflection.rb +154 -0
  320. data/lib/hakumi_components/rails/validation_introspection.rb +25 -73
  321. data/lib/hakumi_components/rails/validation_mapper.rb +148 -201
  322. data/lib/hakumi_components/rails.rb +2 -0
  323. data/lib/hakumi_components/stylesheet_ownership_checker.rb +191 -0
  324. data/lib/hakumi_components/types/form_field.rb +24 -0
  325. data/lib/hakumi_components/types/html.rb +28 -0
  326. data/lib/hakumi_components/types/rendering.rb +10 -0
  327. data/lib/hakumi_components/types/stimulus.rb +19 -0
  328. data/lib/hakumi_components/types/validation.rb +22 -0
  329. data/lib/hakumi_components/types.rb +13 -0
  330. data/lib/hakumi_components/version.rb +2 -1
  331. data/lib/hakumi_components.rb +26 -6
  332. data/lib/tasks/coverage.rake +1 -0
  333. metadata +100 -136
  334. data/sig/action_view/tag_builder.rbs +0 -24
  335. data/sig/active_support/concern_patch.rbs +0 -7
  336. data/sig/generators/hakumi_components/install_generator.rbs +0 -11
  337. data/sig/hakumi_components/admin_panel/component.rbs +0 -28
  338. data/sig/hakumi_components/affix/component.rbs +0 -44
  339. data/sig/hakumi_components/alert/component.rbs +0 -64
  340. data/sig/hakumi_components/anchor/component.rbs +0 -45
  341. data/sig/hakumi_components/anchor/link/component.rbs +0 -31
  342. data/sig/hakumi_components/autocomplete/component.rbs +0 -68
  343. data/sig/hakumi_components/avatar/component.rbs +0 -44
  344. data/sig/hakumi_components/badge/component.rbs +0 -41
  345. data/sig/hakumi_components/base_component.rbs +0 -82
  346. data/sig/hakumi_components/breadcrumb/component.rbs +0 -21
  347. data/sig/hakumi_components/breadcrumb/item/component.rbs +0 -36
  348. data/sig/hakumi_components/button/component.rbs +0 -56
  349. data/sig/hakumi_components/calendar/component.rbs +0 -41
  350. data/sig/hakumi_components/card/component.rbs +0 -50
  351. data/sig/hakumi_components/card/grid/component.rbs +0 -21
  352. data/sig/hakumi_components/card/meta/component.rbs +0 -25
  353. data/sig/hakumi_components/carousel/component.rbs +0 -88
  354. data/sig/hakumi_components/cascader/component.rbs +0 -52
  355. data/sig/hakumi_components/checkbox/component.rbs +0 -46
  356. data/sig/hakumi_components/checkbox/group/component.rbs +0 -34
  357. data/sig/hakumi_components/collapse/component.rbs +0 -57
  358. data/sig/hakumi_components/collapse/panel/component.rbs +0 -47
  359. data/sig/hakumi_components/color_picker/component.rbs +0 -80
  360. data/sig/hakumi_components/concerns/form_field.rbs +0 -89
  361. data/sig/hakumi_components/container/component.rbs +0 -37
  362. data/sig/hakumi_components/date_picker/component.rbs +0 -72
  363. data/sig/hakumi_components/date_picker/range_picker.rbs +0 -68
  364. data/sig/hakumi_components/date_picker/shared_rendering.rbs +0 -41
  365. data/sig/hakumi_components/descriptions/component.rbs +0 -59
  366. data/sig/hakumi_components/descriptions/item/component.rbs +0 -31
  367. data/sig/hakumi_components/divider/component.rbs +0 -39
  368. data/sig/hakumi_components/drawer/component.rbs +0 -66
  369. data/sig/hakumi_components/dropdown/component.rbs +0 -45
  370. data/sig/hakumi_components/dropdown/divider/component.rbs +0 -11
  371. data/sig/hakumi_components/dropdown/item/component.rbs +0 -45
  372. data/sig/hakumi_components/empty/component.rbs +0 -40
  373. data/sig/hakumi_components/flex/component.rbs +0 -47
  374. data/sig/hakumi_components/float_button/back_top/component.rbs +0 -45
  375. data/sig/hakumi_components/float_button/component.rbs +0 -80
  376. data/sig/hakumi_components/float_button/group/component.rbs +0 -95
  377. data/sig/hakumi_components/float_button/group_cluster/component.rbs +0 -60
  378. data/sig/hakumi_components/form/item/component.rbs +0 -39
  379. data/sig/hakumi_components/form_builder.rbs +0 -37
  380. data/sig/hakumi_components/grid/col/component.rbs +0 -50
  381. data/sig/hakumi_components/grid/row/component.rbs +0 -46
  382. data/sig/hakumi_components/icon/component.rbs +0 -56
  383. data/sig/hakumi_components/image/component.rbs +0 -56
  384. data/sig/hakumi_components/image/preview_group/component.rbs +0 -28
  385. data/sig/hakumi_components/input/component.rbs +0 -71
  386. data/sig/hakumi_components/input/password/component.rbs +0 -27
  387. data/sig/hakumi_components/input/text_area/component.rbs +0 -42
  388. data/sig/hakumi_components/input_number/component.rbs +0 -85
  389. data/sig/hakumi_components/layout/component.rbs +0 -21
  390. data/sig/hakumi_components/layout/content/component.rbs +0 -19
  391. data/sig/hakumi_components/layout/footer/component.rbs +0 -19
  392. data/sig/hakumi_components/layout/header/component.rbs +0 -19
  393. data/sig/hakumi_components/layout/sider/component.rbs +0 -19
  394. data/sig/hakumi_components/mentions/component.rbs +0 -75
  395. data/sig/hakumi_components/menu/component.rbs +0 -52
  396. data/sig/hakumi_components/menu/divider/component.rbs +0 -11
  397. data/sig/hakumi_components/menu/group/component.rbs +0 -20
  398. data/sig/hakumi_components/menu/item/component.rbs +0 -42
  399. data/sig/hakumi_components/menu/sub_menu/component.rbs +0 -37
  400. data/sig/hakumi_components/message/component.rbs +0 -50
  401. data/sig/hakumi_components/modal/component.rbs +0 -76
  402. data/sig/hakumi_components/modal/confirm/component.rbs +0 -32
  403. data/sig/hakumi_components/modal/error/component.rbs +0 -27
  404. data/sig/hakumi_components/modal/info/component.rbs +0 -27
  405. data/sig/hakumi_components/modal/success/component.rbs +0 -27
  406. data/sig/hakumi_components/modal/warning/component.rbs +0 -27
  407. data/sig/hakumi_components/notification/component.rbs +0 -64
  408. data/sig/hakumi_components/pagination/component.rbs +0 -113
  409. data/sig/hakumi_components/popconfirm/component.rbs +0 -52
  410. data/sig/hakumi_components/popover/component.rbs +0 -66
  411. data/sig/hakumi_components/progress/component.rbs +0 -201
  412. data/sig/hakumi_components/qr_code/component.rbs +0 -111
  413. data/sig/hakumi_components/radio/component.rbs +0 -55
  414. data/sig/hakumi_components/radio/group/component.rbs +0 -71
  415. data/sig/hakumi_components/rails/attribute_introspection.rbs +0 -16
  416. data/sig/hakumi_components/rails/validation_introspection.rbs +0 -18
  417. data/sig/hakumi_components/rails/validation_mapper.rbs +0 -53
  418. data/sig/hakumi_components/rails.rbs +0 -6
  419. data/sig/hakumi_components/rate/component.rbs +0 -56
  420. data/sig/hakumi_components/result/component.rbs +0 -65
  421. data/sig/hakumi_components/segmented/component.rbs +0 -72
  422. data/sig/hakumi_components/select/component.rbs +0 -73
  423. data/sig/hakumi_components/skeleton/avatar/component.rbs +0 -23
  424. data/sig/hakumi_components/skeleton/button/component.rbs +0 -24
  425. data/sig/hakumi_components/skeleton/component.rbs +0 -76
  426. data/sig/hakumi_components/skeleton/image/component.rbs +0 -22
  427. data/sig/hakumi_components/skeleton/input/component.rbs +0 -23
  428. data/sig/hakumi_components/skeleton/node/component.rbs +0 -21
  429. data/sig/hakumi_components/slider/component.rbs +0 -85
  430. data/sig/hakumi_components/space/compact/component.rbs +0 -21
  431. data/sig/hakumi_components/space/component.rbs +0 -47
  432. data/sig/hakumi_components/spin/component.rbs +0 -77
  433. data/sig/hakumi_components/splitter/component.rbs +0 -27
  434. data/sig/hakumi_components/splitter/panel/component.rbs +0 -36
  435. data/sig/hakumi_components/statistic/component.rbs +0 -97
  436. data/sig/hakumi_components/steps/component.rbs +0 -82
  437. data/sig/hakumi_components/steps/item/component.rbs +0 -29
  438. data/sig/hakumi_components/switch/component.rbs +0 -52
  439. data/sig/hakumi_components/table/column/component.rbs +0 -57
  440. data/sig/hakumi_components/table/column_group/component.rbs +0 -20
  441. data/sig/hakumi_components/table/component.rbs +0 -279
  442. data/sig/hakumi_components/table/concerns/columns.rbs +0 -95
  443. data/sig/hakumi_components/table/concerns/editable.rbs +0 -40
  444. data/sig/hakumi_components/table/concerns/ellipsis.rbs +0 -27
  445. data/sig/hakumi_components/table/concerns/fixed_columns.rbs +0 -33
  446. data/sig/hakumi_components/tabs/component.rbs +0 -66
  447. data/sig/hakumi_components/tabs/item/component.rbs +0 -29
  448. data/sig/hakumi_components/tag/component.rbs +0 -86
  449. data/sig/hakumi_components/tag/group/component.rbs +0 -24
  450. data/sig/hakumi_components/time_picker/component.rbs +0 -72
  451. data/sig/hakumi_components/timeline/component.rbs +0 -61
  452. data/sig/hakumi_components/timeline/item/component.rbs +0 -70
  453. data/sig/hakumi_components/tooltip/component.rbs +0 -73
  454. data/sig/hakumi_components/tour/component.rbs +0 -84
  455. data/sig/hakumi_components/transfer/component.rbs +0 -75
  456. data/sig/hakumi_components/tree/component.rbs +0 -126
  457. data/sig/hakumi_components/tree_select/component.rbs +0 -122
  458. data/sig/hakumi_components/typography/base_component.rbs +0 -57
  459. data/sig/hakumi_components/typography/link/component.rbs +0 -28
  460. data/sig/hakumi_components/typography/paragraph/component.rbs +0 -13
  461. data/sig/hakumi_components/typography/text/component.rbs +0 -10
  462. data/sig/hakumi_components/typography/title/component.rbs +0 -28
  463. data/sig/hakumi_components/upload/component.rbs +0 -78
  464. data/sig/hakumi_components.rbs +0 -96
  465. data/sig/rails/active_model/validations/comparison_validator.rbs +0 -6
  466. data/sig/rails.rbs +0 -18
  467. data/sig/view_component/base.rbs +0 -28
@@ -1,23 +1,41 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  module Table
5
- # A complex Table component supporting sorting, filtering, selection, expansion, and editing.
6
6
  class Component < HakumiComponents::BaseComponent
7
+ extend T::Sig
8
+
9
+ include Concerns::AttributeHelpers
7
10
  include Concerns::Columns
8
11
  include Concerns::Editable
9
12
  include Concerns::FixedColumns
10
13
  include Concerns::Ellipsis
14
+ include Concerns::CellRendering
15
+ include Concerns::SurfaceRendering
16
+
17
+ TableContent = T.type_alias { T.nilable(T.any(Types::Renderable, Proc)) }
18
+ RowSource = T.type_alias { HakumiComponents::Table::RowRecord::Source }
19
+ RowKeyConfig = T.type_alias { HakumiComponents::Table::RowRecord::RowKeyConfig }
20
+ FilterModeValue = T.type_alias { T.nilable(Types::HtmlKey) }
21
+ FilterSearchValue = T.type_alias { HakumiComponents::Table::DefinitionTypes::SearchValue }
22
+ ScrollAxisValue = T.type_alias { T.nilable(T.any(String, Numeric)) }
23
+ ScrollInput = T.type_alias { T.nilable(T::Hash[Types::HtmlKey, ScrollAxisValue]) }
24
+ RowClassName = T.type_alias { T.nilable(T.any(String, Proc)) }
25
+ PaginationValue = T.type_alias { HakumiComponents::Table::Configs::Pagination::Value }
26
+ ControllerLocalScalar = T.type_alias { T.nilable(Types::ValidationPrimitive) }
27
+ ControllerLocalCollection = T.type_alias { T.any(HakumiComponents::Table::DefinitionTypes::RawCollection, HakumiComponents::Table::DefinitionTypes::RawRecord) }
28
+ DisplayRow = T.type_alias { { row: HakumiComponents::Table::RowRecord, depth: Integer } }
29
+ ScrollConfig = T.type_alias { { x: T.nilable(String), y: T.nilable(String) } }
30
+ ControllerLocalValue = T.type_alias { T.nilable(T.any(ControllerLocalScalar, ControllerLocalCollection)) }
31
+ ColumnInput = T.type_alias { Concerns::Columns::ColumnInput }
32
+
33
+ ROW_SELECTION_TYPES = T.let(%i[checkbox radio].freeze, T::Array[Symbol])
34
+ SORT_DIRECTIONS = T.let(%i[ascend descend].freeze, T::Array[Symbol])
35
+ FIXED_SIDES = T.let(%i[left right].freeze, T::Array[Symbol])
36
+ RESPONSIVE_BREAKPOINTS = T.let(%i[xs sm md lg xl xxl].freeze, T::Array[Symbol])
37
+ ROW_BUTTON_ACTIONS = T.let(%i[edit save cancel].freeze, T::Array[Symbol])
11
38
 
12
- # @group Configuration Constants
13
- SIZES = %i[default middle small].freeze
14
- ROW_SELECTION_TYPES = %i[checkbox radio].freeze
15
- SORT_DIRECTIONS = %i[ascend descend].freeze
16
- FIXED_SIDES = %i[left right].freeze
17
- RESPONSIVE_BREAKPOINTS = %i[xs sm md lg xl xxl].freeze
18
- ROW_BUTTON_ACTIONS = %i[edit save cancel].freeze
19
-
20
- # @group Slot Definitions
21
39
  SELECTION_COLUMN = :selection_column
22
40
  EXPAND_COLUMN = :expand_column
23
41
 
@@ -27,7 +45,7 @@ module HakumiComponents
27
45
  sorter: nil, sort_directions: nil, sort_order: nil, default_sort_order: nil,
28
46
  filters: nil, filter_multiple: true, filtered_value: nil, default_filtered_value: nil,
29
47
  filter_mode: nil, filter_search: nil, hidden: false, on_cell: nil, class_name: nil,
30
- **options, &block|
48
+ &block|
31
49
  HakumiComponents::Table::Column::Component.new(
32
50
  title: title,
33
51
  data_index: data_index,
@@ -48,31 +66,18 @@ module HakumiComponents
48
66
  hidden: hidden,
49
67
  on_cell: on_cell,
50
68
  class_name: class_name,
51
- **options,
52
69
  &block
53
70
  )
54
71
  end,
55
72
  as: :column
56
73
  },
57
74
  group: {
58
- renders: lambda do |title:, key: nil, align: nil, width: nil, hidden: false, **options, &block|
59
- HakumiComponents::Table::ColumnGroup::Component.new(
60
- title: title,
61
- key: key,
62
- align: align,
63
- width: width,
64
- hidden: hidden,
65
- **options,
66
- &block
67
- )
68
- end,
75
+ renders: HakumiComponents::Table::ColumnGroup::Component,
69
76
  as: :group
70
77
  }
71
78
  }
72
79
 
73
- # Extracts local variables for the controller from the params hash.
74
- # @param params [Hash] parameters from the request
75
- # @return [Hash] hash of local variables
80
+ sig { params(params: BaseComponent::ControllerOptions).returns(T::Hash[Symbol, ControllerLocalValue]) }
76
81
  def self.extract_controller_locals(params)
77
82
  {
78
83
  columns: parse_json_param(params[:columns]),
@@ -100,7 +105,9 @@ module HakumiComponents
100
105
  }
101
106
  end
102
107
 
108
+ sig { params(value: BaseComponent::RawHtmlInput).returns(ControllerLocalValue) }
103
109
  def self.parse_json_param(value)
110
+ return value.to_unsafe_h if value.is_a?(ActionController::Parameters)
104
111
  return value unless value.is_a?(String)
105
112
 
106
113
  JSON.parse(value)
@@ -108,6 +115,36 @@ module HakumiComponents
108
115
  value
109
116
  end
110
117
 
118
+ sig do
119
+ params(
120
+ columns: T.nilable(T::Array[ColumnInput]),
121
+ data_source: T::Array[RowSource],
122
+ row_key: RowKeyConfig,
123
+ size: T.nilable(Symbol),
124
+ bordered: T.nilable(T::Boolean),
125
+ title: TableContent,
126
+ footer: TableContent,
127
+ row_selection: HakumiComponents::Table::Configs::RowSelection::Input,
128
+ expandable: HakumiComponents::Table::Configs::Expandable::Input,
129
+ pagination: HakumiComponents::Table::Configs::Pagination::Input,
130
+ summary: TableContent,
131
+ empty_text: TableContent,
132
+ sort_directions: T.nilable(T::Array[Symbol]),
133
+ filter_on_close: T.nilable(T::Boolean),
134
+ filter_mode: FilterModeValue,
135
+ filter_search: FilterSearchValue,
136
+ children_column_name: HakumiComponents::Table::DefinitionTypes::ColumnKey,
137
+ indent_size: T.nilable(Integer),
138
+ scroll: ScrollInput,
139
+ sticky: T.nilable(T::Boolean),
140
+ row_class_name: RowClassName,
141
+ editable: HakumiComponents::Table::Configs::Editable::Input,
142
+ row_drag: HakumiComponents::Table::Configs::RowDrag::Input,
143
+ column_drag: T.nilable(T::Boolean),
144
+ data_url: T.nilable(String),
145
+ html_options: Types::HtmlAttributeValue
146
+ ).void
147
+ end
111
148
  def initialize(
112
149
  columns: nil,
113
150
  data_source: [],
@@ -136,596 +173,298 @@ module HakumiComponents
136
173
  data_url: nil,
137
174
  **html_options
138
175
  )
139
- @columns_data = columns
140
- @data_source = data_source
141
- @row_key = row_key
142
- @size = size
143
- @bordered = bordered
144
- @title = title
145
- @footer = footer
146
- @row_selection = row_selection
147
- @expandable = expandable
148
- @pagination = pagination
149
- @summary = summary
150
- @empty_text = empty_text
151
- @sort_directions = Array(sort_directions).presence || SORT_DIRECTIONS
152
- @filter_on_close = filter_on_close
153
- @filter_mode = filter_mode
154
- @filter_search = filter_search
155
- @children_column_name = children_column_name
156
- @indent_size = indent_size
157
- @scroll = normalize_scroll(scroll)
158
- @scroll_x = @scroll&.dig(:x)
159
- @scroll_y = @scroll&.dig(:y)
160
- @sticky = cast_boolean(sticky)
161
- @row_class_name = row_class_name
162
- @editable = normalize_editable(editable)
163
- @row_drag = normalize_row_drag(row_drag)
164
- @column_drag = cast_boolean(column_drag)
165
- @data_url = data_url
166
- @html_options = html_options
167
-
168
- normalize_row_selection!
169
- normalize_expandable!
176
+ @columns_data = T.let(columns, T.nilable(T::Array[ColumnInput]))
177
+ @data_source = T.let(
178
+ Array(data_source).map { |row| HakumiComponents::Table::RowRecord.new(source: row, children_column_name: children_column_name) },
179
+ T::Array[HakumiComponents::Table::RowRecord]
180
+ )
181
+ @row_key = T.let(row_key, RowKeyConfig)
182
+ @size = T.let(size || :default, Symbol)
183
+ @bordered = T.let(bordered == true, T::Boolean)
184
+ @title = T.let(title, TableContent)
185
+ @footer = T.let(footer, TableContent)
186
+ @row_selection = T.let(HakumiComponents::Table::Configs::RowSelection.coerce(row_selection), T.nilable(HakumiComponents::Table::Configs::RowSelection))
187
+ @expandable = T.let(HakumiComponents::Table::Configs::Expandable.coerce(expandable), T.nilable(HakumiComponents::Table::Configs::Expandable))
188
+ @summary = T.let(summary, TableContent)
189
+ @empty_text = T.let(empty_text, TableContent)
190
+ @sort_directions = T.let(Array(sort_directions).presence || SORT_DIRECTIONS, T::Array[Symbol])
191
+ @filter_on_close = T.let(filter_on_close.nil? ? true : filter_on_close, T::Boolean)
192
+ @filter_mode = T.let(normalize_component_symbol(filter_mode, fallback: :menu), Symbol)
193
+ @filter_search = T.let(normalize_filter_search(filter_search), HakumiComponents::Table::DefinitionTypes::SearchValue)
194
+ @children_column_name = T.let(children_column_name, HakumiComponents::Table::DefinitionTypes::ColumnKey)
195
+ @indent_size = T.let(indent_size || 16, Integer)
196
+ @scroll = T.let(normalize_scroll(scroll), T.nilable(ScrollConfig))
197
+ @scroll_x = T.let(@scroll&.dig(:x), T.nilable(String))
198
+ @scroll_y = T.let(@scroll&.dig(:y), T.nilable(String))
199
+ @sticky = T.let(sticky == true, T::Boolean)
200
+ @row_class_name = T.let(row_class_name, RowClassName)
201
+ @editable = T.let(HakumiComponents::Table::Configs::Editable.coerce(editable), T.nilable(HakumiComponents::Table::Configs::Editable))
202
+ @row_drag = T.let(HakumiComponents::Table::Configs::RowDrag.coerce(row_drag), T.nilable(HakumiComponents::Table::Configs::RowDrag))
203
+ @column_drag = T.let(column_drag == true, T::Boolean)
204
+ @data_url = T.let(data_url, T.nilable(String))
205
+ @html_options = T.let(html_options, Types::HtmlAttributes)
206
+ @pagination = T.let(HakumiComponents::Table::Configs::Pagination.coerce(pagination, total: @data_source.size), PaginationValue)
207
+ @header_rows = T.let(nil, T.nilable(T::Array[T::Array[HakumiComponents::Table::HeaderCell]]))
208
+ @display_rows = T.let(nil, T.nilable(T::Array[DisplayRow]))
209
+ @row_render_state = T.let(nil, T.nilable(HakumiComponents::Table::RowRenderState))
170
210
 
171
211
  validate_props!
172
212
  end
173
213
 
174
- attr_reader :row_selection, :expandable, :pagination, :summary
175
-
176
- def table_classes
177
- class_names(
178
- "table",
179
- {
180
- size: @size,
181
- bordered: @bordered,
182
- empty: display_rows.empty?,
183
- sticky: @sticky,
184
- scroll_x: @scroll_x.present?,
185
- scroll_y: @scroll_y.present?,
186
- fixed: fixed_columns?
187
- },
188
- @html_options[:class]
189
- )
214
+ sig { override.returns(T.nilable(HakumiComponents::Table::Configs::RowSelection)) }
215
+ def row_selection_config
216
+ @row_selection
190
217
  end
191
218
 
192
- def table_container_attributes
193
- attrs = {
194
- class: container_classes,
195
- data: {
196
- "hakumi--table-target": "scrollContainer"
197
- }
198
- }
199
- styles = scroll_styles
200
- attrs[:style] = styles if styles.present?
201
- attrs
219
+ sig { override.returns(T.nilable(HakumiComponents::Table::Configs::Expandable)) }
220
+ def expandable_config
221
+ @expandable
202
222
  end
203
223
 
204
- def table_attributes
205
- attrs = { class: "hakumi-table-table" }
206
- attrs[:style] = table_style if table_style.present?
207
- attrs
224
+ sig { returns(PaginationValue) }
225
+ def pagination_config
226
+ @pagination
208
227
  end
209
228
 
210
- def container_classes
211
- class_names(
212
- "table-container",
213
- {
214
- scroll_x: @scroll_x.present?,
215
- scroll_y: @scroll_y.present?
216
- }
217
- )
229
+ sig { override.returns(T.nilable(HakumiComponents::Table::Configs::Editable)) }
230
+ def table_editable_config
231
+ @editable
218
232
  end
219
233
 
220
- def wrapper_attributes
221
- data_attributes = {
222
- controller: "hakumi--table",
223
- "hakumi--table-selection-type-value": @row_selection_type,
224
- "hakumi--table-selected-row-keys-value": @selected_row_keys.to_json,
225
- "hakumi--table-preserve-selected-row-keys-value": @row_selection_preserve,
226
- "hakumi--table-sort-directions-value": @sort_directions.join(","),
227
- "hakumi--table-filter-on-close-value": @filter_on_close,
228
- "hakumi--table-filter-mode-value": @filter_mode,
229
- "hakumi--table-filter-search-value": @filter_search
230
- }
231
- if (editable_json = editable_config_json)
232
- data_attributes["hakumi--table-editable-config-value"] = editable_json
233
- end
234
+ sig { override.returns(T.nilable(HakumiComponents::Table::Configs::RowDrag)) }
235
+ def row_drag_config
236
+ @row_drag
237
+ end
234
238
 
235
- # Server-side pagination/sorting configuration
236
- if @pagination.is_a?(Hash)
237
- if @pagination[:href]
238
- data_attributes["hakumi--table-href-value"] = @pagination[:href]
239
- data_attributes["hakumi--table-server-side-value"] = true
240
-
241
- # Add pagination state for preserve_params (sort state from columns)
242
- data_attributes["pagination-state"] = true
243
- current_sort = current_sort_state
244
- if current_sort
245
- data_attributes["sort-field"] = current_sort[:field]
246
- data_attributes["sort-order"] = current_sort[:order]
247
- end
248
- end
249
- if @pagination[:turbo_frame]
250
- data_attributes["hakumi--table-turbo-frame-value"] = @pagination[:turbo_frame]
251
- end
252
- if @pagination[:sort_field_param]
253
- data_attributes["hakumi--table-sort-field-param-value"] = @pagination[:sort_field_param]
254
- end
255
- if @pagination[:sort_order_param]
256
- data_attributes["hakumi--table-sort-order-param-value"] = @pagination[:sort_order_param]
257
- end
258
- end
239
+ sig { override.returns(Symbol) }
240
+ def surface_size
241
+ @size
242
+ end
259
243
 
260
- # Drag sorting configuration
261
- if @row_drag
262
- data_attributes["hakumi--table-row-drag-value"] = @row_drag[:enabled]
263
- data_attributes["hakumi--table-row-drag-handle-value"] = @row_drag[:handle]
264
- end
265
- if @column_drag
266
- data_attributes["hakumi--table-column-drag-value"] = true
267
- end
244
+ sig { override.returns(T::Boolean) }
245
+ def surface_bordered?
246
+ @bordered
247
+ end
268
248
 
269
- # AJAX data loading configuration
270
- if @data_url
271
- data_attributes["hakumi--table-data-url-value"] = @data_url
272
- data_attributes["hakumi--table-columns-config-value"] = columns_config_json
273
- if @pagination.is_a?(Hash)
274
- data_attributes["hakumi--table-page-size-value"] = @pagination[:page_size] || 10
275
- end
276
- end
249
+ sig { override.returns(T::Boolean) }
250
+ def surface_sticky?
251
+ @sticky
252
+ end
277
253
 
278
- base = {
279
- class: table_classes,
280
- data: data_attributes
281
- }
282
- merge_attributes(base, @html_options)
254
+ sig { override.returns(T.nilable(String)) }
255
+ def surface_scroll_x
256
+ @scroll_x
283
257
  end
284
258
 
285
- def header_rows
286
- @header_rows ||= build_header_rows(normalized_columns)
259
+ sig { override.returns(T.nilable(String)) }
260
+ def surface_scroll_y
261
+ @scroll_y
287
262
  end
288
263
 
289
- def display_rows
290
- @display_rows ||= build_display_rows
264
+ sig { override.returns(Types::HtmlAttributes) }
265
+ def surface_html_options
266
+ @html_options
291
267
  end
292
268
 
293
- def row_key_for(row, index)
294
- case @row_key
295
- when Proc
296
- @row_key.call(row)
297
- when Symbol, String
298
- value_from_row(row, @row_key)
299
- else
300
- row.respond_to?(:[]) ? row[@row_key] : index
301
- end
269
+ sig { override.returns(T.nilable(HakumiComponents::Table::Configs::RowSelection)) }
270
+ def surface_row_selection
271
+ @row_selection
302
272
  end
303
273
 
304
- def row_selected?(row_key)
305
- @selected_row_keys.include?(row_key.to_s)
274
+ sig { override.returns(T::Array[Symbol]) }
275
+ def surface_sort_directions
276
+ @sort_directions
306
277
  end
307
278
 
308
- def row_classes(row, row_index, row_key)
309
- classes = [ "hakumi-table-row" ]
310
- classes << "hakumi-table-row-selected" if row_selected?(row_key)
311
- classes << "hakumi-table-row-odd" if row_index.odd?
312
- if @row_class_name.respond_to?(:call)
313
- classes << @row_class_name.call(row, row_index)
314
- elsif @row_class_name.is_a?(String)
315
- classes << @row_class_name
316
- end
317
- classes.compact.join(" ")
318
- end
319
-
320
- def cell_attributes(column, row, row_index, depth, row_key = nil, raw_value = nil)
321
- attrs = {
322
- class: cell_classes(column),
323
- data: {
324
- column_key: column[:key],
325
- row_key: row_key,
326
- sort_value: extract_sort_value(column, row, raw_value),
327
- value: raw_value
328
- }.compact
329
- }
330
- attrs[:style] = "text-align: #{column[:align]};" if column[:align]
331
- attrs[:style] = [ attrs[:style], "width: #{column[:width]};" ].compact.join(" ") if column[:width]
332
- if column[:on_cell].respond_to?(:call)
333
- cell_attrs = column[:on_cell].call(row, row_index)
334
- attrs[:colspan] = cell_attrs[:colspan] if cell_attrs
335
- attrs[:rowspan] = cell_attrs[:rowspan] if cell_attrs
336
- attrs[:class] = [ attrs[:class], cell_attrs[:class] ].compact.join(" ")
337
- attrs[:style] = [ attrs[:style], cell_attrs[:style] ].compact.join(" ")
338
- end
339
- if depth.positive? && column == first_data_column
340
- attrs[:style] = [ attrs[:style], "padding-left: #{depth * @indent_size}px;" ].compact.join(" ")
341
- end
342
- apply_editable_attributes!(attrs, column)
343
- apply_should_cell_update_attributes!(attrs, column)
344
- apply_fixed_column_attributes!(attrs, column, header: false)
345
- attrs
346
- end
347
-
348
- def header_cell_attributes(column, col_span:, row_span:)
349
- attrs = { class: header_cell_classes(column) }
350
- attrs[:colspan] = col_span if col_span > 1
351
- attrs[:rowspan] = row_span if row_span > 1
352
- attrs[:style] = "text-align: #{column[:align]};" if column[:align]
353
- attrs[:style] = [ attrs[:style], "width: #{column[:width]};" ].compact.join(" ") if column[:width]
354
- apply_fixed_column_attributes!(attrs, column, header: true)
355
- attrs
356
- end
357
-
358
- def cell_content(column, row, row_index, raw_value = nil)
359
- return selection_cell(row, row_index) if column[:selection]
360
- return expand_cell(row, row_index) if column[:expand]
361
- return { drag_handle: true } if column[:drag_handle]
362
-
363
- value = raw_value
364
- value = value_from_row(row, column[:data_index]) if value.nil? && column[:data_index]
365
- if column[:render].respond_to?(:call)
366
- column[:render].call(value, row, row_index)
367
- else
368
- value
369
- end
279
+ sig { override.returns(T::Boolean) }
280
+ def surface_filter_on_close?
281
+ @filter_on_close
370
282
  end
371
283
 
372
- def render_cell_display(column, content, raw_value, row, row_index)
373
- config = ellipsis_config(column)
284
+ sig { override.returns(Symbol) }
285
+ def surface_filter_mode
286
+ @filter_mode
287
+ end
374
288
 
375
- value_fragment = if content.is_a?(ViewComponent::Base)
376
- render(content)
377
- else
378
- content
379
- end
380
- value_fragment = raw_value if value_fragment.nil?
381
-
382
- span_options = { class: "hakumi-table-cell-content" }
383
- title_text = ellipsis_title(config, raw_value, value_fragment)
384
- span_options[:title] = title_text if title_text.present?
385
-
386
- display_value = value_fragment.is_a?(Numeric) ? value_fragment.to_s : value_fragment
387
- inner = tag.span(**span_options) { display_value }
388
-
389
- tooltip_component = ellipsis_tooltip_component(config, raw_value, row, row_index)
390
- tooltip_component ? render(tooltip_component) { inner } : inner
391
- end
392
-
393
- def empty_state
394
- if @empty_text.present?
395
- if @empty_text.is_a?(ViewComponent::Base)
396
- render(@empty_text)
397
- elsif @empty_text.respond_to?(:call)
398
- instance_exec(&@empty_text)
399
- else
400
- @empty_text
401
- end
402
- else
403
- render(HakumiComponents::Empty::Component.new)
404
- end
289
+ sig { override.returns(HakumiComponents::Table::DefinitionTypes::SearchValue) }
290
+ def surface_filter_search
291
+ @filter_search
405
292
  end
406
293
 
407
- def pagination_component
408
- return nil unless @pagination
409
- return nil if @data_url # AJAX mode uses ajax_pagination_component
410
- return @pagination if @pagination.is_a?(ViewComponent::Base)
294
+ sig { override.returns(T.nilable(HakumiComponents::Table::Configs::Editable)) }
295
+ def surface_editable
296
+ @editable
297
+ end
411
298
 
412
- options = @pagination.is_a?(Hash) ? @pagination : {}
413
- normalized = normalize_pagination_options(options)
414
- return nil unless normalized
299
+ sig { override.returns(T.nilable(HakumiComponents::Table::Configs::RowDrag)) }
300
+ def surface_row_drag
301
+ @row_drag
302
+ end
415
303
 
416
- HakumiComponents::Pagination::Component.new(**normalized)
304
+ sig { override.returns(T::Boolean) }
305
+ def surface_column_drag?
306
+ @column_drag
417
307
  end
418
308
 
419
- def ajax_pagination_component
420
- return nil unless @data_url && @pagination
309
+ sig { override.returns(PaginationValue) }
310
+ def surface_pagination
311
+ @pagination
312
+ end
421
313
 
422
- options = @pagination.is_a?(Hash) ? @pagination : {}
423
- HakumiComponents::Pagination::Component.new(
424
- current: 1,
425
- page_size: options[:page_size] || 10,
426
- total: 0,
427
- show_size_changer: options[:show_size_changer] != false
428
- )
314
+ sig { override.returns(T.nilable(String)) }
315
+ def surface_data_url
316
+ @data_url
429
317
  end
430
318
 
431
- def summary_content
432
- return nil unless @summary
433
- return @summary.call(display_rows.map { |row| row[:row] }) if @summary.respond_to?(:call)
319
+ sig { override.returns(TableContent) }
320
+ def surface_empty_text
321
+ @empty_text
322
+ end
434
323
 
324
+ sig { override.returns(TableContent) }
325
+ def surface_summary
435
326
  @summary
436
327
  end
437
328
 
438
- def scroll_styles
439
- styles = []
440
- if @scroll_x
441
- styles << "overflow-x: auto"
442
- end
443
- if @scroll_y
444
- styles << "max-height: #{dimension_to_css(@scroll_y)}"
445
- styles << "overflow-y: auto"
446
- end
447
- styles.join("; ")
329
+ sig { returns(T::Array[T::Array[HakumiComponents::Table::HeaderCell]]) }
330
+ def header_rows
331
+ @header_rows ||= build_header_rows(normalized_columns)
448
332
  end
449
333
 
450
- def table_style
451
- return nil unless @scroll_x
452
-
453
- "min-width: #{dimension_to_css(@scroll_x)}"
334
+ sig { override.returns(T::Array[DisplayRow]) }
335
+ def display_rows
336
+ @display_rows ||= HakumiComponents::Table::DisplayRows.build(
337
+ rows: @data_source,
338
+ pagination: @pagination
339
+ )
454
340
  end
455
341
 
456
- def selection_column?
457
- @row_selection.present?
342
+ sig { params(row: HakumiComponents::Table::RowRecord, index: Integer).returns(RowSource) }
343
+ def row_key_for(row, index)
344
+ row_render_state.row_key_for(row, index)
458
345
  end
459
346
 
460
- def selection_actions?
461
- @row_selection.present? && @row_selection_selections
347
+ sig { params(row_key: RowSource).returns(T::Boolean) }
348
+ def row_selected?(row_key)
349
+ row_render_state.selected?(row_key)
462
350
  end
463
351
 
464
- def selection_all_enabled?
465
- @row_selection_type == :checkbox
352
+ sig { params(row: HakumiComponents::Table::RowRecord, row_index: Integer, row_key: RowSource).returns(String) }
353
+ def row_classes(row, row_index, row_key)
354
+ row_render_state.row_classes(row, row_index, row_key)
466
355
  end
467
356
 
357
+ sig { params(row_key: RowSource).returns(T::Boolean) }
468
358
  def expanded_row?(row_key)
469
- @expanded_row_keys.include?(row_key.to_s)
359
+ row_render_state.expanded?(row_key)
470
360
  end
471
361
 
362
+ sig { params(row: HakumiComponents::Table::RowRecord, row_index: Integer).returns(RowSource) }
472
363
  def expanded_row_content(row, row_index)
473
- return nil unless @expandable&.dig(:expanded_row_render).respond_to?(:call)
474
-
475
- @expandable[:expanded_row_render].call(row, row_index)
476
- end
477
-
478
- def header_filter_options(column)
479
- Array(column[:filters])
364
+ renderer = @expandable&.expanded_row_render
365
+ renderer&.call(row.source, row_index)
480
366
  end
481
367
 
368
+ sig { override.params(column: HakumiComponents::Table::ColumnDefinition).returns(T::Boolean) }
482
369
  def column_sortable?(column)
483
- column[:sorter].present?
370
+ !column.sorter.nil?
484
371
  end
485
372
 
373
+ sig { override.params(column: HakumiComponents::Table::ColumnDefinition).returns(T::Boolean) }
486
374
  def column_filterable?(column)
487
- column[:filters].present?
488
- end
489
-
490
- def column_filter_multiple?(column)
491
- column[:filter_multiple] != false
375
+ column.filters.present?
492
376
  end
493
377
 
378
+ sig { override.params(column: HakumiComponents::Table::ColumnDefinition).returns(HakumiComponents::Table::DefinitionTypes::ScalarList) }
494
379
  def default_filtered_values(column)
495
- Array(column[:filtered_value] || column[:default_filtered_value])
380
+ Array(column.filtered_value || column.default_filtered_value)
496
381
  end
497
382
 
383
+ sig { override.params(column: HakumiComponents::Table::ColumnDefinition).returns(T.nilable(Symbol)) }
498
384
  def default_sort_order(column)
499
- column[:sort_order] || column[:default_sort_order]
500
- end
501
-
502
- def current_sort_state
503
- sorted_column = leaf_columns.find { |col| default_sort_order(col).present? }
504
- return nil unless sorted_column
505
-
506
- {
507
- field: sorted_column[:key]&.to_s || sorted_column[:data_index]&.to_s,
508
- order: default_sort_order(sorted_column)
509
- }
510
- end
511
-
512
- def header_cell_classes(column)
513
- classes = [ "hakumi-table-cell", "hakumi-table-header-cell" ]
514
- classes.concat(responsive_classes(column))
515
- classes << "hakumi-table-cell-ellipsis" if ellipsis_config(column)
516
- classes << "hakumi-table-cell-sortable" if column_sortable?(column)
517
- classes << "hakumi-table-cell-filterable" if column_filterable?(column)
518
- classes << column[:class_name] if column[:class_name]
519
- classes.compact.join(" ")
520
- end
521
-
522
- def cell_classes(column)
523
- classes = [ "hakumi-table-cell" ]
524
- classes.concat(responsive_classes(column))
525
- classes << "hakumi-table-cell-ellipsis" if ellipsis_config(column)
526
- classes << "hakumi-table-cell-selection" if column[:selection]
527
- classes << "hakumi-table-cell-expand" if column[:expand]
528
- classes << column[:class_name] if column[:class_name]
529
- classes.compact.join(" ")
530
- end
531
-
532
- def selection_header_state
533
- total = display_rows.size
534
- selected = @selected_row_keys.size
535
- {
536
- checked: total.positive? && selected == total,
537
- indeterminate: selected.positive? && selected < total
538
- }
385
+ column.sort_order || column.default_sort_order
539
386
  end
540
387
 
541
388
  private
542
389
 
543
- def normalize_row_selection!
544
- @selected_row_keys = Array(@row_selection&.dig(:selected_row_keys) || @row_selection&.dig(:selectedRowKeys)).map(&:to_s)
545
- @row_selection_type = @row_selection.present? ? (@row_selection&.dig(:type)&.to_sym || :checkbox) : nil
546
- @row_selection_preserve = @row_selection&.dig(:preserve_selected_row_keys) || @row_selection&.dig(:preserveSelectedRowKeys) || false
547
- @row_selection_selections = @row_selection&.dig(:selections)
548
- end
549
-
550
- def normalize_expandable!
551
- @expanded_row_keys = Array(@expandable&.dig(:expanded_row_keys) || @expandable&.dig(:expandedRowKeys) || @expandable&.dig(:default_expanded_row_keys) || @expandable&.dig(:defaultExpandedRowKeys)).map(&:to_s)
552
- return unless @expandable.present?
553
-
554
- @expandable[:show_expand_column] = true if @expandable[:show_expand_column].nil?
555
- end
556
-
390
+ sig { void }
557
391
  def validate_props!
558
392
  validate_inclusion!(:size, SIZES)
559
- validate_inclusion!(:row_selection_type, ROW_SELECTION_TYPES) if @row_selection.present?
393
+ if @row_selection
394
+ raise ArgumentError, "row_selection type must be one of #{ROW_SELECTION_TYPES.inspect}" unless ROW_SELECTION_TYPES.include?(@row_selection.type)
395
+ end
560
396
  @sort_directions.each do |direction|
561
397
  raise ArgumentError, "sort_directions must be one of #{SORT_DIRECTIONS.inspect}" unless SORT_DIRECTIONS.include?(direction)
562
398
  end
563
399
  end
564
400
 
401
+ sig { params(value: T.nilable(T::Hash[Types::HtmlKey, ScrollAxisValue])).returns(T.nilable(ScrollConfig)) }
565
402
  def normalize_scroll(value)
566
403
  return nil unless value.is_a?(Hash)
567
404
 
568
405
  {
569
- x: dimension_to_css(value[:x]),
570
- y: dimension_to_css(value[:y])
406
+ x: dimension_to_css(string_or_numeric(value[:x] || value["x"])),
407
+ y: dimension_to_css(string_or_numeric(value[:y] || value["y"]))
571
408
  }.compact.presence
572
409
  end
573
410
 
574
- def responsive_classes(column)
575
- responsive = column[:responsive]
576
- return [] unless responsive.present?
411
+ sig { params(value: T.nilable(Types::HtmlKey), fallback: Symbol).returns(Symbol) }
412
+ def normalize_component_symbol(value, fallback:)
413
+ return value if value.is_a?(Symbol)
414
+ return value.to_sym if value.is_a?(String) && value.present?
577
415
 
578
- responsive.map do |breakpoint|
579
- "hakumi-table-col-show-#{breakpoint}"
580
- end.prepend("hakumi-table-col-responsive")
581
- end
582
-
583
- def extract_sort_value(column, row, raw_value)
584
- sort_value_config = column[:sort_value]
585
- return raw_value unless sort_value_config
586
-
587
- if sort_value_config.respond_to?(:call)
588
- sort_value_config.call(raw_value, row)
589
- elsif sort_value_config.is_a?(Symbol) || sort_value_config.is_a?(String)
590
- row[sort_value_config.to_sym]
591
- else
592
- raw_value
593
- end
416
+ fallback
594
417
  end
595
418
 
596
- def normalize_responsive_breakpoints(value)
597
- return nil unless value.present?
419
+ sig { params(value: HakumiComponents::Table::DefinitionTypes::RawEntry).returns(HakumiComponents::Table::DefinitionTypes::SearchValue) }
420
+ def normalize_filter_search(value)
421
+ return value if value.is_a?(String) || value.is_a?(Symbol) || value == true || value == false
598
422
 
599
- Array(value).map do |breakpoint|
600
- sym = breakpoint.to_s.downcase.to_sym
601
- sym if RESPONSIVE_BREAKPOINTS.include?(sym)
602
- end.compact.presence
603
- end
604
-
605
- def normalize_pagination_options(options)
606
- normalized = options.symbolize_keys
607
-
608
- total = normalized[:total] || (@data_source.respond_to?(:size) ? @data_source.size : display_rows.size)
609
- current = normalized[:current] || 1
610
- page_size = normalized[:page_size] || 10
611
-
612
- result = {
613
- total: total,
614
- current: current,
615
- page_size: page_size
616
- }
617
-
618
- %i[
619
- size align simple show_size_changer show_quick_jumper
620
- page_size_options page_param per_page_param href turbo_frame turbo_action
621
- show_total hide_on_single_page prev_text next_text preserve_params
622
- ].each do |key|
623
- result[key] = normalized[key] if normalized.key?(key)
624
- end
625
-
626
- result
423
+ false
627
424
  end
628
425
 
426
+ sig { override.returns(T::Array[ColumnInput]) }
629
427
  def columns_data
630
- return Array(@columns_data) if @columns_data.present?
631
- return columns.map(&:to_h) if columns.any?
428
+ return @columns_data if @columns_data && !@columns_data.empty?
632
429
 
633
- []
634
- end
430
+ slot_columns = respond_to?(:columns) ? public_send(:columns) : nil
431
+ return [] unless slot_columns.is_a?(Array) && slot_columns.any?
635
432
 
636
- def build_display_rows
637
- rows = Array(@data_source)
638
- rows = flatten_tree(rows)
639
- apply_pagination(rows)
640
- end
433
+ slot_columns.filter_map do |column|
434
+ column_hash = column.respond_to?(:to_h) ? column.to_h : nil
435
+ next unless column_hash.is_a?(Hash)
641
436
 
642
- def flatten_tree(rows, depth = 0)
643
- rows.flat_map do |row|
644
- children = row.respond_to?(:[]) ? row[@children_column_name] || row[@children_column_name.to_s] : nil
645
- current = { row: row, depth: depth }
646
- if children.respond_to?(:each)
647
- [ current, *flatten_tree(children, depth + 1) ]
648
- else
649
- [ current ]
650
- end
437
+ column_hash
651
438
  end
652
439
  end
653
440
 
654
- def apply_pagination(rows)
655
- return rows unless @pagination.is_a?(Hash)
656
-
657
- # Skip client-side pagination if data is already paginated server-side
658
- return rows if @pagination[:server_side] || @pagination[:href]
659
-
660
- current = @pagination[:current] || @pagination[:page] || 1
661
- page_size = @pagination[:page_size] || @pagination[:pageSize] || 10
662
- start = (current.to_i - 1) * page_size.to_i
663
- rows.slice(start, page_size.to_i) || []
664
- end
665
-
666
- def value_from_row(row, data_index)
667
- return nil if data_index.nil?
441
+ sig { override.returns(HakumiComponents::Table::RowRenderState) }
442
+ def row_render_state
443
+ state = @row_render_state
444
+ return state unless state.nil?
668
445
 
669
- if row.is_a?(Hash)
670
- return row[data_index] if row.key?(data_index)
671
- return row[data_index.to_s] if row.key?(data_index.to_s)
672
- end
673
-
674
- return row.public_send(data_index) if row.respond_to?(data_index)
675
-
676
- nil
446
+ state = HakumiComponents::Table::RowRenderState.new(
447
+ row_key: @row_key,
448
+ row_selection: @row_selection,
449
+ expandable: @expandable,
450
+ row_class_name: @row_class_name
451
+ )
452
+ @row_render_state = state
677
453
  end
678
454
 
679
- def selection_cell(row, row_index)
680
- row_key = row_key_for(row, row_index)
681
- {
682
- type: @row_selection_type,
683
- row_key: row_key,
684
- checked: row_selected?(row_key)
685
- }
455
+ sig { override.returns(Integer) }
456
+ def table_indent_size
457
+ @indent_size
686
458
  end
687
459
 
688
- def expand_cell(row, row_index)
689
- row_key = row_key_for(row, row_index)
690
- {
691
- row_key: row_key,
692
- expanded: expanded_row?(row_key)
693
- }
694
- end
460
+ sig { params(value: HakumiComponents::Table::DefinitionTypes::WidthValue).returns(HakumiComponents::Table::DefinitionTypes::WidthValue) }
461
+ def string_or_numeric(value)
462
+ return value if value.is_a?(String) || value.is_a?(Numeric)
695
463
 
696
- # Normalizes row drag configuration.
697
- # Can be: true (drag whole row), :handle (drag via handle only), or Hash with options
698
- #
699
- # @param value [Boolean, Symbol, Hash, nil] row drag configuration
700
- # @return [Hash, nil] normalized configuration { enabled: true, handle: false }
701
- def normalize_row_drag(value)
702
- return nil if value.nil? || value == false
703
-
704
- case value
705
- when true
706
- { enabled: true, handle: false }
707
- when :handle
708
- { enabled: true, handle: true }
709
- when Hash
710
- normalized = value.deep_symbolize_keys
711
- {
712
- enabled: normalized.fetch(:enabled, true),
713
- handle: normalized.fetch(:handle, false)
714
- }
715
- else
716
- nil
717
- end
464
+ nil
718
465
  end
719
466
 
720
- def columns_config_json
721
- leaf_columns.map do |col|
722
- {
723
- key: col[:key],
724
- dataIndex: col[:data_index],
725
- sorter: col[:sorter].present?
726
- }.compact
727
- end.to_json
728
- end
467
+ public :columns_data
729
468
  end
730
469
  end
731
470
  end