ariadne_view_components 0.0.4 → 0.0.5

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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/app/assets/builds/ariadne_view_components.css +1874 -0
  4. data/app/assets/javascripts/ariadne.d.ts +1 -0
  5. data/app/assets/javascripts/ariadne_view_components.js +1 -1
  6. data/app/assets/javascripts/ariadne_view_components.js.map +1 -1
  7. data/app/assets/javascripts/clipboard-copy-component.d.ts +4 -0
  8. data/app/assets/javascripts/slideover-component.d.ts +9 -0
  9. data/app/assets/javascripts/time_ago_component.d.ts +1 -0
  10. data/app/assets/javascripts/tooltip-component.d.ts +24 -0
  11. data/app/assets/stylesheets/application.ariadne_view_components.css +5 -3
  12. data/app/assets/stylesheets/tooltip-component.css +37 -0
  13. data/app/components/ariadne/ariadne.d.ts +1 -0
  14. data/app/components/ariadne/ariadne.js +9 -0
  15. data/app/components/ariadne/ariadne.ts +3 -0
  16. data/app/components/ariadne/base_button.rb +9 -8
  17. data/app/components/ariadne/blankslate_component.rb +1 -1
  18. data/app/components/ariadne/body_component.rb +30 -0
  19. data/app/components/ariadne/button_component.rb +5 -10
  20. data/app/components/ariadne/clipboard-copy-component.d.ts +4 -0
  21. data/app/components/ariadne/clipboard-copy-component.js +18 -0
  22. data/app/components/ariadne/clipboard_copy_component.d.ts +4 -0
  23. data/app/components/ariadne/clipboard_copy_component.html.erb +2 -2
  24. data/app/components/ariadne/clipboard_copy_component.js +18 -0
  25. data/app/components/ariadne/clipboard_copy_component.rb +41 -3
  26. data/app/components/ariadne/comment_component.html.erb +25 -0
  27. data/app/components/ariadne/comment_component.rb +45 -0
  28. data/app/components/ariadne/component.rb +2 -1
  29. data/app/components/ariadne/container_component.rb +1 -1
  30. data/app/components/ariadne/flash_component.rb +1 -1
  31. data/app/components/ariadne/flex_component.rb +51 -0
  32. data/app/components/ariadne/grid_component.html.erb +12 -3
  33. data/app/components/ariadne/grid_component.rb +18 -7
  34. data/app/components/ariadne/header_component.rb +1 -1
  35. data/app/components/ariadne/heading_component.rb +2 -2
  36. data/app/components/ariadne/heroicon_component.html.erb +4 -6
  37. data/app/components/ariadne/heroicon_component.rb +18 -7
  38. data/app/components/ariadne/inline_flex_component.rb +11 -9
  39. data/app/components/ariadne/link_component.rb +13 -8
  40. data/app/components/ariadne/list_component.html.erb +5 -7
  41. data/app/components/ariadne/list_component.rb +4 -34
  42. data/app/components/ariadne/main_component.rb +32 -0
  43. data/app/components/ariadne/slideover-component.d.ts +9 -0
  44. data/app/components/ariadne/slideover-component.js +20 -0
  45. data/app/components/ariadne/slideover_component.d.ts +9 -0
  46. data/app/components/ariadne/slideover_component.html.erb +1 -4
  47. data/app/components/ariadne/slideover_component.js +19 -0
  48. data/app/components/ariadne/slideover_component.rb +19 -15
  49. data/app/components/ariadne/time_ago_component.d.ts +1 -0
  50. data/app/components/ariadne/time_ago_component.js +1 -0
  51. data/app/components/ariadne/tooltip-component.d.ts +24 -0
  52. data/app/components/ariadne/tooltip-component.js +42 -0
  53. data/app/components/ariadne/tooltip-component.ts +57 -0
  54. data/app/components/ariadne/tooltip_component.html.erb +4 -0
  55. data/app/components/ariadne/tooltip_component.rb +34 -31
  56. data/app/lib/ariadne/form_builder.rb +14 -14
  57. data/lib/ariadne/classify.rb +4 -98
  58. data/lib/ariadne/view_components/version.rb +1 -1
  59. data/lib/ariadne/view_components.rb +31 -29
  60. data/lib/rubocop/cop/ariadne/ariadne_heroicon.rb +2 -2
  61. data/lib/tasks/docs.rake +4 -0
  62. data/static/arguments.yml +89 -13
  63. data/static/audited_at.json +4 -0
  64. data/static/classes.yml +40 -8
  65. data/static/constants.json +83 -101
  66. data/static/statuses.json +4 -0
  67. metadata +48 -6
