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,46 +1,82 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  module QrCode
5
6
  class Component < HakumiComponents::BaseComponent
6
- TYPES = [ :canvas, :svg ].freeze
7
- STATUSES = [ :active, :expired, :loading, :scanned ].freeze
8
- ERROR_LEVELS = [ :L, :M, :Q, :H ].freeze
9
-
7
+ extend T::Sig
8
+
9
+ NumberValue = T.type_alias { Numeric }
10
+ NumberInput = T.type_alias { BaseComponent::DimensionInput }
11
+ OptionInput = T.type_alias { BaseComponent::SymbolInput }
12
+ IconRenderable = T.type_alias { T.nilable(Types::ComponentRenderable) }
13
+ IconInput = T.type_alias { T.nilable(T.any(Symbol, Types::Renderable)) }
14
+ StatusRender = T.type_alias { T.nilable(T.any(Types::Renderable, T.proc.params(status: Symbol).returns(Types::RenderedContent))) }
15
+ ControllerOptions = T.type_alias { BaseComponent::ControllerOptions }
16
+ ImageAttributes = T.type_alias { T::Hash[Symbol, Types::HtmlPrimitive] }
17
+ TYPES = T.let([ :canvas, :svg ].freeze, T::Array[Symbol])
18
+ STATUSES = T.let([ :active, :expired, :loading, :scanned ].freeze, T::Array[Symbol])
19
+ ERROR_LEVELS = T.let([ :L, :M, :Q, :H ].freeze, T::Array[Symbol])
20
+
21
+ sig do
22
+ params(params: ControllerOptions).returns(Types::HtmlAttributes)
23
+ end
10
24
  def self.extract_controller_locals(params)
25
+ bordered_value = html_param(params, :bordered)
26
+
11
27
  {
12
- value: params[:value],
13
- size: parse_number(params[:size]),
14
- type: params[:type]&.to_sym,
15
- color: params[:color],
16
- bg_color: params[:bg_color],
17
- icon: params[:icon],
18
- icon_size: parse_number(params[:icon_size]),
19
- status: params[:status]&.to_sym,
20
- status_render: params[:status_render],
21
- bordered: params.key?(:bordered) ? ActiveModel::Type::Boolean.new.cast(params[:bordered]) : nil,
22
- error_level: parse_error_level(params[:error_level]),
23
- download_name: params[:download_name],
24
- aria_label: params[:aria_label]
28
+ value: string_html_param(html_param(params, :value)),
29
+ size: parse_number(html_param(params, :size)),
30
+ type: symbol_html_param(html_param(params, :type)),
31
+ color: string_html_param(html_param(params, :color)),
32
+ bg_color: string_html_param(html_param(params, :bg_color)),
33
+ icon: html_param(params, :icon),
34
+ icon_size: parse_number(html_param(params, :icon_size)),
35
+ status: symbol_html_param(html_param(params, :status)),
36
+ status_render: string_html_param(html_param(params, :status_render)),
37
+ bordered: bordered_value.nil? ? nil : boolean_html_param(bordered_value),
38
+ error_level: parse_error_level(html_param(params, :error_level)),
39
+ download_name: string_html_param(html_param(params, :download_name)),
40
+ aria_label: string_html_param(html_param(params, :aria_label))
25
41
  }
26
42
  end
27
43
 
44
+ sig { params(value: Types::HtmlAttributeValue).returns(T.nilable(NumberValue)) }
28
45
  def self.parse_number(value)
29
46
  return nil if value.nil?
30
- return value if value.is_a?(Numeric)
47
+ return value if value.is_a?(Integer)
48
+ return value if value.is_a?(Float)
31
49
  raw = value.to_s.strip
32
50
  return nil if raw.empty?
33
51
 
34
- number = raw.to_f
35
- number == number.to_i ? number.to_i : number
52
+ raw.include?(".") ? raw.to_f : raw.to_i
36
53
  end
37
54
 
55
+ sig { params(value: Types::HtmlAttributeValue).returns(T.nilable(Symbol)) }
38
56
  def self.parse_error_level(value)
