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,17 +1,36 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  module Tooltip
5
- class Component < HakumiComponents::BaseComponent
6
- TRIGGERS = %i[hover focus click].freeze
7
- PLACEMENTS = %i[
6
+ class Component < HakumiComponents::BaseComponent
7
+ extend T::Sig
8
+
9
+ Trigger = T.type_alias { Types::HtmlKey }
10
+ Placement = T.type_alias { Types::HtmlKey }
11
+ Color = T.type_alias { Types::HtmlKey }
12
+
13
+ TRIGGERS = T.let(%i[hover focus click].freeze, T::Array[Symbol])
14
+ PLACEMENTS = T.let(%i[
8
15
  top top_left top_right
9
16
  bottom bottom_left bottom_right
10
17
  left left_top left_bottom
11
18
  right right_top right_bottom
12
- ].freeze
13
- COLORS = %i[default pink red yellow orange cyan green blue purple geekblue magenta volcano gold lime].freeze
14
-
19
+ ].freeze, T::Array[Symbol])
20
+ COLORS = T.let(%i[default pink red yellow orange cyan green blue purple geekblue magenta volcano gold lime].freeze, T::Array[Symbol])
21
+
22
+ sig do
23
+ params(
24
+ title: HakumiComponents::Types::Renderable,
25
+ placement: Placement,
26
+ trigger: Trigger,
27
+ arrow: T::Boolean,
28
+ color: Color,
29
+ open: T.nilable(T::Boolean),
30
+ fresh: T::Boolean,
31
+ html_options: HakumiComponents::Types::HtmlAttributeValue
32
+ ).void
33
+ end
15
34
  def initialize(
16
35
  title: nil,
17
36
  placement: :top,
@@ -22,59 +41,48 @@ module HakumiComponents
22
41
  fresh: false,
23
42
  **html_options
24
43
  )
25
- @title = title
26
- @placement = placement
27
- @trigger = trigger
28
- @arrow = arrow
29
- @color = color
30
- @open = open
31
- @fresh = fresh
32
- @html_options = html_options
44
+ @title = T.let(title, HakumiComponents::Types::Renderable)
45
+ @placement = T.let(placement.to_sym, Symbol)
46
+ @trigger = T.let(trigger.to_sym, Symbol)
47
+ @arrow = T.let(cast_boolean(arrow) != false, T::Boolean)
48
+ @color = T.let(color.is_a?(String) ? color : color.to_sym, Color)
49
+ @open = T.let(open, T.nilable(T::Boolean))
50
+ @fresh = T.let(cast_boolean(fresh) ? true : false, T::Boolean)
51
+ @html_options = T.let(html_options, HakumiComponents::Types::HtmlAttributes)
33
52
 
34
53
  validate_props!
35
54
  end
36
55
 
37
- attr_reader :title, :placement, :trigger, :arrow, :color, :open, :fresh
38
-
39
- def wrapper_classes
40
- classes = [ "hakumi-tooltip-wrapper" ]
41
- classes << "hakumi-tooltip-open" if @open == true
42
- classes.join(" ")
43
- end
56
+ sig { returns(HakumiComponents::Types::Renderable) }
57
+ attr_reader :title
44
58
 
45
- def tooltip_classes
46
- classes = [ "hakumi-tooltip" ]
47
- classes << placement_class
48
- classes << color_class if preset_color?
49
- classes.join(" ")
50
- end
51
-
52
- def placement_class
53
- "hakumi-tooltip-placement-#{@placement.to_s.dasherize}"
54
- end
59
+ sig { returns(Symbol) }
60
+ attr_reader :placement, :trigger
55
61
 
56
- def color_class
57
- "hakumi-tooltip-#{@color}" if preset_color?
58
- end
62
+ sig { returns(T::Boolean) }
63
+ attr_reader :arrow, :fresh
59
64
 
60
- def preset_color?
61
- @color.is_a?(Symbol) && @color != :default && COLORS.include?(@color)
62
- end
65
+ sig { returns(Color) }
66
+ attr_reader :color
63
67
 
64
- def custom_color?
65
- @color.is_a?(String)
66
- end
68
+ sig { returns(T.nilable(T::Boolean)) }
69
+ attr_reader :open
67
70
 
