ariadne_view_components 0.0.58 → 0.0.64

Sign up to get free protection for your applications and to get access to all the features.
Files changed (264) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +70 -0
  3. data/LICENSE.txt +661 -49
  4. data/README.md +52 -4
  5. data/app/assets/javascripts/ariadne_view_components.js +98 -7
  6. data/app/assets/javascripts/ariadne_view_components.js.map +1 -1
  7. data/app/assets/stylesheets/ariadne_view_components.css +1 -7
  8. data/app/components/ariadne/base_component.rb +79 -27
  9. data/app/components/ariadne/behaviors/tooltipable.rb +120 -0
  10. data/app/components/ariadne/conditional_wrapper.rb +21 -0
  11. data/app/components/ariadne/form/base_component.rb +74 -0
  12. data/app/components/ariadne/form/base_input_component.rb +60 -0
  13. data/app/components/ariadne/form/caption/component.html.erb +10 -0
  14. data/app/components/ariadne/form/caption/component.rb +29 -0
  15. data/app/components/ariadne/form/form_control/component.html.erb +19 -0
  16. data/app/components/ariadne/form/form_control/component.rb +27 -0
  17. data/app/components/ariadne/form/form_reference/component.html.erb +1 -0
  18. data/app/components/ariadne/form/form_reference/component.rb +18 -0
  19. data/app/components/ariadne/form/group/component.html.erb +5 -0
  20. data/app/components/ariadne/form/group/component.rb +27 -0
  21. data/app/components/ariadne/form/hidden_field/component.html.erb +1 -0
  22. data/app/components/ariadne/form/hidden_field/component.rb +15 -0
  23. data/app/components/ariadne/form/separator/component.html.erb +1 -0
  24. data/app/components/ariadne/form/separator/component.rb +8 -0
  25. data/app/components/ariadne/form/spacing_wrapper/component.html.erb +3 -0
  26. data/app/components/ariadne/form/spacing_wrapper/component.rb +8 -0
  27. data/app/components/ariadne/form/text_field/component.html.erb +25 -0
  28. data/app/components/ariadne/form/text_field/component.rb +132 -0
  29. data/app/components/ariadne/form/validation_message/component.html.erb +5 -0
  30. data/app/components/ariadne/form/validation_message/component.rb +14 -0
  31. data/app/components/ariadne/layout/narrow/component.html.erb +10 -0
  32. data/app/components/ariadne/layout/narrow/component.rb +24 -0
  33. data/app/components/ariadne/layout/nav_bar/component.css +0 -0
  34. data/app/components/ariadne/layout/nav_bar/component.html.erb +123 -0
  35. data/app/components/ariadne/layout/nav_bar/component.rb +77 -0
  36. data/app/components/ariadne/ui/button/component.html.erb +5 -0
  37. data/app/components/ariadne/ui/button/component.rb +184 -0
  38. data/app/components/ariadne/ui/clipboard_copy/component.html.erb +8 -0
  39. data/app/components/ariadne/ui/clipboard_copy/component.rb +102 -0
  40. data/app/components/ariadne/ui/clipboard_copy/component.ts +54 -0
  41. data/app/components/ariadne/ui/combobox/component.html.erb +32 -0
  42. data/app/components/ariadne/ui/combobox/component.rb +83 -0
  43. data/app/components/ariadne/ui/combobox/component.ts +119 -0
  44. data/app/components/ariadne/ui/combobox/menu_item/component.html.erb +9 -0
  45. data/app/components/ariadne/ui/combobox/menu_item/component.rb +53 -0
  46. data/app/components/ariadne/ui/combobox/option/component.html.erb +11 -0
  47. data/app/components/ariadne/ui/combobox/option/component.rb +45 -0
  48. data/app/components/ariadne/ui/heroicon/component.html.erb +3 -0
  49. data/app/components/ariadne/ui/heroicon/component.rb +141 -0
  50. data/app/components/ariadne/ui/image/component.rb +69 -0
  51. data/app/components/ariadne/ui/link/component.html.erb +3 -0
  52. data/app/components/ariadne/ui/link/component.rb +56 -0
  53. data/app/components/ariadne/ui/typography/component.html.erb +3 -0
  54. data/app/components/ariadne/ui/typography/component.rb +41 -0
  55. data/app/lib/ariadne/attributes_helper.rb +119 -0
  56. data/app/lib/ariadne/fetch_or_fallback_helper.rb +1 -1
  57. data/app/lib/ariadne/form.rb +16 -0
  58. data/app/lib/ariadne/view_helper.rb +2 -5
  59. data/app/lib/view_components_contrib/html_attrs.rb +64 -0
  60. data/app/lib/view_components_contrib/style_variants.rb +14 -0
  61. data/lib/ariadne/forms/acts_as_component.rb +125 -0
  62. data/lib/ariadne/forms/base.html.erb +8 -0
  63. data/lib/ariadne/forms/base.rb +132 -0
  64. data/lib/ariadne/forms/buffer_rewriter.rb +51 -0
  65. data/lib/ariadne/forms/builder.rb +88 -0
  66. data/lib/ariadne/forms/dsl/button_input.rb +33 -0
  67. data/lib/ariadne/forms/dsl/form_object.rb +26 -0
  68. data/lib/ariadne/forms/dsl/input.rb +322 -0
  69. data/lib/ariadne/forms/dsl/input_group.rb +34 -0
  70. data/lib/ariadne/forms/dsl/input_methods.rb +157 -0
  71. data/lib/ariadne/forms/dsl/submit_button_input.rb +36 -0
  72. data/lib/ariadne/forms/dsl/text_field_input.rb +73 -0
  73. data/lib/ariadne/forms/utils.rb +34 -0
  74. data/lib/ariadne/generate.rb +11 -0
  75. data/lib/ariadne/view_components/engine.rb +24 -7
  76. data/lib/ariadne/view_components/version.rb +1 -1
  77. data/lib/ariadne/view_components.rb +1 -1
  78. data/lib/ariadne/yard/backend.rb +24 -0
  79. data/lib/ariadne/yard/component_manifest.rb +148 -0
  80. data/lib/ariadne/yard/component_ref.rb +49 -0
  81. data/lib/ariadne/yard/docs_helper.rb +98 -0
  82. data/lib/ariadne/yard/info_arch_docs_helper.rb +31 -0
  83. data/lib/ariadne/yard/lookbook_docs_helper.rb +32 -0
  84. data/lib/ariadne/yard/lookbook_pages_backend.rb +235 -0
  85. data/lib/ariadne/yard/registry.rb +136 -0
  86. data/lib/ariadne/yard/renders_many_handler.rb +23 -0
  87. data/lib/ariadne/yard/renders_one_handler.rb +23 -0
  88. data/lib/ariadne/yard.rb +19 -0
  89. data/static/arguments.yml +141 -48
  90. data/static/audited_at.json +0 -9
  91. data/static/classes.yml +210 -209
  92. data/static/constants.json +2 -209
  93. data/static/statuses.json +0 -9
  94. metadata +125 -210
  95. data/app/assets/builds/ariadne_view_components.css +0 -2202
  96. data/app/assets/javascripts/components/ariadne/accumulator_controller/accumulator_controller.d.ts +0 -22
  97. data/app/assets/javascripts/components/ariadne/ariadne-form.d.ts +0 -22
  98. data/app/assets/javascripts/components/ariadne/ariadne.d.ts +0 -2
  99. data/app/assets/javascripts/components/ariadne/clipboard_copy_component/clipboard-copy-component.d.ts +0 -4
  100. data/app/assets/javascripts/components/ariadne/dropdown/menu_component.d.ts +0 -1
  101. data/app/assets/javascripts/components/ariadne/events_controller/events_controller.d.ts +0 -4
  102. data/app/assets/javascripts/components/ariadne/options_controller/options_controller.d.ts +0 -39
  103. data/app/assets/javascripts/components/ariadne/outlet_manager_controller/outlet_manager_controller.d.ts +0 -42
  104. data/app/assets/javascripts/components/ariadne/slideover_component/slideover-component.d.ts +0 -9
  105. data/app/assets/javascripts/components/ariadne/string_match_controller/string_match_controller.d.ts +0 -27
  106. data/app/assets/javascripts/components/ariadne/synced_boolean_attributes_controller/synced_boolean_attributes_controller.d.ts +0 -48
  107. data/app/assets/javascripts/components/ariadne/tab_container_component/tab-container-component.d.ts +0 -1
  108. data/app/assets/javascripts/components/ariadne/tab_nav_component/tab-nav-component.d.ts +0 -9
  109. data/app/assets/javascripts/components/ariadne/time_ago_component/time-ago-component.d.ts +0 -1
  110. data/app/assets/javascripts/components/ariadne/toggleable_controller/toggleable_controller.d.ts +0 -34
  111. data/app/assets/javascripts/components/ariadne/tooltip_component/tooltip-component.d.ts +0 -24
  112. data/app/assets/stylesheets/dropdown.css +0 -46
  113. data/app/assets/stylesheets/prosemirror.css +0 -323
  114. data/app/assets/stylesheets/tooltip-component.css +0 -37
  115. data/app/components/ariadne/accumulator_controller/accumulator_controller.d.ts +0 -22
  116. data/app/components/ariadne/accumulator_controller/accumulator_controller.js +0 -39
  117. data/app/components/ariadne/accumulator_controller/accumulator_controller.ts +0 -48
  118. data/app/components/ariadne/action_card_component.html.erb +0 -13
  119. data/app/components/ariadne/action_card_component.rb +0 -88
  120. data/app/components/ariadne/ariadne-form.d.ts +0 -22
  121. data/app/components/ariadne/ariadne-form.js +0 -85
  122. data/app/components/ariadne/ariadne.d.ts +0 -2
  123. data/app/components/ariadne/ariadne.js +0 -24
  124. data/app/components/ariadne/ariadne.ts +0 -29
  125. data/app/components/ariadne/avatar_component.rb +0 -81
  126. data/app/components/ariadne/avatar_stack_component/avatar_stack_component.html.erb +0 -12
  127. data/app/components/ariadne/avatar_stack_component.rb +0 -75
  128. data/app/components/ariadne/base_button.rb +0 -70
  129. data/app/components/ariadne/blankslate_component/blankslate_component.html.erb +0 -26
  130. data/app/components/ariadne/blankslate_component.rb +0 -148
  131. data/app/components/ariadne/body_component.rb +0 -30
  132. data/app/components/ariadne/bottom_tab_component.html.erb +0 -4
  133. data/app/components/ariadne/bottom_tab_component.rb +0 -44
  134. data/app/components/ariadne/bottom_tab_nav_component.html.erb +0 -5
  135. data/app/components/ariadne/bottom_tab_nav_component.rb +0 -33
  136. data/app/components/ariadne/breadcrumbs_component.html.erb +0 -13
  137. data/app/components/ariadne/breadcrumbs_component.rb +0 -31
  138. data/app/components/ariadne/button_component/button_component.html.erb +0 -4
  139. data/app/components/ariadne/button_component.rb +0 -165
  140. data/app/components/ariadne/checkbox_component.html.erb +0 -5
  141. data/app/components/ariadne/checkbox_component.rb +0 -43
  142. data/app/components/ariadne/clipboard_copy_component/clipboard-copy-component.d.ts +0 -4
  143. data/app/components/ariadne/clipboard_copy_component/clipboard-copy-component.js +0 -18
  144. data/app/components/ariadne/clipboard_copy_component/clipboard-copy-component.ts +0 -19
  145. data/app/components/ariadne/clipboard_copy_component/clipboard_copy_component.html.erb +0 -9
  146. data/app/components/ariadne/clipboard_copy_component.rb +0 -90
  147. data/app/components/ariadne/close_button_component.html.erb +0 -4
  148. data/app/components/ariadne/close_button_component.rb +0 -33
  149. data/app/components/ariadne/combobox_component.html.erb +0 -14
  150. data/app/components/ariadne/combobox_component.rb +0 -76
  151. data/app/components/ariadne/component.rb +0 -127
  152. data/app/components/ariadne/container_component/container_component.html.erb +0 -3
  153. data/app/components/ariadne/container_component.rb +0 -25
  154. data/app/components/ariadne/content.rb +0 -12
  155. data/app/components/ariadne/counter_component.rb +0 -100
  156. data/app/components/ariadne/details_component/details_component.html.erb +0 -4
  157. data/app/components/ariadne/details_component.rb +0 -81
  158. data/app/components/ariadne/dropdown/menu_component.d.ts +0 -1
  159. data/app/components/ariadne/dropdown/menu_component.html.erb +0 -20
  160. data/app/components/ariadne/dropdown/menu_component.js +0 -1
  161. data/app/components/ariadne/dropdown/menu_component.rb +0 -101
  162. data/app/components/ariadne/dropdown/menu_component.ts +0 -1
  163. data/app/components/ariadne/dropdown_component/dropdown_component.html.erb +0 -8
  164. data/app/components/ariadne/dropdown_component.rb +0 -172
  165. data/app/components/ariadne/events_controller/events_controller.d.ts +0 -4
  166. data/app/components/ariadne/events_controller/events_controller.js +0 -6
  167. data/app/components/ariadne/events_controller/events_controller.ts +0 -7
  168. data/app/components/ariadne/flash_component/flash_component.html.erb +0 -31
  169. data/app/components/ariadne/flash_component.rb +0 -128
  170. data/app/components/ariadne/flex_component/flex_component.html.erb +0 -5
  171. data/app/components/ariadne/flex_component.rb +0 -56
  172. data/app/components/ariadne/footer_component/footer_component.html.erb +0 -7
  173. data/app/components/ariadne/footer_component.rb +0 -23
  174. data/app/components/ariadne/grid_component/grid_component.html.erb +0 -26
  175. data/app/components/ariadne/grid_component.rb +0 -67
  176. data/app/components/ariadne/header_component/header_component.html.erb +0 -29
  177. data/app/components/ariadne/header_component.rb +0 -111
  178. data/app/components/ariadne/heading_component.rb +0 -49
  179. data/app/components/ariadne/heroicon_component/heroicon_component.html.erb +0 -4
  180. data/app/components/ariadne/heroicon_component.rb +0 -166
  181. data/app/components/ariadne/image_component.rb +0 -53
  182. data/app/components/ariadne/inline_flex_component/inline_flex_component.html.erb +0 -6
  183. data/app/components/ariadne/inline_flex_component.rb +0 -72
  184. data/app/components/ariadne/layout_component.html.erb +0 -21
  185. data/app/components/ariadne/layout_component.rb +0 -69
  186. data/app/components/ariadne/link_component.rb +0 -65
  187. data/app/components/ariadne/list_component/list_component.html.erb +0 -3
  188. data/app/components/ariadne/list_component.rb +0 -70
  189. data/app/components/ariadne/modal_component.html.erb +0 -11
  190. data/app/components/ariadne/modal_component.rb +0 -88
  191. data/app/components/ariadne/narrow_container_component/narrow_container_component.html.erb +0 -3
  192. data/app/components/ariadne/narrow_container_component.rb +0 -30
  193. data/app/components/ariadne/options_controller/options_controller.d.ts +0 -39
  194. data/app/components/ariadne/options_controller/options_controller.js +0 -89
  195. data/app/components/ariadne/options_controller/options_controller.ts +0 -122
  196. data/app/components/ariadne/outlet_manager_controller/outlet_manager_controller.d.ts +0 -42
  197. data/app/components/ariadne/outlet_manager_controller/outlet_manager_controller.js +0 -237
  198. data/app/components/ariadne/outlet_manager_controller/outlet_manager_controller.ts +0 -278
  199. data/app/components/ariadne/panel_bar_component/panel_bar_component.html.erb +0 -20
  200. data/app/components/ariadne/panel_bar_component.rb +0 -80
  201. data/app/components/ariadne/pill_component/pill_component.html.erb +0 -3
  202. data/app/components/ariadne/pill_component.rb +0 -44
  203. data/app/components/ariadne/popover_component.html.erb +0 -10
  204. data/app/components/ariadne/popover_component.rb +0 -81
  205. data/app/components/ariadne/progress_bar_component.html.erb +0 -5
  206. data/app/components/ariadne/progress_bar_component.rb +0 -63
  207. data/app/components/ariadne/relative_time_component.html.erb +0 -3
  208. data/app/components/ariadne/relative_time_component.rb +0 -61
  209. data/app/components/ariadne/show_more_button_component.html.erb +0 -11
  210. data/app/components/ariadne/show_more_button_component.rb +0 -47
  211. data/app/components/ariadne/slideover_component/slideover-component.d.ts +0 -9
  212. data/app/components/ariadne/slideover_component/slideover-component.js +0 -11
  213. data/app/components/ariadne/slideover_component/slideover-component.ts +0 -17
  214. data/app/components/ariadne/slideover_component/slideover_component.html.erb +0 -9
  215. data/app/components/ariadne/slideover_component.rb +0 -66
  216. data/app/components/ariadne/spinner_component.html.erb +0 -16
  217. data/app/components/ariadne/spinner_component.rb +0 -45
  218. data/app/components/ariadne/string_match_controller/string_match_controller.d.ts +0 -27
  219. data/app/components/ariadne/string_match_controller/string_match_controller.js +0 -51
  220. data/app/components/ariadne/string_match_controller/string_match_controller.ts +0 -65
  221. data/app/components/ariadne/subheader_component.html.erb +0 -11
  222. data/app/components/ariadne/subheader_component.rb +0 -65
  223. data/app/components/ariadne/synced_boolean_attributes_controller/synced_boolean_attributes_controller.d.ts +0 -48
  224. data/app/components/ariadne/synced_boolean_attributes_controller/synced_boolean_attributes_controller.js +0 -207
  225. data/app/components/ariadne/synced_boolean_attributes_controller/synced_boolean_attributes_controller.ts +0 -256
  226. data/app/components/ariadne/tab_component/tab_component.html.erb +0 -3
  227. data/app/components/ariadne/tab_component.rb +0 -98
  228. data/app/components/ariadne/tab_container_component/tab-container-component.d.ts +0 -1
  229. data/app/components/ariadne/tab_container_component/tab-container-component.js +0 -23
  230. data/app/components/ariadne/tab_container_component/tab-container-component.ts +0 -24
  231. data/app/components/ariadne/tab_container_component.erb +0 -10
  232. data/app/components/ariadne/tab_container_component.rb +0 -68
  233. data/app/components/ariadne/tab_nav_component/tab-nav-component.d.ts +0 -9
  234. data/app/components/ariadne/tab_nav_component/tab-nav-component.js +0 -33
  235. data/app/components/ariadne/tab_nav_component/tab-nav-component.ts +0 -34
  236. data/app/components/ariadne/tab_nav_component/tab_nav_component.html.erb +0 -7
  237. data/app/components/ariadne/tab_nav_component.rb +0 -72
  238. data/app/components/ariadne/table_nav_component/table_nav_component.html.erb +0 -52
  239. data/app/components/ariadne/table_nav_component.rb +0 -338
  240. data/app/components/ariadne/text.rb +0 -25
  241. data/app/components/ariadne/time_ago_component/time-ago-component.d.ts +0 -1
  242. data/app/components/ariadne/time_ago_component/time-ago-component.js +0 -1
  243. data/app/components/ariadne/time_ago_component/time-ago-component.ts +0 -1
  244. data/app/components/ariadne/time_ago_component.rb +0 -56
  245. data/app/components/ariadne/timeline_component/timeline_component.html.erb +0 -19
  246. data/app/components/ariadne/timeline_component.rb +0 -34
  247. data/app/components/ariadne/toggle_component/toggle_component.html.erb +0 -15
  248. data/app/components/ariadne/toggle_component.rb +0 -95
  249. data/app/components/ariadne/toggleable_controller/toggleable_controller.d.ts +0 -34
  250. data/app/components/ariadne/toggleable_controller/toggleable_controller.js +0 -54
  251. data/app/components/ariadne/toggleable_controller/toggleable_controller.ts +0 -77
  252. data/app/components/ariadne/tooltip_component/tooltip-component.d.ts +0 -24
  253. data/app/components/ariadne/tooltip_component/tooltip-component.js +0 -43
  254. data/app/components/ariadne/tooltip_component/tooltip-component.ts +0 -57
  255. data/app/components/ariadne/tooltip_component/tooltip_component.html.erb +0 -4
  256. data/app/components/ariadne/tooltip_component.rb +0 -108
  257. data/app/lib/ariadne/action_view_extensions/form_helper.rb +0 -30
  258. data/app/lib/ariadne/audited/dsl.rb +0 -32
  259. data/app/lib/ariadne/form_builder.rb +0 -80
  260. data/app/lib/ariadne/status/dsl.rb +0 -41
  261. data/config/importmap.rb +0 -3
  262. data/exe/tailwindcss +0 -21
  263. data/lib/rubocop/cop/ariadne/base_cop.rb +0 -26
  264. data/tailwind.config.js +0 -70
