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,14 +1,16 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  module Descriptions
5
- # Hakumi Descriptions component
6
- # Displays multiple read-only fields in a group.
7
6
  class Component < HakumiComponents::BaseComponent
8
- SIZE_OPTIONS = [ :default, :middle, :small ].freeze
9
- LAYOUT_OPTIONS = [ :horizontal, :vertical ].freeze
7
+ extend T::Sig
10
8
 
11
- COLUMN_BREAKPOINTS = [ :xs, :sm, :md, :lg, :xl, :xxl ].freeze
9
+ LAYOUTS = T.let(%i[horizontal vertical].freeze, T::Array[Symbol])
10
+ COLUMN_BREAKPOINTS = T.let(%i[xs sm md lg xl xxl].freeze, T::Array[Symbol])
11
+
12
+ renders_one :title
13
+ renders_one :extra
12
14
 
13
15
  renders_many :items, ->(
14
16
  label:,
@@ -16,7 +18,6 @@ module HakumiComponents
16
18
  span: 1,
17
19
  label_style: nil,
18
20
  content_style: nil,
19
- **options,
20
21
  &block
21
22
  ) do
22
23
  item = HakumiComponents::Descriptions::Item::Component.new(
@@ -24,13 +25,24 @@ module HakumiComponents
24
25
  content: content,
25
26
  span: span,
26
27
  label_style: label_style,
27
- content_style: content_style,
28
- **options
28
+ content_style: content_style
29
29
  )
30
30
  item.content = capture(&block) if block
31
31
  item
32
32
  end
33
33
 
34
+ sig do
35
+ params(
36
+ title: Types::Renderable,
37
+ extra: Types::Renderable,
38
+ bordered: T::Boolean,
39
+ size: Symbol,
40
+ layout: Symbol,
41
+ column: T.any(Integer, T::Hash[Symbol, Integer]),
42
+ colon: T::Boolean,
43
+ html_options: Types::HtmlAttributeValue
44
+ ).void
45
+ end
34
46
  def initialize(
35
47
  title: nil,
36
48
  extra: nil,
@@ -41,46 +53,76 @@ module HakumiComponents
41
53
  colon: true,
42
54
  **html_options
43
55
  )
44
- @title = title
45
- @extra = extra
46
- @bordered = bordered
47
- @size = size
48
- @layout = layout
49
- @column = column
50
- @colon = colon
51
- @html_options = html_options
56
+ @title = T.let(title, Types::Renderable)
57
+ @extra = T.let(extra, Types::Renderable)
58
+ @bordered = T.let(cast_boolean(bordered) ? true : false, T::Boolean)
59
+ @size = T.let(size.to_sym, Symbol)
60
+ @layout = T.let(layout.to_sym, Symbol)
61
+ @column = T.let(normalize_column(column), T.any(Integer, T::Hash[Symbol, Integer]))
62
+ @colon = T.let(cast_boolean(colon) != false, T::Boolean)
63
+ @html_options = T.let(html_options, Types::HtmlAttributes)
52
64
 
53
65
  validate_props!
54
66
  end
55
67
 
68
+ sig { returns(Types::HtmlAttributes) }
69
+ def wrapper_attributes
70
+ merge_attributes({ class: wrapper_classes }, @html_options)
71
+ end
72
+
73
+ sig { returns(T::Boolean) }
74
+ def header?
75
+ title_content.present? || extra_content.present?
76
+ end
77
+
78
+ sig { returns(T::Boolean) }
79
+ def vertical_layout?
80
+ @layout == :vertical
81
+ end
82
+
83
+ sig { returns(Types::RenderedContent) }
84
+ def title_content
85
+ return render_value(title) if title?
86
+
87
+ render_value(@title)
88
+ end
89
+
90
+ sig { returns(Types::RenderedContent) }
91
+ def extra_content
92
+ return render_value(extra) if extra?
93
+
94
+ render_value(@extra)
95
+ end
96
+
56
97
  private
57
98
 