68
- def custom_color_style
69
- return unless custom_color?
70
- "background-color: #{@color};"
71
+ sig { returns(String) }
72
+ def wrapper_classes
73
+ extras = T.let([], T::Array[T.nilable(String)])
74
+ extras << "hakumi-tooltip-open" if @open == true
75
+ extras.concat(Array(html_classes(@html_options)).compact)
76
+ class_names("tooltip-wrapper", {}, extras)
71
77
  end
72
78
 
73
- def stimulus_controller
74
- "hakumi--tooltip"
79
+ sig { returns(String) }
80
+ def tooltip_classes
81
+ class_names("tooltip", {}, [ placement_class, (color_class if preset_color?) ])
75
82
  end
76
83
 
77
- def stimulus_values
84
+ sig { returns(HakumiComponents::Types::HtmlAttributes) }
85
+ def wrapper_attributes
78
86
  values = {
79
87
  placement: @placement.to_s.dasherize,
80
88
  trigger: @trigger.to_s,
@@ -83,39 +91,56 @@ module HakumiComponents
83
91
  }
84
92
  values[:open] = @open unless @open.nil?
85
93
  values[:color] = @color.to_s if custom_color?
86
- values
94
+
95
+ merge_attributes(
96
+ { class: wrapper_classes, data: stimulus_attrs(stimulus_controller, values) },
97
+ @html_options
98
+ )
87
99
  end
88
100
 
89
- def wrapper_attributes
90
- base_attrs = {
91
- class: wrapper_classes,
92
- data: {
93
- controller: stimulus_controller
94
- }.merge(stimulus_data_attributes)
95
- }
96
- merge_attributes(base_attrs, @html_options)
101
+ sig { returns(HakumiComponents::Types::Renderable) }
102
+ def tooltip_text
103
+ render_value(@title)
97
104
  end
98
105
 
99
- def stimulus_data_attributes
100
- stimulus_values.transform_keys { |k| "#{stimulus_controller}-#{k.to_s.dasherize}-value" }
106
+ sig { returns(T::Boolean) }
107
+ def tooltip_content?
108
+ value_present?(@title)
101
109
  end
102
110
 
103
- def tooltip_text
104
- @title
111
+ private
112
+
113
+ sig { returns(String) }
114
+ def placement_class
115
+ "hakumi-tooltip-placement-#{@placement.to_s.dasherize}"
105
116
  end
106
117
 
107
- def has_tooltip_content?
108
- @title.present?
118
+ sig { returns(T.nilable(String)) }
119
+ def color_class
120
+ "hakumi-tooltip-#{@color}" if preset_color?
109
121
  end
110
122
 
111
- private
123
+ sig { returns(T::Boolean) }
124
+ def preset_color?
125
+ @color.is_a?(Symbol) && @color != :default && COLORS.include?(@color)
126
+ end
127
+
128
+ sig { returns(T::Boolean) }
129
+ def custom_color?
130
+ @color.is_a?(String)
131
+ end
132
+
133
+ sig { returns(String) }
134
+ def stimulus_controller
135
+ "hakumi--tooltip"
136
+ end
112
137
 
138
+ sig { void }
113
139
  def validate_props!
114
140
  validate_inclusion!(:placement, PLACEMENTS)
115
141
  validate_inclusion!(:trigger, TRIGGERS)
116
- # Only validate color if it's a symbol (preset), strings are custom colors
117
142
  validate_inclusion!(:color, COLORS) if @color.is_a?(Symbol)
118
143
  end
119
- end
144
+ end
120
145
  end
121
146
  end
@@ -1,46 +1,69 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module HakumiComponents
4
5
  module Tour
5
6
  class Component < HakumiComponents::BaseComponent
