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,27 +1,48 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  module InputNumber
5
- # Hakumi InputNumber component
6
- # Numeric input with precision, formatter, and spinner controls
7
- #
8
- # @example Basic usage
9
- # <%= render HakumiComponents::InputNumber::Component.new(name: :amount, value: 10) %>
10
- #
11
- # @example With formatter and prefix
12
- # <%= render HakumiComponents::InputNumber::Component.new(
13
- # name: :price,
14
- # value: 199.95,
15
- # prefix: "$",
16
- # formatter: { style: "currency", currency: "USD", minimumFractionDigits: 2 }
17
- # ) %>
18
6
  class Component < HakumiComponents::BaseComponent
19
- include HakumiComponents::Concerns::FormField
7
+ extend T::Sig
20
8
 
21
- SIZES = [ :small, :middle, :large ].freeze
22
- VARIANTS = [ :default, :filled, :borderless ].freeze
23
- STATUSES = [ :default, :success, :warning, :error ].freeze
9
+ include HakumiComponents::Concerns::InputControl
24
10
 
11
+ NumericLike = T.type_alias { T.any(String, Numeric) }
12
+ FormatterOptions = T.type_alias { T::Hash[Symbol, T.nilable(T.any(String, Symbol, T::Boolean, Numeric))] }
13
+
14
+ VARIANTS = T.let([ :default, :filled, :borderless ].freeze, T::Array[Symbol])
15
+ STATUSES = T.let([ :default, :success, :warning, :error ].freeze, T::Array[Symbol])
16
+
17
+ sig do
18
+ params(
19
+ name: Types::FormFieldName,
20
+ label: T.nilable(String),
21
+ caption: T.nilable(String),
22
+ value: Types::FormFieldValue,
23
+ placeholder: T.nilable(String),
24
+ min: T.nilable(NumericLike),
25
+ max: T.nilable(NumericLike),
26
+ step: NumericLike,
27
+ precision: T.nilable(NumericLike),
28
+ size: Symbol,
29
+ variant: Symbol,
30
+ status: Symbol,
31
+ disabled: T::Boolean,
32
+ readonly: T::Boolean,
33
+ required: T::Boolean,
34
+ prefix: Types::Renderable,
35
+ suffix: Types::Renderable,
36
+ controls: T::Boolean,
37
+ keyboard: T::Boolean,
38
+ wheel: T::Boolean,
39
+ formatter: T.nilable(FormatterOptions),
40
+ standalone: T::Boolean,
41
+ rules: T.nilable(T::Array[Types::ValidationRule]),
42
+ errors: Types::FormFieldErrors,
43
+ html_options: Types::HtmlAttributeValue
44
+ ).void
45
+ end
25
46
  def initialize(
26
47
  name:,
27
48
  label: nil,
@@ -32,7 +53,7 @@ module HakumiComponents
32
53
  max: nil,
33
54
  step: 1,
34
55
  precision: nil,
35
- size: :middle,
56
+ size: :default,
36
57
  variant: :default,
37
58
  status: :default,
38
59
  disabled: false,
@@ -47,16 +68,16 @@ module HakumiComponents
47
68
  standalone: true,
48
69
  rules: nil,
49
70
  errors: [],
50
- **html_attrs
71
+ **html_options
51
72
  )
52
- @name = name
73
+ @name = T.let(name, Types::FormFieldName)
53
74
  @label = label
54
75
  @caption = caption
55
76
  @value = value
56
77
  @placeholder = placeholder
57
78
  @min = min
58
79
  @max = max
59
- @step = step
80
+ @step = T.let(step, NumericLike)
60
81
  @precision = precision
61
82
  @size = size
62
83
  @variant = variant
@@ -69,54 +90,70 @@ module HakumiComponents
69
90
  @controls = controls
70
91
  @keyboard = keyboard
71
92
  @wheel = wheel
72
- @formatter = formatter
93
+ @formatter = T.let(formatter, T.nilable(FormatterOptions))
73
94
  @standalone = standalone