99
+ sig { void }
58
100
  def validate_props!
59
- validate_inclusion!(:size, SIZE_OPTIONS)
60
- validate_inclusion!(:layout, LAYOUT_OPTIONS)
101
+ validate_inclusion!(:size, SIZES)
102
+ validate_inclusion!(:layout, LAYOUTS)
61
103
  end
62
104
 
105
+ sig { returns(Integer) }
63
106
  def max_column_count
64
- case @column
65
- when Integer
107
+ if @column.is_a?(Integer)
66
108
  @column.positive? ? @column : 3
67
- when Hash
68
- values = @column.values.compact
69
- values.empty? ? 3 : values.max
70
109
  else
71
- 3
110
+ values = @column.values
111
+ return 3 if values.empty?
112
+
113
+ values.reduce(0) { |max, value| value > max ? value : max }
72
114
  end
73
115
  end
74
116
 
117
+ sig { returns(T::Array[T::Array[[ HakumiComponents::Descriptions::Item::Component, Integer ]]]) }
75
118
  def rows
76
119
  cols = max_column_count
77
- result = []
78
- current_row = []
79
- current_span = 0
120
+ result = T.let([], T::Array[T::Array[[ HakumiComponents::Descriptions::Item::Component, Integer ]]])
121
+ current_row = T.let([], T::Array[[ HakumiComponents::Descriptions::Item::Component, Integer ]])
122
+ current_span = T.let(0, Integer)
80
123
 
81
124
  items.each do |item|
82
- span = item.span.to_i
83
- span = 1 if span <= 0
125
+ span = item.span.positive? ? item.span : 1
84
126
  span = cols if span > cols
85
127
 
86
128
  if current_span + span > cols && !current_row.empty?
@@ -95,36 +137,44 @@ module HakumiComponents
95
137
 
96
138
  result << current_row unless current_row.empty?
97
139
 
98
- # Fill remaining space in the last row by extending the last item's span
99
140
  result.map do |row|
100
141
  total_span = row.sum { |(_, span)| span }
101
142
  if total_span < cols && !row.empty?
102
143
  remaining = cols - total_span
103
- last_item, last_span = row.last
104
- row[0...-1] + [ [ last_item, last_span + remaining ] ]
144
+ last_item, last_span = row.fetch(row.length - 1)
145
+ prefix = row[0, row.length - 1] || []
146
+ prefix + [ [ last_item, last_span + remaining ] ]
105
147
  else
106
148
  row
107
149
  end
108
150
  end
109
151
  end
110
152
 
153
+ sig { returns(String) }
111
154
  def wrapper_classes
112
- column_classes = build_column_classes
155
+ extras = T.let(build_column_classes, T::Array[String])
156
+ existing_classes = html_classes(@html_options)
157
+ if existing_classes.is_a?(Array)
158
+ extras.concat(existing_classes.compact)
159
+ elsif existing_classes.is_a?(String)
160
+ extras << existing_classes
161
+ end
113
162
 
114
163
  class_names(
115
164
  "descriptions",
116
165
  {
117
166
  bordered: @bordered,
118
- "small": @size == :small,
119
- "middle": @size == :middle,
120
- "vertical": @layout == :vertical
167
+ small: @size == :small,
168
+ default: @size == :default,
169
+ vertical: vertical_layout?
121
170
  },
122
- column_classes
171
+ extras
123
172
  )
124
173
  end
125
174
 
175
+ sig { returns(T::Array[String]) }
126
176
  def build_column_classes
127
- base = []
177
+ base = T.let([], T::Array[String])
128
178
 
129
179
  case @column
130
180
  when Integer
@@ -144,38 +194,25 @@ module HakumiComponents
144
194
  base
145
195
  end
146
196
 
147
- def wrapper_attributes
148
- merge_attributes({ class: wrapper_classes }, @html_options)
149
- end
150
-
151
- def table_classes
152
- "hakumi-descriptions-view"
153
- end
154
-
197
+ sig { returns(String) }
155
198
  def label_cell_classes
