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
@@ -220,7 +220,7 @@
220
220
  align-items: center;
221
221
  justify-content: center;
222
222
 
223
- &.is-expanded .hakumi-table-expand-icon {
223
+ &.hakumi-table-expand-button-expanded .hakumi-table-expand-icon {
224
224
  transform: rotate(45deg);
225
225
  }
226
226
  }
@@ -232,7 +232,7 @@
232
232
  border-right: 2px solid var(--table-muted-color);
233
233
  border-bottom: 2px solid var(--table-muted-color);
234
234
  transform: rotate(-45deg);
235
- transition: transform 0.2s ease;
235
+ transition: transform $transition-duration-base ease;
236
236
  }
237
237
 
238
238
  &-expanded-row {
@@ -243,7 +243,7 @@
243
243
  vertical-align: top;
244
244
  }
245
245
 
246
- &:not(.is-expanded) td {
246
+ &:not(.hakumi-table-row-expanded) td {
247
247
  padding: 0 !important;
248
248
  }
249
249
  }
@@ -307,7 +307,7 @@
307
307
  }
308
308
  }
309
309
 
310
- &-size-middle {
310
+ &-size-default {
311
311
  .hakumi-table-thead th,
312
312
  .hakumi-table-tbody td,
313
313
  .hakumi-table-summary td {
@@ -346,7 +346,7 @@
346
346
  background: var(--table-row-bg);
347
347
  color: var(--table-text-color);
348
348
  font-size: inherit;
349
- transition: border-color 0.2s, box-shadow 0.2s;
349
+ transition: border-color $transition-duration-base, box-shadow $transition-duration-base;
350
350
 
351
351
  &:focus {
352
352
  border-color: var(--color-primary, #1677ff);
@@ -373,7 +373,7 @@
373
373
  color: var(--table-muted-color);
374
374
  padding: 4px;
375
375
  border-radius: 4px;
376
- transition: color 0.2s, background-color 0.2s;
376
+ transition: color $transition-duration-base, background-color $transition-duration-base;
377
377
 
378
378
  &:hover {
379
379
  color: var(--table-text-color);
@@ -82,12 +82,12 @@
82
82
  &-checked {
83
83
  background: var(--color-primary);
84
84
  border-color: var(--color-primary);
85
- color: #fff;
85
+ color: var(--color-text-inverse);
86
86
 
87
87
  &:hover {
88
88
  background: var(--color-primary-hover);
89
89
  border-color: var(--color-primary-hover);
90
- color: #fff;
90
+ color: var(--color-text-inverse);
91
91
  }
92
92
  }
93
93
  }
@@ -17,9 +17,9 @@
17
17
  max-width: 250px;
18
18
  visibility: hidden;
19
19
  opacity: 0;
20
- transition: opacity 0.2s cubic-bezier(0.645, 0.045, 0.355, 1),
21
- visibility 0.2s cubic-bezier(0.645, 0.045, 0.355, 1),
22
- transform 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
20
+ transition: opacity $transition-duration-base $ease-in-out,
21
+ visibility $transition-duration-base $ease-in-out,
22
+ transform $transition-duration-base $ease-in-out;
23
23
  pointer-events: none;
24
24
 
25
25
  &-visible {
@@ -49,7 +49,7 @@
49
49
  min-width: 32px;
50
50
  min-height: 32px;
51
51
  padding: 6px 8px;
52
- color: #fff;
52
+ color: var(--color-text-inverse);
53
53
  text-align: start;
54
54
  text-decoration: none;
55
55
  word-wrap: break-word;
@@ -31,7 +31,7 @@
31
31
  background-color: var(--color-bg-container);
32
32
  border: 1px solid var(--color-border);
33
33
  border-radius: 6px;
34
- transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
34
+ transition: all $transition-duration-base $ease-in-out;
35
35
  width: 100%;
36
36
  height: 32px;
37
37
  padding: 0 30px 0 11px;
@@ -96,7 +96,7 @@
96
96
  margin-top: -6px;
97
97
  font-size: 12px;
98
98
  pointer-events: none;
99
- transition: transform 0.3s;
99
+ transition: transform $transition-duration-slow;
100
100
 
101
101
  .hakumi-tree-select-open & {
102
102
  transform: rotate(180deg);
@@ -121,7 +121,7 @@
121
121
  background: var(--hakumi-tree-select-clear-bg);
122
122
  cursor: pointer;
123
123
  opacity: 0;
124
- transition: color 0.3s ease, opacity 0.15s ease;
124
+ transition: color $transition-duration-slow ease, opacity 0.15s ease;
125
125
 
126
126
  &:hover {
127
127
  color: var(--color-text-tertiary);
@@ -26,7 +26,7 @@
26
26
  color: var(--color-link);
27
27
  cursor: pointer;
28
28
  text-decoration: none;
29
- transition: color 0.2s;
29
+ transition: color $transition-duration-base;
30
30
 
31
31
  &:hover {
32
32
  color: var(--color-link-hover);
@@ -69,7 +69,7 @@
69
69
  margin-left: 4px;
70
70
  color: var(--color-link);
71
71
  cursor: pointer;
72
- transition: color 0.2s;
72
+ transition: color $transition-duration-base;
73
73
 
74
74
  &:hover {
75
75
  color: var(--color-link-hover);
@@ -136,7 +136,7 @@ h5.hakumi-typography,
136
136
  pointer-events: none;
137
137
  z-index: 1070;
138
138
  opacity: 0;
139
- transition: opacity 0.2s ease;
139
+ transition: opacity $transition-duration-base ease;
140
140
  box-shadow: var(--shadow-base);
141
141
 
142
142
  &.hakumi-typography-tooltip-success {
@@ -308,7 +308,7 @@
308
308
  background: rgba(255, 255, 255, 0.2);
309
309
  border: none;
310
310
  border-radius: 50%;
311
- color: #fff;
311
+ color: var(--color-text-inverse);
312
312
  cursor: pointer;
313
313
  font-size: 16px;
314
314
  transition: background-color $transition-duration-base $ease-in-out, transform $transition-duration-base $ease-in-out;
@@ -405,7 +405,7 @@
405
405
  background: rgba(255, 255, 255, 0.1);
406
406
  border: none;
407
407
  border-radius: 50%;
408
- color: #fff;
408
+ color: var(--color-text-inverse);
409
409
  cursor: pointer;
410
410
  font-size: 18px;
411
411
  transition: background-color $transition-duration-base $ease-in-out;
@@ -431,7 +431,7 @@
431
431
  background: rgba(255, 255, 255, 0.1);
432
432
  border: none;
433
433
  border-radius: 50%;
434
- color: #fff;
434
+ color: var(--color-text-inverse);
435
435
  cursor: pointer;
436
436
  font-size: 24px;
437
437
  transition: background-color $transition-duration-base $ease-in-out;
@@ -491,7 +491,7 @@
491
491
  background: rgba(0, 0, 0, 0.6);
492
492
  backdrop-filter: blur(4px);
493
493
  -webkit-backdrop-filter: blur(4px);
494
- color: #fff;
494
+ color: var(--color-text-inverse);
495
495
  font-size: 12px;
496
496
  font-weight: 500;
497
497
  opacity: 0;
@@ -1,52 +1,123 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  class ComponentHandler
6
+ extend T::Sig
7
+
8
+ InputParams = T.type_alias { T.any(ActionController::Parameters, Types::HtmlAttributes) }
9
+ # T.untyped values: locals are passed as Rails view locals, which accept any object.
10
+ # The coerce_local_value method ensures only safe primitive values and containers pass through.
11
+ LocalsHash = T.type_alias { T::Hash[Symbol, T.untyped] }
12
+ UnsafeLocalValue = T.let(Object.new.freeze, Object)
13
+
14
+ COMPONENT_CLASSES = T.let({
15
+ admin_panel: HakumiComponents::AdminPanel::Component,
16
+ affix: HakumiComponents::Affix::Component,
17
+ alert: HakumiComponents::Alert::Component,
18
+ calendar: HakumiComponents::Calendar::Component,
19
+ confirm: HakumiComponents::Modal::Confirm::Component,
20
+ drawer: HakumiComponents::Drawer::Component,
21
+ message: HakumiComponents::Message::Component,
22
+ modal: HakumiComponents::Modal::Component,
23
+ notification: HakumiComponents::Notification::Component,
24
+ popconfirm: HakumiComponents::Popconfirm::Component,
25
+ popover: HakumiComponents::Popover::Component,
26
+ progress: HakumiComponents::Progress::Component,
27
+ qr_code: HakumiComponents::QrCode::Component,
28
+ result: HakumiComponents::Result::Component,
29
+ segmented: HakumiComponents::Segmented::Component,
30
+ skeleton: HakumiComponents::Skeleton::Component,
31
+ spin: HakumiComponents::Spin::Component,
32
+ statistic: HakumiComponents::Statistic::Component,
33
+ table: HakumiComponents::Table::Component,
34
+ tag: HakumiComponents::Tag::Component,
35
+ timeline: HakumiComponents::Timeline::Component,
36
+ transfer: HakumiComponents::Transfer::Component,
37
+ tree: HakumiComponents::Tree::Component
38
+ }.freeze, T::Hash[Symbol, T.class_of(ViewComponent::Base)])
39
+
40
+ sig { params(component: Types::StringOrSymbol, params: InputParams).void }
5
41
  def initialize(component, params)
6
- @component = component.to_sym
7
- @params = params
42
+ @component = T.let(component.to_sym, Symbol)
43
+ @params = T.let(params, InputParams)
8
44
  end
9
45
 
46
+ sig { returns(LocalsHash) }
10
47
  def locals
11
48
  base_locals.merge(specific_locals)
12
49
  end
13
50
 
14
51
  private
15
52
 
53
+ sig { returns(LocalsHash) }
16
54
  def base_locals
55
+ raw_id = HakumiComponents::BaseComponent.html_param(@params, :id)
56
+ id = if raw_id.is_a?(String)
57
+ raw_id.presence
58
+ elsif raw_id.is_a?(Symbol) || raw_id.is_a?(Numeric)
59
+ raw_id.to_s
60
+ end
61
+
17
62
  {
18
- id: @params[:id].presence || "hakumi-#{@component}-#{SecureRandom.hex(4)}"
63
+ id: id || "hakumi-#{@component}-#{SecureRandom.hex(4)}"
19
64
  }
20
65
  end
21
66
 
67
+ sig { returns(LocalsHash) }
22
68
  def specific_locals
23
69
  component_class = resolve_component_class
24
70
  return {} unless component_class.respond_to?(:extract_controller_locals)
25
71
 
26
- component_class.extract_controller_locals(@params)
72
+ raw_locals = component_class.public_send(:extract_controller_locals, @params)
73
+ coerce_locals_hash(raw_locals).compact
27
74
  end
28
75
 
76
+ sig { returns(T.nilable(T.class_of(ViewComponent::Base))) }
29
77
  def resolve_component_class
30
- case @component
31
- when :modal then HakumiComponents::Modal::Component
32
- when :confirm then HakumiComponents::Modal::Confirm::Component
33
- when :alert then HakumiComponents::Alert::Component
34
- when :drawer then HakumiComponents::Drawer::Component
35
- when :message then HakumiComponents::Message::Component
36
- when :notification then HakumiComponents::Notification::Component
37
- when :popover then HakumiComponents::Popover::Component
38
- when :progress then HakumiComponents::Progress::Component
39
- when :result then HakumiComponents::Result::Component
40
- when :skeleton then HakumiComponents::Skeleton::Component
41
- when :spin then HakumiComponents::Spin::Component
42
- when :qr_code then HakumiComponents::QrCode::Component
43
- when :affix then HakumiComponents::Affix::Component
44
- when :segmented then HakumiComponents::Segmented::Component
45
- when :statistic then HakumiComponents::Statistic::Component
46
- when :tag then HakumiComponents::Tag::Component
47
- when :timeline then HakumiComponents::Timeline::Component
48
- when :tree then HakumiComponents::Tree::Component
49
- else nil
78
+ COMPONENT_CLASSES[@component]
79
+ end
80
+
81
+ sig { params(raw_locals: T.untyped).returns(LocalsHash) }
82
+ def coerce_locals_hash(raw_locals)
83
+ return {} if raw_locals.nil?
84
+
85
+ raw_locals.each_with_object(T.let({}, LocalsHash)) do |(key, value), result|
86
+ next unless key.is_a?(Symbol)
87
+ coerced_value = coerce_local_value(value)
88
+ next if coerced_value.equal?(UnsafeLocalValue)
89
+
90
+ result[key] = coerced_value
91
+ end
92
+ end
93
+
94
+ sig { params(value: T.untyped).returns(T.untyped) }
95
+ def coerce_local_value(value)
96
+ return value if value.nil? || value.is_a?(String) || value.is_a?(Symbol) || value.is_a?(Numeric) || value.is_a?(TrueClass) || value.is_a?(FalseClass)
97
+ return coerce_array_value(value) if value.is_a?(Array)
98
+ return coerce_hash_value(value) if value.is_a?(Hash)
99
+
100
+ UnsafeLocalValue
101
+ end
102
+
103
+ sig { params(value: T::Array[T.untyped]).returns(T::Array[T.untyped]) }
104
+ def coerce_array_value(value)
105
+ value.each_with_object(T.let([], T::Array[T.untyped])) do |item, result|
106
+ coerced_item = coerce_local_value(item)
107
+ next if coerced_item.equal?(UnsafeLocalValue)
108
+
109
+ result << coerced_item
110
+ end
111
+ end
112
+
113
+ sig { params(value: T::Hash[T.untyped, T.untyped]).returns(T::Hash[T.untyped, T.untyped]) }
114
+ def coerce_hash_value(value)
115
+ value.each_with_object(T.let({}, T::Hash[T.untyped, T.untyped])) do |(key, item), result|
116
+ next unless key.is_a?(String) || key.is_a?(Symbol) || key.is_a?(Numeric)
117
+ coerced_item = coerce_local_value(item)
118
+ next if coerced_item.equal?(UnsafeLocalValue)
119
+
120
+ result[key] = coerced_item
50
121
  end
51
122
  end
52
123
  end
@@ -1,94 +1,111 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  module Icon
5
- # Loads Ant Design icons from lib/hakumi_components/app/assets/icons
6
6
  class Loader
7
- ICONS_BASE_PATH = if defined?(HakumiComponents::Engine)
8
- HakumiComponents::Engine.root.join("app", "assets", "icons")
9
- else
10
- Rails.root.join("app", "assets", "icons")
7
+ extend T::Sig
8
+
9
+ Cache = T.type_alias { T::Hash[String, T.nilable(String)] }
10
+ @@cache = T.let({}, Cache)
11
+ ICONS_BASE_PATH = T.let(
12
+ if defined?(HakumiComponents::Engine)
13
+ HakumiComponents::Engine.root.join("app", "assets", "icons")
14
+ else
15
+ ::Rails.root.join("app", "assets", "icons")
16
+ end,
17
+ Pathname
18
+ )
19
+
20
+ sig { returns(Cache) }
21
+ def self.cache
22
+ @@cache
11
23
  end
12
24
 
13
- class << self
14
- def cache
15
- @cache ||= {}
16
- end
25
+ sig { params(name: T.nilable(Types::StringOrSymbol), theme: Symbol).returns(T.nilable(String)) }
26
+ def self.load(name, theme = :outlined)
27
+ return nil if name.nil?
17
28
 
18
- def load(name, theme = :outlined)
19
- cache_key = "#{name}_#{theme}"
20
- return cache[cache_key] if cache.key?(cache_key)
29
+ cache_key = "#{name}_#{theme}"
30
+ return cache[cache_key] if cache.key?(cache_key)
21
31
 
22
- svg = read_icon_file(name, theme)
23
- cache[cache_key] = svg
24
- svg
25
- end
32
+ svg = read_icon_file(name, theme)
33
+ cache[cache_key] = svg
34
+ svg
35
+ end
26
36
 
27
- def exists?(name, theme = :outlined)
28
- !load(name, theme).nil?
29
- end
37
+ sig { params(name: T.nilable(Types::StringOrSymbol), theme: Symbol).returns(T::Boolean) }
38
+ def self.exists?(name, theme = :outlined)
39
+ !load(name, theme).nil?
40
+ end
30
41
 
31
- def list_icons(theme = :outlined)
32
- theme_dir = theme_directory(theme)
33
- return [] unless theme_dir.exist?
42
+ sig { params(theme: Symbol).returns(T::Array[String]) }
43
+ def self.list_icons(theme = :outlined)
44
+ theme_dir = theme_directory(theme)
45
+ return [] unless theme_dir.exist?
34
46
 
35
- Dir.glob(theme_dir.join("*.svg")).map do |path|
36
- File.basename(path, ".svg").gsub("-", "_")
37
- end.sort
38
- end
47
+ Dir.glob(theme_dir.join("*.svg").to_s).map do |path|
48
+ File.basename(path, ".svg").gsub("-", "_")
49
+ end.sort
50
+ end
39
51
 
40
- def clear_cache!
41
- @cache = {}
42
- end
52
+ sig { void }
53
+ def self.clear_cache!
54
+ @@cache = {}
55
+ end
43
56
 
44
- private
57
+ sig { params(name: Types::StringOrSymbol, theme: Symbol).returns(T.nilable(String)) }
58
+ def self.read_icon_file(name, theme)
59
+ filepath = icon_filepath(name, theme)
60
+ return nil unless filepath.exist?
45
61
 
46
- def read_icon_file(name, theme)
47
- filepath = icon_filepath(name, theme)
48
- return nil unless filepath.exist?
62
+ svg_content = File.read(filepath)
63
+ enhance_svg(svg_content)
64
+ rescue => e
65
+ ::Rails.logger.error("Error loading icon #{name} (#{theme}): #{e.message}")
66
+ nil
67
+ end
49
68
 
50
- svg_content = File.read(filepath)
51
- enhance_svg(svg_content)
52
- rescue => e
53
- Rails.logger.error("Error loading icon #{name} (#{theme}): #{e.message}")
54
- nil
55
- end
69
+ sig { params(name: Types::StringOrSymbol, theme: Symbol).returns(Pathname) }
70
+ def self.icon_filepath(name, theme)
71
+ theme_dir = theme_directory(theme)
72
+ filename = kebabize(name.to_s)
73
+ theme_dir.join("#{filename}.svg")
74
+ end
56
75
 
57
- def icon_filepath(name, theme)
58
- theme_dir = theme_directory(theme)
59
- filename = kebabize(name.to_s)
60
- theme_dir.join("#{filename}.svg")
76
+ sig { params(theme: Symbol).returns(Pathname) }
77
+ def self.theme_directory(theme)
78
+ theme_str = case theme.to_sym
79
+ when :outlined then "outlined"
80
+ when :filled then "filled"
81
+ when :two_tone, :twotone then "twotone"
82
+ else "outlined"
61
83
  end
62
84
 
63
- def theme_directory(theme)
64
- theme_str = case theme.to_sym
65
- when :outlined then "outlined"
66
- when :filled then "filled"
67
- when :two_tone, :twotone then "twotone"
68
- else "outlined"
69
- end
70
-
71
- ICONS_BASE_PATH.join(theme_str)
72
- end
85
+ ICONS_BASE_PATH.join(theme_str)
86
+ end
73
87
 
74
- def enhance_svg(svg_content)
75
- svg = svg_content.dup
88
+ sig { params(svg_content: String).returns(String) }
89
+ def self.enhance_svg(svg_content)
90
+ svg = svg_content.dup
76
91
 
77
- svg.sub!("<svg", '<svg width="1em"') unless svg.include?("width=")
78
- svg.sub!("<svg", '<svg height="1em"') unless svg.include?("height=")
79
- svg.sub!("<svg", '<svg fill="currentColor"') unless svg.include?("fill=")
92
+ svg.sub!("<svg", '<svg width="1em"') unless svg.include?("width=")
93
+ svg.sub!("<svg", '<svg height="1em"') unless svg.include?("height=")
94
+ svg.sub!("<svg", '<svg fill="currentColor"') unless svg.include?("fill=")
80
95
 
81
- svg
82
- end
96
+ svg
97
+ end
83
98
 
84
- def kebabize(str)
85
- str.gsub(/::/, "/")
86
- .gsub(/([A-Z]+)([A-Z][a-z])/, '\1-\2')
87
- .gsub(/([a-z\d])([A-Z])/, '\1-\2')
88
- .tr("_", "-")
89
- .downcase
90
- end
99
+ sig { params(str: String).returns(String) }
100
+ def self.kebabize(str)
101
+ str.gsub(/::/, "/")
102
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1-\2')
103
+ .gsub(/([a-z\d])([A-Z])/, '\1-\2')
104
+ .tr("_", "-")
105
+ .downcase
91
106
  end
107
+
108
+ private_class_method :read_icon_file, :icon_filepath, :theme_directory, :enhance_svg, :kebabize
92
109
  end
93
110
  end
94
111
  end
@@ -1,42 +1,50 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  module Illustrations
5
- # Loads SVG illustrations stored under lib/hakumi_components/app/assets/illustrations
6
6
  class Loader
7
- ILLUSTRATIONS_PATH = if defined?(HakumiComponents::Engine)
8
- HakumiComponents::Engine.root.join("app", "assets", "illustrations")
9
- else
10
- Rails.root.join("lib", "hakumi_components", "app", "assets", "illustrations")
11
- end
7
+ extend T::Sig
12
8
 
13
- class << self
14
- def load(name)
15
- filename = "#{name}.svg"
16
- cache[filename] ||= read_svg(filename)
17
- end
9
+ Cache = T.type_alias { T::Hash[String, T.nilable(ActiveSupport::SafeBuffer)] }
10
+ @@cache = T.let({}, Cache)
11
+ ILLUSTRATIONS_PATH = T.let(
12
+ if defined?(HakumiComponents::Engine)
13
+ HakumiComponents::Engine.root.join("app", "assets", "illustrations")
14
+ else
15
+ ::Rails.root.join("lib", "hakumi_components", "app", "assets", "illustrations")
16
+ end,
17
+ Pathname
18
+ )
18
19
 
19
- def clear_cache!
20
- @cache = {}
21
- end
20
+ sig { params(name: String).returns(T.nilable(ActiveSupport::SafeBuffer)) }
21
+ def self.load(name)
22
+ filename = "#{name}.svg"
23
+ cache[filename] ||= read_svg(filename)
24
+ end
22
25
 
23
- private
26
+ sig { void }
27
+ def self.clear_cache!
28
+ @@cache = {}
29
+ end
24
30
 
25
- def cache
26
- @cache ||= {}
27
- end
31
+ sig { returns(Cache) }
32
+ def self.cache
33
+ @@cache
34
+ end
28
35
 
29
- def read_svg(filename)
30
- path = ILLUSTRATIONS_PATH.join(filename)
31
- return nil unless path.exist?
36
+ sig { params(filename: String).returns(T.nilable(ActiveSupport::SafeBuffer)) }
37
+ def self.read_svg(filename)
38
+ path = ILLUSTRATIONS_PATH.join(filename)
39
+ return nil unless path.exist?
32
40
 
33
- svg = File.read(path)
34
- svg.respond_to?(:html_safe) ? svg.html_safe : svg
35
- rescue => e
36
- ::Rails.logger.error("Error loading illustration #{filename}: #{e.message}")
37
- nil
38
- end
41
+ ActiveSupport::SafeBuffer.new(File.read(path))
42
+ rescue => e
43
+ ::Rails.logger.error("Error loading illustration #{filename}: #{e.message}")
44
+ nil
39
45
  end
46
+
47
+ private_class_method :cache, :read_svg
40
48
  end
41
49
  end
42
50
  end
@@ -1 +1,4 @@
1
- <%= render HakumiComponents::Alert::Component.new(**local_assigns) %>
1
+ <%= render HakumiComponents::Alert::Component.new(**local_assigns.except(:message_text, :description_text, :title, :message, :description).merge(
2
+ message_text: local_assigns[:message_text] || local_assigns[:message],
3
+ description_text: local_assigns[:description_text] || local_assigns[:description]
4
+ ).compact) %>
@@ -1,6 +1,6 @@
1
1
  <%= render HakumiComponents::Drawer::Component.new(
2
2
  id: local_assigns[:id],
3
- open: local_assigns[:open],
3
+ open: local_assigns.fetch(:open, false),
4
4
  placement: local_assigns[:placement] || :right,
5
5
  size: local_assigns[:size] || :default,
6
6
  width: local_assigns[:width],
@@ -1,13 +1,13 @@
1
1
  <%= render HakumiComponents::Statistic::Component.new(
2
- id: id,
3
- title: title,
4
- value: value,
5
- precision: precision,
6
- prefix: prefix,
7
- suffix: suffix,
8
- animated: animated,
9
- duration: duration,
10
- countdown: countdown,
11
- format: format,
12
- aria_label: aria_label
2
+ id: local_assigns[:id],
3
+ title: local_assigns[:title],
4
+ value: local_assigns[:value],
5
+ precision: local_assigns[:precision],
6
+ prefix: local_assigns[:prefix],
7
+ suffix: local_assigns[:suffix],
8
+ animated: local_assigns.fetch(:animated, false),
9
+ duration: local_assigns.fetch(:duration, 800),
10
+ countdown: local_assigns.fetch(:countdown, false),
11
+ format: local_assigns[:format],
12
+ aria_label: local_assigns[:aria_label]
13
13
  ) %>