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,34 +1,50 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
1
4
  module HakumiComponents
2
5
  module Space
3
6
  module Compact
4
- class Component < ViewComponent::Base
7
+ class Component < HakumiComponents::BaseComponent
8
+ extend T::Sig
9
+ DIRECTIONS = T.let(%i[horizontal vertical].freeze, T::Array[Symbol])
10
+
11
+ sig do
12
+ params(
13
+ direction: T.any(Symbol, String),
14
+ block: T::Boolean,
15
+ html_options: HakumiComponents::Types::HtmlAttributeValue
16
+ ).void
17
+ end
5
18
  def initialize(direction: :horizontal, block: false, **html_options)
6
- @direction = direction
7
- @block = block
8
- @html_options = html_options
19
+ @direction = T.let(direction.to_sym, Symbol)
20
+ @block = T.let(block, T::Boolean)
21
+ @html_options = T.let(html_options, HakumiComponents::Types::HtmlAttributes)
22
+
23
+ validate_props!
9
24
  end
10
25
 
11
26
  private
12
27
 
13
- def html_attributes
14
- attrs = @html_options.dup
15
- attrs[:class] = css_classes
16
- attrs[:style] = inline_styles
17
- attrs
28
+ sig { void }
29
+ def validate_props!
30
+ validate_inclusion!(:direction, DIRECTIONS)
18
31
  end
19
32
 
20
- def css_classes
21
- classes = [ "hakumi-space-compact" ]
22
- classes << "hakumi-space-compact-#{@direction}"
23
- classes << "hakumi-space-compact-block" if @block
24
- classes << @html_options[:class] if @html_options[:class]
25
- classes.join(" ")
33
+ sig { returns(String) }
34
+ def wrapper_classes
35
+ class_names(
36
+ "space-compact",
37
+ { @direction => true, block: @block },
38
+ html_classes(@html_options)
39
+ )
26
40
  end
27
41
 
28
- def inline_styles
29
- styles = []
30
- styles << @html_options[:style] if @html_options[:style]
31
- styles.join("; ")
42
+ sig { returns(HakumiComponents::Types::HtmlAttributes) }
43
+ def wrapper_attributes
44
+ merge_attributes(
45
+ { class: wrapper_classes },
46
+ @html_options.except(:class)
47
+ )
32
48
  end
33
49
  end
34
50
  end
@@ -1,4 +1,4 @@
1
- <div <%= tag.attributes(html_attributes) %>>
1
+ <div <%= tag.attributes(wrapper_attributes) %>>
2
2
  <% if items? %>
3
3
  <% items.each_with_index do |item, index| %>
4
4
  <%= item %>
@@ -1,69 +1,105 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
1
4
  module HakumiComponents
2
5
  module Space
3
- class Component < ViewComponent::Base
6
+ class Component < HakumiComponents::BaseComponent
7
+ extend T::Sig
8
+
9
+ Direction = T.type_alias { T.any(Symbol, String) }
10
+ Size = T.type_alias { T.any(Symbol, Integer) }
11
+
12
+ DIRECTIONS = T.let(%i[horizontal vertical].freeze, T::Array[Symbol])
13
+ ALIGNMENTS = T.let(%i[start center end baseline].freeze, T::Array[Symbol])
14
+
4
15
  renders_many :items, "ItemComponent"
5
16
 
17
+ sig do
18
+ params(
19
+ direction: Direction,
20
+ size: Size,
21
+ align: T.nilable(T.any(Symbol, String)),
22
+ wrap: T::Boolean,
23
+ block: T::Boolean,
24
+ split: HakumiComponents::Types::Renderable,
25
+ html_options: HakumiComponents::Types::HtmlAttributeValue
26
+ ).void
27
+ end
6
28
  def initialize(direction: :horizontal, size: :small, align: nil, wrap: false, block: false, split: nil, **html_options)
7
- @direction = direction
8
- @size = size
9
- @align = align
10
- @wrap = wrap
11
- @block = block
12
- @split = split
13
- @html_options = html_options
29
+ @direction = T.let(direction.to_sym, Symbol)
30
+ @size = T.let(size, Size)
31
+ @align = T.let(align&.to_sym, T.nilable(Symbol))
32
+ @wrap = T.let(wrap, T::Boolean)
33
+ @block = T.let(block, T::Boolean)
34
+ @split = T.let(split, HakumiComponents::Types::Renderable)
35
+ @html_options = T.let(html_options, HakumiComponents::Types::HtmlAttributes)
36
+
37
+ validate_props!
14
38
  end
