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
@@ -0,0 +1,79 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module HakumiComponents
5
+ module Skeleton
6
+ class AvatarConfig
7
+ extend T::Sig
8
+
9
+ Size = T.type_alias { T.any(Symbol, Numeric) }
10
+ ShapeInput = T.type_alias { T.any(Symbol, String) }
11
+ Input = T.type_alias { T.any(T::Boolean, Types::HtmlAttributes, HakumiComponents::Skeleton::AvatarConfig) }
12
+ SHAPES = T.let(%i[circle square].freeze, T::Array[Symbol])
13
+
14
+ sig { params(size: Size, shape: Symbol).void }
15
+ def initialize(size: :default, shape: :circle)
16
+ @size = T.let(normalize_size(size), Size)
17
+ @shape = T.let(normalize_shape(shape), Symbol)
18
+ validate!
19
+ end
20
+
21
+ sig { returns(Size) }
22
+ attr_reader :size
23
+
24
+ sig { returns(Symbol) }
25
+ attr_reader :shape
26
+
27
+ sig { params(value: Input).returns(T.nilable(HakumiComponents::Skeleton::AvatarConfig)) }
28
+ def self.coerce(value)
29
+ return nil if value == false
30
+ return new if value == true
31
+ return value if value.is_a?(HakumiComponents::Skeleton::AvatarConfig)
32
+
33
+ size = value[:size]
34
+ shape = value[:shape]
35
+ resolved_size = if size.is_a?(Symbol) || size.is_a?(Numeric)
36
+ size
37
+ elsif size.is_a?(String)
38
+ size.to_sym
39
+ else
40
+ :default
41
+ end
42
+ resolved_shape = if shape.is_a?(Symbol)
43
+ shape
44
+ elsif shape.is_a?(String)
45
+ shape.to_sym
46
+ else
47
+ :circle
48
+ end
49
+
50
+ new(size: resolved_size, shape: resolved_shape)
51
+ end
52
+
53
+ private
54
+
55
+ sig { params(size: Size).returns(Size) }
56
+ def normalize_size(size)
57
+ return size if size.is_a?(Numeric)
58
+
59
+ size.to_sym
60
+ end
61
+
62
+ sig { params(shape: ShapeInput).returns(Symbol) }
63
+ def normalize_shape(shape)
64
+ shape.to_sym
65
+ end
66
+
67
+ sig { void }
68
+ def validate!
69
+ allowed_sizes = HakumiComponents::BaseComponent::SIZES
70
+ if !@size.is_a?(Numeric) && !allowed_sizes.include?(@size)
71
+ raise ArgumentError, "avatar size must be one of #{allowed_sizes.inspect}, got #{@size.inspect}"
72
+ end
73
+ return if SHAPES.include?(@shape)
74
+
75
+ raise ArgumentError, "avatar shape must be one of #{SHAPES.inspect}, got #{@shape.inspect}"
76
+ end
77
+ end
78
+ end
79
+ end
@@ -1,54 +1,72 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  module Skeleton
5
6
  module Button
6
7
  class Component < HakumiComponents::BaseComponent
7
- SIZES = [ :small, :default, :large ].freeze
8
- SHAPES = [ :default, :circle, :round ].freeze
8
+ extend T::Sig
9
9
 
10
+ SHAPES = T.let(%i[default circle round].freeze, T::Array[Symbol])
11
+
12
+ sig do
13
+ params(
14
+ active: T::Boolean,
15
+ size: T.any(Symbol, String),
16
+ shape: T.any(Symbol, String),
17
+ block: T::Boolean,
18
+ html_options: Types::HtmlAttributeValue
19
+ ).void
20
+ end
10
21
  def initialize(active: false, size: :default, shape: :default, block: false, **html_options)
11
- @active = active
12
- @size = normalize_size(size)
13
- @shape = normalize_shape(shape)
14
- @block = block
15
- @html_options = html_options
22
+ @active = T.let(active, T::Boolean)
23
+ @size = T.let(normalize_size(size), Symbol)
24
+ @shape = T.let(normalize_shape(shape), Symbol)
25
+ @block = T.let(block, T::Boolean)
26
+ @html_options = T.let(html_options, Types::HtmlAttributes)
16
27
 
17
28
  validate_props!
18
29
  end
19
30
 
