anchor_view_components 0.20.1 → 0.22.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -0
  3. data/app/assets/builds/anchor-view-components.css +1 -1
  4. data/app/assets/images/icons/calendar.svg +7 -0
  5. data/app/assets/images/icons/check.svg +4 -0
  6. data/app/assets/images/icons/paste-clipboard.svg +5 -0
  7. data/app/assets/images/icons/search.svg +5 -0
  8. data/app/assets/stylesheets/components/button.css +1 -1
  9. data/app/components/anchor/action_menu_component.html.erb +8 -10
  10. data/app/components/anchor/action_menu_component.rb +15 -6
  11. data/app/components/anchor/anchor_view_components.ts +2 -0
  12. data/app/components/anchor/autocomplete_component.html.erb +6 -7
  13. data/app/components/anchor/autocomplete_component.rb +29 -8
  14. data/app/components/anchor/badge_component.html.erb +3 -6
  15. data/app/components/anchor/badge_component.rb +0 -10
  16. data/app/components/anchor/banner_component.html.erb +1 -7
  17. data/app/components/anchor/banner_component.rb +0 -10
  18. data/app/components/anchor/button_component.html.erb +10 -17
  19. data/app/components/anchor/button_component.rb +14 -21
  20. data/app/components/anchor/component.rb +22 -5
  21. data/app/components/anchor/copy_to_clipboard_component.en.yml +2 -0
  22. data/app/components/anchor/copy_to_clipboard_component.html.erb +21 -0
  23. data/app/components/anchor/copy_to_clipboard_component.rb +15 -0
  24. data/app/components/anchor/copy_to_clipboard_controller.ts +34 -0
  25. data/app/components/anchor/dialog_component.html.erb +3 -4
  26. data/app/components/anchor/icon_component.html.erb +1 -3
  27. data/app/components/anchor/icon_component.rb +1 -1
  28. data/app/components/anchor/loading_indicator_component.html.erb +3 -4
  29. data/app/components/anchor/logo_component.html.erb +1 -4
  30. data/app/components/anchor/logo_component.rb +1 -1
  31. data/app/components/anchor/panel/body_component.html.erb +3 -5
  32. data/app/components/anchor/panel_component.html.erb +3 -1
  33. data/app/components/anchor/popover_component.html.erb +3 -7
  34. data/app/components/anchor/popover_controller.ts +21 -15
  35. data/app/components/anchor/prose_component.html.erb +5 -4
  36. data/app/components/anchor/radio_button_collection_component.html.erb +1 -0
  37. data/app/components/anchor/radio_button_collection_component.rb +35 -0
  38. data/app/components/anchor/radio_button_component.html.erb +11 -0
  39. data/app/components/anchor/radio_button_component.rb +105 -0
  40. data/app/components/anchor/side_nav_component.html.erb +8 -9
  41. data/app/components/anchor/side_nav_component.rb +4 -1
  42. data/app/components/anchor/tab_bar/tab_component.html.erb +8 -6
  43. data/app/components/anchor/tab_bar/tab_component.rb +2 -2
  44. data/app/components/anchor/tab_bar_component.html.erb +3 -4
  45. data/app/components/anchor/tab_bar_component.rb +3 -2
  46. data/app/components/anchor/table_component.rb +1 -1
  47. data/app/components/anchor/text_component.html.erb +1 -6
  48. data/app/components/anchor/text_component.rb +5 -14
  49. data/app/components/anchor/text_field_component.html.erb +19 -1
  50. data/app/components/anchor/text_field_component.rb +35 -16
  51. data/app/components/anchor/toast_component.html.erb +5 -8
  52. data/app/components/anchor/toast_component.rb +8 -12
  53. data/app/components/anchor/toast_controller.ts +5 -1
  54. data/app/helpers/anchor/fetch_or_fallback_helper.rb +26 -0
  55. data/app/helpers/anchor/form_builder.rb +52 -29
  56. data/app/helpers/anchor/tailwind_constants.rb +0 -37
  57. data/app/helpers/anchor/view_helper.rb +11 -0
  58. data/lib/anchor/view_components/engine.rb +0 -1
  59. data/lib/anchor/view_components/version.rb +1 -1
  60. data/previews/anchor/copy_to_clipboard_component_preview.rb +7 -0
  61. data/previews/anchor/forms_preview.rb +45 -0
  62. data/previews/forms/default.html.erb +6 -4
  63. data/previews/forms/radio_button_collection.html.erb +51 -0
  64. data/previews/forms/with_icons.html.erb +10 -0
  65. metadata +17 -2
