ariadne_view_components 0.0.4 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/app/assets/javascripts/ariadne-form-with.d.ts +20 -0
  4. data/app/assets/javascripts/ariadne-form.d.ts +22 -0
  5. data/app/assets/javascripts/ariadne.d.ts +1 -0
  6. data/app/assets/javascripts/ariadne_view_components.js +7 -1
  7. data/app/assets/javascripts/ariadne_view_components.js.map +1 -1
  8. data/app/assets/javascripts/clipboard-copy-component.d.ts +4 -0
  9. data/app/assets/javascripts/comment-component.d.ts +13 -0
  10. data/app/assets/javascripts/rich-text-area-component.d.ts +4 -0
  11. data/app/assets/javascripts/slideover-component.d.ts +9 -0
  12. data/app/assets/javascripts/time-ago-component.d.ts +1 -0
  13. data/app/assets/javascripts/time_ago_component.d.ts +1 -0
  14. data/app/assets/javascripts/tooltip-component.d.ts +24 -0
  15. data/app/assets/stylesheets/application.ariadne_view_components.css +6 -3
  16. data/app/assets/stylesheets/prosemirror.css +323 -0
  17. data/app/assets/stylesheets/tooltip-component.css +37 -0
  18. data/app/components/ariadne/ariadne-form.ts +96 -0
  19. data/app/components/ariadne/ariadne.ts +11 -1
  20. data/app/components/ariadne/base_button.rb +12 -12
  21. data/app/components/ariadne/base_component.rb +13 -131
  22. data/app/components/ariadne/blankslate_component.html.erb +5 -5
  23. data/app/components/ariadne/blankslate_component.rb +5 -10
  24. data/app/components/ariadne/body_component.rb +30 -0
  25. data/app/components/ariadne/button_component.rb +12 -16
  26. data/app/components/ariadne/clipboard_copy_component.html.erb +5 -4
  27. data/app/components/ariadne/clipboard_copy_component.rb +41 -3
  28. data/app/components/ariadne/comment-component.ts +55 -0
  29. data/app/components/ariadne/comment_component.html.erb +22 -0
  30. data/app/components/ariadne/comment_component.rb +57 -0
  31. data/app/components/ariadne/component.rb +4 -3
  32. data/app/components/ariadne/container_component.rb +1 -1
  33. data/app/components/ariadne/counter_component.rb +4 -4
  34. data/app/components/ariadne/flash_component.html.erb +12 -12
  35. data/app/components/ariadne/flash_component.rb +17 -17
  36. data/app/components/ariadne/flex_component.rb +49 -0
  37. data/app/components/ariadne/footer_component.html.erb +1 -1
  38. data/app/components/ariadne/footer_component.rb +1 -1
  39. data/app/components/ariadne/grid_component.html.erb +13 -4
  40. data/app/components/ariadne/grid_component.rb +22 -11
  41. data/app/components/ariadne/header_component.html.erb +7 -7
  42. data/app/components/ariadne/header_component.rb +8 -8
  43. data/app/components/ariadne/heading_component.rb +3 -3
  44. data/app/components/ariadne/heroicon_component.html.erb +4 -6
  45. data/app/components/ariadne/heroicon_component.rb +21 -10
  46. data/app/components/ariadne/inline_flex_component.rb +14 -12
  47. data/app/components/ariadne/link_component.rb +13 -8
  48. data/app/components/ariadne/list_component.html.erb +5 -7
  49. data/app/components/ariadne/list_component.rb +9 -38
  50. data/app/components/ariadne/main_component.rb +32 -0
  51. data/app/components/ariadne/narrow_container_component.html.erb +3 -0
  52. data/app/components/ariadne/narrow_container_component.rb +30 -0
  53. data/app/components/ariadne/panel_bar_component.html.erb +20 -0
  54. data/app/components/ariadne/panel_bar_component.rb +79 -0
  55. data/app/components/ariadne/pill_component.rb +2 -2
  56. data/app/components/ariadne/rich-text-area-component.ts +32 -0
  57. data/app/components/ariadne/rich_text_area_component.html.erb +6 -0
  58. data/app/components/ariadne/rich_text_area_component.rb +35 -0
  59. data/app/components/ariadne/slideover-component.ts +3 -3
  60. data/app/components/ariadne/slideover_component.html.erb +3 -6
  61. data/app/components/ariadne/slideover_component.rb +19 -15
  62. data/app/components/ariadne/tab_bar_component.html.erb +3 -0
  63. data/app/components/ariadne/tab_bar_component.rb +45 -0
  64. data/app/components/ariadne/tab_component.html.erb +7 -0
  65. data/app/components/ariadne/tab_component.rb +43 -0
  66. data/app/components/ariadne/{time_ago_component.ts → time-ago-component.ts} +0 -0
  67. data/app/components/ariadne/time_ago_component.rb +2 -2
  68. data/app/components/ariadne/timeline_component.html.erb +6 -6
  69. data/app/components/ariadne/tooltip-component.ts +57 -0
  70. data/app/components/ariadne/tooltip_component.html.erb +4 -0
  71. data/app/components/ariadne/tooltip_component.rb +34 -31
  72. data/app/lib/ariadne/action_view_extensions/form_helper.rb +4 -1
  73. data/app/lib/ariadne/fetch_or_fallback_helper.rb +3 -1
  74. data/app/lib/ariadne/form_builder.rb +22 -22
  75. data/app/lib/ariadne/icon_helper.rb +1 -1
  76. data/lib/ariadne/view_components/engine.rb +171 -3
  77. data/lib/ariadne/view_components/version.rb +1 -1
  78. data/lib/ariadne/view_components.rb +31 -30
  79. data/lib/rubocop/config/default.yml +0 -6
  80. data/lib/rubocop/cop/ariadne/no_tag_memoize.rb +1 -0
  81. data/lib/tasks/docs.rake +9 -0
  82. data/static/arguments.yml +186 -15
  83. data/static/audited_at.json +12 -2
  84. data/static/classes.yml +200 -154
  85. data/static/constants.json +168 -146
  86. data/static/statuses.json +12 -2
  87. metadata +65 -13
  88. data/lib/ariadne/classify/utilities.rb +0 -199
  89. data/lib/ariadne/classify/utilities.yml +0 -1817
  90. data/lib/ariadne/classify/validation.rb +0 -18
  91. data/lib/ariadne/classify.rb +0 -218
  92. data/lib/rubocop/cop/ariadne/ariadne_heroicon.rb +0 -252
  93. data/lib/rubocop/cop/ariadne/component_name_migration.rb +0 -35
  94. data/lib/rubocop/cop/ariadne/system_argument_instead_of_class.rb +0 -57
  95. data/lib/tasks/utilities.rake +0 -121