@@ -6,15 +6,19 @@ module Ariadne
6
6
  # `Heroicon` renders an <%= link_to_heroicons %> with <%= link_to_attributes_docs %>.
7
7
  # `Heroicon` can also be rendered with the `heroicon` helper.
8
8
  class HeroiconComponent < Ariadne::Component
9
+ DEFAULT_TEXT_CLASSES = "pl-2"
10
+
9
11
  include IconHelper
10
12
  include HeroiconsHelper
11
13
 
12
- SIZE_DEFAULT = :s
13
- SIZE_MEDIUM = :m
14
+ SIZE_DEFAULT = :sm
15
+ SIZE_MEDIUM = :md
16
+ SIZE_LARGE = :lg
14
17
 
15
18
  SIZE_MAPPINGS = {
16
19
  SIZE_DEFAULT => 16,
17
20
  SIZE_MEDIUM => 24,
21
+ SIZE_LARGE => 128,
18
22
  }.freeze
19
23
  SIZE_OPTIONS = SIZE_MAPPINGS.keys
20
24
 
@@ -62,7 +66,7 @@ module Ariadne
62
66
  # <%= render(Ariadne::HeroiconComponent.new(icon: :check, variant: HeroiconsHelper::Icon::VARIANT_SOLID)) %>
63
67
  #
64
68
  # @example Medium
65
- # <%= render(Ariadne::HeroiconComponent.new(icon: :"user-group", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, size: :m)) %>
69
+ # <%= render(Ariadne::HeroiconComponent.new(icon: :"user-group", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, size: :md)) %>
66
70
  #
67
71
  # @example Helper
68
72
  # <%= ariadne_heroicon(icon: :check, variant: HeroiconsHelper::Icon::VARIANT_OUTLINE) %>
@@ -73,7 +77,9 @@ module Ariadne
73
77
  # @param variant [String] <%= one_of(HeroiconsHelper::Icon::VARIANTS, sort: false) %>
74
78
  # @param size [Symbol] <%= one_of(Ariadne::HeroiconComponent::SIZE_MAPPINGS, sort: false) %>
75
79
  # @param attributes [Hash] <%= link_to_attributes_docs %>
76
- def initialize(tag: :svg, icon:, variant:, size: SIZE_DEFAULT, classes: "", attributes: {})
80
+ # @param text_classes [String] <%= link_to_classes_docs %>
81
+ # @param text_attributes [Hash] <%= link_to_attributes_docs %>
82
+ def initialize(tag: :svg, icon:, variant:, size: SIZE_DEFAULT, classes: "", attributes: {}, text_classes: "", text_attributes: {})
77
83
  @tag = check_incoming_tag(:svg, tag)
78
84
 
79
85
  check_icon_presence!(icon, variant)
@@ -107,11 +113,16 @@ module Ariadne
107
113
  classes
108
114
  )
109
115
  @attributes.merge!(@icon.attributes.except(:class, :"aria-hidden"))
116
+
117
+ @text_classes = class_names(DEFAULT_TEXT_CLASSES, text_classes)
118
+ @text_attributes = text_attributes
110
119
  end
111
120
 
112
- def self._after_compile
113
- HeroiconsHelper::Cache.preload!(PRELOADED_ICONS) do |found, icon|
114
- HeroiconComponent.new(icon: icon[:name], variant: icon[:variant]) unless found
121
+ class << self
122
+ def _after_compile
123
+ HeroiconsHelper::Cache.preload!(PRELOADED_ICONS) do |found, icon|
124
+ HeroiconComponent.new(icon: icon[:name], variant: icon[:variant]) unless found
125
+ end
115
126
  end
116
127
  end
117
128
  end
@@ -24,19 +24,21 @@ module Ariadne
24
24
  </svg>
25
25
  MSG
26
26
 