@@ -14,25 +14,21 @@ module Anchor
14
14
  }.freeze
15
15
  VARIANT_OPTIONS = VARIANT_MAPPINGS.keys
16
16
 
17
- def initialize(
18
- id: self.class.generate_id,
19
- role: :alert,
20
- variant: VARIANT_DEFAULT
21
- )
22
- @variant = VARIANT_MAPPINGS[
23
- fetch_or_fallback(VARIANT_OPTIONS, variant, VARIANT_DEFAULT)
24
- ]
25
- @role = role
26
-
27
- super
17
+ def initialize(id: self.class.generate_id, **kwargs)
18
+ @id = id
19
+ super(**kwargs, id:)
28
20
  end
29
21
 
30
22
  private
31
23
 
32
- attr_reader :variant, :role, :id
24
+ attr_reader :id
33
25
 
34
26
  def render?
35
27
  content.present?
36
28
  end
29
+
30
+ def test_id
31
+ wrapper_options.dig(:data, :testid) || "toast"
32
+ end
37
33
  end
38
34
  end
@@ -15,7 +15,11 @@ export default class extends Controller<HTMLDivElement> {
15
15
  }, this.showDelayValue);
16
16
 
17
17
  setTimeout(() => {
18
- this.element.hidePopover();
18
+ this.element.remove();
19
19
  }, this.hideDelayValue);
20
20
  }
21
+
22
+ disconnect(): void {
23
+ this.element.remove();
24
+ }
21
25
  }
@@ -16,5 +16,31 @@ module Anchor
16
16
  fallback
17
17
  end
18
18
  end
19
+
20
+ private
21
+
22
+ def add_variant_classes_if_available(classes:, variant:)
23
+ if supports_variants?
24
+ variant ||= self.class::VARIANT_DEFAULT
25
+
26
+ variant_class = self.class::VARIANT_MAPPINGS[
27
+ fetch_or_fallback(
28
+ self.class::VARIANT_OPTIONS,
29
+ variant,
30
+ self.class::VARIANT_DEFAULT
31
+ )
32
+ ]
33
+
34
+ [variant_class, *classes]
35
+ else
36
+ classes
37
+ end
38
+ end
39
+
40
+ def supports_variants?
41
+ self.class.const_defined?(:VARIANT_MAPPINGS) \
42
+ && self.class.const_defined?(:VARIANT_DEFAULT) \
43
+ && self.class.const_defined?(:VARIANT_OPTIONS)
44
+ end
19
45
  end
20
46
  end
@@ -2,6 +2,46 @@ module Anchor
2
2
  class FormBuilder < ActionView::Helpers::FormBuilder
3
3
  delegate :concat, :content_tag, :render, to: :@template
4
4
 
5
+ def initialize(object_name, object, template, options, &)
6
+ super(
7
+ object_name,
8
+ object,
9
+ view_component?(template) ? template.helpers : template,
10
+ options,
11
+ &
12
+ )
13
+ end
14
+
15
+ def collection_radio_buttons(
16
+ attribute,
17
+ collection,
18
+ value_method,
19
+ text_method,
20
+ options = {},
21
+ html_options = {}
22
+ )
23
+ render RadioButtonCollectionComponent.new(
24
+ form_builder: self,
25
+ attribute:,
26
+ collection:,
27
+ value_method:,
28
+ text_method:,
29
+ **options,
30
+ **html_options
31
+ ) do |component|
32
+ super(
33
+ attribute,
34
+ collection,
35
+ value_method,
36
+ text_method,
37
+ options,
38
+ component.options.merge(html_options),
39
+ ) do |radio|
40
+ render component.radio(radio:)
41
+ end
42
+ end
43
+ end
44
+
5
45
  def error_message_for(attribute, options = {})