74
- @rules = rules
75
- @errors = Array(errors)
76
- @html_attrs = html_attrs
95
+ @rules = T.let(rules, T.nilable(T::Array[Types::ValidationRule]))
96
+ @errors = T.let(errors, Types::FormFieldErrors)
97
+ @html_options = T.let(html_options, Types::HtmlAttributes)
98
+ initialize_input_control_contract!(
99
+ name: @name,
100
+ label: @label,
101
+ caption: @caption,
102
+ value: @value,
103
+ placeholder: @placeholder,
104
+ size: @size,
105
+ disabled: @disabled,
106
+ readonly: @readonly,
107
+ errors: @errors,
108
+ standalone: @standalone,
109
+ required: @required,
110
+ html_options: @html_options,
111
+ rules: @rules
112
+ )
77
113
 
78
114
  validate_props!
79
115
  end
80
116
 
81
117
  private
82
118
 
119
+ sig { void }
83
120
  def validate_props!
84
121
  validate_inclusion!(:size, SIZES)
85
122
  validate_inclusion!(:variant, VARIANTS)
86
123
  validate_inclusion!(:status, STATUSES)
87
124
  validate_numeric_like!(@step, "step")
88
- validate_numeric_like!(@min, "min") if @min
89
- validate_numeric_like!(@max, "max") if @max
90
- validate_numeric_like!(@precision, "precision") if @precision
91
-
92
- return if @formatter.nil? || @formatter.is_a?(Hash)
93
-
94
- raise ArgumentError, "formatter must be a Hash of Intl.NumberFormat options"
125
+ validate_numeric_like!(@min, "min")
126
+ validate_numeric_like!(@max, "max")
127
+ validate_numeric_like!(@precision, "precision")
95
128
  end
96
129
 
130
+ sig { params(value: T.nilable(NumericLike), name: String).void }
97
131
  def validate_numeric_like!(value, name)
132
+ return if value.nil?
98
133
  return if value.is_a?(Numeric) || value.is_a?(String)
99
134
 
100
135
  raise ArgumentError, "#{name} must be a number or string"
101
136
  end
102
137
 
138
+ sig { returns(String) }
103
139
  def component_html_class
104
140
  class_names(
105
141
  "input-number",
106
142
  {
107
- @size => @size != :middle,
143
+ input_control_size => input_control_size != :default,
108
144
  @variant => @variant != :default,
109
- disabled: @disabled,
110
- readonly: @readonly,
145
+ disabled: input_control_disabled,
146
+ readonly: input_control_readonly,
111
147
  "no-controls": !@controls,
112
- "has-prefix": @prefix.present?,
113
- "has-suffix": @suffix.present?,
148
+ "has-prefix": value_present?(@prefix),
149
+ "has-suffix": value_present?(@suffix),
114
150
  status: @status != :default ? @status : nil
115
151
  },
116
- @html_attrs[:wrapper_class]
152
+ [ wrapper_class_name ]
117
153
  )
118
154
  end
119
155
 
156
+ sig { returns(Types::HtmlAttributes) }
120
157
  def wrapper_attributes
121
158
  merge_attributes(
122
159
  {
@@ -129,70 +166,115 @@ module HakumiComponents
129
166
  hakumi__input_number_precision_value: @precision,
130
167
  hakumi__input_number_keyboard_value: @keyboard,
131
168
  hakumi__input_number_wheel_value: @wheel,
132
- hakumi__input_number_disabled_value: @disabled,
169
+ hakumi__input_number_disabled_value: input_control_disabled,
133
170
  hakumi__input_number_formatter_options_value: formatter_options_json
134
171
  }.compact
135
172
  },
136
173
  {
137
- id: @html_attrs[:id],
138
- data: @html_attrs[:data]
174
+ id: input_id,
175
+ data: html_data_attributes
139
176
  }.compact
140
177
  )
141
178
  end
142
179
 
180
+ sig { returns(String) }
143
181
  def input_classes
144
- class_names("input-number-input", {}, @html_attrs[:class])
182
+ class_names("input-number-input", {}, [ html_class_name ])
145
183
  end
146
184
 
185
+ sig { returns(Types::HtmlAttributes) }
147
186
  def input_attributes