@@ -3,9 +3,10 @@
3
3
  module Ariadne
4
4
  # `List` is used to show a list of items in a vertical format.
5
5
  class ListComponent < Ariadne::Component
6
- DEFAULT_UL_CLASSES = "divide-y divide-gray-300"
6
+ DEFAULT_TAG = :ul
7
+ DEFAULT_UL_CLASSES = "ariadne-divide-y ariadne-divide-gray-300"
7
8
 
8
- renders_many :items, "Item"
9
+ renders_many :items, "ListItem"
9
10
 
10
11
  # @example Basic
11
12
  # <% numbers = [1, 2, 3] %>
@@ -17,28 +18,13 @@ module Ariadne
17
18
  # <% end %>
18
19
  # <% end %>
19
20
  #
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
21
  #
31
22
  # @param classes [String] <%= link_to_classes_docs %>
32
23
  # @param attributes [Hash] <%= link_to_attributes_docs %>
33
24
  def initialize(classes: "", attributes: {})
34
- @tag = :ul
25
+ @tag = DEFAULT_TAG
35
26
  @classes = class_names(DEFAULT_UL_CLASSES, classes)
36
27
  @attributes = attributes
37
- @attributes[:"data-controller"] = "highlight"
38
- end
39
-
40
- def selected?
41
- false
42
28
  end