@@ -0,0 +1,69 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ module Ariadne
5
+ module UI
6
+ module Image
7
+ # @example Default
8
+ #
9
+ # <%= render(Ariadne::ImageComponent.new(src: "https://github.com/github.png", alt: "GitHub")) %>
10
+ #
11
+ # @example Helper
12
+ #
13
+ # <%= ariadne_image(src: "https://github.com/github.png", alt: "GitHub") %>
14
+ #
15
+ # @example Lazy loading
16
+ #
17
+ # <%= render(Ariadne::ImageComponent.new(src: "https://github.com/github.png", alt: "GitHub", lazy: true)) %>
18
+ #
19
+ # @example Custom size
20
+ #
21
+ # <%= render(Ariadne::ImageComponent.new(src: "https://github.com/github.png", alt: "GitHub", attributes: { height: 100, width: 100 })) %>
22
+ #
23
+ # @param tag [Symbol, String] The rendered tag name
24
+ # @param src [String] The source url of the image.
25
+ # @param alt [String] Specifies an alternate text for the image.
26
+ # @param lazy [Boolean] Whether or not to lazily load the image.
27
+ # @param classes [String] <%= link_to_classes_docs %>
28
+ # @param attributes [Hash] <%= link_to_attributes_docs %>
29
+ class Component < Ariadne::BaseComponent
30
+ option :src
31
+ option :alt
32
+ option :size, default: -> { :original }
33
+ option :lazy, default: -> { false }
34
+
35
+ accepts_html_attributes do |html_attrs|
36
+ html_attrs[:class] = Ariadne::ViewComponents.tailwind_merger.merge([style(size: @size), html_attrs[:class]].join(" "))
37
+
38
+ html_attrs[:src] = @src
39
+ html_attrs[:alt] = @alt
40
+
41
+ next unless @lazy
42
+
43
+ html_attrs[:loading] = :lazy
44
+ html_attrs[:decoding] = :async
45
+ end
46
+
47
+ style do
48
+ base do
49
+ ["ariadne-object-cover", "ariadne-object-center"]
50
+ end
51
+
52
+ variants do
53
+ size do
54
+ xs { "ariadne-w-4" }
55
+ sm { "ariadne-w-6" }
56
+ md { "ariadne-w-8" }
57
+ lg { "ariadne-w-12" }
58
+ xl { "ariadne-w-16" }
59
+ end
60
+ end
61
+ end
62
+
63
+ erb_template <<~ERB
64
+ <img class="<%= html_attrs[:class] %>" <%= html_attributes %> />
65
+ ERB
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,3 @@
1
+ <a href="<%= href %>" class="<%= style(theme:, size:) %>" <%= html_attributes %>>
2
+ <%= content %>
3
+ </a>
@@ -0,0 +1,56 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ module Ariadne
5
+ module UI
6
+ module Link
7
+ class Component < Ariadne::BaseComponent
8
+ option :href
9
+
10
+ option :theme, default: proc { :base }
11
+ option :size, default: proc { :base }
12
+
13
+ include Ariadne::Behaviors::Tooltipable
14
+
15
+ style do
16
+ base do
17
+ [
18
+ "ariadne-inline-flex",
19
+ "ariadne-items-center",
20
+ "ariadne-border-b",
21
+ "ariadne-border-transparent",
22
+ ]
23
+ end
24
+
25
+ variants do
26
+ theme do
27
+ base do
28
+ [
29
+ "[&>svg]:ariadne-text-zinc-400",
30
+ "[&>svg]:dark:ariadne-text-zinc-600",
31
+ "hover:ariadne-text-indigo-600",
32
+ "dark:hover:ariadne-text-indigo-400",
33
+ "hover:ariadne-border-indigo-600",
34
+ "dark:hover:ariadne-border-indigo-400",
35
+ "focus:ariadne-text-indigo-600",
36
+ "dark:focus:ariadne-text-indigo-400",
37
+ "focus:!ariadne-border-transparent",
38
+ "active:ariadne-bg-indigo-700/10",
39
+ "active:dark:ariadne-bg-indigo-300/10",
40
+ ]
41
+ end
42
+ nude { "" }
43
+ thick { "ariadne-font-semibold" }
44
+ end
45
+ size do
46
+ xs { "ariadne-text-xs ariadne-gap-0.5 [&>svg]:ariadne-size-3" }
47
+ sm { "ariadne-text-sm ariadne-gap-0.5 [&>svg]:ariadne-size-4" }
48
+ md { "ariadne-text-base ariadne-gap-1 [&>svg]:ariadne-size-4" }
49
+ lg { "ariadne-text-lg ariadne-gap-1 [&>svg]:ariadne-size-5" }
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,3 @@
1
+ <%= content_tag(tag_name, html_attrs) do %>
2
+ <%= content %>
3
+ <% end %>
@@ -0,0 +1,41 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ module Ariadne
5
+ module UI
6
+ module Typography
7
+ class Component < Ariadne::BaseComponent
8
+ option :type
9
+
10
+ accepts_html_attributes do |html_attrs|
11
+ html_attrs[:class] = Ariadne::ViewComponents.tailwind_merger.merge([style(type: @type), html_attrs[:class]].join(" "))
12
+ end
13
+
14
+ def tag_name
15
+ case type
16
+ when :heading
17
+ :h1
18
+ else
19
+ :span
20
+ end
21
+ end
22
+
23
+ style do
24
+ variants do
25
+ type do
26
+ heading do
27
+ [
28
+ "ariadne-scroll-m-20",
29
+ "ariadne-text-4xl",
30
+ "ariadne-font-extrabold",
31
+ "ariadne-tracking-tight",
32
+ "lg:ariadne-text-5xl",
33
+ ]
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ariadne
4
+ # :nodoc:
5
+ module AttributesHelper
6
+ PLURAL_ARIA_ATTRIBUTES = [:describedby, :labelledby].freeze
7
+ PLURAL_DATA_ATTRIBUTES = [:target, :targets].freeze
8
+
9
+ def prepend_controller(html_attrs, name = stimulus_name)
10
+ prepend_data_attribute(html_attrs, :controller, name)
11
+ end
12
+
13
+ def prepend_action(html_attrs, action)
14
+ prepend_data_attribute(html_attrs, :action, action)
15
+ end
16
+
17
+ def prepend_data_attribute(html_attrs, attr_name, attr_value)
18
+ html_attrs[:data] ||= {}
19
+ html_attrs[:data][attr_name] = "#{attr_value} #{html_attrs[:data][attr_name]}".strip
20
+ html_attrs
21
+ end
22
+
23
+ def aria(html_attrs, val)
24
+ html_attrs[:"aria-#{val}"] || html_attrs.dig(:aria, val.to_sym)
25
+ end
26
+
27
+ def data(html_attrs, val)
28
+ html_attrs[:"data-#{val}"] || html_attrs.dig(:data, val.to_sym)
29
+ end
30
+
31
+ # Merges hashes that contain "aria-*" keys and nested aria: hashes. Removes keys from
32
+ # each hash and returns them in the new hash.
33
+ #
34
+ # Eg. merge_aria({ "aria-disabled": "true" }, { aria: { invalid: "true" } })
35
+ # => { disabled: "true", invalid: "true" }
36
+ #
37
+ # Certain aria attributes can contain multiple values separated by spaces. merge_aria
38
+ # will combine these plural attributes into a composite string.
39
+ #
40
+ # Eg. merge_aria({ "aria-labelledby": "foo" }, { aria: { labelledby: "bar" } })
41
+ # => { labelledby: "foo bar" }
42
+ #
43
+ # It's designed to be used to normalize and merge aria information from system_arguments
44
+ # hashes. Consider using this pattern in component initializers:
45
+ #
46
+ # @system_arguments[:aria] = merge_aria(
47
+ # @system_arguments,
48
+ # { aria: { labelled_by: id } }
49
+ # )
50
+ def merge_aria(*hashes)
51
+ merge_prefixed_attribute_hashes(
52
+ *hashes, prefix: :aria, plural_keys: PLURAL_ARIA_ATTRIBUTES
53
+ )
54
+ end
55
+
56
+ # Merges hashes that contain "data-*" keys and nested data: hashes. Removes keys from
57
+ # each hash and returns them in the new hash.
58
+ #
59
+ # Eg. merge_data({ "data-foo": "true" }, { data: { bar: "true" } })
60
+ # => { foo: "true", bar: "true" }
61
+ #
62
+ # Certain data attributes can contain multiple values separated by spaces. merge_data
63
+ # will combine these plural attributes into a composite string.
64
+ #
65
+ # Eg. merge_data({ "data-target": "foo" }, { data: { target: "bar" } })
66
+ # => { target: "foo bar" }
67
+ #
68
+ # It's designed to be used to normalize and merge data information from system_arguments
69
+ # hashes. Consider using this pattern in component initializers:
70
+ #
71
+ # @system_arguments[:data] = merge_aria(
72
+ # @system_arguments,
73
+ # { data: { foo: "bar" } }
74
+ # )
75
+ def merge_data(*hashes)
76
+ merge_prefixed_attribute_hashes(
77
+ *hashes, prefix: :data, plural_keys: PLURAL_DATA_ATTRIBUTES
78
+ )
79
+ end
80
+
81
+ def merge_prefixed_attribute_hashes(*hashes, prefix:, plural_keys:)
82
+ {}.tap do |result|
83
+ hashes.each do |hash|
84
+ next unless hash
85
+
86
+ prefix_hash = hash.delete(prefix) || {}
87
+
88
+ prefix_hash.each_pair do |key, val|
89
+ result[key] =
90
+ if plural_keys.include?(key)
91
+ [*(result[key] || "").split, val].join(" ").strip
92
+ else
93
+ val
94
+ end
95
+ end
96
+
97
+ hash.delete_if do |key, val|
98
+ key_s = key.to_s
99
+
100
+ if key.start_with?("#{prefix}-")
101
+ bare_key = key_s.sub("#{prefix}-", "").to_sym
102
+
103
+ result[bare_key] =
104
+ if plural_keys.include?(bare_key)
105
+ [*(result[bare_key] || "").split, val].join(" ").strip
106
+ else
107
+ val
108
+ end
109
+
110
+ true
111
+ else
112
+ false
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -34,7 +34,7 @@ module Ariadne
34
34
  check_against_given_value = against || given_value