27
- renders_one :icon, lambda { |icon, tag: :svg, variant:, size: Ariadne::HeroiconComponent::SIZE_DEFAULT, classes: "", attributes: {}|
28
- Ariadne::HeroiconComponent.new(tag: tag, icon: icon, variant: variant, size: size, classes: classes, attributes: attributes)
27
+ DEFAULT_TEXT_OPEN_CLASSES = "text-state-open"
28
+ DEFAULT_TEXT_CLOSED_CLASSES = "text-state-closed"
29
+ DEFAULT_TEXT_CLASSES = "pl-2 text-sm font-medium text-gray-900"
30
+ renders_one :icon, lambda { |tag: :svg, icon:, variant:, size: Ariadne::HeroiconComponent::SIZE_DEFAULT, classes: "", attributes: {}, text_classes: "", text_attributes: {}|
31
+ actual_text_classes = class_names(DEFAULT_TEXT_CLASSES, text_classes)
32
+ Ariadne::HeroiconComponent.new(tag: tag, icon: icon, variant: variant, size: size, classes: classes, attributes: attributes, text_classes: actual_text_classes, text_attributes: text_attributes) { content }
29
33
  }
30
34
 
31
- renders_one :item, lambda { |tag: :span, classes: "", attributes: {}|
32
- Ariadne::BaseComponent.new(tag: tag, classes: classes, attributes: attributes) { content }
35
+ renders_one :item, lambda { |classes: "", attributes: {}|
36
+ Ariadne::BaseComponent.new(tag: :span, classes: classes, attributes: attributes) { content }
33
37
  }
34
38
 
35
- DEFAULT_TEXT_OPEN_CLASSES = "text-state-open"
36
- DEFAULT_TEXT_CLOSED_CLASSES = "text-state-closed"
37
- DEFAULT_TEXT_CLASSES = "pl-2 text-sm font-medium text-gray-900 text-sm"
39
+ DEFAULT_LABEL_CLASSES = "pl-2 text-sm font-medium text-gray-900"
38
40
  renders_one :text, lambda { |classes: "", attributes: {}|
39
- actual_classes = class_names(DEFAULT_TEXT_CLASSES, classes)
41
+ actual_classes = class_names(DEFAULT_LABEL_CLASSES, classes)
40
42
  Ariadne::BaseComponent.new(tag: :span, classes: actual_classes, attributes: attributes) { content }
41
43
  }
42
44
 
@@ -47,7 +49,7 @@ module Ariadne
47
49
  # <% end %>
48
50
  #
49
51
  # <%= render(Ariadne::InlineFlexComponent.new) do |c| %>
50
- # <% c.icon(:check, size: :s, variant: HeroiconsHelper::Icon::VARIANT_SOLID) %>
52
+ # <% c.icon(icon: :check, size: :sm, variant: HeroiconsHelper::Icon::VARIANT_SOLID) %>
51
53
  # <% c.text { "Closed" } %>
52
54
  # <% end %>
53
55
  #
@@ -6,19 +6,22 @@ module Ariadne
6
6
  DEFAULT_TAG = :a
7
7
  TAG_OPTIONS = [DEFAULT_TAG, :span].freeze
8
8
 
9
- # `Tooltip` that appears on mouse hover or keyboard focus over the link. Use tooltips sparingly and as a last resort.
9
+ DEFAULT_CLASSES = "cursor-pointer"
10
+ DEFAULT_ACTIONABLE_CLASSES = " cursor-pointer underline decoration-double font-semibold hover:text-button-text-color focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-500"
11
+
12
+ # `Tooltip` that appears on mouse hover or keyboard focus over the button. Use tooltips sparingly and as a last resort.
13
+ # **Important:** This tooltip defaults to `type: :description`. In a few scenarios, `type: :label` may be more appropriate.
10
14
  # Consult the <%= link_to_component(Ariadne::TooltipComponent) %> documentation for more information.
11
15
  #
12
16
  # @param tag [Symbol, String] The rendered tag name
13
17
  # @param text [String] The text content of the tooltip. This should be brief and no longer than a sentence.
18
+ # @param direction [Symbol] <%= one_of(Ariadne::TooltipComponent::VALID_PLACEMENTS) %>
14
19
  # @param classes [String] <%= link_to_classes_docs %>
15
- # @param attributes [Hash] <%= link_to_attributes_docs %>
16
- renders_one :tooltip, lambda { |tag: :"tool-tip", text:, classes: "", attributes: {}|
20
+ # @param attributes [Hash] Same arguments as <%= link_to_component(Ariadne::TooltipComponent) %>.
21
+ renders_one :tooltip, lambda { |tag: Ariadne::TooltipComponent::DEFAULT_TAG, text:, direction: Ariadne::TooltipComponent::DEFAULT_PLACEMENT, type: Ariadne::TooltipComponent::TYPE_DEFAULT, classes: "", attributes: {}|
17
22
  raise ArgumentError, "Links with a tooltip must have a unique `id` set on the `LinkComponent`." if @id.blank?
18
23
 
19
- actual_classes = class_names(classes)
20
-
21
- Ariadne::TooltipComponent.new(tag: tag, text: text, classes: actual_classes, attributes: attributes)
24
+ Ariadne::TooltipComponent.new(tag: tag, for_id: @id, text: text, direction: direction, type: type, classes: classes, attributes: attributes)
22
25
  }
23
26
 
24
27
  # @example Default
@@ -38,9 +41,10 @@ module Ariadne
38
41
  #
39
42
  # @param tag [String] <%= one_of(Ariadne::LinkComponent::TAG_OPTIONS) %>
40
43
  # @param href [String] URL to be used for the link.
44
+ # @param actionable [Boolean] If true, adds additional classes to the link to make it more aware.
41
45
  # @param classes [String] <%= link_to_classes_docs %>
42
46
  # @param attributes [Hash] <%= link_to_attributes_docs %>
43
- def initialize(tag: DEFAULT_TAG, href:, classes: "", attributes: {})
47
+ def initialize(tag: DEFAULT_TAG, href:, actionable: false, classes: "", attributes: {})
44
48
  @tag = check_incoming_tag(DEFAULT_TAG, tag)
45
49
 
46
50
  @attributes = attributes
@@ -48,7 +52,8 @@ module Ariadne
48
52
 
49
53
  @id = @attributes[:id]
50
54
 
51
- @classes = classes
55
+ @classes = class_names(DEFAULT_CLASSES, classes)
56
+ @classes << DEFAULT_ACTIONABLE_CLASSES if actionable
52
57
  end
53
58
 
54
59
  def call
@@ -1,17 +1,15 @@
1
1
  <%= render Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes) do |list| %>
2
2
  <% items.each do |item| %>
3
3
  <% if item.linked? %>
4
- <li data-highlight-target="highlightable" class="relative <%= selected? ? 'bg-button-bg-color' : 'hover:bg-button-hover-color' %> focus:ring-2 focus:ring-offset-2 focus:ring-purple-500">
5
- <%= render(item.link) do %>
6
- <%= item.header %>
4
+ <%= render Ariadne::BaseComponent.new(tag: :li, classes: item.classes, attributes: item.attributes) do %>
5
+ <%= render Ariadne::LinkComponent.new(href: item.link[:href], classes: item.link[:classes], attributes: item.link[:attributes]) do %>
7
6
  <%= item.entry %>
8
7
  <% end %>
9
- </li>
8
+ <% end %>
10
9
  <% else %>
11
- <li data-highlight-target="highlightable" class="relative <%= selected? ? 'bg-button-bg-color' : 'hover:bg-button-hover-color' %> focus:ring-2 focus:ring-offset-2 focus:ring-purple-500">
12
- <%= item.header %>
10
+ <%= render Ariadne::BaseComponent.new(tag: :li, classes: item.classes, attributes: item.attributes) do %>
13
11
  <%= item.entry %>
14
- </li>
12
+ <% end %>
15
13
  <% end %>
16
14
  <% end %>
17
15
  <% end %>
@@ -17,16 +17,6 @@ module Ariadne
17
17
  # <% end %>
18
18
  # <% end %>
19
19
  #
20
- # @example With a header
21
- # <% numbers = [1, 2, 3] %>
22
- # <%= render(Ariadne::ListComponent.new) do |list| %>
23
- # <% numbers.each_with_index do |number, idx| %>
24
- # <%= list.item do |item| %>
25
- # <%= item.header { idx } %>
26
- # <%= item.entry { number } %>
27
- # <% end %>
28
- # <% end %>
29
- # <% end %>
30
20
  #
31
21
  # @param classes [String] <%= link_to_classes_docs %>
32
22
  # @param attributes [Hash] <%= link_to_attributes_docs %>
@@ -34,11 +24,6 @@ module Ariadne
34
24
  @tag = :ul
35
25
  @classes = class_names(DEFAULT_UL_CLASSES, classes)
36
26
  @attributes = attributes
37
- @attributes[:"data-controller"] = "highlight"
38
- end
39
-
40
- def selected?
41
- false
42
27
  end
43
28
 
44
29
  def render?
@@ -48,33 +33,22 @@ module Ariadne
48
33
  # This component is part of `ListComponent` and should not be
49
34
  # used as a standalone component.
50
35
  class Item < Ariadne::Component
51
- renders_one :header, lambda { |static_content = nil, &block|
52
- next static_content if static_content.present?
53
-
54
- render(Ariadne::BaseComponent.new(tag: :div, classes: "flex justify-between")) do
55
- view_context.capture { block&.call }
56
- end
57
- }
36
+ DEFAULT_ITEM_CLASSES = "relative p-1.5 focus:ring-2 focus:ring-offset-2 focus:ring-purple-500 hover:bg-button-hover-color"
58
37
 
59
38
  renders_one :entry, lambda { |static_content = nil, &block|
60
39
  next static_content if static_content.present?
61
40
 
62
- render(Ariadne::BaseComponent.new(tag: :div, classes: "mt-1")) do
41
+ render(Ariadne::BaseComponent.new(tag: :div)) do
63
42
  view_context.capture { block&.call }
64
43
  end
65
44
  }
66
45
 
67
- attr_accessor :selected
68
46
  attr_reader :link, :classes, :attributes
69
47
 
70
48
  def initialize(link: {}, classes: "", attributes: {})
71
- if link.present?
72
- @link = Ariadne::LinkComponent.new(**link)
73
- end
74
-
75
- @classes = classes
49
+ @link = link
50
+ @classes = class_names(DEFAULT_ITEM_CLASSES, classes)
76
51
  @attributes = attributes
77
- @selected = false
78
52
  end
79
53
 
80
54
  def selected?
@@ -86,10 +60,6 @@ module Ariadne
86
60
  end
87
61
 
88
62
  def call
89
- if selected
90
- link_arguments[:"aria-current"] = "page"
91
- end
92
-
93
63
  Ariadne::BaseComponent.new(tag: :div, classes: @classes, attributes: @attributes)
94
64
  end
95
65
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ariadne
4
+ # Add a general description of component here
5
+ # Add additional usage considerations or best practices that may aid the user to use the component correctly.
6
+ # @accessibility Add any accessibility considerations
7
+ class MainComponent < Ariadne::Component
8
+ DEFAULT_CLASSES = "flex-auto"
9
+
10
+ # @example Default
11
+ #
12
+ # <%= render(Ariadne::MainComponent.new) { "Example" } %>
13
+ #
14
+ # @param classes [String] <%= link_to_classes_docs %>
15
+ # @param attributes [Hash] <%= link_to_attributes_docs %>
16
+ def initialize(classes: "", attributes: {})
17
+ @tag = :main
18
+ @classes = class_names(
19
+ DEFAULT_CLASSES,
20
+ classes
21
+ )
22
+
23
+ @attributes = attributes
24
+ end
25
+
26
+ def call
27
+ render(Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes)) do
28
+ render(Ariadne::ContainerComponent.new) { content }
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,9 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ export default class SlideoverComponent extends Controller {
3
+ static targets: string[];
4
+ readonly expandableTarget: HTMLDivElement;
5
+ readonly expandWrapperTarget: HTMLDivElement;
6
+ readonly slidePanelTargets: [HTMLDivElement];
7
+ readonly buttonWrapperTarget: HTMLDivElement;
8
+ toggle(): void;
9
+ }
@@ -0,0 +1,20 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ export default class SlideoverComponent extends Controller {
3
+ toggle() {
4
+ var _a;
5
+ this.expandableTarget.classList.toggle('hidden');
6
+ this.expandWrapperTarget.classList.toggle('bg-filter-panel');
7
+ for (const slidePanel of this.slidePanelTargets) {
8
+ slidePanel.classList.toggle('hidden');
9
+ }
10
+ this.buttonWrapperTarget.classList.toggle('bg-filter-panel');
11
+ if ((_a = document.getElementById('btnClose')) === null || _a === void 0 ? void 0 : _a.classList.contains('hidden')) {
12
+ const formID = this.buttonWrapperTarget.getAttribute('data-slideover-component-form-id');
13
+ if (formID) {
14
+ const form = document.getElementById(formID);
15
+ form === null || form === void 0 ? void 0 : form.submit();
16
+ }
17
+ }
18
+ }
19
+ }
20
+ SlideoverComponent.targets = ['expandable', 'expandWrapper', 'slidePanel', 'buttonWrapper'];
@@ -0,0 +1,9 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ export default class SlideoverComponent extends Controller {
3
+ static targets: string[];
4
+ readonly expandableTarget: HTMLDivElement;
5
+ readonly expandWrapperTarget: HTMLDivElement;
6
+ readonly slidePanelTargets: [HTMLDivElement];
7
+ readonly buttonWrapperTarget: HTMLDivElement;
8
+ toggle(): void;
9
+ }
@@ -1,11 +1,8 @@
1
1
  <%= render Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes) do |slideover| %>