6
46
  render ErrorMessageComponent.new(
7
47
  form_builder: self,
@@ -24,7 +64,9 @@ module Anchor
24
64
  def text_field(attribute, options = {})
25
65
  render TextFieldComponent.new(
26
66
  form_builder: self,
27
- attribute:
67
+ attribute:,
68
+ starting_icon: options.delete(:starting_icon),
69
+ ending_icon: options.delete(:ending_icon)
28
70
  ) do |component|
29
71
  super attribute, component.options.merge(options)
30
72
  end
@@ -32,33 +74,6 @@ module Anchor
32
74
 
33
75
  # The following methods are pending to be replaced with ViewComponents.
34
76
 
35
- def collection_radio_buttons(
36
- attribute,
37
- collection,
38
- value_method,
39
- text_method,
40
- options = {},
41
- html_options = {}
42
- )
43
- content_tag :div, class: "flex flex-col space-y-2 text-base" do
44
- super(
45
- attribute,
46
- collection,
47
- value_method,
48
- text_method,
49
- options,
50
- html_options.merge(class: Anchor::TailwindConstants::RADIO)
51
- ) do |radio|
52
- content_tag :div, class: "inline-flex items-center gap-1" do
53
- concat(radio.radio_button(
54
- data: { testId: "radio-#{attribute}-#{radio.value}".dasherize }
55
- ))
56
- concat(radio.label { i18n_label("#{attribute}.#{radio.value}") })
57
- end
58
- end
59
- end
60
- end
61
-
62
77
  def datetime_field(attribute, options = {})
63
78
  super attribute, options.merge(class: Anchor::TailwindConstants::INPUT)
64
79
  end
@@ -111,7 +126,15 @@ module Anchor
111
126
  private
112
127
 
113
128
  def i18n_label(attribute)
114
- object.class.human_attribute_name attribute
129
+ if object.class.respond_to?(:human_attribute_name)
130
+ object.class.human_attribute_name(attribute)
131
+ else
132
+ attribute
133
+ end
134
+ end
135
+
136
+ def view_component?(template)
137
+ template.is_a? ViewComponent::Base
115
138
  end
116
139
  end
117
140
  end
@@ -11,7 +11,6 @@ module Anchor
11
11
  text-base
12
12
  min-h-[40px]
13
13
  resize-none
14
- mt-1
15
14
  block
16
15
  w-full
17
16
  rounded
@@ -21,42 +20,6 @@ module Anchor
21
20
  [&[readonly]]:shadow-none
22
21
  ).freeze
23
22
 
24
- RADIO = %w(
25
- appearance-none
26
- w-[18px]
27
- m-[3px]
28
- aspect-square
29
- rounded-full
30
- border-2
31
- border-grey-60
32
- hover:border-grey-80
33
- checked:bg-gradient-radial
34
- checked:from-blue-50
35
- checked:from-[50%]
36
- checked:to-transparent
37
- checked:to-[54%]
38
- checked:border-blue-50
39
- checked:hover:from-blue-60
40
- checked:hover:from-[50%]
41
- checked:hover:to-transparent
42
- checked:hover:to-[54%]
43
- checked:hover:border-blue-60
44
- disabled:border-grey-40
45
- disabled:checked:border-grey-40
46
- disabled:checked:from-grey-40
47
- disabled:checked:from-[50%]
48
- disabled:checked:to-transparent
49
- disabled:checked:to-[54%]
50
- disabled:checked:border-grey-40
51
- aria-readonly:border-grey-40
52
- aria-readonly:checked:border-grey-40
53
- aria-readonly:checked:from-grey-40
54
- aria-readonly:checked:from-[50%]
55
- aria-readonly:checked:to-transparent
56
- aria-readonly:checked:to-[54%]
57
- aria-readonly:checked:border-grey-40
58
- ).freeze
59
-
60
23
  TEXT_AREA = %w(
61
24
  h-[120px]
62
25
  ).freeze
@@ -7,6 +7,7 @@ module Anchor
7
7
  banner
8
8
  breadcrumbs
9
9
  button
10
+ copy_to_clipboard
10
11
  dialog
11
12
  favicons
12
13
  icon
@@ -67,6 +68,7 @@ module Anchor
67
68
  file = ::Anchor::ViewComponents::SvgResolver.resolve(name)
68
69
  doc = Nokogiri::HTML::DocumentFragment.parse(file)
69
70
  svg = doc.at_css "svg"
71
+ attributes[:class] = class_names(attributes[:class])
70
72
 
71
73
  attributes.each_pair do |key, value|
72
74
  svg[key] = value
@@ -89,5 +91,14 @@ module Anchor
89
91
  popovertarget:,
90
92
  }
91
93
  end
94
+
95
+ def merge_options(original, new)
96
+ original.except(:class, :data, :aria).merge(
97
+ aria: original.fetch(:aria, {}).merge(new.delete(:aria) || {}),
98
+ class: class_names(original[:class], new.delete(:class)),
99
+ data: original.fetch(:data, {}).merge(new.delete(:data) || {}),
100
+ **new
101
+ )
102
+ end
92
103
  end
93
104
  end
@@ -25,7 +25,6 @@ module Anchor
25
25
 
26
26
  initializer "anchor_view_components.helper" do
