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,39 +1,55 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  module Skeleton
5
6
  module Node
6
7
  class Component < HakumiComponents::BaseComponent
8
+ extend T::Sig
9
+
10
+ sig do
11
+ params(
12
+ active: T::Boolean,
13
+ size: T.any(Integer, String),
14
+ html_options: Types::HtmlAttributeValue
15
+ ).void
16
+ end
7
17
  def initialize(active: false, size: 40, **html_options)
8
- @active = active
9
- @size = size
10
- @html_options = html_options
18
+ @active = T.let(active, T::Boolean)
19
+ @size = T.let(size, T.any(Integer, String))
20
+ @html_options = T.let(html_options, Types::HtmlAttributes)
11
21
 
12
22
  validate_props!
13
23
  end
14
24
 
25
+ sig { returns(Types::HtmlAttributes) }
15
26
  def wrapper_attributes
16
27
  merge_attributes({ class: wrapper_classes }, @html_options.except(:class))
17
28
  end
18
29
 
30
+ sig { returns(String) }
19
31
  def node_classes
20
32
  class_names("skeleton-node")
21
33
  end
22
34
 
35
+ sig { returns(T.nilable(String)) }
23
36
  def node_style
24
- return nil unless @size
37
+ css = dimension_to_css(@size)
38
+ return nil unless css
25
39
 
26
- "width: #{dimension_to_css(@size)}; height: #{dimension_to_css(@size)};"
40
+ "width: #{css}; height: #{css};"
27
41
  end
28
42
 
29
43
  private
30
44
 
45
+ sig { returns(String) }
31
46
  def wrapper_classes
32
- class_names("skeleton", { element: true, active: @active }, @html_options[:class])
47
+ component_classes("skeleton", { element: true, active: @active }, @html_options)
33
48
  end
34
49
 
50
+ sig { void }
35
51
  def validate_props!
36
- return if @size.nil? || @size.is_a?(Numeric) || @size.is_a?(String)
52
+ return if @size.is_a?(Numeric) || @size.is_a?(String)
37
53
 
38
54
  raise ArgumentError, "size must be a number or string"
39
55
  end