2
- <div data-slideover-component-target="expandWrapper" class="flex flex-col">
2
+ <div data-slideover-component-target="expandWrapper" class="flex flex-col z-10">
3
3
  <div data-slideover-component-target="expandable" class="hidden bg-filter-panel px-3 pb-4">
4
4
  <%= content %>
5
5
  </div>
6
- <div class="relative top-4 inset-0 flex flex-row items-center bg-filter-panel" aria-hidden="true">
7
- <div class="w-full border-t border-billy-purple z-10"></div>
8
- </div>
9
6
  <div data-slideover-component-target="buttonWrapper" data-slideover-component-form-id="<%= @form_id %>" class="relative flex justify-center">
10
7
  <%= open_button %>
11
8
  <%= close_button %>
@@ -0,0 +1,19 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ export default class SlideoverComponent extends Controller {
3
+ toggle() {
4
+ var _a;
5
+ // eslint-disable-next-line no-debugger
6
+ debugger;
7
+ this.expandableTarget.classList.toggle('hidden');
8
+ this.expandWrapperTarget.classList.toggle('bg-filter-panel');
9
+ for (const slidePanel of this.slidePanelTargets) {
10
+ slidePanel.classList.toggle('hidden');
11
+ }
12
+ this.buttonWrapperTarget.classList.toggle('bg-filter-panel');
13
+ if ((_a = document.getElementById('btnClose')) === null || _a === void 0 ? void 0 : _a.classList.contains('hidden')) {
14
+ const form = this.buttonWrapperTarget.closest('form');
15
+ form === null || form === void 0 ? void 0 : form.submit();
16
+ }
17
+ }
18
+ }
19
+ SlideoverComponent.targets = ['expandable', 'expandWrapper', 'slidePanel', 'buttonWrapper'];
@@ -8,14 +8,14 @@ module Ariadne
8
8
  DEFAULT_TAG = :div