39
57
  return nil if value.nil?
40
58
 
41
59
  value.to_s.strip.presence&.upcase&.to_sym
42
60
  end
43
61
 
62
+ sig do
63
+ params(
64
+ value: String,
65
+ size: NumberInput,
66
+ type: OptionInput,
67
+ color: T.nilable(String),
68
+ bg_color: T.nilable(String),
69
+ icon: IconInput,
70
+ icon_size: NumberInput,
71
+ status: OptionInput,
72
+ status_render: StatusRender,
73
+ bordered: T.nilable(T::Boolean),
74
+ error_level: OptionInput,
75
+ download_name: T.nilable(String),
76
+ aria_label: T.nilable(String),
77
+ html_options: Types::HtmlAttributeValue
78
+ ).void
79
+ end
44
80
  def initialize(
45
81
  value:,
46
82
  size: 160,
@@ -57,32 +93,33 @@ module HakumiComponents
57
93
  aria_label: nil,
58
94
  **html_options
59
95
  )
60
- @value = value
61
- @size = self.class.parse_number(size) || 160
62
- @type = normalize_symbol(type) || :canvas
63
- @color = normalize_string(color)
64
- @bg_color = normalize_string(bg_color)
65
- @icon_input = icon
66
- @icon_size = self.class.parse_number(icon_size) || 40
96
+ @value = T.let(value, String)
97
+ @size = T.let(self.class.parse_number(size) || 160, NumberValue)
98
+ @type = T.let(normalize_symbol(type) || :canvas, Symbol)
99
+ @color = T.let(normalize_string(color), T.nilable(String))
100
+ @bg_color = T.let(normalize_string(bg_color), T.nilable(String))
101
+ @icon_input = T.let(icon, IconInput)
102
+ @icon_size = T.let(self.class.parse_number(icon_size) || 40, NumberValue)
67
103
  resolve_icon!
68
- @status = normalize_symbol(status) || :active
69
- @status_render = status_render
70
- @bordered = bordered.nil? ? true : ActiveModel::Type::Boolean.new.cast(bordered)
71
- @error_level = normalize_error_level(error_level) || :M
72
- @download_name = normalize_string(download_name)
73
- @aria_label = normalize_string(aria_label)
74
- @html_options = html_options
104
+ @status = T.let(normalize_symbol(status) || :active, Symbol)
105
+ @status_render = T.let(status_render, StatusRender)
106
+ @bordered = T.let(bordered.nil? ? true : cast_boolean(bordered) == true, T::Boolean)
107
+ @error_level = T.let(normalize_error_level(error_level) || :M, Symbol)
108
+ @download_name = T.let(normalize_string(download_name), T.nilable(String))
109
+ @aria_label = T.let(normalize_string(aria_label), T.nilable(String))
110
+ @html_options = T.let(html_options, Types::HtmlAttributes)
75
111
 
76
112
  validate_props!
77
113
  end
78
114
 
115
+ sig { returns(Types::HtmlAttributes) }
79
116
  def wrapper_attributes
80
117
  merge_attributes(
81
118
  {
82
119
  class: wrapper_classes,
83
120
  style: wrapper_styles,
84
121
  role: "img",
85
- "aria-label": @aria_label || "QR Code",
122
+ "aria-label": @aria_label || t_default(:aria_label, default: "QR Code"),
86
123
  "aria-busy": loading? ? "true" : "false",
87
124
  data: data_attributes
88
125
  },
@@ -90,39 +127,46 @@ module HakumiComponents
90
127
  )
91
128
  end
92
129
 
130
+ sig { returns(Types::HtmlAttributes) }
93
131
  def renderer_attributes
94
- {
132
+ T.let({
95
133
  class: "hakumi-qr-code-inner",
96
134
  data: { "hakumi--qr-code-target": "renderer" }
97
- }
135
+ }, Types::HtmlAttributes)
98
136
  end
99
137
 
138
+ sig { returns(T::Boolean) }
100
139
  def icon?
101
140
  icon_component? || icon_image?