156
- classes = [ "hakumi-descriptions-item-label" ]
157
- classes << "hakumi-descriptions-item-label-colon" if @colon && @layout == :horizontal
158
- classes.join(" ")
199
+ class_names("descriptions-item-label", { colon: @colon && !vertical_layout? })
159
200
  end
160
201
 
202
+ sig { returns(String) }
161
203
  def content_cell_classes
162
204
  "hakumi-descriptions-item-content"
163
205
  end
164
206
 
165
- def render_title
166
- return nil unless @title
167
-
168
- content_tag(:div, class: "hakumi-descriptions-title") do
169
- @title
170
- end
171
- end
172
-
173
- def render_extra
174
- return nil unless @extra
207
+ sig { params(column: T.any(Integer, T::Hash[Symbol, Integer])).returns(T.any(Integer, T::Hash[Symbol, Integer])) }
208
+ def normalize_column(column)
209
+ return column if column.is_a?(Integer)
175
210
 
176
- content_tag(:div, class: "hakumi-descriptions-extra") do
177
- @extra
211
+ normalized = T.let({}, T::Hash[Symbol, Integer])
212
+ column.each do |key, value|
213
+ normalized[key.to_sym] = value
178
214
  end
215
+ normalized
179
216
  end
180
217
  end
181
218
  end
@@ -1,12 +1,31 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  module Descriptions
5
6
  module Item
6
7
  class Component < HakumiComponents::BaseComponent
7
- attr_accessor :content
8
- attr_reader :label, :span, :label_style, :content_style
8
+ extend T::Sig
9
9
 
10
+ sig { returns(Types::Renderable) }
11
+ attr_reader :label, :content
12
+
13
+ sig { returns(Integer) }
14
+ attr_reader :span
15
+
16
+ sig { returns(T.nilable(String)) }
17
+ attr_reader :label_style, :content_style
18
+
19
+ sig do
20
+ params(
21
+ label: Types::Renderable,
22
+ content: Types::Renderable,
23
+ span: Integer,
24
+ label_style: T.nilable(String),
25
+ content_style: T.nilable(String),
26
+ html_options: Types::HtmlAttributeValue
27
+ ).void
28
+ end
10
29
  def initialize(
11
30
  label:,
12
31
  content: nil,
@@ -15,12 +34,17 @@ module HakumiComponents
15
34
  content_style: nil,
16
35
  **html_options
17
36
  )
18
- @label = label
19
- @content = content
20
- @span = span
21
- @label_style = label_style
22
- @content_style = content_style
23
- @html_options = html_options
37
+ @label = T.let(label, Types::Renderable)
38
+ @content = T.let(content, Types::Renderable)
39
+ @span = T.let(span, Integer)
40
+ @label_style = T.let(label_style, T.nilable(String))
41
+ @content_style = T.let(content_style, T.nilable(String))
42
+ @html_options = T.let(html_options, Types::HtmlAttributes)
43
+ end
44
+
45
+ sig { params(value: Types::Renderable).returns(Types::Renderable) }
46
+ def content=(value)
47
+ @content = value
24
48
  end
25
49
  end
26
50
  end
@@ -1,11 +1,23 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  module Divider
5
6
  class Component < HakumiComponents::BaseComponent
6
- ORIENTATIONS = [ :horizontal, :vertical ].freeze
7
- PLACEMENTS = [ :left, :center, :right ].freeze
7
+ extend T::Sig
8
8
 
9
+ ORIENTATIONS = T.let([ :horizontal, :vertical ].freeze, T::Array[Symbol])
10
+ PLACEMENTS = T.let([ :left, :center, :right ].freeze, T::Array[Symbol])
11
+
12
+ sig do
13
+ params(
14
+ orientation: Symbol,
15
+ dashed: T::Boolean,
16
+ plain: T::Boolean,
17
+ orientation_margin: T.nilable(Symbol),
18
+ html_options: HakumiComponents::Types::HtmlAttributeValue
19
+ ).void
20
+ end
9
21
  def initialize(
10
22
  orientation: :horizontal,
11
23
  dashed: false,
@@ -13,15 +25,16 @@ module HakumiComponents
13
25
  orientation_margin: nil,
14
26
  **html_options
15
27
  )