148
187
  merge_attributes(
149
188
  {
150
189
  type: "text",
151
190
  inputmode: "decimal",
152
- name: @name,
191
+ name: form_field_name,
153
192
  id: input_id,
154
- value: @value,
155
- placeholder: @placeholder,
193
+ value: input_control_value,
194
+ placeholder: input_control_placeholder,
156
195
  class: input_classes,
157
- disabled: @disabled ? true : nil,
158
- readonly: @readonly ? true : nil,
196
+ disabled: input_control_disabled ? true : nil,
197
+ readonly: input_control_readonly ? true : nil,
159
198
  autocomplete: "off",
160
199
  role: "spinbutton",
161
- "aria-invalid": has_error? ? "true" : nil,
200
+ "aria-invalid": error? ? "true" : nil,
162
201
  "aria-describedby": describedby_ids,
163
202
  "aria-valuemin": @min,
164
203
  "aria-valuemax": @max,
165
- "aria-valuenow": @value,
204
+ "aria-valuenow": input_control_value,
166
205
  data: {
167
206
  action: "input->hakumi--input-number#handleInput focus->hakumi--input-number#handleFocus blur->hakumi--input-number#handleBlur keydown->hakumi--input-number#handleKeydown wheel->hakumi--input-number#handleWheel",
168
207
  hakumi__input_number_target: "input"
169
208
  }
170
209
  }.compact,
171
- @html_attrs.except(:id, :wrapper_class)
210
+ form_field_html_options.except(:id, :wrapper_class)
172
211
  )
173
212
  end
174
213
 
214
+ sig { returns(T.nilable(ActiveSupport::SafeBuffer)) }
175
215
  def prefix_element
176
- return nil unless @prefix.present?
216
+ prefix_content = render_adornment_content(@prefix)
217
+ return nil if prefix_content.nil?
177
218
 
178
- content_tag(:span, render_value(@prefix), class: "hakumi-input-number-prefix")
219
+ content_tag(:span, prefix_content, class: "hakumi-input-number-prefix")
179
220
  end
180
221
 
222
+ sig { returns(T.nilable(ActiveSupport::SafeBuffer)) }
181
223
  def suffix_element
182
- return nil unless @suffix.present?
224
+ suffix_content = render_adornment_content(@suffix)
225
+ return nil if suffix_content.nil?
183
226
 
184
- content_tag(:span, render_value(@suffix), class: "hakumi-input-number-suffix")
227
+ content_tag(:span, suffix_content, class: "hakumi-input-number-suffix")
185
228
  end
186
229
 
230
+ sig { returns(T::Boolean) }
187
231
  def controls?
188
232
  @controls
189
233
  end
190
234
 
235
+ sig { returns(T.nilable(String)) }
191
236
  def formatter_options_json
192
- return nil unless @formatter.present?
237
+ return nil if @formatter.nil? || @formatter.empty?
193
238
 
194
239
  @formatter.to_json
195
240
  end
241
+
242
+ sig { params(value: Types::Renderable).returns(T.nilable(T.any(String, ActiveSupport::SafeBuffer))) }
243
+ def render_adornment_content(value)
244
+ return nil unless value_present?(value)
245
+ return value if value.is_a?(ActiveSupport::SafeBuffer) || value.is_a?(String)
246
+ return render(value).to_s if value.is_a?(ViewComponent::Base)
247
+
248
+ nil
249
+ end
250
+
251
+ sig { returns(Types::DataAttributes) }
252
+ def html_data_attributes
253
+ data_attributes = T.let({}, Types::DataAttributes)
254
+ html_data = form_field_html_options[:data]
255
+ return data_attributes unless html_data.is_a?(Hash)
256
+
257
+ html_data.each do |key, value|
258
+ next unless key.is_a?(String) || key.is_a?(Symbol)
259
+ next unless value.nil? || value.is_a?(String) || value.is_a?(Symbol) || value.is_a?(TrueClass) || value.is_a?(FalseClass) || value.is_a?(Numeric)
260
+
261
+ data_attributes[key] = value
262
+ end
263
+
264
+ data_attributes
265
+ end
266
+
267
+ sig { returns(T.nilable(String)) }
268
+ def html_class_name
269
+ css_class = form_field_html_options[:class]
270
+ css_class.is_a?(String) ? css_class : nil
271
+ end
272
+
273
+ sig { returns(T.nilable(String)) }
274
+ def wrapper_class_name
275
+ wrapper_class = form_field_html_options[:wrapper_class]
276
+ wrapper_class.is_a?(String) ? wrapper_class : nil
277
+ end
196
278
  end