31
+ sig { returns(Types::HtmlAttributes) }
20
32
  def wrapper_attributes
21
33
  merge_attributes({ class: wrapper_classes }, @html_options.except(:class))
22
34
  end
23
35
 
36
+ sig { returns(String) }
24
37
  def button_classes
25
- modifiers = {}
26
- modifiers[@size] = true if @size && @size != :default
27
- modifiers[@shape] = true if @shape && @shape != :default
38
+ modifiers = T.let({}, Types::ClassModifiers)
39
+ modifiers[@size] = true if @size != :default
40
+ modifiers[@shape] = true if @shape != :default
28
41
 
29
42
  class_names("skeleton-button", modifiers)
30
43
  end
31
44
 
32
45
  private
33
46
 
47
+ sig { params(size: T.any(Symbol, String)).returns(Symbol) }
34
48
  def normalize_size(size)
35
49
  size.to_sym
36
50
  end
37
51
 
52
+ sig { params(shape: T.any(Symbol, String)).returns(Symbol) }
38
53
  def normalize_shape(shape)
39
54
  shape.to_sym
40
55
  end
41
56
 
57
+ sig { returns(String) }
42
58
  def wrapper_classes
43
- class_names("skeleton", { element: true, active: @active, block: @block }, @html_options[:class])
59
+ component_classes("skeleton", { element: true, active: @active, block: @block }, @html_options)
44
60
  end
45
61
 
62
+ sig { void }
46
63
  def validate_props!
47
- validate_inclusion_value(:size, @size, SIZES) if @size
48
- validate_inclusion_value(:shape, @shape, SHAPES) if @shape
64
+ validate_inclusion_value(name: :size, value: @size, allowed: SIZES)
65
+ validate_inclusion_value(name: :shape, value: @shape, allowed: SHAPES)
49
66
  end
50
67
 
51
- def validate_inclusion_value(name, value, allowed)
68
+ sig { params(name: Symbol, value: Symbol, allowed: T::Array[Symbol]).void }
69
+ def validate_inclusion_value(name:, value:, allowed:)
52
70
  return if allowed.include?(value)
53
71
 
54
72
  raise ArgumentError, "#{name} must be one of #{allowed.inspect}, got #{value.inspect}"
@@ -1,26 +1,51 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  module Skeleton
5
6
  class Component < HakumiComponents::BaseComponent
6
- AVATAR_SIZES = [ :small, :default, :large ].freeze
7
- AVATAR_SHAPES = [ :circle, :square ].freeze
8
- DEFAULT_PARAGRAPH_ROWS = 3
9
-
7
+ extend T::Sig
8
+
9
+ ConfigToggle = T.type_alias { T::Boolean }
10
+ ConfigInput = T.type_alias { T.any(ConfigToggle, Types::HtmlAttributes) }
11
+ ConfigParam = T.type_alias { T.any(ActionController::Parameters, Types::HtmlAttributeValue) }
12
+ ConfigValue = T.type_alias { T.nilable(T.any(ConfigToggle, Types::HtmlAttributes)) }
13
+ AvatarInput = T.type_alias { T.any(ConfigInput, HakumiComponents::Skeleton::AvatarConfig) }
14
+ TitleInput = T.type_alias { T.any(ConfigInput, HakumiComponents::Skeleton::TitleConfig) }
15
+ ParagraphInput = T.type_alias { T.any(ConfigInput, HakumiComponents::Skeleton::ParagraphConfig) }
16
+ DEFAULT_PARAGRAPH_ROWS = T.let(3, Integer)
17
+
18
+ sig { params(params: BaseComponent::ControllerOptions).returns(T::Hash[Symbol, ConfigValue]) }
10
19
  def self.extract_controller_locals(params)
20
+ loading_value = html_param(params, :loading)
21
+ avatar_value = html_param(params, :avatar)
22
+ title_value = html_param(params, :title)
23
+ paragraph_value = html_param(params, :paragraph)
24
+
11
25
  locals = {
12
- loading: params.key?(:loading) ? ActiveModel::Type::Boolean.new.cast(params[:loading]) : true,
13
- active: ActiveModel::Type::Boolean.new.cast(params[:active]),
14
- round: ActiveModel::Type::Boolean.new.cast(params[:round])
26
+ loading: loading_value.nil? ? true : boolean_html_param(loading_value) != false,
27
+ active: boolean_html_param(html_param(params, :active)) == true,
28
+ round: boolean_html_param(html_param(params, :round)) == true
15
29
  }
