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,128 +1,168 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  module Concerns
5
- # Shared behavior for form field components
6
- # Provides common methods for handling errors, labels, captions, and accessibility
7
6
  module FormField
8
- attr_reader :name, :label, :caption, :errors, :required, :size, :standalone
7
+ extend T::Sig
8
+ extend T::Helpers
9
9
 
10
- # Check if field has validation errors
11
- #
12
- # @return [Boolean]
13
- def has_error?
14
- @errors.any?
10
+ abstract!
11
+
12
+ include FormFieldInterface
13
+
14
+ requires_ancestor { HakumiComponents::BaseComponent }
15
+
16
+ sig { override.returns(HakumiComponents::Concerns::FormFieldContract) }
17
+ def form_field_contract
18
+ contract = T.let(@form_field_contract, T.nilable(HakumiComponents::Concerns::FormFieldContract))
19
+ return contract unless contract.nil?
20
+
21
+ Kernel.raise "form_field_contract must be initialized"
22
+ end
23
+
24
+ sig { returns(Types::FormFieldName) }
25
+ def form_field_name
26
+ form_field_contract.name
27
+ end
28
+
29
+ sig { returns(T.nilable(String)) }
30
+ def form_field_label
31
+ form_field_contract.label
32
+ end
33
+
34
+ sig { returns(T.nilable(String)) }
35
+ def form_field_caption
36
+ form_field_contract.caption
37
+ end
38
+
39
+ sig { returns(Types::FormFieldErrors) }
40
+ def form_field_errors
41
+ form_field_contract.errors
42
+ end
43
+
44
+ sig { returns(T::Boolean) }
45
+ def form_field_standalone
46
+ form_field_contract.standalone
47
+ end
48
+
49
+ sig { returns(T::Boolean) }
50
+ def form_field_required
51
+ form_field_contract.required
52
+ end
53
+
54
+ sig { returns(Types::HtmlAttributes) }
55
+ def form_field_html_options
56
+ form_field_contract.html_options
57
+ end
58
+
59
+ sig { returns(T.nilable(T::Array[Types::ValidationRule])) }
60
+ def form_field_rules
61
+ form_field_contract.rules
62
+ end
63
+
64
+ sig { returns(T::Boolean) }
65
+ def error?
66
+ form_field_errors.any?
15
67
  end
16
68
 
17
- # Check if component is in standalone mode
18
- #
19
- # @return [Boolean]
69
+ sig { returns(T::Boolean) }
20
70
  def standalone?
21
- @standalone
71
+ form_field_standalone
22
72
  end
23
73
 
24
- # Get the input field ID
25
- # Works with both @html_options and @html_attrs
26
- #
27
- # @return [String]
74
+ sig { returns(Types::StringOrSymbol) }
28
75
  def input_id
29
- options = instance_variable_defined?(:@html_options) ? @html_options : @html_attrs
30
- options&.dig(:id) || @name
76
+ html_options = form_field_html_options
77
+ id = html_options[:id]
78
+ return id if id.is_a?(String) || id.is_a?(Symbol)
79
+
80
+ form_field_name
31
81
  end
32
82
 
33
- # Generate CSS classes for form item wrapper
34
- #
35
- # @return [String]
83
+ sig { returns(String) }
36
84
  def form_item_classes
37
85
  class_names(
38
86
  "form-item",
39
87
  {
40
- "has-error": has_error?,
41
- "with-help": has_error? || @caption
88
+ "has-error": error?,
89
+ "with-help": error? || !caption_blank?
42
90
  }
43
91
  )
44
92
  end
45
93
 
46
- # Generate aria-describedby attribute value
47
- #
48
- # @return [String, nil]
94
+ sig { returns(T.nilable(String)) }
49
95
  def describedby_ids
50
- # @type var ids: Array[String]
51
- ids = []
52
- ids << "#{@name}_caption" if @caption
53
- ids << "#{@name}_error" if has_error?
54
- ids.any? ? ids.join(" ") : nil
96
+ ids = T.let([], T::Array[String])
97
+ ids << "#{form_field_name}_caption" unless caption_blank?
98
+ ids << "#{form_field_name}_error" if error?
99
+ ids.empty? ? nil : ids.join(" ")
55
100
  end
56
101
 
57
- # Get first error message
58
- #
59
- # @return [String, nil]
102
+ sig { returns(T.nilable(String)) }
60
103
  def error_message
61
- @errors.first if has_error?
104
+ form_field_errors.first
62
105
  end