@@ -0,0 +1,92 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module HakumiComponents
5
+ module Skeleton
6
+ class ParagraphConfig
7
+ extend T::Sig
8
+
9
+ WidthValue = T.type_alias { T.any(Integer, String) }
10
+ WidthSource = T.type_alias { T.nilable(T.any(WidthValue, T::Array[WidthValue])) }
11
+ Input = T.type_alias { T.any(T::Boolean, Types::HtmlAttributes, HakumiComponents::Skeleton::ParagraphConfig) }
12
+
13
+ sig { params(rows: Integer, width_source: WidthSource).void }
14
+ def initialize(rows: 3, width_source: nil)
15
+ @rows = T.let(rows, Integer)
16
+ @width_source = T.let(width_source, WidthSource)
17
+ validate!
18
+ end
19
+
20
+ sig { returns(Integer) }
21
+ attr_reader :rows
22
+
23
+ sig { params(default_rows: Integer).returns(T::Array[WidthValue]) }
24
+ def row_widths(default_rows)
25
+ rows = @rows.positive? ? @rows : default_rows
26
+ resolved = case @width_source
27
+ when Array
28
+ @width_source
29
+ when nil
30
+ default_widths(rows)
31
+ else
32
+ Array.new(rows, @width_source)
33
+ end
34
+
35
+ normalized = resolved.first(rows)
36
+ normalized.fill("100%", normalized.length...rows)
37
+ normalized
38
+ end
39
+
40
+ sig { params(value: Input).returns(T.nilable(HakumiComponents::Skeleton::ParagraphConfig)) }
41
+ def self.coerce(value)
42
+ return nil if value == false
43
+ return new if value == true
44
+ return value if value.is_a?(HakumiComponents::Skeleton::ParagraphConfig)
45
+
46
+ rows = parse_rows(value[:rows])
47
+ widths = parse_width_source(value[:widths], value[:width])
48
+ new(rows: rows || 3, width_source: widths)
49
+ end
50
+
51
+ class << self
52
+ extend T::Sig
53
+
54
+ private
55
+
56
+ sig { params(value: Types::HtmlAttributeValue).returns(T.nilable(Integer)) }
57
+ def parse_rows(value)
58
+ return value if value.is_a?(Integer)
59
+ return value.to_i if value.is_a?(String) && value.present?
60
+
61
+ nil
62
+ end
63
+
64
+ sig { params(widths: Types::HtmlAttributeValue, width: Types::HtmlAttributeValue).returns(WidthSource) }
65
+ def parse_width_source(widths, width)
66
+ if widths.is_a?(Array)
67
+ return widths.compact
68
+ end
69
+ return width if width.is_a?(Integer) || width.is_a?(String)
70
+
71
+ nil
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ sig { params(rows: Integer).returns(T::Array[WidthValue]) }
78
+ def default_widths(rows)
79
+ widths = T.let(Array.new(rows, "100%"), T::Array[WidthValue])
80
+ widths[-1] = "61%" if rows > 1
81
+ widths
82
+ end
83
+
84
+ sig { void }
85
+ def validate!
86
+ return if @rows >= 1
87
+
88
+ raise ArgumentError, "paragraph rows must be a positive integer"
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,31 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module HakumiComponents
5
+ module Skeleton
6
+ class TitleConfig
7
+ extend T::Sig
8
+
9
+ WidthValue = T.type_alias { T.any(Integer, String) }
10
+ Input = T.type_alias { T.any(T::Boolean, Types::HtmlAttributes, HakumiComponents::Skeleton::TitleConfig) }
11
+
12
+ sig { params(width: T.nilable(WidthValue)).void }
13
+ def initialize(width: nil)
14
+ @width = T.let(width, T.nilable(WidthValue))
15
+ end
16
+
17
+ sig { returns(T.nilable(WidthValue)) }
18
+ attr_reader :width
19
+
20
+ sig { params(value: Input).returns(T.nilable(HakumiComponents::Skeleton::TitleConfig)) }
21
+ def self.coerce(value)
22
+ return nil if value == false
23
+ return new if value == true
24
+ return value if value.is_a?(HakumiComponents::Skeleton::TitleConfig)
25
+
26
+ width = value[:width]
27
+ new(width: width.is_a?(Integer) || width.is_a?(String) ? width : nil)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -7,12 +7,12 @@
7
7
  <div
8
8
  class="hakumi-slider-handle"
9
9
  role="slider"
10
- tabindex="<%= @disabled ? -1 : 0 %>"
10
+ tabindex="<%= slider_disabled? ? -1 : 0 %>"
11
11
  data-hakumi--slider-target="handle"
12
12
  data-index="<%= index %>"
13
- aria-disabled="<%= @disabled %>"
14
- aria-valuemin="<%= @min %>"
15
- aria-valuemax="<%= @max %>"
13
+ aria-disabled="<%= slider_disabled? %>"
14
+ aria-valuemin="<%= slider_min %>"
15
+ aria-valuemax="<%= slider_max %>"
16
16
  >
17
17
  <span class="hakumi-slider-tooltip" data-hakumi--slider-target="tooltip"></span>
18
18
  </div>
@@ -20,16 +20,16 @@
20
20
 
21
21
  <% if marks? %>
22
22
  <div class="hakumi-slider-marks" data-hakumi--slider-target="marks">
23
- <% @marks.each do |mark| %>
24
- <span class="hakumi-slider-mark" style="<%= mark_style(mark[:value]) %>">
23
+ <% slider_marks.each do |mark| %>
24
+ <span class="hakumi-slider-mark" style="<%= mark_style(mark.value) %>">
25
25
  <span class="hakumi-slider-mark-dot"></span>