16
30
 
17
- locals[:avatar] = normalize_config_param(params[:avatar]) if params.key?(:avatar)
18
- locals[:title] = normalize_config_param(params[:title]) if params.key?(:title)
19
- locals[:paragraph] = normalize_config_param(params[:paragraph]) if params.key?(:paragraph)
31
+ locals[:avatar] = normalize_config_param(avatar_value) unless avatar_value.nil?
32
+ locals[:title] = normalize_config_param(title_value) unless title_value.nil?
33
+ locals[:paragraph] = normalize_config_param(paragraph_value) unless paragraph_value.nil?
20
34
 
21
35
  locals
22
36
  end
23
37
 
38
+ sig do
39
+ params(
40
+ loading: T::Boolean,
41
+ active: T::Boolean,
42
+ avatar: AvatarInput,
43
+ title: TitleInput,
44
+ paragraph: ParagraphInput,
45
+ round: T::Boolean,
46
+ html_options: Types::HtmlAttributeValue
47
+ ).void
48
+ end
24
49
  def initialize(
25
50
  loading: true,
26
51
  active: false,
@@ -30,21 +55,21 @@ module HakumiComponents
30
55
  round: false,
31
56
  **html_options
32
57
  )
33
- @loading = loading
34
- @active = active
35
- @round = round
36
- @avatar = normalize_config(avatar)
37
- @title = normalize_config(title)
38
- @paragraph = normalize_config(paragraph)
39
- @html_options = html_options
40
-
41
- validate_props!
58
+ @loading = T.let(loading, T::Boolean)
59
+ @active = T.let(active, T::Boolean)
60
+ @round = T.let(round, T::Boolean)
61
+ @avatar = T.let(HakumiComponents::Skeleton::AvatarConfig.coerce(avatar), T.nilable(HakumiComponents::Skeleton::AvatarConfig))
62
+ @title = T.let(HakumiComponents::Skeleton::TitleConfig.coerce(title), T.nilable(HakumiComponents::Skeleton::TitleConfig))
63
+ @paragraph = T.let(HakumiComponents::Skeleton::ParagraphConfig.coerce(paragraph), T.nilable(HakumiComponents::Skeleton::ParagraphConfig))
64
+ @html_options = T.let(html_options, Types::HtmlAttributes)
42
65
  end
43
66
 
67
+ sig { returns(T::Boolean) }
44
68
  def loading?
45
69
  @loading
46
70
  end
47
71
 
72
+ sig { returns(Types::HtmlAttributes) }
48
73
  def wrapper_attributes
49
74
  merge_attributes(
50
75
  { class: wrapper_classes },
@@ -52,94 +77,85 @@ module HakumiComponents
52
77
  )
53
78
  end
54
79
 
80
+ sig { returns(T::Boolean) }
55
81
  def avatar?
56
82
  !@avatar.nil?
57
83
  end
58
84
 
85
+ sig { returns(T::Boolean) }
59
86
  def title?
60
87
  !@title.nil?
61
88
  end
62
89
 
90
+ sig { returns(T::Boolean) }
63
91
  def paragraph?
64
92
  !@paragraph.nil?
65
93
  end
66
94
 
95
+ sig { returns(String) }
67
96
  def avatar_classes
68
97
  modifiers = {}
69
- modifiers[avatar_size] = true if avatar_size && avatar_size != :default
98
+ modifiers[avatar_size] = true if avatar_size != :default
70
99
  modifiers[avatar_shape] = true if avatar_shape
71
100
 
72
101
  class_names("skeleton-avatar", modifiers)
73
102
  end
74
103
 
104
+ sig { returns(T.nilable(String)) }
75
105
  def avatar_style
76
106
  return nil unless avatar_size.is_a?(Numeric)
77
107
 
78
108
  "width: #{avatar_size}px; height: #{avatar_size}px;"
79
109
  end
80
110
 
111
+ sig { returns(T.nilable(String)) }
81
112
  def title_style
82
- width = dimension_to_css(@title&.dig(:width))
113
+ width = @title.nil? ? nil : dimension_to_css(@title.width)
83
114
  return nil unless width
84
115
 
85
116
  "width: #{width};"
86
117
  end