9
9
  TAG_OPTIONS = [DEFAULT_TAG].freeze
10
10
 
11
- DIRECTION_Y = :y
12
- DIRECTION_X = :x
13
- VALID_DIRECTIONS = [DIRECTION_Y, DIRECTION_X].freeze
11
+ DIRECTION_Y_DOWN = :yd
12
+ DIRECTION_X_LEFT = :xl
13
+ VALID_DIRECTIONS = [DIRECTION_Y_DOWN, DIRECTION_X_LEFT].freeze
14
14
 
15
15
  DEFAULT_CLASSES = ""
16
16
 
17
- DEFAULT_BUTTON_CLASSES = "inline-flex items-center shadow-sm px-4 py-1.5 border border-our-purple-300 z-50 text-sm leading-5 font-medium rounded-full text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
18
- renders_one :open_button, lambda { |text:, classes: "", attributes: {}|
17
+ DEFAULT_BUTTON_CLASSES = "inline-flex items-center shadow-sm px-4 py-1.5 pb-2 text-sm leading-5 font-medium rounded-full " + Ariadne::ButtonComponent::SCHEME_CLASS_MAPPINGS[:default]
18
+ renders_one :open_button, lambda { |label:, classes: "", attributes: {}, text_classes: ""|
19
19
  actual_classes = class_names(DEFAULT_BUTTON_CLASSES, classes)
20
20
 
21
21
  attributes[:id] ||= "btnOpen"
@@ -23,15 +23,17 @@ module Ariadne
23
23
  attributes[:"data-action"] ||= "click->slideover-component#toggle"
24
24
  attributes[:type] ||= "submit"
25
25
 
26
+ icon = case @direction
27
+ when DIRECTION_Y_DOWN
28
+ :"chevron-double-down"
29
+ end
30
+
26
31
  render(Ariadne::BaseComponent.new(tag: :button, classes: actual_classes, attributes: attributes)) do
27
- render(Ariadne::InlineFlexComponent.new(attributes: { "data-slideover-component-target" => "slide-panel" })) do |flex|
28
- flex.icon(:"chevron-double-down", size: :s, variant: HeroiconsHelper::Icon::VARIANT_SOLID)
29
- flex.text { text }
30
- end
32
+ render(Ariadne::HeroiconComponent.new(icon: icon, size: :sm, variant: HeroiconsHelper::Icon::VARIANT_SOLID, attributes: { "data-slideover-component-target" => "slide-panel" }, text_classes: text_classes)) { label }
31
33
  end
32
34
  }
33
35
 
34
- renders_one :close_button, lambda { |text:, classes: "", attributes: {}|
36
+ renders_one :close_button, lambda { |label:, classes: "", attributes: {}, text_classes: ""|
35
37
  actual_classes = class_names(DEFAULT_BUTTON_CLASSES, classes)
36
38
 
37
39
  attributes[:id] ||= "btnClose"
@@ -39,17 +41,19 @@ module Ariadne
39
41
  attributes[:"data-action"] ||= "click->slideover-component#toggle"
40
42
  attributes[:type] ||= "submit"
41
43
 
44
+ icon = case @direction
45
+ when DIRECTION_Y_DOWN
46
+ :"chevron-double-up"
47
+ end
48
+
42
49
  render(Ariadne::BaseComponent.new(tag: :button, classes: actual_classes, attributes: attributes)) do
43
- render(Ariadne::InlineFlexComponent.new(attributes: { "data-slideover-component-target" => "slide-panel" })) do |flex|
44
- flex.icon(:"chevron-double-up", size: :s, variant: HeroiconsHelper::Icon::VARIANT_SOLID)
45
- flex.text { text }
46
- end
50
+ render(Ariadne::HeroiconComponent.new(icon: icon, size: :sm, variant: HeroiconsHelper::Icon::VARIANT_SOLID, attributes: { "data-slideover-component-target" => "slide-panel" }, text_classes: text_classes)) { label }
47
51
  end
48
52
  }
49
53
 
50
54
  # @example Default
51
55
  #
52
- # <%= render(Ariadne::SlideoverComponent.new(direction: Ariadne::SlideoverComponent::DIRECTION_Y)) { "Example" } %>
56
+ # <%= render(Ariadne::SlideoverComponent.new(direction: Ariadne::SlideoverComponent::DIRECTION_Y_DOWN)) { "Example" } %>
53
57
  #
54
58
  # @param tag [Symbol, String] The rendered tag name.
55
59
  # @param direction [Symbol] <%= one_of(Ariadne::SlideoverComponent::VALID_DIRECTIONS) %>
@@ -0,0 +1 @@
1
+ import '@github/time-elements';
@@ -0,0 +1 @@
1
+ import '@github/time-elements';
@@ -0,0 +1,24 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ import type { Instance, Placement } from '@popperjs/core';
3
+ export default class TooltipComponent extends Controller {
4
+ static targets: string[];
5
+ readonly triggerTarget: HTMLElement;
6
+ readonly tooltipTarget: HTMLElement;
7
+ static values: {
8
+ placement: {
9
+ type: StringConstructor;
10
+ default: string;
11
+ };
12
+ offset: {
13
+ type: ArrayConstructor;
14
+ default: number[];
15
+ };
16
+ };
17
+ readonly placementValue: Placement;
18
+ readonly offsetValue: Array<number>;
19
+ popperInstance: Instance;
20
+ connect(): void;
21
+ disconnect(): void;
22
+ show(): void;
23
+ hide(): void;
24
+ }
@@ -0,0 +1,42 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+ import { createPopper } from '@popperjs/core';
3
+ export default class TooltipComponent extends Controller {
4
+ // Create a new Popper instance
5
+ connect() {
6
+ this.popperInstance = createPopper(this.triggerTarget, this.tooltipTarget, {
7
+ placement: this.placementValue,
8
+ modifiers: [
9
+ {
10
+ name: 'offset',
11
+ options: {
12
+ offset: this.offsetValue
13
+ }
14
+ }
15
+ ]
16
+ });
17
+ }
18
+ // Destroy the Popper instance
19
+ disconnect() {
20
+ if (this.popperInstance) {
21
+ this.popperInstance.destroy();
22
+ }
23
+ }
24
+ show() {
25
+ this.tooltipTarget.setAttribute('data-tooltip-show', '');
26
+ this.tooltipTarget.classList.remove('invisible');
27
+ // We need to tell Popper to update the tooltip position
28
+ // after we show the tooltip, otherwise it will be incorrect
29
+ this.popperInstance.update();
30
+ this.dispatch('shown', { detail: { trigger: this.triggerTarget, tooltip: this.tooltipTarget } });
31
+ }
32
+ hide() {
33
+ this.tooltipTarget.removeAttribute('data-tooltip-show');
34
+ this.tooltipTarget.classList.add('invisible');
35
+ this.dispatch('hidden', { detail: { trigger: this.triggerTarget, tooltip: this.tooltipTarget } });
36
+ }
37
+ }
38
+ TooltipComponent.targets = ['trigger', 'tooltip'];
39
+ TooltipComponent.values = {
40
+ placement: { type: String, default: 'top' },
41
+ offset: { type: Array, default: [0, 8] }
42
+ };
@@ -0,0 +1,57 @@
1
+ import {Controller} from '@hotwired/stimulus'
2
+ import {createPopper} from '@popperjs/core'
3
+ import type {Instance, Placement} from '@popperjs/core'
4
+
5
+ export default class TooltipComponent extends Controller {
6
+ static targets = ['trigger', 'tooltip']
7
+ declare readonly triggerTarget: HTMLElement
8
+ declare readonly tooltipTarget: HTMLElement
9
+
10
+ static values = {
11
+ placement: {type: String, default: 'top'},
12
+ offset: {type: Array, default: [0, 8]}
13
+ }
14
+ declare readonly placementValue: Placement
15
+ declare readonly offsetValue: Array<number>
16
+
17
+ popperInstance: Instance
18
+
19
+ // Create a new Popper instance
20
+ connect() {
21
+ this.popperInstance = createPopper(this.triggerTarget, this.tooltipTarget, {
22
+ placement: this.placementValue,
23
+ modifiers: [
24
+ {
25
+ name: 'offset',
26
+ options: {
27
+ offset: this.offsetValue
28
+ }
29
+ }
30
+ ]
31
+ })
32
+ }
33
+
34
+ // Destroy the Popper instance
35
+ disconnect() {
36
+ if (this.popperInstance) {
37
+ this.popperInstance.destroy()
38
+ }
39
+ }
40
+
41
+ show() {
42
+ this.tooltipTarget.setAttribute('data-tooltip-show', '')
43
+ this.tooltipTarget.classList.remove('invisible')
44
+
45
+ // We need to tell Popper to update the tooltip position
46
+ // after we show the tooltip, otherwise it will be incorrect
47
+ this.popperInstance.update()
48
+ this.dispatch('shown', {detail: {trigger: this.triggerTarget, tooltip: this.tooltipTarget}})
49
+ }
50
+
51
+ hide() {
52
+ this.tooltipTarget.removeAttribute('data-tooltip-show')
53
+ this.tooltipTarget.classList.add('invisible')
54
+
55
+ this.dispatch('hidden', {detail: {trigger: this.triggerTarget, tooltip: this.tooltipTarget}})
56
+ }
57
+ }
@@ -0,0 +1,4 @@
1
+ <%= render Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes) do %>
2
+ <span><%= @text %></span>
3
+ <span class="tooltip-arrow absolute block" data-popper-arrow></span>
4
+ <% end %>