26
- <span class="hakumi-slider-mark-label"><%= mark[:label] %></span>
26
+ <span class="hakumi-slider-mark-label"><%= mark.label %></span>
27
27
  </span>
28
28
  <% end %>
29
29
  </div>
30
30
  <% end %>
31
31
 
32
- <% if @dots %>
32
+ <% if slider_dots? %>
33
33
  <div class="hakumi-slider-dots" data-hakumi--slider-target="dots">
34
34
  <% dot_values.each do |value| %>
35
35
  <span class="hakumi-slider-dot" style="<%= mark_style(value) %>"></span>
@@ -42,15 +42,15 @@
42
42
  type: "hidden",
43
43
  name: input_name,
44
44
  id: input_id_for(index),
45
- value: @range ? Array(@value || @default_value)[index] : (@value || @default_value),
46
- disabled: @disabled ? true : nil,
45
+ value: current_input_value(index),
46
+ disabled: slider_disabled? ? true : nil,
47
47
  data: { "hakumi--slider-target": "input" }
48
48
  ) %>
49
49
  <% end %>
50
50
  <% end %>
51
51
  <% end %>
52
52
 
53
- <% if @standalone %>
53
+ <% if standalone? %>
54
54
  <%= slider_control %>
55
55
  <% else %>
56
56
  <div <%= tag.attributes(form_item_attributes).to_s.html_safe %>>
@@ -1,12 +1,48 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  module Slider
5
- # Hakumi Slider component
6
- # Supports single and range sliders with marks, dots, and vertical layout.
7
6
  class Component < HakumiComponents::BaseComponent
7
+ extend T::Sig
8
+
8
9
  include HakumiComponents::Concerns::FormField
9
10
 
11
+ MarkScalar = T.type_alias { T.nilable(Types::ValidationPrimitive) }
12
+ MarkHash = T.type_alias { T::Hash[Types::HtmlKey, MarkScalar] }
13
+ MarkMap = T.type_alias { T::Hash[Types::ValidationPrimitive, Types::ValidationPrimitive] }
14
+ MarkEntry = T.type_alias { T.any(HakumiComponents::Slider::Mark, MarkHash, Types::ValidationPrimitive) }
15
+ NumericInput = T.type_alias { T.any(Numeric, String) }
16
+ MarksInput = T.type_alias do
17
+ T.nilable(T.any(MarkMap, T::Array[MarkEntry]))
18
+ end
19
+
20
+ sig do
21
+ params(
22
+ name: T.nilable(Types::FormFieldName),
23
+ label: T.nilable(String),
24
+ caption: T.nilable(String),
25
+ value: Types::FormFieldValue,
26
+ default_value: Types::FormFieldValue,
27
+ min: NumericInput,
28
+ max: NumericInput,
29
+ step: NumericInput,
30
+ range: T::Boolean,
31
+ vertical: T::Boolean,
32
+ marks: MarksInput,
33
+ dots: T::Boolean,
34
+ tooltip_visible: T.nilable(T::Boolean),
35
+ keyboard: T::Boolean,
36
+ disabled: T::Boolean,
37
+ allow_cross: T::Boolean,
38
+ handle_min: Types::FormFieldValue,
39
+ handle_max: Types::FormFieldValue,
40
+ standalone: T::Boolean,
41
+ required: T::Boolean,
42
+ errors: Types::FormFieldErrors,
43
+ html_options: Types::HtmlAttributeValue
44
+ ).void
45
+ end
10
46
  def initialize(
11
47
  name: nil,
12
48
  label: nil,
@@ -29,34 +65,48 @@ module HakumiComponents
29
65
  standalone: true,
30
66
  required: false,
31
67
  errors: [],
32
- **html_attrs
68
+ **html_options
33
69
  )