15
39
 
40
+ sig { returns(HakumiComponents::Types::Renderable) }
16
41
  attr_reader :split
17
42
 
18
43
  private
19
44
 
20
- def html_attributes
21
- attrs = @html_options.dup
22
- attrs[:class] = css_classes
23
- attrs[:style] = inline_styles
24
- attrs
45
+ sig { void }
46
+ def validate_props!
47
+ validate_inclusion!(:direction, DIRECTIONS)
48
+ validate_inclusion!(:align, ALIGNMENTS) if @align
49
+ validate_size!
25
50
  end
26
51
 
27
- def css_classes
28
- classes = [ "hakumi-space" ]
29
- classes << "hakumi-space-#{@direction}"
30
- classes << "hakumi-space-align-#{@align}" if @align
31
- classes << "hakumi-space-wrap" if @wrap
32
- classes << "hakumi-space-block" if @block
33
- classes << @html_options[:class] if @html_options[:class]
34
- classes.join(" ")
52
+ sig { void }
53
+ def validate_size!
54
+ return if @size.is_a?(Integer)
55
+ return if SIZES.include?(@size)
56
+
57
+ raise ArgumentError, "size must be one of #{SIZES.inspect} or an Integer, got #{@size.inspect}"
35
58
  end
36
59
 
37
- def inline_styles
38
- styles = []
60
+ sig { returns(String) }
61
+ def wrapper_classes
62
+ class_names(
63
+ "space",
64
+ {
65
+ @direction => true,
66
+ "align-#{@align}": @align.present?,
67
+ wrap: @wrap,
68
+ block: @block
69
+ },
70
+ html_classes(@html_options)
71
+ )
72
+ end
39
73
 
74
+ sig { returns(HakumiComponents::Types::HtmlAttributes) }
75
+ def wrapper_attributes
76
+ merge_attributes(
77
+ { class: wrapper_classes, style: inline_styles },
78
+ @html_options.except(:class, :style)
79
+ )
80
+ end
81
+
82
+ sig { returns(String) }
83
+ def inline_styles
40
84
  gap_size = case @size
41
85
  when :small then "8px"
42
- when :middle then "16px"
86
+ when :default then "16px"
43
87
  when :large then "24px"
44
88
  when Integer then "#{@size}px"
45
89
  else "8px"
46
90
  end
47
91
 
48
- styles << "gap: #{gap_size}"
49
- styles << @html_options[:style] if @html_options[:style]
50
- styles.join("; ")
51
- end
92
+ styles = T.let([ "gap: #{gap_size}" ], T::Array[String])
93
+ custom_style = html_style(@html_options)
94
+ styles << custom_style if custom_style
52
95
 
53
- def call
54
- return nil if items.empty?
55
-
56
- safe_join(items.map { |item| content_tag(:div, item, class: "hakumi-space-item") }, split_content)
96
+ build_inline_style(styles) || "gap: #{gap_size}"
57
97
  end
58
98
 
59
- private
60
-
61
- def split_content
62
- return nil unless @split
63
-
64
- content_tag(:div, @split, class: "hakumi-space-split")
65
- end
66
99
  class ItemComponent < ViewComponent::Base
100
+ extend T::Sig
101
+
102
+ sig { returns(ActiveSupport::SafeBuffer) }
67
103
  def call
68
104
  content_tag(:div, content, class: "hakumi-space-item")
69
105
  end
@@ -1,39 +1,67 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  module Spin
5
6
  class Component < HakumiComponents::BaseComponent
6
- SIZES = [ :small, :default, :large ].freeze
7
+ extend T::Sig
7
8
 
9
+ DelayInput = T.type_alias { BaseComponent::DimensionInput }
10
+ ProgressPercent = T.type_alias { T.nilable(T.any(Numeric, Symbol)) }
11
+ PercentInput = T.type_alias { T.nilable(T.any(Numeric, Symbol, String)) }
12
+ TipContent = T.type_alias { T.nilable(Types::Renderable) }
13
+ ControllerLocalValue = T.type_alias { Types::HtmlPrimitive }
14
+
15
+ sig do
16
+ params(params: BaseComponent::ControllerOptions).returns(T::Hash[Symbol, ControllerLocalValue])
17
+ end
8
18
  def self.extract_controller_locals(params)