63
106
 
64
- # Render label element (wraps label in div for proper styling)
65
- #
66
- # @param field_id [String] ID of the input field
67
- # @return [String, nil]
107
+ sig { params(field_id: T.nilable(Types::StringOrSymbol)).returns(T.nilable(ActiveSupport::SafeBuffer)) }
68
108
  def render_label(field_id: nil)
69
- return nil if @label.blank?
109
+ label = form_field_label
110
+ return nil if label.nil? || label.strip.empty?
70
111
 
71
112
  content_tag(:div, class: "hakumi-form-item-label") do
72
- content_tag(:label, for: field_id || @name) do
113
+ content_tag(:label, for: field_id || form_field_name) do
73
114
  safe_join([
74
- (@required ? content_tag(:span, "*", class: "hakumi-form-item-required-mark") : nil),
75
- @label
115
+ (form_field_required ? content_tag(:span, "*", class: "hakumi-form-item-required-mark") : nil),
116
+ label
76
117
  ].compact)
77
118
  end
78
119
  end
79
120
  end
80
121
 
81
- # Render caption (help text) element
82
- #
83
- # @return [String, nil]
122
+ sig { returns(T.nilable(ActiveSupport::SafeBuffer)) }
84
123
  def render_caption
85
- return nil if @caption.blank?
124
+ caption = form_field_caption
125
+ return nil if caption.nil? || caption.strip.empty?
86
126
 
87
- content_tag(:div, @caption, class: "hakumi-form-item-extra", id: "#{@name}_caption")
127
+ content_tag(:div, caption, class: "hakumi-form-item-extra", id: "#{form_field_name}_caption")
88
128
  end
89
129
 
90
- # Render error message element
91
- #
92
- # @return [String, nil]
130
+ sig { returns(T.nilable(ActiveSupport::SafeBuffer)) }
93
131
  def render_error
94
- return nil unless has_error?
132
+ return nil unless error?
95
133
 