34
- @name = name || generate_id("slider")
35
- @label = label
36
- @caption = caption
37
- @value = value
38
- @default_value = default_value
39
- @min = min
40
- @max = max
41
- @step = step
42
- @range = cast_boolean(range)
43
- @vertical = cast_boolean(vertical)
44
- @marks = normalize_marks(marks)
45
- @dots = cast_boolean(dots)
46
- @tooltip_visible = tooltip_visible
47
- @keyboard = cast_boolean(keyboard)
48
- @disabled = cast_boolean(disabled)
49
- @allow_cross = cast_boolean(allow_cross)
50
- @handle_min = handle_min
51
- @handle_max = handle_max
52
- @standalone = cast_boolean(standalone)
53
- @required = cast_boolean(required)
54
- @errors = Array(errors)
55
- @html_attrs = html_attrs
70
+ validate_numeric_like!(min, "min")
71
+ validate_numeric_like!(max, "max")
72
+ validate_numeric_like!(step, "step")
73
+
74
+ @name = T.let(name || generate_id("slider"), Types::FormFieldName)
75
+ @label = T.let(label, T.nilable(String))
76
+ @caption = T.let(caption, T.nilable(String))
77
+ @value = T.let(value, Types::FormFieldValue)
78
+ @default_value = T.let(default_value, Types::FormFieldValue)
79
+ @min = T.let(min.to_s, String)
80
+ @max = T.let(max.to_s, String)
81
+ @step = T.let(step.to_s, String)
82
+ @range = T.let(cast_boolean(range) ? true : false, T::Boolean)
83
+ @vertical = T.let(cast_boolean(vertical) ? true : false, T::Boolean)
84
+ @marks = T.let(normalize_marks(marks), T::Array[HakumiComponents::Slider::Mark])
85
+ @dots = T.let(cast_boolean(dots) ? true : false, T::Boolean)
86
+ @tooltip_visible = T.let(cast_boolean(tooltip_visible), T.nilable(T::Boolean))
87
+ @keyboard = T.let(cast_boolean(keyboard) != false, T::Boolean)
88
+ @disabled = T.let(cast_boolean(disabled) ? true : false, T::Boolean)
89
+ @allow_cross = T.let(cast_boolean(allow_cross) != false, T::Boolean)
90
+ @handle_min = T.let(handle_min, Types::FormFieldValue)
91
+ @handle_max = T.let(handle_max, Types::FormFieldValue)
92
+ @standalone = T.let(cast_boolean(standalone) ? true : false, T::Boolean)
93
+ @required = T.let(cast_boolean(required) ? true : false, T::Boolean)
94
+ @errors = T.let(Array(errors), Types::FormFieldErrors)
95
+ @html_options = T.let(html_options, Types::HtmlAttributes)
96
+ initialize_form_field_contract!(
97
+ name: @name,
98
+ label: @label,
99
+ caption: @caption,
100
+ errors: @errors,
101
+ standalone: @standalone,
102
+ required: @required,
103
+ html_options: @html_options
104
+ )
56
105
 
57
106
  validate_props!
58
107
  end
59
108
 
109
+ sig { returns(Types::HtmlAttributes) }
60
110
  def wrapper_attributes
61
111
  merge_attributes(
62
112
  {
@@ -79,33 +129,63 @@ module HakumiComponents
79
129
  }.compact
80
130
  },
81
131
  {
82
- id: @html_attrs[:id],
83
- data: @html_attrs[:data]
132
+ id: @html_options[:id],
133
+ data: @html_options[:data]
84
134
  }.compact
85
135
  )
86
136
  end
87
137
 
138
+ sig { returns(Types::FormFieldName) }
88
139
  def input_name
89
- return @name unless @range
90
- return @name if @name.to_s.end_with?("[]")
140
+ return form_field_name unless @range
141
+ return form_field_name if form_field_name.to_s.end_with?("[]")
91
142
 
92
- "#{@name}[]"
143
+ "#{form_field_name}[]"
93
144
  end
94
145
 
146
+ sig { params(index: Integer).returns(String) }
95
147
  def input_id_for(index)
96
- return input_id unless @range
148
+ return input_id.to_s unless @range
97
149
 