197
279
  end
198
280
  end
@@ -1 +1 @@
1
- <section <%= tag.attributes(html_attributes) %>><%= content %></section>
1
+ <%= content_tag :section, content, wrapper_attributes %>
@@ -1,21 +1,28 @@
1
- class HakumiComponents::Layout::Component < HakumiComponents::BaseComponent
2
- def initialize(has_sider: false, **html_options)
3
- @has_sider = has_sider
4
- @html_options = html_options
5
- end
1
+ # typed: strict
2
+ # frozen_string_literal: true
6
3
 
7
- private
4
+ module HakumiComponents
5
+ module Layout
6
+ class Component < BaseComponent
7
+ extend T::Sig
8
8
 
9
- def html_attributes
10
- attrs = @html_options.dup
11
- attrs[:class] = css_classes
12
- attrs
13
- end
9
+ sig { params(has_sider: T::Boolean, html_options: Types::HtmlAttributeValue).void }
10
+ def initialize(has_sider: false, **html_options)
11
+ @has_sider = T.let(has_sider, T::Boolean)
12
+ @html_options = T.let(html_options, Types::HtmlAttributes)
13
+ end
14
+
15
+ private
16
+
17
+ sig { returns(String) }
18
+ def wrapper_classes
19
+ component_classes("layout", { "has-sider": @has_sider }, @html_options)
20
+ end
14
21
 
15
- def css_classes
16
- classes = [ "hakumi-layout" ]
17
- classes << "hakumi-layout-has-sider" if @has_sider
18
- classes << @html_options[:class] if @html_options[:class]
19
- classes.join(" ")
22
+ sig { returns(Types::HtmlAttributes) }
23
+ def wrapper_attributes
24
+ merge_attributes({ class: wrapper_classes }, @html_options.except(:class))
25
+ end
26
+ end
20
27
  end
21
28
  end
@@ -1 +1 @@
1
- <main <%= tag.attributes(html_attributes) %>><%= content %></main>
1
+ <%= content_tag :main, content, wrapper_attributes %>
@@ -1,19 +1,29 @@
1
- class HakumiComponents::Layout::Content::Component < HakumiComponents::BaseComponent
2
- def initialize(**html_options)
3
- @html_options = html_options
4
- end
1
+ # typed: strict
2
+ # frozen_string_literal: true
5
3
 
6
- private
4
+ module HakumiComponents
5
+ module Layout
6
+ module Content
7
+ class Component < BaseComponent
8
+ extend T::Sig
7
9
 
8
- def html_attributes
9
- attrs = @html_options.dup
10
- attrs[:class] = css_classes
11
- attrs
12
- end
10
+ sig { params(html_options: Types::HtmlAttributeValue).void }
11
+ def initialize(**html_options)
12
+ @html_options = T.let(html_options, Types::HtmlAttributes)
13
+ end
14
+
15
+ private
16
+
17
+ sig { returns(String) }
18
+ def wrapper_classes
19
+ component_classes("layout-content", {}, @html_options)
20
+ end
13
21
 
14
- def css_classes
15
- classes = [ "hakumi-layout-content" ]
16
- classes << @html_options[:class] if @html_options[:class]
17
- classes.join(" ")
22
+ sig { returns(Types::HtmlAttributes) }
23
+ def wrapper_attributes
24
+ merge_attributes({ class: wrapper_classes }, @html_options.except(:class))
25
+ end
26
+ end
27
+ end
18
28
  end
19
29
  end
@@ -1 +1 @@
1
- <footer <%= tag.attributes(html_attributes) %>><%= content %></footer>
1
+ <%= content_tag :footer, content, wrapper_attributes %>
@@ -1,19 +1,29 @@
1
- class HakumiComponents::Layout::Footer::Component < HakumiComponents::BaseComponent
2
- def initialize(**html_options)
3
- @html_options = html_options
4
- end
1
+ # typed: strict
2
+ # frozen_string_literal: true
5
3
 