87
118
 
119
+ sig { returns(T::Array[T.nilable(String)]) }
88
120
  def paragraph_row_widths
89
121
  return [] unless paragraph?
122
+ paragraph = @paragraph
123
+ return [] if paragraph.nil?
90
124
 
91
- rows = paragraph_rows
92
- widths = @paragraph&.dig(:widths) || @paragraph&.dig(:width)
93
-
94
- resolved = case widths
95
- when Array
96
- widths
97
- when nil
98
- default_paragraph_widths(rows)
99
- else
100
- Array.new(rows, widths)
101
- end
102
-
103
- resolved = resolved.first(rows)
104
- resolved.fill("100%", resolved.length...rows)
105
- resolved.map { |value| dimension_to_css(value) }
125
+ paragraph.row_widths(DEFAULT_PARAGRAPH_ROWS).map { |value| dimension_to_css(value) }
106
126
  end
107
127
 
128
+ sig { params(width: T.nilable(String)).returns(T.nilable(String)) }
108
129
  def paragraph_row_style(width)
109
130
  return nil unless width
110
131
 
111
132
  "width: #{width};"
112
133
  end
113
134
 
114
- def paragraph_rows
115
- rows = @paragraph&.dig(:rows)
116
- rows = rows.to_i if rows.is_a?(String)
117
- rows.presence || DEFAULT_PARAGRAPH_ROWS
118
- end
119
-
120
135
  private
121
136
 
137
+ sig { params(value: ConfigParam).returns(ConfigValue) }
122
138
  def self.normalize_config_param(value)
123
139
  return nil if value.nil?
124
140
 
125
- if value.is_a?(ActionController::Parameters)
126
- value = value.to_unsafe_h
127
- end
128
-
129
- return value.symbolize_keys if value.is_a?(Hash)
141
+ if value.is_a?(ActionController::Parameters) || value.is_a?(Hash)
142
+ source = value.is_a?(ActionController::Parameters) ? value.to_unsafe_h : value
143
+ attrs = T.let({}, Types::HtmlAttributes)
144
+ source.each do |key, entry|
145
+ next unless key.is_a?(String) || key.is_a?(Symbol)
146
+ next unless entry.nil? || entry.is_a?(String) || entry.is_a?(Symbol) || entry.is_a?(TrueClass) || entry.is_a?(FalseClass) || entry.is_a?(Numeric) || entry.is_a?(Hash) || entry.is_a?(Array)
130
147
 
131
- ActiveModel::Type::Boolean.new.cast(value)
132
- end
133
-
134
- def normalize_config(value)
135
- return nil if value.nil? || value == false
136
- return {} if value == true
148
+ attrs[key.to_sym] = entry
149
+ end
150
+ return attrs
151
+ end
137
152
 
138
- return value.to_h.symbolize_keys if value.respond_to?(:to_h)
153
+ return cast_boolean(value) if value.is_a?(String) || value.is_a?(Symbol) || value.is_a?(TrueClass) || value.is_a?(FalseClass) || value.is_a?(Numeric)
139
154
 
140
- {}
155
+ nil
141
156
  end
142
157
 
158
+ sig { returns(String) }
143
159
  def wrapper_classes
144
160
  modifiers = {
145
161
  active: @active,
@@ -149,51 +165,21 @@ module HakumiComponents
149
165
  round: @round
150
166
  }
151
167
 
152
- class_names("skeleton", modifiers, @html_options[:class])
168
+ component_classes("skeleton", modifiers, @html_options)
153
169
  end
154
170
 
171
+ sig { returns(T.any(Symbol, Numeric)) }
155
172
  def avatar_size
156
- size = @avatar&.dig(:size)
157
- size = size.to_sym if size.is_a?(String)
158
- size.presence || :default
159
- end
160
-
161
- def avatar_shape
162
- shape = @avatar&.dig(:shape)
163
- shape = shape.to_sym if shape.is_a?(String)
164
- shape.presence || :circle
165
- end
166
-
167
- def default_paragraph_widths(rows)
168
- widths = Array.new(rows, "100%")
169
- widths[-1] = "61%" if rows > 1
170
- widths
171
- end
173
+ return :default if @avatar.nil?
172
174
 