43
29
 
44
30
  def render?
@@ -47,34 +33,23 @@ module Ariadne
47
33
 
48
34
  # This component is part of `ListComponent` and should not be
49
35
  # used as a standalone component.
50
- 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
+ class ListItem < Ariadne::Component
37
+ DEFAULT_ITEM_CLASSES = "ariadne-relative ariadne-p-1.5 focus:ariadne-ring-2 focus:ariadne-ring-offset-2 focus:ariadne-ring-purple-500 hover:ariadne-bg-button-hover-color"
58
38
 
59
39
  renders_one :entry, lambda { |static_content = nil, &block|
60
40
  next static_content if static_content.present?
61
41
 
62
- render(Ariadne::BaseComponent.new(tag: :div, classes: "mt-1")) do
42
+ render(Ariadne::BaseComponent.new(tag: :div)) do
63
43
  view_context.capture { block&.call }
64
44
  end
65
45
  }
66
46
 
67
- attr_accessor :selected
68
47
  attr_reader :link, :classes, :attributes
69
48
 
70
49
  def initialize(link: {}, classes: "", attributes: {})
71
- if link.present?
72
- @link = Ariadne::LinkComponent.new(**link)
73
- end
74
-
75
- @classes = classes
50
+ @link = link
51
+ @classes = class_names(DEFAULT_ITEM_CLASSES, classes)
76
52
  @attributes = attributes
77
- @selected = false
78
53
  end
79
54
 
80
55
  def selected?
@@ -86,10 +61,6 @@ module Ariadne
86
61
  end
87
62
 
88
63
  def call
89
- if selected
90
- link_arguments[:"aria-current"] = "page"
91
- end
92
-
93
64
  Ariadne::BaseComponent.new(tag: :div, classes: @classes, attributes: @attributes)
94
65
  end
95
66
  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,3 @@