98
150
  "#{input_id}_#{index}"
99
151
  end
100
152
 
153
+ sig { returns(Integer) }
101
154
  def handle_count
102
155
  @range ? 2 : 1
103
156
  end
104
157
 
158
+ sig { returns(T::Boolean) }
105
159
  def marks?
106
160
  @marks.any?
107
161
  end
108
162
 
163
+ sig { returns(T::Array[HakumiComponents::Slider::Mark]) }
164
+ def slider_marks
165
+ @marks
166
+ end
167
+
168
+ sig { returns(T::Boolean) }
169
+ def slider_dots?
170
+ @dots
171
+ end
172
+
173
+ sig { returns(T::Boolean) }
174
+ def slider_disabled?
175
+ @disabled
176
+ end
177
+
178
+ sig { returns(String) }
179
+ def slider_min
180
+ @min
181
+ end
182
+
183
+ sig { returns(String) }
184
+ def slider_max
185
+ @max
186
+ end
187
+
188
+ sig { params(value: String).returns(String) }
109
189
  def mark_style(value)
110
190
  percent = position_percent(value)
111
191
  if @vertical
@@ -115,6 +195,7 @@ module HakumiComponents
115
195
  end
116
196
  end
117
197
 
198
+ sig { returns(T::Array[String]) }
118
199
  def dot_values
119
200
  return [] unless @dots
120
201
 
@@ -123,32 +204,39 @@ module HakumiComponents
123
204
  step = @step.to_f
124
205
  return [] if step <= 0
125
206
 
126
- values = []
207
+ values = T.let([], T::Array[String])
127
208
  current = min
128
209
  while current <= max + (step / 1000.0)
129
- values << current
210
+ values << current.to_s
130
211
  current += step
131
212
  end
132
213
  values
133
214
  end
134
215
 
216
+ sig { params(index: Integer).returns(T.nilable(String)) }
217
+ def current_input_value(index = 0)
218
+ values = normalized_input_values
219
+ return values.first unless @range
220
+
221
+ values[index]
222
+ end
223
+
135
224
  private
136
225
 
226
+ sig { void }
137
227
  def validate_props!
138
- validate_numeric_like!(@min, "min")
139
- validate_numeric_like!(@max, "max")
140
- validate_numeric_like!(@step, "step")
141
-
142
228
  validate_range_values!(@value, "value") if @value
143
229
  validate_range_values!(@default_value, "default_value") if @default_value
144
230
  end
145
231
 
232
+ sig { params(value: NumericInput, name: String).void }
146
233
  def validate_numeric_like!(value, name)
147
234
  return if value.is_a?(Numeric) || value.is_a?(String)
148
235
 
149
236
  raise ArgumentError, "#{name} must be a number or string"
150
237
  end
151
238
 
239
+ sig { params(value: Types::FormFieldValue, name: String).void }
152
240
  def validate_range_values!(value, name)
153
241
  if @range
154
242
  unless value.is_a?(Array) && value.size == 2
@@ -159,6 +247,7 @@ module HakumiComponents
159
247
  end
160
248
  end
161
249
 
250
+ sig { returns(String) }
162
251
  def component_html_class
163
252
  class_names(
164
253
  "slider",
@@ -170,59 +259,89 @@ module HakumiComponents
170
259
  "with-dots": @dots,
171
260
  "tooltip-visible": tooltip_visible_class?
172
261
  },
173
- @html_attrs[:wrapper_class]
262
+ [ wrapper_class_name ]
174
263
  )
175
264
  end
176
265
 
266
+ sig { returns(T::Boolean) }
177
267
  def tooltip_visible_class?
178
268
  @tooltip_visible == true
179
269
  end
180
270
 
271
+ sig { returns(T.nilable(T::Boolean)) }
181
272
  def tooltip_visible_value
182
- return nil if @tooltip_visible.nil?
183
-
184
- cast_boolean(@tooltip_visible)
273
+ @tooltip_visible
185
274
  end