35
35
  if allowed_values.include?(check_against_given_value)
36
36
  given_value
37
- else
37
+ elsif fallback_raises
38
38
  raise InvalidValueError, <<~MSG
39
39
  fetch_or_raise was called with an invalid value.
40
40
 
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ariadne
4
+ # :nodoc:
5
+ module Form
6
+ def self.inline_form(builder, base = nil, &block)
7
+ base ||= defined?(ApplicationForm) ? ApplicationForm : Ariadne::Forms::Base
8
+
9
+ klass = Class.new(base) do
10
+ form(&block)
11
+ end
12
+
13
+ klass.new(builder)
14
+ end
15
+ end
16
+ end
@@ -7,14 +7,11 @@ module Ariadne
7
7
  class ViewHelperNotFound < StandardError; end
8
8
 
9
9
  HELPERS = {
10
- heroicon: "Ariadne::HeroiconComponent",
11
- heading: "Ariadne::HeadingComponent",
12
- time_ago: "Ariadne::TimeAgoComponent",
13
- image: "Ariadne::ImageComponent",
10
+ heroicon: "Ariadne::UI::Heroicon::Component",
14
11
  }.freeze
15
12
 
16
13
  HELPERS.each do |name, component|
17
- define_method "ariadne_#{name}" do |*args, **kwargs, &block|
14
+ define_method :"ariadne_#{name}" do |*args, **kwargs, &block|
18
15
  render component.constantize.new(*args, **kwargs), &block