27
27
  ActiveSupport.on_load(:action_controller_base) do
28
- require "anchor/view_helper"
29
28
  helper Anchor::ViewHelper
30
29
  end
31
30
  end
@@ -1,5 +1,5 @@
1
1
  module Anchor
2
2
  module ViewComponents
3
- VERSION = "0.20.1".freeze
3
+ VERSION = "0.22.0".freeze
4
4
  end
5
5
  end
@@ -0,0 +1,7 @@
1
+ module Anchor
2
+ class CopyToClipboardComponentPreview < Preview
3
+ def default
4
+ anchor_copy_to_clipboard(value: "Copy Me")
5
+ end
6
+ end
7
+ end
@@ -1,16 +1,61 @@
1
1
  module Anchor
2
2
  class FormsPreview < Preview
3
+ Option = Data.define(:value, :text, :description)
4
+
3
5
  def default
4
6
  model = FakeUser.new(name: "Jerry Seinfeld")
5
7
 
6
8
  render_with_template(template: "forms/default", locals: { model: })
7
9
  end
8
10
 
11
+ def with_icons
12
+ render_with_template(template: "forms/with_icons")
13
+ end
14
+
9
15
  def with_errors
10
16
  model = FakeUser.new
11
17
  model.valid?
12
18
 
13
19
  render_with_template(template: "forms/default", locals: { model: })
14
20
  end
21
+
22
+ def radio_button_collection
23
+ model = FakeUser.new
24
+
25
+ render_with_template(
26
+ template: "forms/radio_button_collection",
27
+ locals: { model:, object_options:, hash_options: }
28
+ )
29
+ end
30
+
31
+ private
32
+
33
+ def object_options
34
+ [
35
+ Option.new(
36
+ value: "english",
37
+ text: "English",
38
+ description: "Object #1"
39
+ ),
40
+ Option.new(
41
+ value: "portuguese",
42
+ text: "Portuguese",
43
+ description: "Object #2"
44
+ ),
45
+ Option.new(
46
+ value: "spanish",
47
+ text: "Spanish",
48
+ description: "Object #3"
49
+ ),
50
+ ]
51
+ end
52
+
53
+ def hash_options
54
+ [
55
+ { value: "english", text: "English", description: "Hash #1" },
56
+ { value: "portuguese", text: "Portuguese", description: "Hash #2" },
57
+ { value: "spanish", text: "Spanish", description: "Hash #3" },
58
+ ]
59
+ end
15
60
  end
16
61
  end
@@ -1,5 +1,7 @@
1
- <%= anchor_form_with model:, url: false do |form| %>
2
- <%= form.label :name %>
3
- <%= form.text_field :name %>
4
- <%= form.error_message_for :name %>
1
+ <%= anchor_form_with model:, url: false, class: "flex flex-col gap-4" do |form| %>
2
+ <%= tag.div do %>
3
+ <%= form.label :name %>
4
+ <%= form.text_field :name %>
5
+ <%= form.error_message_for :name %>
6
+ <% end %>
5
7
  <% end %>
@@ -0,0 +1,51 @@
1
+ <div class="space-y-5">
2
+ <%= anchor_form_with url: false do |form| %>
3
+ <%= tag.div do %>
4
+ <%= form.legend "Object options" %>
5
+ <%= form.collection_radio_buttons(
6
+ :language,
7
+ object_options,
8
+ :value,
9
+ :text,
10
+ { checked: FakeUser::LANGUAGES.sample }
11
+ ) %>
12
+ <% end %>
13
+ <% end %>
14
+
15
+ <%= anchor_form_with url: false do |form| %>
16
+ <%= tag.div do %>
17
+ <%= form.legend "Hash options" %>
18
+ <%= form.collection_radio_buttons(
19
+ :language,
20
+ hash_options,
21
+ ->(option) { option[:value] },
22
+ ->(option) { option[:text] },
23
+ { checked: FakeUser::LANGUAGES.sample }
24
+ ) %>
25
+ <% end %>
26
+ <% end %>
27
+
28
+ <%= anchor_form_with model:, url: false do |form| %>
29
+ <%= tag.div do %>
30
+ <%= form.legend "Translated descriptions" %>
31
+ <%= form.collection_radio_buttons(
32
+ :language,
33
+ FakeUser::LANGUAGES,
34
+ :to_s,
35
+ :titleize,
36
+ ) %>
37
+ <% end %>
38
+ <% end %>
39
+
40
+ <%= anchor_form_with model: FakeCar.new, url: false do |form| %>
41
+ <%= tag.div do %>
42
+ <%= form.legend "No descriptions" %>
43
+ <%= form.collection_radio_buttons(
44
+ :color,
45
+ FakeCar::COLORS,
46
+ :to_s,
47
+ :titleize,
48
+ ) %>
49
+ <% end %>
50
+ <% end %>
51
+ </div>
@@ -0,0 +1,10 @@
1
+ <%= anchor_form_with url: false, method: :get do |form| %>
2
+ <div class="flex flex-col gap-4">
3
+ <%= form.text_field :search, placeholder: "Search…",
4
+ starting_icon: :search %>
5
+ <%= form.text_field :search, placeholder: "Search…",
6
+ ending_icon: :calendar %>
7
+ <%= form.text_field :search, placeholder: "Search…", starting_icon: :search,
8
+ ending_icon: :calendar %>
9
+ </div>
10
+ <% end %>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: anchor_view_components
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.20.1
4
+ version: 0.22.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Buoy Software
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-26 00:00:00.000000000 Z
11
+ date: 2023-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -55,14 +55,18 @@ files:
55
55
  - app/assets/images/favicon.ico