186
275
 
276
+ sig { params(value: Types::FormFieldValue).returns(T.nilable(String)) }
187
277
  def data_value(value)
188
278
  return nil if value.nil?
189
279
 
190
280
  Array(value).to_json
191
281
  end
192
282
 
283
+ sig { params(value: Types::FormFieldValue).returns(T.nilable(String)) }
193
284
  def handle_bounds_value(value)
194
285
  return nil if value.nil?
195
286
 
196
287
  Array(value).to_json
197
288
  end
198
289
 
290
+ sig { params(marks: MarksInput).returns(T::Array[HakumiComponents::Slider::Mark]) }
199
291
  def normalize_marks(marks)
200
292
  return [] if marks.nil?
201
293
 
202
294
  entries = if marks.is_a?(Hash)
203
- marks.map { |value, label| { value: value, label: label } }
295
+ marks.map { |value, label| HakumiComponents::Slider::Mark.new(value: value.to_s, label: label.to_s) }
204
296
  else
205
- Array(marks).map do |mark|
206
- if mark.is_a?(Hash)
207
- value = mark[:value] || mark["value"]
208
- label = mark[:label] || mark["label"] || value
209
- { value: value, label: label }
210
- else
211
- { value: mark, label: mark }
212
- end
213
- end
297
+ Array(marks).filter_map do |mark|
298
+ next mark if mark.is_a?(HakumiComponents::Slider::Mark)
299
+
300
+ if mark.is_a?(Hash)
301
+ value = mark[:value] || mark["value"]
302
+ label = mark[:label] || mark["label"] || value
303
+ next nil if value.nil?
304
+
305
+ HakumiComponents::Slider::Mark.new(value: value.to_s, label: label.to_s)
306
+ else
307
+ HakumiComponents::Slider::Mark.new(value: mark.to_s, label: mark.to_s)
308
+ end
309
+ end
214
310
  end
215
311
 
216
- entries.compact.select { |entry| entry[:value].present? }.sort_by { |entry| entry[:value].to_f }
312
+ entries.sort_by(&:numeric_value)
217
313
  end
218
314
 
315
+ sig { params(value: String).returns(Float) }
219
316
  def position_percent(value)
220
317
  min = @min.to_f
221
318
  max = @max.to_f
222
- return 0 if max == min
319
+ return 0.0 if max == min
223
320
 
224
321
  ((value.to_f - min) / (max - min) * 100).clamp(0, 100)
225
322
  end
323
+
324
+ sig { returns(T::Array[String]) }
325
+ def normalized_input_values
326
+ value = @value.nil? ? @default_value : @value
327
+ return [] if value.nil?
328
+
329
+ if value.is_a?(Array)
330
+ value.filter_map do |item|
331
+ next if item.nil?
332
+
333
+ item.to_s
334
+ end
335
+ else
336
+ [ value.to_s ]
337
+ end
338
+ end
339
+
340
+ sig { returns(T.nilable(String)) }
341
+ def wrapper_class_name
342
+ css_class = @html_options[:wrapper_class]
343
+ css_class.is_a?(String) ? css_class : nil
344
+ end
226
345
  end
227
346
  end
228
347
  end
@@ -0,0 +1,27 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module HakumiComponents
5
+ module Slider
6
+ class Mark
7
+ extend T::Sig
8
+
9
+ sig { params(value: String, label: String).void }
10
+ def initialize(value:, label:)
11
+ @value = value
12
+ @label = label
13
+ end
14
+
15
+ sig { returns(String) }
16
+ attr_reader :value
17
+
18
+ sig { returns(String) }
19
+ attr_reader :label
20
+
21
+ sig { returns(Float) }
22
+ def numeric_value
23
+ @value.to_f
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,3 +1 @@
1
- <div <%= tag.attributes(html_attributes) %>>
2
- <%= content %>
3
- </div>
1
+ <%= content_tag :div, content, wrapper_attributes %>