6
- private
4
+ module HakumiComponents
5
+ module Layout
6
+ module Footer
7
+ class Component < BaseComponent
8
+ extend T::Sig
7
9
 
8
- def html_attributes
9
- attrs = @html_options.dup
10
- attrs[:class] = css_classes
11
- attrs
12
- end
10
+ sig { params(html_options: Types::HtmlAttributeValue).void }
11
+ def initialize(**html_options)
12
+ @html_options = T.let(html_options, Types::HtmlAttributes)
13
+ end
14
+
15
+ private
16
+
17
+ sig { returns(String) }
18
+ def wrapper_classes
19
+ component_classes("layout-footer", {}, @html_options)
20
+ end
13
21
 
14
- def css_classes
15
- classes = [ "hakumi-layout-footer" ]
16
- classes << @html_options[:class] if @html_options[:class]
17
- classes.join(" ")
22
+ sig { returns(Types::HtmlAttributes) }
23
+ def wrapper_attributes
24
+ merge_attributes({ class: wrapper_classes }, @html_options.except(:class))
25
+ end
26
+ end
27
+ end
18
28
  end
19
29
  end
@@ -1 +1 @@
1
- <header <%= tag.attributes(html_attributes) %>><%= content %></header>
1
+ <%= content_tag :header, content, wrapper_attributes %>
@@ -1,19 +1,29 @@
1
- class HakumiComponents::Layout::Header::Component < HakumiComponents::BaseComponent
2
- def initialize(**html_options)
3
- @html_options = html_options
4
- end
1
+ # typed: strict
2
+ # frozen_string_literal: true
5
3
 
6
- private
4
+ module HakumiComponents
5
+ module Layout
6
+ module Header
7
+ class Component < BaseComponent
8
+ extend T::Sig
7
9
 
8
- def html_attributes
9
- attrs = @html_options.dup
10
- attrs[:class] = css_classes
11
- attrs
12
- end
10
+ sig { params(html_options: Types::HtmlAttributeValue).void }
11
+ def initialize(**html_options)
12
+ @html_options = T.let(html_options, Types::HtmlAttributes)
13
+ end
14
+
15
+ private
16
+
17
+ sig { returns(String) }
18
+ def wrapper_classes
19
+ component_classes("layout-header", {}, @html_options)
20
+ end
13
21
 
14
- def css_classes
15
- classes = [ "hakumi-layout-header" ]
16
- classes << @html_options[:class] if @html_options[:class]
17
- classes.join(" ")
22
+ sig { returns(Types::HtmlAttributes) }
23
+ def wrapper_attributes
24
+ merge_attributes({ class: wrapper_classes }, @html_options.except(:class))
25
+ end
26
+ end
27
+ end
18
28
  end
19
29
  end
@@ -1 +1 @@
1
- <aside <%= tag.attributes(html_attributes) %>><%= content %></aside>
1
+ <%= content_tag :aside, content, wrapper_attributes %>
@@ -1,56 +1,90 @@
1
- class HakumiComponents::Layout::Sider::Component < HakumiComponents::BaseComponent
2
- def initialize(
3
- width: 200,
4
- collapsed_width: 80,
5
- collapsible: false,
6
- collapsed: false,
7
- theme: :dark,
8
- breakpoint: nil,
9
- **html_options
10
- )
11
- @width = width
12
- @collapsed_width = collapsed_width
13
- @collapsible = collapsible
14
- @collapsed = collapsed
15
- @theme = theme
16
- @breakpoint = breakpoint
17
- @html_options = html_options
18
- end
1
+ # typed: strict
2
+ # frozen_string_literal: true
19
3
 
20
- private
4
+ module HakumiComponents
5
+ module Layout
6
+ module Sider
7
+ class Component < BaseComponent
8
+ extend T::Sig
9
+ THEMES = T.let(%i[dark light].freeze, T::Array[Symbol])
10
+ BREAKPOINTS = T.let(%i[xs sm md lg xl].freeze, T::Array[Symbol])
21
11
 