1
+ <%= render Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes) do |component| %>
2
+ <%= content %>
3
+ <% end %>
@@ -0,0 +1,30 @@
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 NarrowContainerComponent < Ariadne::Component
8
+ DEFAULT_TAG = :div
9
+ TAG_OPTIONS = [DEFAULT_TAG].freeze
10
+
11
+ DEFAULT_CLASSES = "ariadne-max-w-7xl ariadne-mx-auto ariadne-py-12 ariadne-px-4 sm:ariadne-px-6 lg:ariadne-py-16 lg:ariadne-px-8"
12
+
13
+ # @example Default
14
+ # <%= render(Ariadne::NarrowContainerComponent.new) do |container| %>
15
+ # <%= render(Ariadne::ButtonComponent.new) { "Click me!" } %>
16
+ # <% end %>
17
+ #
18
+ # @param classes [String] <%= link_to_classes_docs %>
19
+ # @param attributes [Hash] <%= link_to_attributes_docs %>
20
+ def initialize(classes: "", attributes: {})
21
+ @tag = :div
22
+ @classes = class_names(
23
+ DEFAULT_CLASSES,
24
+ classes
25
+ )
26
+
27
+ @attributes = attributes
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,20 @@
1
+ <%= render Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes) do |list| %>
2
+ <% panels.each_with_index do |panel, idx| %>
3
+ <%= render Ariadne::BaseComponent.new(tag: :li, classes: panel.classes, attributes: panel.attributes) do %>
4
+ <%= render Ariadne::BaseComponent.new(tag: :div, classes: Ariadne::PanelBarComponent::PanelItem::DEFAULT_WRAPPER_CLASSES) do %>
5
+ <span class="ariadne-px-6 ariadne-py-4 ariadne-flex ariadne-items-center ariadne-text-sm ariadne-font-medium">
6
+ <%= panel.icon %>
7
+ <span class="ariadne-ml-4 ariadne-text-sm ariadne-font-medium ariadne-text-gray-900"><%= panel.label %></span>
8
+ <!-- Arrow separator for lg screens and up -->
9
+ <% if idx + 1 < panels.size %>
10
+ <div class="md:ariadne-block ariadne-hidden ariadne-absolute ariadne-top-0 ariadne-right-0 ariadne-h-full ariadne-w-5" aria-hidden="true">
11
+ <svg class="ariadne-h-full ariadne-w-full ariadne-text-gray-300" viewBox="0 0 22 80" fill="none" preserveAspectRatio="none">
12
+ <path d="M0 -2L20 40L0 82" vector-effect="non-scaling-stroke" stroke="currentcolor" stroke-linejoin="round"></path>
13
+ </svg>
14
+ </div>
15
+ <% end %>
16
+ </span>
17
+ <% end %>
18
+ <% end %>
19
+ <% end %>
20
+ <% end %>
@@ -0,0 +1,79 @@
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 PanelBarComponent < Ariadne::Component
8
+ DEFAULT_TAG = :ol
9
+ TAG_OPTIONS = [DEFAULT_TAG].freeze
10
+
11
+ DEFAULT_CLASSES = "ariadne-border ariadne-border-gray-300 ariadne-rounded-md ariadne-divide-y ariadne-divide-gray-300 md:ariadne-flex md:ariadne-divide-y-0"
12
+
13
+ renders_many :panels, "PanelItem"
14
+
15
+ # @example Default
16
+ #
17
+ # <%= render(Ariadne::PanelBarComponent.new) { "Example" } %>
18
+ #
19
+ # @param tag [Symbol, String] The rendered tag name.
20
+ # @param classes [String] <%= link_to_classes_docs %>
21
+ # @param attributes [Hash] <%= link_to_attributes_docs %>
22
+ def initialize(classes: "", attributes: {})
23
+ @tag = DEFAULT_TAG
24
+ @classes = class_names(
25
+ DEFAULT_CLASSES,
26
+ classes
27
+ )
28
+
29
+ @attributes = attributes
30
+ @attributes[:role] ||= "list"
31
+ end
32
+
33
+ # def render?
34
+ # items.any?
35
+ # end
36
+
37
+ # This component is part of `PanelBarComponent` and should not be
38
+ # used as a standalone component.
39
+ class PanelItem < Ariadne::Component
40
+ DEFAULT_ITEM_CLASSES = "ariadne-relative md:ariadne-flex-1 md:ariadne-flex"
41
+ DEFAULT_WRAPPER_CLASSES = "group ariadne-flex ariadne-items-center ariadne-w-full"
42
+
43
+ renders_one :icon, lambda { |static_content = nil, &block|
44
+ next static_content if static_content.present?
45
+
46
+ view_context.capture { block&.call }
47
+ }
48
+
49
+ renders_one :label, lambda { |static_content = nil, &block|
50
+ next static_content if static_content.present?
51
+
52
+ view_context.capture { block&.call }
53
+ }
54
+
55
+ attr_reader :link, :classes, :attributes
56
+
57
+ def initialize(link: {}, classes: "", attributes: {})
58
+ @link = link
59
+ if @link.present?
60
+ @link["classes"] = class_names(DEFAULT_WRAPPER_CLASSES, @link["classes"])
61
+ end
62
+ @classes = class_names(DEFAULT_ITEM_CLASSES, classes)
63
+ @attributes = attributes
64
+ end
65
+
66
+ def selected?
67
+ @selected
68
+ end
69
+
70
+ def linked?
71
+ @link.present?
72
+ end
73
+
74
+ def call
75
+ Ariadne::BaseComponent.new(tag: :div, classes: @classes, attributes: @attributes)
76
+ end
77
+ end
78
+ end
79
+ end
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ariadne
4
- # Creates a rounded label that resembles a medicine pill.
4
+ # Creates a ariadne-rounded label that resembles a medicine pill.
5
5
  class PillComponent < Ariadne::Component
6
6
  DEFAULT_TAG = :span
7
7
  TAG_OPTIONS = [DEFAULT_TAG].freeze
8
8
 