6
- SIZES = %w[small default large].freeze
7
- TYPES = %w[default primary].freeze
8
- PLACEMENTS = %w[
7
+ extend T::Sig
8
+
9
+ Size = T.type_alias { T.any(Symbol, String) }
10
+ Type = T.type_alias { T.any(Symbol, String) }
11
+ Placement = T.type_alias { T.any(Symbol, String) }
12
+
13
+ TYPES = T.let(%i[default primary].freeze, T::Array[Symbol])
14
+ PLACEMENTS = T.let(%i[
9
15
  top top_left top_right
10
16
  bottom bottom_left bottom_right
11
17
  left left_top left_bottom
12
18
  right right_top right_bottom
13
- ].freeze
14
-
19
+ ].freeze, T::Array[Symbol])
20
+
21
+ sig do
22
+ params(
23
+ steps: T::Array[HakumiComponents::Tour::Step::Source],
24
+ open: T::Boolean,
25
+ current: Integer,
26
+ size: Size,
27
+ type: Type,
28
+ placement: Placement,
29
+ mask: T::Boolean,
30
+ mask_closable: T::Boolean,
31
+ closable: T::Boolean,
32
+ show_progress: T::Boolean,
33
+ html_options: HakumiComponents::Types::HtmlAttributeValue
34
+ ).void
35
+ end
15
36
  def initialize(
16
37
  steps: [],
17
38
  open: false,
18
39
  current: 0,
19
- size: "default",
20
- type: "default",
21
- placement: "bottom",
40
+ size: :default,
41
+ type: :default,
42
+ placement: :bottom,
22
43
  mask: true,
23
44
  mask_closable: true,
24
45
  closable: true,
25
46
  show_progress: true,
26
- **html_attrs
47
+ **html_options
27
48
  )
28
- @steps = steps
29
- @open = open
30
- @current = current
31
- @size = size
32
- @type = type
33
- @placement = placement
34
- @mask = mask
35
- @mask_closable = mask_closable
36
- @closable = closable
37
- @show_progress = show_progress
38
- @html_attrs = html_attrs
39
- @component_id = @html_attrs[:id] || generate_id("hakumi-tour", length: 6)
49
+ @steps = T.let(steps, T::Array[HakumiComponents::Tour::Step::Source])
50
+ @open = T.let(open, T::Boolean)
51
+ @current = T.let(current, Integer)
52
+ @size = T.let(size.to_sym, Symbol)
53
+ @type = T.let(type.to_sym, Symbol)
54
+ @placement = T.let(placement.to_sym, Symbol)
55
+ @mask = T.let(mask, T::Boolean)
56
+ @mask_closable = T.let(mask_closable, T::Boolean)
57
+ @closable = T.let(closable, T::Boolean)
58
+ @show_progress = T.let(show_progress, T::Boolean)
59
+ @html_options = T.let(html_options, HakumiComponents::Types::HtmlAttributes)
60
+ raw_id = @html_options[:id]
61
+ @component_id = T.let(raw_id.nil? ? generate_id("hakumi-tour", length: 6) : raw_id.to_s, String)
40
62
 
41
63
  validate_props!
42
64
  end
43
65
 
66
+ sig { returns(HakumiComponents::Types::HtmlAttributes) }
44
67
  def component_html_attributes
45
68
  merge_attributes(
46
69
  {
@@ -51,33 +74,38 @@ module HakumiComponents
51
74
  hakumi__tour_open_value: @open,
52
75
  hakumi__tour_current_value: @current,
53
76
  hakumi__tour_steps_value: steps_json,
54
- hakumi__tour_placement_value: normalized_placement(@placement),
77
+ hakumi__tour_placement_value: @placement.to_s.tr("_", "-"),
55
78
  hakumi__tour_mask_value: @mask,
56
79
  hakumi__tour_mask_closable_value: @mask_closable,
57
80
  hakumi__tour_closable_value: @closable,
58
81
  hakumi__tour_show_progress_value: @show_progress
59
82
  }
60
83
  },
61
- @html_attrs
84
+ @html_options
62
85
  )
63
86
  end
64
87
 
88
+ sig { returns(String) }
65
89
  def title_id
66
90
  "#{@component_id}-title"
67
91
  end
68
92
 
93
+ sig { returns(String) }
69
94
  def body_id
70
95
  "#{@component_id}-body"
71
96
  end
72
97
 
98
+ sig { returns(String) }
73
99
  def current_step_title
74
- current_step[:title]
100
+ current_step.title
75
101
  end
76
102
 
103
+ sig { returns(String) }
77
104
  def current_step_body
78
- current_step[:body]
105
+ current_step.body
79
106
  end
80
107
 
108
+ sig { returns(T.nilable(String)) }
81
109
  def progress_label
82
110
  return nil unless @show_progress
83
111
  return "0 / 0" if normalized_steps.empty?
@@ -85,24 +113,28 @@ module HakumiComponents
85
113
  "#{current_index + 1} / #{normalized_steps.length}"
86
114
  end
87
115
 
116
+ sig { returns(T::Boolean) }
88
117
  def first_step?
89
118
  current_index.zero?
90
119
  end
91
120
 
121
+ sig { returns(T::Boolean) }
92
122
  def last_step?