19
+ spinning_value = html_param(params, :spinning)
20
+
9
21
  {
10
- spinning: params.key?(:spinning) ? ActiveModel::Type::Boolean.new.cast(params[:spinning]) : true,
11
- size: params[:size]&.to_sym,
12
- tip: params[:tip],
13
- delay: parse_delay(params[:delay]),
14
- fullscreen: ActiveModel::Type::Boolean.new.cast(params[:fullscreen]),
15
- percent: parse_percent(params[:percent])
22
+ spinning: spinning_value.nil? ? true : boolean_html_param(spinning_value) != false,
23
+ size: symbol_html_param(html_param(params, :size)),
24
+ tip: string_html_param(html_param(params, :tip)),
25
+ delay: parse_delay(html_param(params, :delay)),
26
+ fullscreen: boolean_html_param(html_param(params, :fullscreen)) == true,
27
+ percent: parse_percent(html_param(params, :percent))
16
28
  }
17
29
  end
18
30
 
31
+ sig { params(value: Types::HtmlAttributeValue).returns(T.nilable(Integer)) }
19
32
  def self.parse_delay(value)
20
33
  return nil if value.nil?
21
- return value if value.is_a?(Numeric)
34
+ return value if value.is_a?(Integer)
35
+ return value.to_i if value.is_a?(Float)
22
36
 
23
37
  value.to_s.strip.presence&.to_i
24
38
  end
25
39
 
40
+ sig { params(value: Types::HtmlAttributeValue).returns(ProgressPercent) }
26
41
  def self.parse_percent(value)
27
42
  return nil if value.nil?
28
43
 
29
44
  string_value = value.to_s.strip
30
45
  return :auto if string_value == "auto"
31
46
 
32
- return value if value.is_a?(Numeric)
47
+ return value if value.is_a?(Integer)
48
+ return value if value.is_a?(Float)
33
49
 
34
50
  string_value.presence&.to_f
35
51
  end
36
52
 
53
+ sig do
54
+ params(
55
+ spinning: T::Boolean,
56
+ size: T.nilable(Symbol),
57
+ tip: TipContent,
58
+ delay: DelayInput,
59
+ indicator: TipContent,
60
+ fullscreen: T::Boolean,
61
+ percent: PercentInput,
62
+ html_options: Types::HtmlAttributeValue
63
+ ).void
64
+ end
37
65
  def initialize(
38
66
  spinning: true,
39
67
  size: :default,
@@ -44,18 +72,19 @@ module HakumiComponents
44
72
  percent: nil,
45
73
  **html_options
46
74
  )
47
- @spinning = ActiveModel::Type::Boolean.new.cast(spinning)
48
- @size = (size || :default).to_sym
49
- @tip = tip
50
- @delay = delay
51
- @indicator = indicator
52
- @fullscreen = fullscreen
53
- @percent = normalize_percent(percent)
54
- @html_options = html_options
75
+ @spinning = T.let(cast_boolean(spinning) == true, T::Boolean)
76
+ @size = T.let(size.nil? ? :default : size.to_sym, Symbol)
77
+ @tip = T.let(tip, TipContent)
78
+ @delay = T.let(normalize_delay(delay), Integer)
79
+ @indicator = T.let(indicator, TipContent)
80
+ @fullscreen = T.let(fullscreen, T::Boolean)
81
+ @percent = T.let(normalize_percent(percent), ProgressPercent)
82
+ @html_options = T.let(html_options, Types::HtmlAttributes)
55
83
 
56
84
  validate_props!
57
85
  end
58
86
 
87
+ sig { returns(Types::HtmlAttributes) }
59
88
  def wrapper_attributes