102
141
  end
103
142
 
143
+ sig { returns(Types::RenderedContent) }
104
144
  def icon_markup
145
+ icon_component = @icon_component
105
146
  if icon_image?
106
147
  tag.img(**icon_image_attributes)
107
- elsif icon_component?
108
- render(@icon_component)
148
+ elsif !icon_component.nil?
149
+ render(icon_component)
109
150
  end
110
151
  end
111
152
 
153
+ sig { returns(ImageAttributes) }
112
154
  def icon_image_attributes
113
- {
155
+ T.let({
114
156
  src: @icon_url,
115
157
  alt: "",
116
158
  class: "hakumi-qr-code-icon-image",
117
159
  "aria-hidden": true,
118
160
  role: "presentation"
119
- }
161
+ }, ImageAttributes)
120
162
  end
121
163
 
164
+ sig { returns(T::Boolean) }
122
165
  def status_overlay?
123
166
  @status != :active
124
167
  end
125
168
 
169
+ sig { returns(Types::RenderedContent) }
126
170
  def status_overlay_markup
127
171
  return nil unless status_overlay?
128
172
 
@@ -132,25 +176,25 @@ module HakumiComponents
132
176
  default_status_overlay
133
177
  end
134
178
 
179
+ sig { returns(String) }
135
180
  def status_text
136
- case @status
137
- when :expired
138
- "Expired"
139
- when :loading
140
- "Loading"
141
- when :scanned
142
- "Scanned"
143
- else
144
- "Active"
181
+ key = "status.#{@status}"
182
+ default = case @status
183
+ when :expired then "Expired"
184
+ when :loading then "Loading"
185
+ when :scanned then "Scanned"
186
+ else "Active"
145
187
  end
188
+ t_default(key, default: default)
146
189
  end
147
190
 
191
+ sig { returns(T.nilable(String)) }
148
192
  def status_description
149
193
  case @status
150
194
  when :expired
151
- "Please refresh to continue"
195
+ t_default("description.expired", default: "Please refresh to continue")
152
196
  when :scanned
153
- "You can now continue"
197
+ t_default("description.scanned", default: "You can now continue")
154
198
  else
155
199
  nil
156
200
  end
@@ -158,21 +202,23 @@ module HakumiComponents
158
202
 
159
203
  private
160
204
 
205
+ sig { void }
161
206
  def validate_props!
162
207
  validate_required!(:value)
163
208
  validate_inclusion!(:type, TYPES)
164
209
  validate_inclusion!(:status, STATUSES)
165
210
  validate_inclusion!(:error_level, ERROR_LEVELS)
166
211
 
167
- if @size.nil? || @size.to_f <= 0
212
+ if @size.to_f <= 0
168
213
  raise ArgumentError, "size must be a positive number"
169
214
  end
170
215
 
171
- if icon? && (@icon_size.nil? || @icon_size.to_f <= 0)
216
+ if icon? && @icon_size.to_f <= 0
172
217
  raise ArgumentError, "icon_size must be a positive number"
173
218
  end
174
219
  end
175
220
 
221
+ sig { returns(String) }
176
222
  def wrapper_classes
177
223
  modifiers = {
178
224
  @type => true,
@@ -182,9 +228,10 @@ module HakumiComponents
182
228
  "custom-status" => custom_status_render?
183
229
  }
184
230
 
185
- class_names("qr-code", modifiers, [ @html_options[:class] ])
231
+ component_classes("qr-code", modifiers, @html_options)
186
232
  end
187
233
 
234
+ sig { returns(String) }
188
235
  def wrapper_styles