93
123
  normalized_steps.any? && current_index == normalized_steps.length - 1
94
124
  end
95
125
 
96
126
  private
97
127
 
128
+ sig { returns(String) }
98
129
  def component_html_class
99
130
  modifiers = { "open" => @open }
100
- modifiers[@size] = true if @size != "default"
101
- modifiers[@type] = true if @type != "default"
131
+ modifiers[@size] = true if @size != :default
132
+ modifiers[@type] = true if @type != :default
102
133
 
103
- class_names("tour", modifiers, [ @html_attrs[:class] ])
134
+ class_names("tour", modifiers, html_classes(@html_options))
104
135
  end
105
136
 
137
+ sig { void }
106
138
  def validate_props!
107
139
  validate_inclusion!(:size, SIZES)
108
140
  validate_inclusion!(:type, TYPES)
@@ -110,49 +142,42 @@ module HakumiComponents
110
142
  validate_steps!
111
143
  end
112
144
 
145
+ sig { void }
113
146
  def validate_steps!
114
- Array(@steps).each_with_index do |step, index|
115
- step_hash = step.respond_to?(:to_h) ? step.to_h : {}
116
- placement = step_hash[:placement] || step_hash["placement"]
117
- next if placement.nil?
118
- next if PLACEMENTS.include?(placement.to_s)
147
+ @steps.each_with_index do |step, index|
148
+ placement = HakumiComponents::Tour::Step.from_input(step, default_placement: @placement).placement
149
+ next if PLACEMENTS.include?(placement)
119
150
 
120
151
  raise ArgumentError, "steps[#{index}] placement must be one of #{PLACEMENTS.inspect}, got #{placement.inspect}"
121
152
  end
122
153
  end
123
154
 
155
+ sig { returns(T::Array[HakumiComponents::Tour::Step]) }
124
156
  def normalized_steps
125
- @normalized_steps ||= Array(@steps).map do |step|
126
- step_hash = step.respond_to?(:to_h) ? step.to_h : {}
127
- step_hash = step_hash.transform_keys { |key| key.to_sym }
128
-
129
- {
130
- title: step_hash[:title].to_s,
131
- body: (step_hash[:body] || step_hash[:description]).to_s,
132
- target: step_hash[:target].presence,
133
- placement: normalized_placement(step_hash[:placement] || @placement)
134
- }
157
+ @normalized_steps = T.let(@normalized_steps, T.nilable(T::Array[HakumiComponents::Tour::Step])) if instance_variable_defined?(:@normalized_steps)
158
+ @normalized_steps ||= @steps.map do |step|
159
+ HakumiComponents::Tour::Step.from_input(step, default_placement: @placement)
135
160
  end
136
161
  end
137
162
 
163
+ sig { returns(String) }
138
164
  def steps_json
139
- normalized_steps.to_json
165
+ normalized_steps.map(&:to_h).to_json
140
166
  end
141
167
 
168
+ sig { returns(HakumiComponents::Tour::Step) }
142
169
  def current_step
143
- normalized_steps[current_index] || { title: "", body: "" }
170
+ normalized_steps[current_index] || HakumiComponents::Tour::Step.new(title: "", body: "", placement: @placement)
144
171
  end
145
172
 
173
+ sig { returns(Integer) }
146
174
  def current_index
147
175
  return 0 if normalized_steps.empty?
176
+
148
177
  index = @current.to_i
149
178
  index = 0 if index.negative?
150
179
  index >= normalized_steps.length ? normalized_steps.length - 1 : index
151
180
  end
152
-
153
- def normalized_placement(value)
154
- value.to_s.tr("_", "-")
155
- end
156
181
  end
157
182
  end
158
183
  end