16
- @orientation = orientation
17
- @dashed = dashed
18
- @plain = plain
19
- @orientation_margin = orientation_margin
20
- @html_options = html_options
28
+ @orientation = T.let(orientation, Symbol)
29
+ @dashed = T.let(dashed, T::Boolean)
30
+ @plain = T.let(plain, T::Boolean)
31
+ @orientation_margin = T.let(orientation_margin, T.nilable(Symbol))
32
+ @html_options = T.let(html_options, HakumiComponents::Types::HtmlAttributes)
21
33
 
22
34
  validate_props!
23
35
  end
24
36
 
37
+ sig { returns(ActiveSupport::SafeBuffer) }
25
38
  def call
26
39
  if @orientation == :vertical
27
40
  content_tag(:span, nil, wrapper_attributes)
@@ -32,30 +45,37 @@ module HakumiComponents
32
45
 
33
46
  private
34
47
 
48
+ sig { void }
35
49
  def validate_props!
36
50
  validate_inclusion!(:orientation, ORIENTATIONS)
37
51
  validate_inclusion!(:orientation_margin, PLACEMENTS) if @orientation_margin
38
52
  end
39
53
 
54
+ sig { returns(String) }
40
55
  def wrapper_classes
41
- classes = [ "hakumi-divider", "hakumi-divider-#{@orientation}" ]
42
- classes << "hakumi-divider-dashed" if @dashed
43
- classes << "hakumi-divider-with-text" if content.present?
44
- classes << "hakumi-divider-plain" if @plain && content.present?
45
- classes << "hakumi-divider-with-text-#{@orientation_margin}" if content.present? && @orientation_margin
46
- classes << @html_options[:class] if @html_options[:class]
47
- classes.join(" ")
56
+ with_text = @orientation == :horizontal && content.present?
57
+ modifiers = {
58
+ @orientation => true,
59
+ dashed: @dashed,
60
+ "with-text": with_text,
61
+ plain: @plain && with_text
62
+ }
63
+ modifiers[:"with-text-#{@orientation_margin}"] = true if with_text && @orientation_margin
64
+
65
+ class_names("divider", modifiers, html_classes(@html_options))
48
66
  end
49
67
 
68
+ sig { returns(HakumiComponents::Types::HtmlAttributes) }
50
69
  def wrapper_attributes
51
- attrs = {
70
+ attrs = T.let({
52
71
  class: wrapper_classes,
53
72
  role: "separator"
54
- }
73
+ }, HakumiComponents::Types::HtmlAttributes)
55
74
 
56
75
  merge_attributes(attrs, @html_options.except(:class))
57
76
  end
58
77
 
78
+ sig { returns(T.nilable(ActiveSupport::SafeBuffer)) }
59
79
  def content_wrapper
60
80
  return nil if content.blank?
61
81
 
@@ -23,8 +23,8 @@
23
23
  </span>
24
24
  </button>
25
25
  <% end %>
26
- <% if header? %>
27
- <div class="hakumi-drawer-title"><%= header %></div>
26
+ <% if header_content.present? %>
27
+ <div class="hakumi-drawer-title"><%= header_content %></div>
28
28
  <% end %>
29
29
  </div>
30
30
  <% if extra? %>
@@ -1,21 +1,68 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  module Drawer
5
- class Component < HakumiComponents::BaseComponent
6
- PLACEMENTS = %i[left right top bottom].freeze
7
- SIZES = {
6
+ class Component < HakumiComponents::BaseComponent
7
+ extend T::Sig
8
+
9
+ Placement = T.type_alias { Types::HtmlKey }
10
+ Size = T.type_alias { T.any(Integer, Types::HtmlKey) }
11
+ ResolvedSize = T.type_alias { T.any(Symbol, Integer) }
12
+
13
+ PLACEMENTS = T.let(%i[left right top bottom].freeze, T::Array[Symbol])
14
+ SIZES = T.let({
8
15
  default: 378,
9
16
  large: 736
10
- }.freeze
17
+ }.freeze, T::Hash[Symbol, Integer])
11
18
 