96
- content_tag(:div, error_message,
134
+ content_tag(
135
+ :div,
136
+ error_message,
97
137
  class: "hakumi-form-item-explain-error",
98
- id: "#{@name}_error",
138
+ id: "#{form_field_name}_error",
99
139
  role: "alert"
100
140
  )
101
141
  end
102
142
 
103
- # Render explain section (caption or error)
104
- #
105
- # @return [String, nil]
143
+ sig { returns(T.nilable(ActiveSupport::SafeBuffer)) }
106
144
  def render_explain
107
- return nil unless @caption || has_error?
145
+ return nil if caption_blank? && !error?
108
146
 
109
- content_tag(:div, class: "hakumi-form-item-explain") do
110
- has_error? ? render_error : render_caption
147
+ explain_content = if error?
148
+ render_error
149
+ else
150
+ render_caption
111
151
  end
152
+ return nil if explain_content.nil?
153
+
154
+ content_tag(:div, class: "hakumi-form-item-explain") { explain_content }
112
155
  end
113
156
 
114
- # Generate form item wrapper attributes
115
- #
116
- # @param additional_data [Hash] Additional data attributes
117
- # @return [Hash]
157
+ sig { params(additional_data: Types::DataAttributes).returns(Types::HtmlAttributes) }
118
158
  def form_item_attributes(additional_data: {})
119
159
  data_attrs = additional_data.dup
160
+ rules = form_field_rules
120
161
 
121
- # Add controller if rules exist
122
- if defined?(@rules) && @rules
162
+ if rules && !rules.empty?
123
163
  data_attrs[:controller] = "hakumi--form-item"
124
- data_attrs[:hakumi__form_item_field_name_value] = @name.to_s
125
- data_attrs[:hakumi__form_item_rules_value] = @rules.to_json
164
+ data_attrs[:hakumi__form_item_field_name_value] = form_field_name.to_s
165
+ data_attrs[:hakumi__form_item_rules_value] = rules.to_json
126
166
  end
127
167
 
128
168
  {
@@ -130,6 +170,67 @@ module HakumiComponents
130
170
  data: data_attrs.empty? ? nil : data_attrs
131
171
  }.compact
132
172
  end
173
+
174
+ private
175
+
176
+ sig do
177
+ params(
178
+ name: Types::FormFieldName,
179
+ label: T.nilable(String),
180
+ caption: T.nilable(String),
181
+ errors: Types::FormFieldErrors,
182
+ standalone: T::Boolean,
183
+ required: T::Boolean,
184
+ html_options: Types::HtmlAttributes,
185
+ rules: T.nilable(T::Array[Types::ValidationRule])
186
+ ).returns(HakumiComponents::Concerns::FormFieldContract)
187
+ end
188
+ def build_form_field_contract(name:, label:, caption:, errors:, standalone:, required:, html_options:, rules: nil)
189
+ HakumiComponents::Concerns::FormFieldContract.new(
190
+ name: name,
191
+ label: label,
192
+ caption: caption,
193
+ errors: errors,
194
+ standalone: standalone,
195
+ required: required,
196
+ html_options: html_options,
197
+ rules: rules
198
+ )
199
+ end
200
+
201
+ sig do
202
+ params(
203
+ name: Types::FormFieldName,
204
+ label: T.nilable(String),
205
+ caption: T.nilable(String),
206
+ errors: Types::FormFieldErrors,
207
+ standalone: T::Boolean,
208
+ required: T::Boolean,
209
+ html_options: Types::HtmlAttributes,
210
+ rules: T.nilable(T::Array[Types::ValidationRule])
211
+ ).void
212
+ end
213
+ def initialize_form_field_contract!(name:, label:, caption:, errors:, standalone:, required:, html_options:, rules: nil)
214
+ @form_field_contract = T.let(
215
+ build_form_field_contract(
216
+ name: name,
217
+ label: label,
218
+ caption: caption,
219
+ errors: errors,
220
+ standalone: standalone,
221
+ required: required,
222
+ html_options: html_options,
223
+ rules: rules
224
+ ),
225
+ T.nilable(HakumiComponents::Concerns::FormFieldContract)
226
+ )
227
+ end
228
+
229
+ sig { returns(T::Boolean) }
230
+ def caption_blank?
231
+ caption = form_field_caption
232
+ caption.nil? || caption.strip.empty?
233
+ end
133
234
  end
134
235
  end
135
236
  end
@@ -0,0 +1,57 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module HakumiComponents
5
+ module Concerns
6
+ class FormFieldContract
7
+ extend T::Sig
8
+
9
+ sig do
10
+ params(
11
+ name: Types::FormFieldName,
12
+ label: T.nilable(String),
13
+ caption: T.nilable(String),
14
+ errors: Types::FormFieldErrors,
15
+ standalone: T::Boolean,
16
+ required: T::Boolean,
17
+ html_options: Types::HtmlAttributes,
18
+ rules: T.nilable(T::Array[Types::ValidationRule])
19
+ ).void
20
+ end
21
+ def initialize(name:, label:, caption:, errors:, standalone:, required:, html_options:, rules:)
22
+ @name = name
23
+ @label = label
24
+ @caption = caption
25
+ @errors = errors
26
+ @standalone = standalone
27
+ @required = required
28
+ @html_options = html_options
29
+ @rules = rules
30
+ end
31
+
32
+ sig { returns(Types::FormFieldName) }
33
+ attr_reader :name
34
+
35
+ sig { returns(T.nilable(String)) }
36
+ attr_reader :label
37
+
38
+ sig { returns(T.nilable(String)) }
39
+ attr_reader :caption
40
+
41
+ sig { returns(Types::FormFieldErrors) }
42
+ attr_reader :errors
43
+
44
+ sig { returns(T::Boolean) }
45
+ attr_reader :standalone
46
+
47
+ sig { returns(T::Boolean) }
48
+ attr_reader :required
49
+
50
+ sig { returns(Types::HtmlAttributes) }
51
+ attr_reader :html_options
52
+
53
+ sig { returns(T.nilable(T::Array[Types::ValidationRule])) }
54
+ attr_reader :rules
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,16 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module HakumiComponents
5
+ module Concerns
6
+ module FormFieldInterface
7
+ extend T::Sig
8
+ extend T::Helpers
9
+
10
+ interface!
11
+
12
+ sig { abstract.returns(HakumiComponents::Concerns::FormFieldContract) }
13
+ def form_field_contract; end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,111 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module HakumiComponents
5
+ module Concerns
6
+ module InputControl
7
+ extend T::Sig
8
+ extend T::Helpers
9
+
10
+ abstract!
11
+
12
+ include FormField
13
+ include InputControlInterface
14
+
15
+ sig { override.returns(InputControlContract) }
16
+ def input_control_contract
17
+ contract = T.let(@input_control_contract, T.nilable(InputControlContract))
18
+ return contract unless contract.nil?
19
+
20
+ Kernel.raise "input_control_contract must be initialized"
21
+ end
22
+
23
+ sig { override.returns(Types::FormFieldValue) }
24
+ def input_control_value
25
+ input_control_contract.value
26
+ end
27
+
28
+ sig { override.returns(T.nilable(String)) }
29
+ def input_control_placeholder
30
+ input_control_contract.placeholder
31
+ end
32
+
33
+ sig { override.returns(Symbol) }
34
+ def input_control_size
35
+ input_control_contract.size
36
+ end
37
+
38
+ sig { override.returns(T::Boolean) }
39
+ def input_control_disabled
40
+ input_control_contract.disabled
41
+ end
42
+
43
+ sig { override.returns(T::Boolean) }
44
+ def input_control_readonly
45
+ input_control_contract.readonly
46
+ end
47
+
48
+ sig { override.returns(T::Boolean) }
49
+ def input_control_has_value?
50
+ value = input_control_value
51
+ if value.is_a?(Array)
52
+ return value.any? do |item|
53
+ next false if item.nil? || item == false
54
+ next !item.empty? if item.is_a?(String)
55
+
56
+ true
57
+ end
58
+ end
59
+
60
+ return false if value.nil? || value == false
61
+ return !value.empty? if value.is_a?(String)
62
+
63
+ true
64
+ end
65
+
66
+ private
67
+
68
+ sig do
69
+ params(
70
+ name: Types::FormFieldName,
71
+ label: T.nilable(String),
72
+ caption: T.nilable(String),
73
+ value: Types::FormFieldValue,
74
+ placeholder: T.nilable(String),
75
+ size: Symbol,
76
+ disabled: T::Boolean,
77
+ readonly: T::Boolean,
78
+ required: T::Boolean,
79
+ standalone: T::Boolean,
80
+ errors: Types::FormFieldErrors,
81
+ html_options: Types::HtmlAttributes,
82
+ rules: T.nilable(T::Array[Types::ValidationRule])
83
+ ).void
84
+ end
85
+ def initialize_input_control_contract!(name:, label:, caption:, value:, placeholder:, size:, disabled:, readonly:, required:, standalone:, errors:, html_options:, rules: nil)
86
+ initialize_form_field_contract!(
87
+ name: name,
88
+ label: label,
89
+ caption: caption,
90
+ errors: errors,
91
+ standalone: standalone,
92
+ required: required,
93
+ html_options: html_options,
94
+ rules: rules
95
+ )
96
+
97
+ @input_control_contract = T.let(
98
+ InputControlContract.new(
99
+ form_field_contract: form_field_contract,
100
+ value: value,
101
+ placeholder: placeholder,
102
+ size: size,
103
+ disabled: disabled,
104
+ readonly: readonly
105
+ ),
106
+ T.nilable(InputControlContract)
107
+ )
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,47 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module HakumiComponents
5
+ module Concerns
6
+ class InputControlContract
7
+ extend T::Sig
8
+
9
+ sig do
10
+ params(
11
+ form_field_contract: FormFieldContract,
12
+ value: Types::FormFieldValue,
13
+ placeholder: T.nilable(String),
14
+ size: Symbol,
15
+ disabled: T::Boolean,
16
+ readonly: T::Boolean
17
+ ).void
18
+ end
19
+ def initialize(form_field_contract:, value:, placeholder:, size:, disabled:, readonly:)
20
+ @form_field_contract = form_field_contract
21
+ @value = value
22
+ @placeholder = placeholder
23
+ @size = size
24
+ @disabled = disabled
25
+ @readonly = readonly
26
+ end
27
+
28
+ sig { returns(FormFieldContract) }
29
+ attr_reader :form_field_contract
30
+
31
+ sig { returns(Types::FormFieldValue) }
32
+ attr_reader :value
33
+
34
+ sig { returns(T.nilable(String)) }
35
+ attr_reader :placeholder
36
+
37
+ sig { returns(Symbol) }
38
+ attr_reader :size
39
+
40
+ sig { returns(T::Boolean) }
41
+ attr_reader :disabled
42
+
43
+ sig { returns(T::Boolean) }
44
+ attr_reader :readonly
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,34 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module HakumiComponents
5
+ module Concerns
6
+ module InputControlInterface
7
+ extend T::Sig
8
+ extend T::Helpers
9
+
10
+ interface!
11
+
12
+ sig { abstract.returns(HakumiComponents::Concerns::InputControlContract) }
13
+ def input_control_contract; end
14
+
15
+ sig { abstract.returns(HakumiComponents::Types::FormFieldValue) }
16
+ def input_control_value; end
17
+
18
+ sig { abstract.returns(T.nilable(String)) }
19
+ def input_control_placeholder; end
20
+
21
+ sig { abstract.returns(Symbol) }
22
+ def input_control_size; end
23
+
24
+ sig { abstract.returns(T::Boolean) }
25
+ def input_control_disabled; end
26
+
27
+ sig { abstract.returns(T::Boolean) }
28
+ def input_control_readonly; end
29
+
30
+ sig { abstract.returns(T::Boolean) }
31
+ def input_control_has_value?; end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,122 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module HakumiComponents
5
+ module Concerns
6
+ module SelectionControl
7
+ extend T::Sig
8
+ extend T::Helpers
9
+
10
+ abstract!
11
+
12
+ include FormField
13
+ include SelectionControlInterface
14
+
15
+ sig { override.returns(SelectionControlContract) }
16
+ def selection_control_contract
17
+ contract = T.let(@selection_control_contract, T.nilable(SelectionControlContract))
18
+ return contract unless contract.nil?
19
+
20
+ Kernel.raise "selection_control_contract must be initialized"
21
+ end
22
+
23
+ sig { override.returns(Types::FormFieldValue) }
24
+ def selection_control_value
25
+ selection_control_contract.value
26
+ end
27
+
28
+ sig { override.returns(T.nilable(String)) }
29
+ def selection_control_placeholder
30
+ selection_control_contract.placeholder
31
+ end
32
+
33
+ sig { override.returns(Symbol) }
34
+ def selection_control_size
35
+ selection_control_contract.size
36
+ end
37
+
38
+ sig { override.returns(T::Boolean) }
39
+ def selection_control_disabled
40
+ selection_control_contract.disabled
41
+ end
42
+
43
+ sig { override.returns(T::Boolean) }
44
+ def selection_control_allow_clear
45
+ selection_control_contract.allow_clear
46
+ end
47
+
48
+ sig { override.returns(T::Boolean) }
49
+ def selection_control_has_value?
50
+ value = selection_control_value
51
+ if value.is_a?(Array)
52
+ return value.any? do |item|
53
+ next false if item.nil? || item == false
54
+ next !item.empty? if item.is_a?(String)
55
+
56
+ true
57
+ end
58
+ end
59
+
60
+ return false if value.nil? || value == false
61
+ return !value.empty? if value.is_a?(String)
62
+
63
+ true
64
+ end
65
+
66
+ private
67
+
68
+ sig { returns(T.nilable(String)) }
69
+ def selection_control_html_class_name
70
+ css_class = form_field_html_options[:class]
71
+ css_class.is_a?(String) ? css_class : nil
72
+ end
73
+
74
+ sig { returns(Types::HtmlAttributes) }
75
+ def selection_control_html_options_without_class
76
+ form_field_html_options.except(:class)
77
+ end
78
+
79
+ sig do
80
+ params(
81
+ name: Types::FormFieldName,
82
+ label: T.nilable(String),
83
+ caption: T.nilable(String),
84
+ value: Types::FormFieldValue,
85
+ placeholder: T.nilable(String),
86
+ size: Symbol,
87
+ disabled: T::Boolean,
88
+ allow_clear: T::Boolean,
89
+ required: T::Boolean,
90
+ standalone: T::Boolean,
91
+ errors: Types::FormFieldErrors,
92
+ html_options: Types::HtmlAttributes,
93
+ rules: T.nilable(T::Array[Types::ValidationRule])
94
+ ).void
95
+ end
96
+ def initialize_selection_control_contract!(name:, label:, caption:, value:, placeholder:, size:, disabled:, allow_clear:, required:, standalone:, errors:, html_options:, rules: nil)
97
+ initialize_form_field_contract!(
98
+ name: name,
99
+ label: label,
100
+ caption: caption,
101
+ errors: errors,
102
+ standalone: standalone,
103
+ required: required,
104
+ html_options: html_options,
105
+ rules: rules
106
+ )
107
+
108
+ @selection_control_contract = T.let(
109
+ SelectionControlContract.new(
110
+ form_field_contract: form_field_contract,
111
+ value: value,
112
+ placeholder: placeholder,
113
+ size: size,
114
+ disabled: disabled,
115
+ allow_clear: allow_clear
116
+ ),
117
+ T.nilable(SelectionControlContract)
118
+ )
119
+ end
120
+ end
121
+ end
122
+ end