173
- def validate_props!
174
- if avatar?
175
- size = avatar_size
176
- shape = avatar_shape
177
-
178
- validate_inclusion_value(:avatar_size, size, AVATAR_SIZES) if size && !size.is_a?(Numeric)
179
- validate_inclusion_value(:avatar_shape, shape, AVATAR_SHAPES) if shape
180
- end
181
-
182
- if paragraph?
183
- rows = @paragraph[:rows]
184
- rows = rows.to_i if rows.is_a?(String)
185
- if rows && (!rows.is_a?(Integer) || rows < 1)
186
- raise ArgumentError, "paragraph rows must be a positive integer"
187
- end
188
-
189
- @paragraph[:rows] = rows if rows
190
- end
175
+ @avatar.size
191
176
  end
192
177
 
193
- def validate_inclusion_value(name, value, allowed)
194
- return if allowed.include?(value)
178
+ sig { returns(Symbol) }
179
+ def avatar_shape
180
+ return :circle if @avatar.nil?
195
181
 
196
- raise ArgumentError, "#{name} must be one of #{allowed.inspect}, got #{value.inspect}"
182
+ @avatar.shape
197
183
  end
198
184
  end
199
185
  end
@@ -1,39 +1,57 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  module Skeleton
5
6
  module Image
6
7
  class Component < HakumiComponents::BaseComponent
7
- DEFAULT_ICON_NAME = "picture"
8
- DEFAULT_ICON_THEME = :outlined
9
- DEFAULT_ICON_SIZE = 48
10
- ICON_SCALE = 0.55
11
- MIN_ICON_SIZE = 32
12
-
8
+ extend T::Sig
9
+
10
+ SizeInput = T.type_alias { BaseComponent::DimensionInput }
11
+ DEFAULT_ICON_NAME = T.let("picture", String)
12
+ DEFAULT_ICON_THEME = T.let(:outlined, Symbol)
13
+ DEFAULT_ICON_SIZE = T.let(48, Integer)
14
+ ICON_SCALE = T.let(0.55, Float)
15
+ MIN_ICON_SIZE = T.let(32, Integer)
16
+
17
+ sig do
18
+ params(
19
+ active: T::Boolean,
20
+ width: SizeInput,
21
+ height: SizeInput,
22
+ html_options: Types::HtmlAttributeValue
23
+ ).void
24
+ end
13
25
  def initialize(active: false, width: 96, height: 96, **html_options)
14
- @active = active
15
- @width = width
16
- @height = height
17
- @html_options = html_options
26
+ @active = T.let(active, T::Boolean)
27
+ @width = T.let(width, SizeInput)
28
+ @height = T.let(height, SizeInput)
29
+ @html_options = T.let(html_options, Types::HtmlAttributes)
18
30
 
19
31
  validate_props!
20
32
  end
21
33
 
34
+ sig { returns(Types::HtmlAttributes) }
22
35
  def wrapper_attributes
23
36
  merge_attributes({ class: wrapper_classes }, @html_options.except(:class))
24
37
  end
25
38
 
39
+ sig { returns(String) }
26
40
  def image_classes
27
41
  class_names("skeleton-image")
28
42
  end
29
43
 
44
+ sig { returns(T.nilable(String)) }
30
45
  def image_style
31
- styles = []
32
- styles << "width: #{dimension_to_css(@width)}" if @width
33
- styles << "height: #{dimension_to_css(@height)}" if @height
34
- styles.join("; ") if styles.any?
46
+ styles = T.let([], T::Array[String])
47
+ width_css = dimension_to_css(@width)
48
+ height_css = dimension_to_css(@height)
49
+ styles << "width: #{width_css}" if width_css
50
+ styles << "height: #{height_css}" if height_css
51
+ styles.any? ? styles.join("; ") : nil
35
52
  end
36
53
 
54
+ sig { returns(Types::HtmlAttributes) }
37
55
  def icon_component_options