19
16
  end
20
17
  end
@@ -0,0 +1,64 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ require "action_view/helpers/tag_helper"
5
+
6
+ module ViewComponentContrib
7
+ module HTMLAttrs
8
+ class AttributesHash < ::Hash
9
+ TAG_BUILDER = ActionView::Helpers::TagHelper::TagBuilder.new(nil)
10
+ TAG_OPTIONS = ActionView::Helpers::TagHelper::TagBuilder.instance_method(:tag_options)
11
+
12
+ def to_html(nested: false)
13
+ # TODO: implement + change usage by @tag nested-attributes
14
+ tag_options(self)&.html_safe # rubocop:disable Rails/OutputSafety
15
+ end
16
+ private def tag_options(...) = TAG_OPTIONS.bind_call(TAG_BUILDER, ...)
17
+ end
18
+
19
+ extend ActiveSupport::Concern
20
+
21
+ class_methods do
22
+ def accepts_html_attributes_for(name, **defaults, &block)
23
+ html_attribute_accessors[name] = defaults
24
+
25
+ name = name.to_sym
26
+ method_name = :"#{name}_attrs"
27
+ ivar_name = :"@#{method_name}"
28
+
29
+ attr_reader(method_name)
30
+
31
+ mod = Module.new do
32
+ define_method(:initialize) do |**options|
33
+ value = self.class.default_html_attributes_for(name).deep_merge!(options.delete(method_name).to_h)
34
+ super(**options)
35
+ instance_exec(value, &block) if block
36
+ instance_variable_set(ivar_name, value)
37
+ end
38
+ end
39
+
40
+ prepend(mod)
41
+ end
42
+
43
+ def accepts_html_attributes(**defaults, &block)
44
+ accepts_html_attributes_for(:html, **defaults, &block)
45
+ end
46
+
47
+ def html_attribute_accessors
48
+ @html_attribute_accessors ||=
49
+ if superclass.respond_to?(:html_attribute_accessors)
50
+ superclass.html_attribute_accessors.deep_dup
51
+ else
52
+ {}
53
+ end
54
+ end
55
+
56
+ def default_html_attributes_for(name)
57
+ html_attribute_accessors.fetch(name).each_with_object(AttributesHash.new) do |(k, v), acc|
58
+ acc[k] = v.is_a?(Proc) ? v.call : v
59
+ acc
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponentContrib
4
+ module StyleVariants
5
+ module ClassMethods
6
+ # Returns the name of the default style set based on the class name:
7
+ # MyComponent::Component => my_component
8
+ # Namespaced::MyComponent => my_component
9
+ def default_style_name
10
+ @default_style_name ||= name.split("::")[-2].underscore.presence || "component"
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+
5
+ module Ariadne
6
+ module Forms
7
+ # :nodoc:
8
+ module ActsAsComponent
9
+ # :nodoc:
10
+ module InstanceMethods
11
+ delegate :render, :content_tag, :output_buffer, to: :@view_context
12
+
13
+ def render_in(view_context, &block)
14
+ @view_context = view_context
15
+ before_render
16
+ perform_render(&block)
17
+ end
18
+
19
+ # This is necessary to restore the functionality changed by https://github.com/rails/rails/pull/47194.
20
+ # I would love to remove this at some point, perhaps if we ever decide to replace
21
+ # ActsAsComponent with view component.
22
+ def capture(*args, &block)
23
+ old_buffer = @view_context.output_buffer
24
+ @view_context.output_buffer = ActionView::OutputBuffer.new
25
+ @view_context.capture(*args, &block)
26
+ ensure
27
+ @view_context.output_buffer = old_buffer
28
+ end
29
+
30
+ # :nocov:
31
+ def perform_render(&_block)
32
+ raise NotImplementedError, "subclasses must implement ##{__method__}."
33
+ end
34
+ # :nocov:
35
+
36
+ def before_render; end
37
+
38
+ # :nocov:
39
+ def set_original_view_context(view_context)
40
+ @view_context = view_context
41
+ end
42
+ # :nocov:
43
+ end
44
+
45
+ def self.extended(base)
46
+ base.include(InstanceMethods)
47
+ end
48
+
49
+ TemplateGlob = Struct.new(:glob_pattern, :method_name, :on_compile_callback)
50
+ TemplateParams = Struct.new(:source, :identifier, :type, :format, keyword_init: true)
51
+
52
+ attr_accessor :template_root_path
53
+
54
+ def renders_templates(glob_pattern, method_name = nil, &block)
55
+ template_globs << TemplateGlob.new(glob_pattern, method_name, block)
56
+ end
57
+ alias_method :renders_template, :renders_templates
58
+
59
+ def compile!
60
+ # always recompile in dev
61
+ return if defined?(@compiled) && @compiled && !Rails.env.development?
62
+
63
+ template_globs.each do |template_glob|
64
+ compile_templates_in(template_glob)
65
+ end
66
+
67
+ @compiled = true
68
+ end
69
+
70
+ private
71
+
72
+ def template_globs
73
+ @template_globs ||= []
74
+ end
75
+
76
+ def compile_templates_in(template_glob)
77
+ pattern = if Pathname(template_glob.glob_pattern).absolute?
78
+ template_glob.glob_pattern
79
+ else
80
+ # skip compilation for anonymous form classes, as in tests
81
+ return unless template_root_path
82
+
83
+ File.join(template_root_path, template_glob.glob_pattern)
84
+ end
85
+
86
+ template_paths = Dir.glob(pattern)
87
+
88
+ raise "Cannot compile multiple templates with the same method name." if template_paths.size > 1 && template_glob.method_name
89
+
90
+ template_paths.each do |template_path|
91
+ method_name = template_glob.method_name
92
+ method_name ||= "render_#{File.basename(template_path).chomp(".html.erb")}"
93
+ define_template_method(template_path, method_name)
94
+ template_glob&.on_compile_callback&.call(template_path)
95
+ end
96
+ end
97
+
98
+ def define_template_method(template_path, method_name)
99
+ class_eval(<<-RUBY, template_path, 0)
100
+ private def #{method_name}
101
+ capture { #{compile_template(template_path)} }
102
+ end
103
+ RUBY
104
+ # rubocop:enable Style/EvalWithLocation
105
+ # rubocop:enable Style/DocumentDynamicEvalDefinition
106
+ end
107
+
108
+ def compile_template(path)
109
+ handler = ActionView::Template.handler_for_extension("erb")
110
+ template = File.read(path)
111
+ template_params = TemplateParams.new({
112
+ source: template,
113
+ identifier: __FILE__,
114
+ type: "text/html",
115
+ format: "text/html",
116
+ })
117
+
118
+ # change @output_buffer ivar to output_buffer method call
119
+ BufferRewriter.rewrite(
120
+ handler.call(template_params, template),
121
+ )
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,8 @@
1
+ <div class="ariadne-flex ariadne-flex-col ariadne-gap-8">
2
+ <% inputs.each do |input| %>
3
+ <%= render(input.to_component) %>
4
+ <% end %>
5
+ </div>
6
+ <% if after_content? %>
7
+ <%= render_after_content %>
8
+ <% end %>
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ariadne
4
+ module Forms
5
+ # :nodoc:
6
+ class Base
7
+ extend ActsAsComponent
8
+
9
+ renders_template File.join(__dir__, "base.html.erb"), :render_base_form
10
+
11
+ class << self
12
+ attr_reader :has_after_content, :__vcf_form_block, :__vcf_builder
13
+ alias_method :after_content?, :has_after_content
14
+
15
+ def form(&block)
16
+ @__vcf_form_block = block
17
+ end
18
+
19
+ def new(builder, **options)
20
+ if builder && !builder.is_a?(Ariadne::Forms::Builder)
21
+ raise ArgumentError, "please pass an instance of Ariadne::Forms::Builder when " \
22
+ "constructing a form object (consider using the `ariadne_form_with` helper)"
23
+ end
24
+
25
+ allocate.tap do |form|
26
+ form.instance_variable_set(:@builder, builder)
27
+ form.send(:initialize, **options)
28
+ end
29
+ end
30
+
31
+ def inherited(base)
32
+ form_path = Ariadne::Forms::Utils.const_source_location(base.name)
33
+ return unless form_path
34
+
35
+ base.template_root_path = File.join(File.dirname(form_path), base.name.demodulize.underscore)
36
+
37
+ base.renders_template("after_content.html.erb") do
38
+ base.instance_variable_set(:@has_after_content, true)
39
+ end
40
+
41
+ base.renders_templates("*_caption.html.erb") do |path|
42
+ base.fields_with_caption_templates << File.basename(path).chomp("_caption.html.erb").to_sym
43
+ end
44
+ end
45
+
46
+ def caption_template?(field_name)
47
+ fields_with_caption_templates.include?(sanitize_field_name_for_template_path(field_name))
48
+ end
49
+
50
+ def fields_with_caption_templates
51
+ @fields_with_caption_templates ||= []
52
+ end
53
+
54
+ def sanitize_field_name_for_template_path(field_name)
55
+ field_name.to_s.delete_suffix("?").to_sym
56
+ end
57
+ end
58
+
59
+ def inputs
60
+ @inputs ||= form_object.inputs.map do |input|
61
+ next input unless input.input?
62
+
63
+ # wrap inputs in a group (unless they are already groups)
64
+ if input.type == :group
65
+ input
66
+ else
67
+ Ariadne::Forms::Dsl::InputGroup.new(builder: @builder, form: self) do |group|
68
+ group.send(:add_input, input)
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ def each_input_in(root_input, &block)
75
+ return enum_for(__method__, root_input) unless block
76
+
77
+ root_input.inputs.each do |input|
78
+ if input.respond_to?(:inputs)
79
+ each_input_in(input, &block)
80
+ else
81
+ yield input
82
+ end
83
+ end
84
+ end
85
+
86
+ def before_render
87
+ each_input_in(self) do |input|
88
+ if input.input? && input.invalid? && input.focusable?
89
+ input.autofocus!
90
+ break
91
+ end
92
+ end
93
+ end
94
+
95
+ def caption_template?(*args)
96
+ self.class.caption_template?(*args)
97
+ end
98
+
99
+ def after_content?(*args)
100
+ self.class.after_content?(*args)
101
+ end
102
+
103
+ def render_caption_template(field_name)
104
+ send(:"render_#{self.class.sanitize_field_name_for_template_path(field_name)}_caption")
105
+ end
106
+
107
+ def perform_render(&_block)
108
+ return "" unless render?
109
+
110
+ Base.compile!
111
+ self.class.compile!
112
+
113
+ render_base_form
114
+ end
115
+
116
+ def render?
117
+ true
118
+ end
119
+
120
+ private
121
+
122
+ def form_object
123
+ @__pf_form_object ||= Ariadne::Forms::Dsl::FormObject.new(builder: @builder, form: self).tap do |obj|
124
+ # compile before adding inputs so caption templates are identified
125
+ self.class.compile!
126
+ instance_exec(obj, &self.class.__vcf_form_block)
127
+ end
128
+ # rubocop:enable Naming/MemoizedInstanceVariableName
129
+ end
130
+ end
131
+ end
132
+ end