@@ -0,0 +1,86 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module HakumiComponents
5
+ module Tour
6
+ class Step
7
+ extend T::Sig
8
+
9
+ InputValue = T.type_alias { T.nilable(Types::StringOrSymbol) }
10
+ InputHash = T.type_alias { T.any(T::Hash[Symbol, InputValue], T::Hash[String, InputValue]) }
11
+ Source = T.type_alias { T.any(Step, InputHash) }
12
+
13
+ sig do
14
+ params(
15
+ title: String,
16
+ body: String,
17
+ placement: Symbol,
18
+ target: T.nilable(String)
19
+ ).void
20
+ end
21
+ def initialize(title:, body:, placement:, target: nil)
22
+ @title = title
23
+ @body = body
24
+ @target = target
25
+ @placement = placement
26
+ end
27
+
28
+ sig { returns(String) }
29
+ attr_reader :title
30
+
31
+ sig { returns(String) }
32
+ attr_reader :body
33
+
34
+ sig { returns(T.nilable(String)) }
35
+ attr_reader :target
36
+
37
+ sig { returns(Symbol) }
38
+ attr_reader :placement
39
+
40
+ sig { params(step: Source, default_placement: Symbol).returns(Step) }
41
+ def self.from_input(step, default_placement:)
42
+ return step if step.is_a?(Step)
43
+
44
+ title = read_input(step, :title).to_s
45
+ body = read_input(step, :body, :description).to_s
46
+ target = read_input(step, :target)&.to_s
47
+ placement = (read_input(step, :placement) || default_placement).to_s.to_sym
48
+
49
+ Step.new(
50
+ title: title,
51
+ body: body,
52
+ placement: placement,
53
+ target: target
54
+ )
55
+ end
56
+
57
+ sig { returns(T::Hash[Symbol, T.nilable(String)]) }
58
+ def to_h
59
+ {
60
+ title: @title,
61
+ body: @body,
62
+ target: @target,
63
+ placement: @placement.to_s.tr("_", "-")
64
+ }
65
+ end
66
+
67
+ class << self
68
+ extend T::Sig
69
+
70
+ private
71
+
72
+ sig { params(input: InputHash, keys: T.any(Symbol, String)).returns(InputValue) }
73
+ def read_input(input, *keys)
74
+ keys.each do |key|
75
+ return input[key] if input.key?(key)
76
+
77
+ string_key = key.to_s
78
+ return input[string_key] if input.key?(string_key)
79
+ end
80
+
81
+ nil
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,66 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module HakumiComponents
5
+ module Transfer
6
+ module Coercion
7
+ extend T::Sig
8
+ extend self
9
+
10
+ ItemValue = T.type_alias { HakumiComponents::Types::FormFieldScalar }
11
+ TitleValue = T.type_alias { T.any(String, Symbol, Numeric) }
12
+ ItemHash = T.type_alias { T::Hash[HakumiComponents::Types::HtmlKey, ItemValue] }
13
+ ItemInput = T.type_alias { T.any(HakumiComponents::Transfer::Item, ItemHash, HakumiComponents::Types::FormFieldScalar) }
14
+
15
+ sig { params(items: T::Array[ItemInput], disabled: T::Boolean).returns(T::Array[HakumiComponents::Transfer::Item]) }
16
+ def items(items, disabled:)
17
+ items.map.with_index do |item, index|
18
+ normalize_item(item, index: index, disabled: disabled)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ sig { params(item: ItemInput, index: Integer, disabled: T::Boolean).returns(HakumiComponents::Transfer::Item) }
25
+ def normalize_item(item, index:, disabled:)
26
+ return item if item.is_a?(HakumiComponents::Transfer::Item)
27
+
28
+ if item.is_a?(Hash)
29
+ key = item[:key] || item["key"] || index
30
+ raw_title = item[:title] || item["title"] || key
31
+ title = coerce_title(raw_title)
32
+ return HakumiComponents::Transfer::Item.new(
33
+ key: key.to_s,
34
+ title: title,
35
+ description: normalize_string(item[:description] || item["description"]),
36
+ disabled: disabled || (item[:disabled] == true) || (item["disabled"] == true),
37
+ class_name: normalize_string(item[:class_name] || item["class_name"])
38
+ )
39
+ end
40
+
41
+ HakumiComponents::Transfer::Item.new(
42
+ key: item.to_s,
43
+ title: coerce_title(item),
44
+ description: nil,
45
+ disabled: disabled,
46
+ class_name: nil
47
+ )
48
+ end
49
+
50
+ sig { params(value: ItemValue).returns(TitleValue) }
51
+ def coerce_title(value)
52
+ return value if value.is_a?(String) || value.is_a?(Symbol) || value.is_a?(Numeric)
53
+
54
+ value.to_s
55
+ end
56
+
57
+ sig { params(value: ItemValue).returns(T.nilable(String)) }
58
+ def normalize_string(value)
59
+ return nil if value.nil?
60
+
61
+ normalized = value.to_s.strip
62
+ normalized.empty? ? nil : normalized
63
+ end
64
+ end
65
+ end
66
+ end