12
- # Slots for content
13
19
  renders_one :header
14
20
  renders_one :body
15
21
  renders_one :footer
16
22
  renders_one :extra
17
23
 
24
+ sig do
25
+ params(
26
+ params: BaseComponent::ControllerOptions
27
+ ).returns(HakumiComponents::Types::HtmlAttributes)
28
+ end
29
+ def self.extract_controller_locals(params)
30
+ {
31
+ open: boolean_html_param(html_param(params, :open)),
32
+ placement: symbol_html_param(html_param(params, :placement)),
33
+ size: size_param(html_param(params, :size)),
34
+ width: integer_html_param(html_param(params, :width)),
35
+ height: integer_html_param(html_param(params, :height)),
36
+ closable: boolean_html_param(html_param(params, :closable) || true),
37
+ mask: boolean_html_param(html_param(params, :mask) || true),
38
+ mask_closable: boolean_html_param(html_param(params, :mask_closable) || true),
39
+ keyboard: boolean_html_param(html_param(params, :keyboard) || true),
40
+ destroy_on_close: boolean_html_param(html_param(params, :destroy_on_close)),
41
+ title: html_primitive_param(html_param(params, :title)),
42
+ message: html_primitive_param(html_param(params, :message))
43
+ }.compact
44
+ end
45
+
46
+ sig do
47
+ params(
48
+ title: HakumiComponents::Types::Renderable,
49
+ message: HakumiComponents::Types::Renderable,
50
+ open: T::Boolean,
51
+ placement: Placement,
52
+ size: Size,
53
+ width: T.nilable(Integer),
54
+ height: T.nilable(Integer),
55
+ closable: T::Boolean,
56
+ mask: T::Boolean,
57
+ mask_closable: T::Boolean,
58
+ keyboard: T::Boolean,
59
+ destroy_on_close: T::Boolean,
60
+ html_options: HakumiComponents::Types::HtmlAttributeValue
61
+ ).void
62
+ end
18
63
  def initialize(
64
+ title: nil,
65
+ message: nil,
19
66
  open: false,
20
67
  placement: :right,
21
68
  size: :default,
@@ -26,49 +73,56 @@ module HakumiComponents
26
73
  mask_closable: true,
27
74
  keyboard: true,
28
75
  destroy_on_close: false,
29
- **html_attributes
76
+ **html_options
30
77
  )
31
- @open = open
32
- @placement = placement
33
- @size = size
34
- @width = width
35
- @height = height
36
- @closable = closable
37
- @mask = mask
38
- @mask_closable = mask_closable
39
- @keyboard = keyboard
40
- @destroy_on_close = destroy_on_close
41
- @html_attributes = html_attributes
78
+ @title = T.let(title, HakumiComponents::Types::Renderable)
79
+ @message = T.let(message, HakumiComponents::Types::Renderable)
80
+ @open = T.let(open, T::Boolean)
81
+ @placement = T.let(placement.to_sym, Symbol)
82
+ @size = T.let(size.is_a?(String) ? size.to_sym : size, ResolvedSize)
83
+ @width = T.let(width, T.nilable(Integer))
84
+ @height = T.let(height, T.nilable(Integer))
85
+ @closable = T.let(closable, T::Boolean)
86
+ @mask = T.let(mask, T::Boolean)
87
+ @mask_closable = T.let(mask_closable, T::Boolean)
88
+ @keyboard = T.let(keyboard, T::Boolean)
89
+ @destroy_on_close = T.let(destroy_on_close, T::Boolean)
90
+ @html_options = T.let(html_options, HakumiComponents::Types::HtmlAttributes)
42
91
 