56
56
  - app/assets/images/favicon.svg
57
57
  - app/assets/images/icons/README.md
58
+ - app/assets/images/icons/calendar.svg
58
59
  - app/assets/images/icons/cancel.svg
59
60
  - app/assets/images/icons/check-circle.svg
61
+ - app/assets/images/icons/check.svg
60
62
  - app/assets/images/icons/fast-left-circle.svg
61
63
  - app/assets/images/icons/loading-indicator.svg
62
64
  - app/assets/images/icons/menu.svg
63
65
  - app/assets/images/icons/nav-arrow-down.svg
64
66
  - app/assets/images/icons/nav-arrow-left.svg
65
67
  - app/assets/images/icons/nav-arrow-right.svg
68
+ - app/assets/images/icons/paste-clipboard.svg
69
+ - app/assets/images/icons/search.svg
66
70
  - app/assets/images/icons/warning-triangle.svg
67
71
  - app/assets/stylesheets/anchor-view-components.tailwind.css
68
72
  - app/assets/stylesheets/components/action-menu.css
@@ -86,6 +90,10 @@ files:
86
90
  - app/components/anchor/button_component.html.erb
87
91
  - app/components/anchor/button_component.rb
88
92
  - app/components/anchor/component.rb
93
+ - app/components/anchor/copy_to_clipboard_component.en.yml
94
+ - app/components/anchor/copy_to_clipboard_component.html.erb
95
+ - app/components/anchor/copy_to_clipboard_component.rb
96
+ - app/components/anchor/copy_to_clipboard_controller.ts
89
97
  - app/components/anchor/dialog_component.html.erb
90
98
  - app/components/anchor/dialog_component.rb
91
99
  - app/components/anchor/dialog_controller.ts
@@ -116,6 +124,10 @@ files:
116
124
  - app/components/anchor/popover_controller.ts
117
125
  - app/components/anchor/prose_component.html.erb
118
126
  - app/components/anchor/prose_component.rb
127
+ - app/components/anchor/radio_button_collection_component.html.erb
128
+ - app/components/anchor/radio_button_collection_component.rb
129
+ - app/components/anchor/radio_button_component.html.erb
130
+ - app/components/anchor/radio_button_component.rb
119
131
  - app/components/anchor/side_nav_component.en.yml
120
132
  - app/components/anchor/side_nav_component.html.erb
121
133
  - app/components/anchor/side_nav_component.rb
@@ -154,6 +166,7 @@ files:
154
166
  - previews/anchor/banner_component_preview.rb
155
167
  - previews/anchor/breadcrumbs_component_preview.rb
156
168
  - previews/anchor/button_component_preview.rb
169
+ - previews/anchor/copy_to_clipboard_component_preview.rb
157
170
  - previews/anchor/dialog_component_preview.rb
158
171
  - previews/anchor/dialog_component_preview/with_custom_show_button.html.erb
159
172
  - previews/anchor/dialog_component_preview/with_footer.html.erb
@@ -173,6 +186,8 @@ files:
173
186
  - previews/anchor/text_component_preview.rb
174
187
  - previews/anchor/toast_component_preview.rb
175
188
  - previews/forms/default.html.erb
189
+ - previews/forms/radio_button_collection.html.erb
190
+ - previews/forms/with_icons.html.erb
176
191
  - previews/pages/forms.md.erb
177
192
  - previews/pages/helpers.md.erb
178
193
  - previews/pages/icons.md.erb