60
89
  merge_attributes(
61
90
  {
@@ -69,10 +98,12 @@ module HakumiComponents
69
98
  )
70
99
  end
71
100
 
101
+ sig { returns(T::Boolean) }
72
102
  def nested?
73
- content? && !@fullscreen
103
+ content.present? && !@fullscreen
74
104
  end
75
105
 
106
+ sig { returns(Types::RenderedContent) }
76
107
  def indicator_markup
77
108
  return render_value(@indicator) if @indicator.present?
78
109
  return progress_indicator if progress?
@@ -80,25 +111,33 @@ module HakumiComponents
80
111
  default_indicator
81
112
  end
82
113
 
114
+ sig { returns(Types::RenderedContent) }
83
115
  def tip_markup
84
116
  render_value(@tip)
85
117
  end
86
118
 
119
+ sig { returns(T::Boolean) }
87
120
  def show_text?
88
121
  @tip.present?
89
122
  end
90
123
 
124
+ sig { returns(T::Boolean) }
91
125
  def progress?
92
126
  !@percent.nil?
93
127
  end
94
128
 
129
+ sig { returns(T::Boolean) }
95
130
  def progress_auto?
96
131
  @percent == :auto
97
132
  end
98
133
 
134
+ sig { returns(HakumiComponents::Progress::Component) }
99
135
  def progress_component
136
+ percent = numeric_percent
137
+ raise "progress_component requires numeric percent" if percent.nil?
138
+
100
139
  HakumiComponents::Progress::Component.new(
101
- percent: @percent,
140
+ percent: percent,
102
141
  type: :circle,
103
142
  size: progress_size,
104
143
  stroke_width: 6,
@@ -108,6 +147,7 @@ module HakumiComponents
108
147
 
109
148
  private
110
149
 
150
+ sig { void }
111
151
  def validate_props!
112
152
  validate_inclusion!(:size, SIZES)
113
153
 
@@ -124,6 +164,7 @@ module HakumiComponents
124
164
  @percent = @percent.clamp(0, 100)
125
165
  end
126
166
 
167
+ sig { returns(String) }
127
168
  def wrapper_classes
128
169
  modifiers = {
129
170
  spinning: spinning_class?,
@@ -137,17 +178,16 @@ module HakumiComponents
137
178
  modifiers[:sm] = true if @size == :small
138
179
  modifiers[:lg] = true if @size == :large
139
180
 
140
- extras = [ @html_options[:class] ]
141
- extras << "hakumi-spin-nested-loading" if nested?
142
-
143
- class_names("spin", modifiers, extras)
181
+ classes = component_classes("spin", modifiers, @html_options)
182
+ nested? ? [ classes, "hakumi-spin-nested-loading" ].join(" ") : classes
144
183
  end
145
184
 
185
+ sig { returns(Types::DataAttributes) }
146
186
  def data_attributes
147
- data = {
187
+ data = T.let({
148
188
  controller: "hakumi--spin",
149
189
  "hakumi--spin-spinning-value": @spinning
150
- }
190
+ }, Types::DataAttributes)
151
191
 
152
192
  delay_value = normalized_delay
153
193
  data["hakumi--spin-delay-value"] = delay_value if delay_value.positive?
@@ -156,47 +196,68 @@ module HakumiComponents
156
196
  data
157
197
  end
158
198
 
199
+ sig { returns(Integer) }
159
200
  def normalized_delay
160
- return 0 if @delay.nil?
161
- return @delay if @delay.is_a?(Numeric)
162
-
163
- @delay.to_s.strip.presence&.to_i || 0
201
+ @delay
164
202
  end
165
203
 
204
+ sig { returns(PercentInput) }
166
205
  def percent_value
167
206
  return nil unless progress?
168
207
  return "auto" if progress_auto?
169
208
 
170
- @percent
209
+ numeric_percent
171
210
  end
172
211
 
212
+ sig { returns(T::Boolean) }
173
213
  def spinning_class?
174
214
  return false unless @spinning
175
215
 
176
216
  normalized_delay <= 0
177
217
  end
178
218
 
219
+ sig { returns(Types::RenderedContent) }
179
220
  def progress_indicator
180
221
  return default_indicator if progress_auto?
181
222
 
182
223
  render progress_component
183
224
  end
184
225
 
226
+ sig { returns(ActiveSupport::SafeBuffer) }
185
227
  def default_indicator
186
228
  tag.span(class: "hakumi-spin-dot", "aria-hidden": true) do
187
229
  safe_join(Array.new(4) { tag.span(class: "hakumi-spin-dot-item") })
188
230
  end
189
231
  end
190
232
 
233
+ sig { params(value: PercentInput).returns(ProgressPercent) }
191
234
  def normalize_percent(value)
192
235
  return nil if value.nil?
193
236
  return :auto if value == :auto || value.to_s.strip == "auto"
194
- return value if value.is_a?(Numeric)
237
+ return value if value.is_a?(Integer)
238
+ return value if value.is_a?(Float)
195
239
 
196
240
  parsed = value.to_s.strip
197
241
  parsed.presence&.to_f
198
242
  end
199
243
 
244
+ sig { params(value: DelayInput).returns(Integer) }
245
+ def normalize_delay(value)
246
+ return 0 if value.nil?
247
+ return value if value.is_a?(Integer)
248
+ return value.to_i if value.is_a?(Float)
249
+
250
+ value.to_s.strip.presence&.to_i || 0
251
+ end
252
+
253
+ sig { returns(T.nilable(Numeric)) }
254
+ def numeric_percent
255
+ return nil unless @percent.is_a?(Numeric)
256
+
257
+ @percent
258
+ end
259
+
260
+ sig { returns(Integer) }
200
261
  def progress_size
201
262
  case @size
202
263
  when :small then 44
@@ -1,3 +1,9 @@
1
- <div <%= tag.attributes(html_attributes) %>>
2
- <%= content %>
3
- </div>
1
+ <%= tag.div(**wrapper_attributes) do %>
2
+ <% if panels.any? %>
3
+ <% panels.each do |panel| %>
4
+ <%= panel %>
5
+ <% end %>
6
+ <% else %>
7
+ <%= content %>
8
+ <% end %>
9
+ <% end %>
@@ -1,37 +1,70 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
1
4
  module HakumiComponents
2
5
  module Splitter
3
6
  class Component < HakumiComponents::BaseComponent
7
+ extend T::Sig
8
+
9
+ LAYOUTS = T.let(%i[horizontal vertical].freeze, T::Array[Symbol])
10
+
11
+ renders_many :panels, ->(size: nil, min: nil, max: nil, resizable: true, collapsible: false, **options) do
12
+ T.bind(self, HakumiComponents::Splitter::Component)
13
+ HakumiComponents::Splitter::Panel::Component.new(
14
+ size: size,
15
+ min: min,
16
+ max: max,
17
+ resizable: resizable,
18
+ collapsible: collapsible,
19
+ layout: layout,
20
+ **options
21
+ )
22
+ end
23
+
24
+ sig do
25
+ params(
26
+ layout: Symbol,
27
+ resizable: T::Boolean,
28
+ html_options: Types::HtmlAttributeValue
29
+ ).void
30
+ end
4
31
  def initialize(layout: :horizontal, resizable: true, **html_options)
5
- @layout = layout
6
- @resizable = resizable
7
- @html_options = html_options
32
+ @layout = T.let(layout, Symbol)
33
+ @resizable = T.let(resizable, T::Boolean)
34
+ @html_options = T.let(html_options, Types::HtmlAttributes)
35
+ validate_props!
8
36
  end
9
37
 
10
38
  private
11
39
 
12
- def html_attributes
13
- attrs = @html_options.dup
14
- attrs[:class] = css_classes
15
- attrs[:style] = inline_styles
16
- attrs[:data] ||= {}
17
- attrs[:data][:controller] = "hakumi--splitter"
18
- attrs[:data][:hakumi__splitter_layout_value] = @layout.to_s
19
- attrs[:data][:hakumi__splitter_resizable_value] = @resizable
20
- attrs[:id] ||= generate_id("hakumi-splitter", length: 6)
21
- attrs
40
+ sig { returns(Symbol) }
41
+ attr_reader :layout
42
+
43
+ sig { returns(String) }
44
+ def wrapper_classes
45
+ component_classes("splitter", { @layout => true }, @html_options)
22
46
  end
23
47
 
24
- def css_classes
25
- classes = [ "hakumi-splitter" ]
26
- classes << "hakumi-splitter-#{@layout}"
27
- classes << @html_options[:class] if @html_options[:class]
28
- classes.join(" ")
48
+ sig { returns(Types::HtmlAttributes) }
49
+ def wrapper_attributes
50
+ existing_id = @html_options[:id]
51
+ id_value = existing_id.is_a?(String) ? existing_id : generate_id("hakumi-splitter", length: 6)
52
+
53
+ data = T.let({
54
+ controller: "hakumi--splitter",
55
+ hakumi__splitter_layout_value: @layout.to_s,
56
+ hakumi__splitter_resizable_value: @resizable
57
+ }, Types::DataAttributes)
58
+
59
+ merge_attributes(
60
+ { class: wrapper_classes, id: id_value, data: data },
61
+ @html_options.except(:class, :id)
62
+ )
29
63
  end
30
64
 
31
- def inline_styles
32
- styles = []
33
- styles << @html_options[:style] if @html_options[:style]
34
- styles.join("; ")
65
+ sig { void }
66
+ def validate_props!
67
+ validate_inclusion!(:layout, LAYOUTS)
35
68
  end
36
69
  end
37
70
  end
@@ -1,3 +1 @@
1
- <div <%= tag.attributes(html_attributes) %>>
2
- <%= content %>
3
- </div>
1
+ <%= content_tag :div, content, wrapper_attributes %>