22
- def html_attributes
23
- attrs = @html_options.dup
24
- attrs[:class] = css_classes
25
- attrs[:style] = inline_styles
26
- attrs
27
- end
12
+ sig do
13
+ params(
14
+ width: Integer,
15
+ collapsed_width: Integer,
16
+ collapsible: T::Boolean,
17
+ collapsed: T::Boolean,
18
+ theme: Symbol,
19
+ breakpoint: T.nilable(Symbol),
20
+ html_options: Types::HtmlAttributeValue
21
+ ).void
22
+ end
23
+ def initialize(
24
+ width: 200,
25
+ collapsed_width: 80,
26
+ collapsible: false,
27
+ collapsed: false,
28
+ theme: :dark,
29
+ breakpoint: nil,
30
+ **html_options
31
+ )
32
+ @width = T.let(width, Integer)
33
+ @collapsed_width = T.let(collapsed_width, Integer)
34
+ @collapsible = T.let(collapsible, T::Boolean)
35
+ @collapsed = T.let(collapsed, T::Boolean)
36
+ @theme = T.let(theme, Symbol)
37
+ @breakpoint = T.let(breakpoint, T.nilable(Symbol))
38
+ @html_options = T.let(html_options, Types::HtmlAttributes)
28
39
 
29
- def css_classes
30
- classes = [ "hakumi-layout-sider" ]
31
- classes << "hakumi-layout-sider-dark" if @theme.to_sym == :dark
32
- classes << "hakumi-layout-sider-light" if @theme.to_sym == :light
33
- classes << "hakumi-layout-sider-collapsed" if @collapsed
34
- classes << "hakumi-layout-sider-has-trigger" if @collapsible
35
- classes << @html_options[:class] if @html_options[:class]
36
- classes.join(" ")
37
- end
40
+ validate_props!
41
+ end
42
+
43
+ private
44
+
45
+ sig { void }
46
+ def validate_props!
47
+ validate_inclusion!(:theme, THEMES)
48
+ validate_inclusion!(:breakpoint, BREAKPOINTS) if @breakpoint
49
+ end
50
+
51
+ sig { returns(String) }
52
+ def wrapper_classes
53
+ modifiers = T.let({
54
+ dark: @theme == :dark,
55
+ light: @theme == :light,
56
+ collapsed: @collapsed,
57
+ "has-trigger": @collapsible
58
+ }, Types::ClassModifiers)
59
+ modifiers[@breakpoint] = true if @breakpoint
60
+
61
+ component_classes("layout-sider", modifiers, @html_options)
62
+ end
63
+
64
+ sig { returns(Types::HtmlAttributes) }
65
+ def wrapper_attributes
66
+ merge_attributes(
67
+ { class: wrapper_classes, style: inline_styles },
68
+ @html_options.except(:class, :style)
69
+ )
70
+ end
71
+
72
+ sig { returns(String) }
73
+ def inline_styles
74
+ active_width = @collapsed ? @collapsed_width : @width
75
+ styles = T.let([
76
+ "flex: 0 0 #{active_width}px",
77
+ "max-width: #{active_width}px",
78
+ "min-width: #{active_width}px",
79
+ "width: #{active_width}px"
80
+ ], T::Array[String])
81
+
82
+ existing_style = html_style(@html_options)
83
+ styles << existing_style if existing_style
38
84
 
39
- def inline_styles
40
- styles = []
41
- if @collapsed
42
- styles << "flex: 0 0 #{@collapsed_width}px"
43
- styles << "max-width: #{@collapsed_width}px"
44
- styles << "min-width: #{@collapsed_width}px"
45
- styles << "width: #{@collapsed_width}px"
46
- else
47
- styles << "flex: 0 0 #{@width}px"
48
- styles << "max-width: #{@width}px"
49
- styles << "min-width: #{@width}px"
50
- styles << "width: #{@width}px"
85
+ styles.join("; ")
86
+ end
87
+ end
51
88
  end
52
- combined_styles = styles.join("; ")
53
- combined_styles += "; #{@html_options[:style]}" if @html_options[:style]
54
- combined_styles
55
89
  end
56
90
  end