38
56
  {
39
57
  name: DEFAULT_ICON_NAME,
@@ -46,31 +64,37 @@ module HakumiComponents
46
64
 
47
65
  private
48
66
 
67
+ sig { returns(Integer) }
49
68
  def calculated_icon_size
50
69
  dimension = [ numeric_dimension(@width), numeric_dimension(@height) ].compact.min
51
70
  return DEFAULT_ICON_SIZE unless dimension
52
71
 
53
- [ (dimension * ICON_SCALE).round, MIN_ICON_SIZE ].max
72
+ scaled = (dimension * ICON_SCALE).round.to_i
73
+ scaled > MIN_ICON_SIZE ? scaled : MIN_ICON_SIZE
54
74
  end
55
75
 
76
+ sig { params(value: SizeInput).returns(T.nilable(Numeric)) }
56
77
  def numeric_dimension(value)
57
78
  return value if value.is_a?(Numeric)
58
- return value.to_f if value.is_a?(String) && value.strip.end_with?("px")
79
+ return nil unless value.is_a?(String)
59
80
 
60
- nil
81
+ value.strip.end_with?("px") ? value.to_f : nil
61
82
  end
62
83
 
84
+ sig { returns(String) }
63
85
  def wrapper_classes
64
- class_names("skeleton", { element: true, active: @active }, @html_options[:class])
86
+ component_classes("skeleton", { element: true, active: @active }, @html_options)
65
87
  end
66
88
 
89
+ sig { void }
67
90
  def validate_props!
68
- validate_size!(:width, @width)
69
- validate_size!(:height, @height)
91
+ validate_size!(name: :width, value: @width)
92
+ validate_size!(name: :height, value: @height)
70
93
  end
71
94
 
72
- def validate_size!(name, value)
73
- return if value.nil? || value.is_a?(Numeric) || value.is_a?(String)
95
+ sig { params(name: Symbol, value: SizeInput).void }
96
+ def validate_size!(name:, value:)
97
+ return if value.is_a?(Numeric) || value.is_a?(String)
74
98
 
75
99
  raise ArgumentError, "#{name} must be a number or string"
76
100
  end
@@ -1,46 +1,61 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  module Skeleton
5
6
  module Input
6
7
  class Component < HakumiComponents::BaseComponent
7
- SIZES = [ :small, :default, :large ].freeze
8
+ extend T::Sig
8
9
 
10
+ sig do
11
+ params(
12
+ active: T::Boolean,
13
+ size: T.any(Symbol, String),
14
+ block: T::Boolean,
15
+ html_options: Types::HtmlAttributeValue
16
+ ).void
17
+ end
9
18
  def initialize(active: false, size: :default, block: false, **html_options)
10
- @active = active
11
- @size = normalize_size(size)
12
- @block = block
13
- @html_options = html_options
19
+ @active = T.let(active, T::Boolean)
20
+ @size = T.let(normalize_size(size), Symbol)
21
+ @block = T.let(block, T::Boolean)
22
+ @html_options = T.let(html_options, Types::HtmlAttributes)
14
23
 
15
24
  validate_props!
16
25
  end
17
26
 
27
+ sig { returns(Types::HtmlAttributes) }
18
28
  def wrapper_attributes
19
29
  merge_attributes({ class: wrapper_classes }, @html_options.except(:class))
20
30
  end
21
31
 
32
+ sig { returns(String) }
22
33
  def input_classes
23
- modifiers = {}
24
- modifiers[@size] = true if @size && @size != :default
34
+ modifiers = T.let({}, Types::ClassModifiers)
35
+ modifiers[@size] = true if @size != :default
25
36
 
26
37
  class_names("skeleton-input", modifiers)
27
38
  end
28
39
 
29
40
  private
30
41
 
42
+ sig { params(size: T.any(Symbol, String)).returns(Symbol) }
31
43
  def normalize_size(size)
32
44
  size.to_sym
33
45
  end
34
46
 
47
+ sig { returns(String) }
35
48
  def wrapper_classes
36
- class_names("skeleton", { element: true, active: @active, block: @block }, @html_options[:class])
49
+ component_classes("skeleton", { element: true, active: @active, block: @block }, @html_options)
37
50
  end
38
51
 
52
+ sig { void }
39
53
  def validate_props!
40
- validate_inclusion_value(:size, @size, SIZES) if @size
54
+ validate_inclusion_value(name: :size, value: @size, allowed: SIZES)
41
55
  end
42
56
 
43
- def validate_inclusion_value(name, value, allowed)
57
+ sig { params(name: Symbol, value: Symbol, allowed: T::Array[Symbol]).void }
58
+ def validate_inclusion_value(name:, value:, allowed:)
44
59
  return if allowed.include?(value)
45
60
 
46
61
  raise ArgumentError, "#{name} must be one of #{allowed.inspect}, got #{value.inspect}"