anchor_view_components 0.20.1 → 0.22.0

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 (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