189
236
  styles = {
190
237
  "--hakumi-qr-code-size" => size_css_value,
@@ -196,27 +243,24 @@ module HakumiComponents
196
243
  styles.compact.map { |key, value| "#{key}: #{value}" }.join("; ")
197
244
  end
198
245
 
246
+ sig { returns(String) }
199
247
  def size_css_value
200
- return nil unless @size
201
-
202
- value = @size.to_f
203
- value = value.to_i if value == value.to_i
204
- "#{value}px"
248
+ "#{formatted_number(@size)}px"
205
249
  end
206
250
 
251
+ sig { returns(T.nilable(String)) }
207
252
  def icon_css_value
208
253
  return nil unless icon?
209
254
 
210
- value = @icon_size.to_f
211
- value = value.to_i if value == value.to_i
212
- "#{value}px"
255
+ "#{formatted_number(@icon_size)}px"
213
256
  end
214
257
 
258
+ sig { void }
215
259
  def resolve_icon!
216
- @icon_component = nil
217
- @icon_url = nil
260
+ @icon_component = T.let(nil, IconRenderable)
261
+ @icon_url = T.let(nil, T.nilable(String))
218
262
 
219
- if @icon_input.respond_to?(:render_in)
263
+ if @icon_input.is_a?(ViewComponent::Base) || @icon_input.is_a?(ViewComponent::Slot)
220
264
  @icon_component = @icon_input
221
265
  return
222
266
  end
@@ -235,16 +279,19 @@ module HakumiComponents
235
279
  @icon_component = HakumiComponents::Icon::Component.new(name: icon_name, size: icon_component_size)
236
280
  end
237
281
 
282
+ sig { returns(T::Boolean) }
238
283
  def icon_component?
239
- @icon_component.present?
284
+ !@icon_component.nil?
240
285
  end
241
286
 
287
+ sig { returns(T::Boolean) }
242
288
  def icon_image?
243
289
  @icon_url.present?
244
290
  end
245
291
 
292
+ sig { returns(Types::DataAttributes) }
246
293
  def data_attributes
247
- data = {
294
+ data = T.let({
248
295
  controller: "hakumi--qr-code",
249
296
  "hakumi--qr-code-value-value": @value,
250
297
  "hakumi--qr-code-size-value": @size,
@@ -253,34 +300,40 @@ module HakumiComponents
253
300
  "hakumi--qr-code-bg-color-value": @bg_color,
254
301
  "hakumi--qr-code-error-level-value": @error_level,
255
302
  "hakumi--qr-code-status-value": @status
256
- }
303
+ }, Types::DataAttributes)
257
304
 
258
305
  data["hakumi--qr-code-download-name-value"] = @download_name if @download_name.present?
259
306
  data
260
307
  end
261
308
 
309
+ sig { returns(T::Boolean) }
262
310
  def loading?
263
311
  @status == :loading
264
312
  end
265
313
 
314
+ sig { returns(T::Boolean) }
266
315
  def custom_status_render?
267
316
  @status_render.present?
268
317
  end
269
318
 
319
+ sig { returns(Types::RenderedContent) }
270
320
  def custom_status_overlay
271
321
  return unless custom_status_render?
272
322
 
273
- if @status_render.respond_to?(:call)
323
+ if @status_render.is_a?(Proc)
274
324
  return view_context.capture { @status_render.call(@status) }
275
325
  end
276
326
 
277
- return render(@status_render) if @status_render.respond_to?(:render_in)
327
+ if @status_render.is_a?(ViewComponent::Base) || @status_render.is_a?(ViewComponent::Slot)
328
+ return render(@status_render)
329
+ end
278
330
 
279
331
  @status_render
280
332
  end
281
333
 
334
+ sig { returns(ActiveSupport::SafeBuffer) }
282
335
  def default_status_overlay
283
- content = []
336
+ content = T.let([], T::Array[Types::RenderedContent])
284
337
  if loading?
285
338
  content << render(HakumiComponents::Spin::Component.new(size: :small))
286
339
  end
@@ -295,6 +348,7 @@ module HakumiComponents
295
348
  end
296
349
  end
297
350
 
351
+ sig { params(value: OptionInput).returns(T.nilable(Symbol)) }
298
352
  def normalize_symbol(value)
299
353
  return nil if value.nil?
300
354
 
@@ -305,11 +359,13 @@ module HakumiComponents
305
359
  raw.to_sym
306
360
  end
307
361
 
362
+ sig { params(value: OptionInput).returns(T.nilable(Symbol)) }
308
363
  def normalize_error_level(value)
309
364
  symbol = normalize_symbol(value)
310
365
  symbol&.to_s&.upcase&.to_sym
311
366
  end
312
367
 
368
+ sig { params(value: T.nilable(Types::ValidationComparable)).returns(T.nilable(String)) }
313
369
  def normalize_string(value)
314
370
  return nil if value.nil?
315
371
 
@@ -317,6 +373,7 @@ module HakumiComponents
317
373
  raw.empty? ? nil : raw
318
374
  end
319
375
 
376
+ sig { params(value: IconInput).returns(T.nilable(Symbol)) }
320
377
  def extract_icon_name(value)
321
378
  case value
322
379
  when Symbol
@@ -330,10 +387,19 @@ module HakumiComponents
330
387
  end
331
388
  end
332
389
 
390
+ sig { returns(Integer) }
333
391
  def icon_component_size
334
392
  size = (@icon_size.to_f * 0.65).round
335
393
  size.positive? ? size : 24
336
394
  end
395
+
396
+ sig { params(value: NumberValue).returns(NumberValue) }
397
+ def formatted_number(value)
398
+ return value if value.is_a?(Integer)
399
+
400
+ remainder = value % 1
401
+ remainder.zero? ? value.to_i : value
402
+ end
337
403
  end
338
404
  end
339
405
  end
@@ -2,15 +2,15 @@
2
2
  <label class="<%= wrapper_classes %>" data-controller="<%= data_controllers %>" data-hakumi--radio-checked-value="<%= @checked %>" data-hakumi--radio-variant-value="default">
3
3
  <span class="<%= radio_classes %>" data-hakumi--radio-target="radio">
4
4
  <%= radio_button_tag(
5
- @name,
5
+ form_field_name,
6
6
  @value,
7
7
  @checked,
8
8
  id: input_id,
9
9
  disabled: @disabled,
10
10
  autofocus: @auto_focus,
11
- required: @required,
11
+ required: form_field_required,
12
12
  class: "hakumi-radio-input",
13
- "aria-invalid": has_error? ? "true" : nil,
13
+ "aria-invalid": error? ? "true" : nil,
14
14
  "aria-describedby": describedby_ids,
15
15
  data: (@html_options[:data] || {}).merge({
16
16
  hakumi__radio_target: "input",
@@ -1,12 +1,31 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  module Radio
5
6
  class Component < HakumiComponents::BaseComponent
6
- include HakumiComponents::Concerns::FormField
7
+ extend T::Sig
7
8
 
8
- SIZES = [ :small, :middle, :large ].freeze
9
+ include HakumiComponents::Concerns::FormField
9
10
 
11
+ sig do
12
+ params(
13
+ name: Types::FormFieldName,
14
+ value: HakumiComponents::Types::FormFieldScalar,
15
+ text: Types::Renderable,
16
+ label: T.nilable(String),
17
+ caption: T.nilable(String),
18
+ checked: T::Boolean,
19
+ disabled: T::Boolean,
20
+ size: Symbol,
21
+ id: T.nilable(Types::FormFieldName),
22
+ auto_focus: T::Boolean,
23
+ required: T::Boolean,
24
+ standalone: T::Boolean,
25
+ errors: Types::FormFieldErrors,
26
+ html_options: Types::HtmlAttributeValue
27
+ ).void
28
+ end
10
29
  def initialize(
11
30
  name:,
12
31
  value: nil,
@@ -15,7 +34,7 @@ module HakumiComponents
15
34
  caption: nil,
16
35
  checked: false,
17
36
  disabled: false,
18
- size: :middle,
37
+ size: :default,
19
38
  id: nil,
20
39
  auto_focus: false,
21
40
  required: false,
@@ -24,54 +43,68 @@ module HakumiComponents
24
43
  **html_options
25
44
  )
26
45
  @name = name
27
- @value = value
46
+ @value = T.let(value, HakumiComponents::Types::FormFieldScalar)
28
47
  @text = text
29
48
  @label = label
30
49
  @caption = caption
31
50
  @checked = checked
32
51
  @disabled = disabled
33
52
  @size = size
34
- @id = id || generate_id("radio")
53
+ @id = T.let(id || generate_id("radio"), Types::FormFieldName)
35
54
  @auto_focus = auto_focus
36
55
  @required = required
37
56
  @standalone = standalone
38
- @errors = Array(errors)
39
- @html_options = html_options
57
+ @errors = T.let(errors, Types::FormFieldErrors)
58
+ @html_options = T.let(html_options, Types::HtmlAttributes)
40
59
  @html_options[:id] ||= @id
60
+ initialize_form_field_contract!(
61
+ name: @name,
62
+ label: @label,
63
+ caption: @caption,
64
+ errors: @errors,
65
+ standalone: @standalone,
66
+ required: @required,
67
+ html_options: @html_options
68
+ )
41
69
 
42
70
  validate_props!
43
71
  end
44
72
 
73
+ sig { returns(String) }
45
74
  def wrapper_classes
46
75
  modifiers = {
47
76
  checked: @checked,
48
77
  disabled: @disabled
49
78
  }
50
- modifiers[@size] = true if @size != :middle
79
+ modifiers[@size] = true if @size != :default
51
80
 
52
81
  class_names("radio-wrapper", modifiers)
53
82
  end
54
83
 
84
+ sig { returns(String) }
55
85
  def radio_classes
56
86
  modifiers = {
57
87
  checked: @checked,
58
88
  disabled: @disabled
59
89
  }
60
- modifiers[@size] = true if @size != :middle
90
+ modifiers[@size] = true if @size != :default
61
91
 
62
92
  class_names("radio", modifiers)
63
93
  end
64
94
 
95
+ sig { returns(String) }
65
96
  def data_controllers
66
97
  "hakumi--radio"
67
98
  end
68
99
 
100
+ sig { returns(Types::Renderable) }
69
101
  def label_text
70
102
  @text || content
71
103
  end
72
104
 
73
105
  private
74
106
 
107
+ sig { void }
75
108
  def validate_props!
76
109
  validate_inclusion!(:size, SIZES)
77
110
  end
@@ -2,11 +2,11 @@
2
2
  <%= tag.div(**wrapper_attributes) do %>
3
3
  <% normalized_options.each_with_index do |option, index| %>
4
4
  <% if button_group? %>
5
- <label class="<%= button_wrapper_classes(option) %>" data-controller="hakumi--radio" data-hakumi--radio-checked-value="<%= option_checked?(option[:value]) %>" data-hakumi--radio-variant-value="button">
5
+ <label class="<%= button_wrapper_classes(option) %>" data-controller="hakumi--radio" data-hakumi--radio-checked-value="<%= option_checked?(option.value) %>" data-hakumi--radio-variant-value="button">
6
6
  <%= radio_button_tag(
7
- @name,
8
- option[:value],
9
- option_checked?(option[:value]),
7
+ form_field_name,
8
+ option.value,
9
+ option_checked?(option.value),
10
10
  id: option_id(index),
11
11
  class: "hakumi-radio-button-input",
12
12
  disabled: option_disabled?(option),
@@ -15,16 +15,16 @@
15
15
  action: "change->hakumi--radio#toggle"
16
16
  }
17
17
  ) %>
18
- <span class="hakumi-radio-button-label"><%= option[:label] %></span>
18
+ <span class="hakumi-radio-button-label"><%= option.label %></span>
19
19
  </label>
20
20
  <% else %>
21
21
  <%= render HakumiComponents::Radio::Component.new(
22
- name: @name,
23
- value: option[:value],
24
- checked: option_checked?(option[:value]),
22
+ name: form_field_name,
23
+ value: option.value,
24
+ checked: option_checked?(option.value),
25
25
  disabled: option_disabled?(option),
26
26
  size: @size,
27
- text: option[:label]
27
+ text: option.label
28
28
  ) %>
29
29
  <% end %>
30
30
  <% end %>