9
- DEFAULT_CLASSES = "flex-shrink-0 inline-block px-2 py-0.5 text-xs font-medium rounded-full"
9
+ DEFAULT_CLASSES = "ariadne-flex-shrink-0 ariadne-inline-block ariadne-px-2 ariadne-py-0.5 ariadne-text-xs ariadne-font-medium ariadne-rounded-full"
10
10
 
11
11
  # @example Default
12
12
  #
@@ -0,0 +1,32 @@
1
+ import {Controller} from '@hotwired/stimulus'
2
+
3
+ import {Editor} from '@tiptap/core'
4
+ import {StarterKit} from '@tiptap/starter-kit'
5
+
6
+ export default class RichTextArea extends Controller {
7
+ connect() {
8
+ const editorElement = document.querySelector('.tiptap-editor')
9
+ if (editorElement) {
10
+ new Editor({
11
+ element: editorElement,
12
+ extensions: [StarterKit],
13
+ content: 'Hello World!',
14
+ editorProps: {
15
+ attributes: {
16
+ class:
17
+ 'ariadne-prose ariadne-prose-sm sm:ariadne-prose lg:ariadne-prose-lg xl:ariadne-prose-2xl ariadne-m-5 focus:ariadne-outline-none'
18
+ }
19
+ }
20
+ })
21
+
22
+ const tiptapValueContainer = document.querySelector('input[data-tiptap-value-container=true]')
23
+ if (tiptapValueContainer) {
24
+ const parentForm = editorElement.closest('form')
25
+
26
+ parentForm?.addEventListener('submit', () => {
27
+ tiptapValueContainer.setAttribute('value', editorElement.textContent || '')
28
+ })
29
+ }
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,6 @@
1
+ <%= render(Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes)) do %>
2
+ <% if @has_form %>
3
+ <input type="hidden" data-tiptap-value-container=true name="<%= @name %>" id="<%= @name %>" />
4
+ <% end %>
5
+ <textarea class="tiptap-editor"></textarea>
6
+ <% end %>
@@ -0,0 +1,35 @@
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 RichTextAreaComponent < Ariadne::Component
8
+ DEFAULT_TAG = :div
9
+ DEFAULT_CLASSES = "ariadne-block ariadne-w-full ariadne-border-0 ariadne-py-3 focus:ariadne-ring-0 sm:ariadne-text-sm"
10
+
11
+ # @example Default
12
+ #
13
+ # <%= render(Ariadne::RichTextAreaComponent.new(name: "bodytext", sr_label: "Enter message contents")) { "Example" } %>
14
+ #
15
+ # @param name [Symbol] Identifies the form/param name for this rich text area.
16
+ # @param sr_label [String] A label to introduce these tabs for screen readers.
17
+ # @param has_form [Boolean] Indicates whether this component is wrapped in a form.
18
+ # @param classes [String] <%= link_to_classes_docs %>
19
+ # @param attributes [Hash] <%= link_to_attributes_docs %>
20
+ def initialize(name:, sr_label:, has_form: true, classes: "", attributes: {})
21
+ @tag = DEFAULT_TAG
22
+ @name = name
23
+ @sr_label = sr_label
24
+ @has_form = has_form
25
+
26
+ @classes = class_names(
27
+ DEFAULT_CLASSES,
28
+ classes
29
+ )
30
+ @attributes = attributes
31
+ @attributes[:"data-controller"] = "rich-text-area-component"
32
+ @attributes[:"data-has-form"] = true if @has_form
33
+ end
34
+ end
35
+ end
@@ -9,13 +9,13 @@ export default class SlideoverComponent extends Controller {
9
9
  declare readonly buttonWrapperTarget: HTMLDivElement
10
10
 
11
11
  toggle() {
12
- this.expandableTarget.classList.toggle('hidden')
12
+ this.expandableTarget.classList.toggle('ariadne-hidden')
13
13
  this.expandWrapperTarget.classList.toggle('bg-filter-panel')
14
14
  for (const slidePanel of this.slidePanelTargets) {
15
- slidePanel.classList.toggle('hidden')
15
+ slidePanel.classList.toggle('ariadne-hidden')
16
16
  }
17
17
  this.buttonWrapperTarget.classList.toggle('bg-filter-panel')
18
- if (document.getElementById('btnClose')?.classList.contains('hidden')) {
18
+ if (document.getElementById('btnClose')?.classList.contains('ariadne-hidden')) {
19
19
  const formID = this.buttonWrapperTarget.getAttribute('data-slideover-component-form-id')
20
20
  if (formID) {
21
21
  const form = <HTMLFormElement>document.getElementById(formID)
@@ -1,12 +1,9 @@
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">
3
- <div data-slideover-component-target="expandable" class="hidden bg-filter-panel px-3 pb-4">
2
+ <div data-slideover-component-target="expandWrapper" class="ariadne-flex ariadne-flex-col ariadne-z-10">
3
+ <div data-slideover-component-target="expandable" class="ariadne-hidden bg-filter-panel ariadne-px-3 ariadne-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
- <div data-slideover-component-target="buttonWrapper" data-slideover-component-form-id="<%= @form_id %>" class="relative flex justify-center">
6
+ <div data-slideover-component-target="buttonWrapper" data-slideover-component-form-id="<%= @form_id %>" class="ariadne-relative ariadne-flex ariadne-justify-center">
10
7
  <%= open_button %>
11
8
  <%= close_button %>
12
9
  </div>
@@ -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 = "ariadne-inline-flex ariadne-items-center ariadne-shadow-sm ariadne-px-4 ariadne-py-1.5 ariadne-pb-2 ariadne-text-sm ariadne-leading-5 ariadne-font-medium ariadne-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,3 @@
1
+ <%= render Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes) do |component| %>
2
+ <%= content %>
3
+ <% end %>
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ariadne
4
+ # A container for a row of tags.
5
+ # @accessibility This component requires you to pass in a `sr_label`
6
+ # attribute, which will be used to label the tabs for screen readers.
7
+ class TabBarComponent < Ariadne::Component
8
+ DEFAULT_TAG = :nav
9
+ TAG_OPTIONS = [DEFAULT_TAG].freeze
10
+
11
+ DEFAULT_CLASSES = "ariadne--mb-px ariadne-flex ariadne-space-x-8 ariadne-bg-transparent"
12
+
13
+ # Tabs to be rendered. For more information, refer to <%= link_to_component(Ariadne::TabComponent) %>.
14
+ #
15
+ # @param selected [Boolean] Whether the tab is selected.
16
+ # @param classes [String] <%= link_to_classes_docs %>
17
+ # @param attributes [Hash] <%= link_to_attributes_docs %>
18
+ renders_many :tabs, lambda { |selected: false, classes: "", attributes: {}|
19
+ Ariadne::TabComponent.new(
20
+ selected: selected,
21
+ classes: classes,
22
+ attributes: attributes
23
+ )
24
+ }
25
+
26
+ # @example Default
27
+ #
28
+ # <%= render(Ariadne::TabBarComponent.new(sr_label: "Navigation tabs")) { "Example" } %>
29
+ #
30
+ # @param tag [Symbol, String] The rendered tag name.
31
+ # @param sr_label [String] A label to introduce these tabs for screen readers.
32
+ # @param classes [String] <%= link_to_classes_docs %>
33
+ # @param attributes [Hash] <%= link_to_attributes_docs %>
34
+ def initialize(tag: DEFAULT_TAG, sr_label:, classes: "", attributes: {})
35
+ @tag = check_incoming_tag(DEFAULT_TAG, tag)
36
+ @classes = class_names(
37
+ DEFAULT_CLASSES,
38
+ classes
39
+ )
40
+ @sr_label = sr_label
41
+ @attributes = attributes
42
+ @attributes[:"aria-label"] ||= "Tabs"
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,7 @@
1
+ <%= render(Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes)) do |component| %>
2
+ <% if text.present? %>
3
+ <%= text %>
4
+ <% else %>
5
+ <%= content %>
6
+ <% end %>
7
+ <% end %>
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ariadne
4
+ # Represents a sequence of tabs which, when clicked, swap between panel contents.
5
+ class TabComponent < Ariadne::Component
6
+ DEFAULT_TAG = :button
7
+ TAG_OPTIONS = [DEFAULT_TAG].freeze
8
+
9
+ # The Tab's text.
10
+ #
11
+ # @param kwargs [Hash] The same arguments as <%= link_to_component(Ariadne::Text) %>.
12
+ renders_one :text, Ariadne::Text
13
+
14
+ attr_reader :selected
15
+
16
+ DEFAULT_CLASSES = "ariadne-border-gray-300 ariadne-border ariadne-shadow ariadne-py-5 ariadne-px-5 ariadne-rounded-md"
17
+
18
+ BASE_TAB_CLASSES = "ariadne-whitespace-nowrap ariadne-py-4 ariadne-px-1 ariadne-border-b-2 ariadne-font-medium ariadne-text-sm"
19
+
20
+ # @example Default
21
+ #
22
+ # <%= render(Ariadne::TabComponent.new) { "Example" } %>
23
+ #
24
+ # @param tag [Symbol, String] The rendered tag name.
25
+ # @param selected [Boolean] Whether the tab is selected or not.
26
+ # @param classes [String] <%= link_to_classes_docs %>
27
+ # @param attributes [Hash] <%= link_to_attributes_docs %>
28
+ def initialize(tag: DEFAULT_TAG, selected: false, classes: "", attributes: {})
29
+ @tag = check_incoming_tag(DEFAULT_TAG, tag)
30
+ @classes = class_names(
31
+ DEFAULT_CLASSES,
32
+ classes
33
+ )
34
+
35
+ @attributes = attributes
36
+ @attributes[:id] ||= "tabs-tab-#{@tab_idx}"
37
+ @attributes[:"aria-controls"] = "tabs-panel-#{@tab_idx}"
38
+ @attributes[:"aria-current"] = "page" if selected
39
+ @attributes[:selected] = selected
40
+ @classes = class_names(BASE_TAB_CLASSES, classes)
41
+ end
42
+ end
43
+ end
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ariadne
4
- # Displays a time relative to how long ago it was. This component requires JavaScript.
4
+ # Displays a time ariadne-relative to how long ago it was. This component requires JavaScript.
5
5
  class TimeAgoComponent < Ariadne::Component
6
6
  DEFAULT_TAG = :"time-ago"
7
7
  TAG_OPTIONS = [DEFAULT_TAG].freeze
8
8
 
9
- DEFAULT_CLASSES = "whitespace-nowrap"
9
+ DEFAULT_CLASSES = "ariadne-whitespace-nowrap"
10
10
 
11
11
  # @example Default
12
12
  #
@@ -1,13 +1,13 @@
1
1
  <%= render Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes) do %>
2
2
  <div>
3
- <div class="divide-y divide-gray-200">
4
- <div class="pb-4">
5
- <h2 id="activity-title" class="text-lg font-medium text-gray-900">Timeline</h2>
3
+ <div class="ariadne-divide-y ariadne-divide-gray-200">
4
+ <div class="ariadne-pb-4">
5
+ <h2 id="activity-title" class="ariadne-text-lg ariadne-font-medium ariadne-text-gray-900">Timeline</h2>
6
6
  </div>
7
- <div class="pt-6">
7
+ <div class="ariadne-pt-6">
8
8
  <!-- Activity feed-->
9
- <div class="flow-root">
10
- <ul role="list" class="-mb-8">
9
+ <div class="ariadne-flow-root">
10
+ <ul role="list" class="ariadne--mb-8">
11
11
  <% items.each do %>
12
12
  <%= items %>
13
13
  <% end %>
@@ -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('ariadne-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('ariadne-invisible')
54
+
55
+ this.dispatch('ariadne-hidden', {detail: {trigger: this.triggerTarget, tooltip: this.tooltipTarget}})
56
+ }
57
+ }