43
92
  validate_props!
44
93
  end
45
94
 
95
+ sig { returns(String) }
46
96
  def drawer_classes
47
- classes = [ "hakumi-drawer", "hakumi-drawer-#{@placement}" ]
48
- classes << "hakumi-drawer-open" if @open
49
- classes.join(" ")
97
+ class_names("drawer", { @placement => true, open: @open })
50
98
  end
51
99
 
100
+ sig { returns(HakumiComponents::Types::HtmlAttributes) }
52
101
  def root_attributes
53
102
  base_attrs = {
54
103
  class: drawer_classes,
55
104
  data: data_attributes
56
105
  }
57
106
 
58
- merge_attributes(base_attrs, @html_attributes)
107
+ merge_attributes(base_attrs, @html_options)
59
108
  end
60
109
 
110
+ sig { returns(HakumiComponents::Types::DataAttributes) }
61
111
  def data_attributes
62
- {
112
+ data = T.let({
63
113
  controller: "hakumi--drawer",
64
114
  hakumi__drawer_open_value: @open,
65
115
  hakumi__drawer_placement_value: @placement.to_s,
66
116
  hakumi__drawer_mask_closable_value: @mask_closable,
67
117
  hakumi__drawer_keyboard_value: @keyboard,
68
118
  hakumi__drawer_destroy_on_close_value: @destroy_on_close
69
- }.merge(@html_attributes[:data] || {})
119
+ }, HakumiComponents::Types::DataAttributes)
120
+ existing = @html_options[:data]
121
+ existing.each { |key, value| data[key] = value } if existing.is_a?(Hash)
122
+ data
70
123
  end
71
124
 
125
+ sig { returns(String) }
72
126
  def wrapper_style
73
127
  size_value = resolve_size
74
128
  if %i[left right].include?(@placement)
@@ -78,31 +132,60 @@ module HakumiComponents
78
132
  end
79
133
  end
80
134
 
135
+ sig { returns(T::Boolean) }
81
136
  def render_header?
82
- header? || @closable || extra?
137
+ header? || value_present?(@title) || @closable || extra?
83
138
  end
84
139
 
140
+ sig { returns(T::Boolean) }
85
141
  def render_footer?
86
142
  footer?
87
143
  end
88
144
 
89
- # Content resolution: body slot > block content
145
+ sig { returns(HakumiComponents::Types::Renderable) }
90
146
  def body_content
91
- body? ? body : content
147
+ return render_value(body) if body?
148
+ return render_value(content) if content.present?
149
+
150
+ render_value(@message)
151
+ end
152
+
153
+ sig { returns(HakumiComponents::Types::Renderable) }
154
+ def header_content
155
+ return render_value(header) if header?
156
+
157
+ render_value(@title)
92
158
  end
93
159
 
94
160
  private
95
161
 
162
+ class << self
163
+ extend T::Sig
164
+
165
+ private
166
+
167
+ sig { params(value: HakumiComponents::Types::HtmlAttributeValue).returns(T.nilable(ResolvedSize)) }
168
+ def size_param(value)
169
+ return value if value.is_a?(Integer)
170
+ return symbol_html_param(value) if value.is_a?(String) || value.is_a?(Symbol)
171
+
172
+ nil
173
+ end
174
+ end
175
+
176
+ sig { returns(Integer) }
96
177
  def resolve_size
97
- return @size if @size.is_a?(Numeric) || @size.is_a?(String)
178
+ return @size if @size.is_a?(Integer)
98
179
 
99
- SIZES.fetch(@size, SIZES[:default])
180
+ value = SIZES[@size]
181
+ value.nil? ? SIZES.fetch(:default) : value
100
182
  end
101
183
 
184
+ sig { void }
102
185
  def validate_props!
103
186
  validate_inclusion!(:placement, PLACEMENTS)
104
187
  validate_inclusion!(:size, SIZES.keys) if @size.is_a?(Symbol)
105
188
  end
106
- end
189
+ end
107
190
  end
108
191
  end