ariadne_view_components 0.0.12-x86_64-darwin → 0.0.14-x86_64-darwin

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/ariadne.d.ts +1 -0
  3. data/app/assets/javascripts/ariadne_view_components.js +2 -2
  4. data/app/assets/javascripts/ariadne_view_components.js.map +1 -1
  5. data/app/assets/javascripts/comment-component.d.ts +1 -2
  6. data/app/assets/javascripts/tab-container-component.d.ts +1 -0
  7. data/app/assets/javascripts/tab-nav-component.d.ts +9 -0
  8. data/app/assets/stylesheets/ariadne_view_components.css +1 -0
  9. data/app/assets/stylesheets/dropdown.css +46 -0
  10. data/app/assets/stylesheets/tooltip-component.css +8 -8
  11. data/app/components/ariadne/ariadne.ts +3 -2
  12. data/app/components/ariadne/avatar_component.rb +81 -0
  13. data/app/components/ariadne/avatar_stack_component.html.erb +12 -0
  14. data/app/components/ariadne/avatar_stack_component.rb +75 -0
  15. data/app/components/ariadne/base_button.rb +13 -4
  16. data/app/components/ariadne/blankslate_component.rb +4 -4
  17. data/app/components/ariadne/body_component.rb +1 -1
  18. data/app/components/ariadne/button_component.html.erb +1 -1
  19. data/app/components/ariadne/button_component.rb +11 -5
  20. data/app/components/ariadne/comment-component.ts +32 -50
  21. data/app/components/ariadne/comment_component.html.erb +31 -13
  22. data/app/components/ariadne/comment_component.rb +18 -6
  23. data/app/components/ariadne/component.rb +3 -5
  24. data/app/components/ariadne/container_component.rb +1 -1
  25. data/app/components/ariadne/counter_component.rb +1 -1
  26. data/app/components/ariadne/details_component.html.erb +4 -0
  27. data/app/components/ariadne/details_component.rb +80 -0
  28. data/app/components/ariadne/dropdown/menu_component.html.erb +20 -0
  29. data/app/components/ariadne/dropdown/menu_component.rb +101 -0
  30. data/app/components/ariadne/dropdown/menu_component.ts +1 -0
  31. data/app/components/ariadne/dropdown_component.html.erb +8 -0
  32. data/app/components/ariadne/dropdown_component.rb +172 -0
  33. data/app/components/ariadne/flash_component.rb +1 -1
  34. data/app/components/ariadne/flex_component.rb +2 -2
  35. data/app/components/ariadne/footer_component.html.erb +1 -1
  36. data/app/components/ariadne/footer_component.rb +1 -1
  37. data/app/components/ariadne/grid_component.html.erb +2 -2
  38. data/app/components/ariadne/grid_component.rb +10 -8
  39. data/app/components/ariadne/header_component.rb +3 -3
  40. data/app/components/ariadne/heroicon_component.html.erb +1 -1
  41. data/app/components/ariadne/heroicon_component.rb +7 -6
  42. data/app/components/ariadne/inline_flex_component.html.erb +1 -0
  43. data/app/components/ariadne/inline_flex_component.rb +8 -1
  44. data/app/components/ariadne/link_component.rb +2 -2
  45. data/app/components/ariadne/list_component.html.erb +2 -11
  46. data/app/components/ariadne/list_component.rb +11 -15
  47. data/app/components/ariadne/main_component.rb +2 -2
  48. data/app/components/ariadne/narrow_container_component.rb +1 -1
  49. data/app/components/ariadne/panel_bar_component.rb +2 -2
  50. data/app/components/ariadne/pill_component.rb +20 -6
  51. data/app/components/ariadne/rich-text-area-component.ts +4 -4
  52. data/app/components/ariadne/rich_text_area_component.html.erb +2 -2
  53. data/app/components/ariadne/rich_text_area_component.rb +2 -2
  54. data/app/components/ariadne/slideover_component.html.erb +1 -1
  55. data/app/components/ariadne/slideover_component.rb +2 -2
  56. data/app/components/ariadne/tab-container-component.ts +24 -0
  57. data/app/components/ariadne/tab-nav-component.ts +34 -0
  58. data/app/components/ariadne/tab_component.html.erb +2 -6
  59. data/app/components/ariadne/tab_component.rb +75 -19
  60. data/app/components/ariadne/tab_container_component.erb +12 -0
  61. data/app/components/ariadne/tab_container_component.rb +67 -0
  62. data/app/components/ariadne/tab_nav_component.html.erb +7 -0
  63. data/app/components/ariadne/tab_nav_component.rb +72 -0
  64. data/app/components/ariadne/table_nav_component.html.erb +52 -0
  65. data/app/components/ariadne/table_nav_component.rb +338 -0
  66. data/app/components/ariadne/time_ago_component.rb +1 -1
  67. data/app/components/ariadne/timeline_component.rb +1 -1
  68. data/app/components/ariadne/tooltip_component.html.erb +1 -1
  69. data/app/components/ariadne/tooltip_component.rb +4 -4
  70. data/app/lib/ariadne/action_view_extensions/form_helper.rb +21 -7
  71. data/app/lib/ariadne/fetch_or_fallback_helper.rb +11 -3
  72. data/app/lib/ariadne/form_builder.rb +2 -2
  73. data/app/lib/ariadne/icon_helper.rb +17 -13
  74. data/lib/ariadne/view_components/constants.rb +2 -2
  75. data/lib/ariadne/view_components/statuses.rb +2 -2
  76. data/lib/ariadne/view_components/version.rb +1 -1
  77. data/lib/rubocop/config/default.yml +1 -1
  78. data/lib/tasks/docs.rake +22 -97
  79. data/static/arguments.yml +151 -23
  80. data/static/audited_at.json +17 -1
  81. data/static/classes.yml +160 -268
  82. data/static/constants.json +208 -40
  83. data/static/statuses.json +17 -1
  84. data/tailwind.config.js +28 -19
  85. metadata +24 -10
  86. data/app/components/ariadne/tab_bar_component.html.erb +0 -3
  87. data/app/components/ariadne/tab_bar_component.rb +0 -45
  88. data/app/lib/ariadne/join_style_arguments_helper.rb +0 -14
  89. data/app/lib/ariadne/tab_nav_helper.rb +0 -35
  90. data/app/lib/ariadne/tabbed_component_helper.rb +0 -39
  91. data/app/lib/ariadne/test_selector_helper.rb +0 -20
  92. data/app/lib/ariadne/underline_nav_helper.rb +0 -44
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ariadne
4
+ # Use `TabNavComponent` to style navigation links, typically placed at the top
5
+ # of the page.
6
+ #
7
+ # For panel navigation, use <%= link_to_component(Ariadne::TabContainerComponent) %> instead.
8
+ #
9
+ # @accessibility
10
+ # - By default, `TabNavComponent` renders links within a `<nav>` element. `<nav>` has an
11
+ # implicit landmark role of `navigation` which should be reserved for main links.
12
+ # For all other set of links, set tag to `:div`.
13
+ # - See <%= link_to_component(Ariadne::TabComponent) %> for additional
14
+ # accessibility considerations.
15
+ class TabNavComponent < Ariadne::Component
16
+ DEFAULT_TAG = :nav
17
+ TAG_OPTIONS = [DEFAULT_TAG, :div].freeze
18
+
19
+ BODY_TAG_DEFAULT = :ul
20
+
21
+ # keep this consistent with tab-container-component.ts
22
+ SELECTED_CLASSES = "ariadne-border-indigo-500 ariadne-text-indigo-600"
23
+ UNSELECTED_CLASSES = "ariadne-text-gray-500 hover:ariadne-text-gray-700 hover:ariadne-border-gray-300"
24
+
25
+ DEFAULT_CLASSES = ""
26
+
27
+ # Tabs to be rendered. Use the tabs to list page links.
28
+ #
29
+ # @param selected [Boolean] Whether the tab is selected.
30
+ # @param classes [String] <%= link_to_classes_docs %>
31
+ # @param attributes [Hash] <%= link_to_attributes_docs %>
32
+ renders_many :tabs, lambda { |selected: false, href: nil, classes: "", attributes: {}|
33
+ attributes[:href] = href
34
+ attributes[:"data-tab-nav-component-target"] = "tab"
35
+ attributes[:"data-action"] = "click->tab-nav-component#toggle"
36
+
37
+ actual_classes = class_names(selected ? SELECTED_CLASSES : UNSELECTED_CLASSES, classes)
38
+ Ariadne::TabComponent.new(
39
+ selected: selected,
40
+
41
+ classes: actual_classes,
42
+ attributes: attributes,
43
+ )
44
+ }
45
+
46
+ # @example Default with `<nav>`
47
+ # @description
48
+ # `<nav>` is a landmark and should be reserved for main navigation links. See <%= link_to_accessibility %>.
49
+ # @code
50
+ # <%= render(Ariadne::TabNavComponent.new(label: "Nav")) do |c| %>
51
+ # <% c.tab(selected: true, href: "#") { "Tab 1" } %>
52
+ # <% c.tab(href: "#") { "Tab 2" } %>
53
+ # <% c.tab(href: "#") { "Tab 3" } %>
54
+ # <% end %>
55
+ #
56
+ # @param label [String] Sets an `aria-label` that helps assistive technology users understand the purpose of the links, and distinguish it from similar elements.
57
+ # @param tag [Symbol, String] The rendered tag name.
58
+ # @param classes [String] <%= link_to_classes_docs %>
59
+ # @param attributes [Hash] <%= link_to_attributes_docs %>
60
+ def initialize(label:, tag: DEFAULT_TAG, classes: "", attributes: {})
61
+ @tag = check_incoming_tag(DEFAULT_TAG, tag)
62
+ @classes = class_names(
63
+ DEFAULT_CLASSES,
64
+ classes,
65
+ )
66
+
67
+ @attributes = attributes
68
+ @attributes[:"aria-label"] = label
69
+ @attributes[:"data-controller"] = "tab-nav-component"
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,52 @@
1
+ <div class="ariadne-inline-block ariadne-min-w-full ariadne-py-2 ariadne-align-middle md:ariadne-px-6 lg:ariadne-px-8">
2
+ <div class="ariadne-overflow-hidden ariadne-shadow ariadne-ring-1 ariadne-ring-black ariadne-ring-opacity-5 md:ariadne-rounded-lg">
3
+ <%= render(Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes)) do |table| %>
4
+ <% if has_header_row? %>
5
+ <thead>
6
+ <%= render(Ariadne::BaseComponent.new(tag: :tr, classes: header_row.classes, attributes: header_row.attributes)) do %>
7
+ <%= header_row.selection_cell %>
8
+ <%= header_row.main_cell %>
9
+ <% header_row.action_cells.each_with_index do |action_cell, idx| %>
10
+ <% if idx.zero? %>
11
+ <%= action_cell %>
12
+ <% elsif idx == header_row.action_cells.size - 1 %>
13
+ <%= action_cell %>
14
+ <% else %>
15
+ <%= action_cell %>
16
+ <% end %>
17
+ <% end %>
18
+ <% end %>
19
+ </thead>
20
+ <% end %>
21
+ <tbody>
22
+ <% rows.each do |row| %>
23
+ <%= render(Ariadne::BaseComponent.new(tag: :tr, classes: row.classes, attributes: row.attributes)) do %>
24
+ <%= row.selection_cell %>
25
+ <%= row.main_cell %>
26
+ <% row.metadata_cells.each_with_index do |metadata_cell, idx| %>
27
+ <% if idx.zero? %>
28
+ <%= metadata_cell %>
29
+ <% elsif idx == row.metadata_cells.size - 1 %>
30
+ <%= metadata_cell %>
31
+ <% else %>
32
+ <%= metadata_cell %>
33
+ <% end %>
34
+ <% end %>
35
+ <% end %>
36
+ <% end %>
37
+ </tbody>
38
+ <% end %>
39
+ </div>
40
+ <% if has_footer? %>
41
+ <%= render(Ariadne::BaseComponent.new(tag: :div, classes: footer.classes, attributes: footer.attributes)) do %>
42
+ <%= footer.records_info %>
43
+ <%= render(Ariadne::BaseComponent.new(tag: :nav, classes: footer.pagination_bar.classes, attributes: footer.pagination_bar.attributes)) do %>
44
+ <%= footer.pagination_bar.prev_page %>
45
+ <% footer.pagination_bar.items.each do |item| %>
46
+ <%= item %>
47
+ <% end %>
48
+ <%= footer.pagination_bar.next_page %>
49
+ <% end %>
50
+ <% end %>
51
+ <% end %>
52
+ </div>
@@ -0,0 +1,338 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ariadne
4
+ # The `TableNavComponent` is used to render a table navigation.
5
+ class TableNavComponent < Ariadne::Component
6
+ DEFAULT_CLASSES = "ariadne-min-w-full ariadne-divide-y ariadne-divide-gray-300"
7
+
8
+ renders_one :header_row, "BaseRowItem::HeaderRowItem"
9
+
10
+ renders_many :rows, "BaseRowItem::RowItem"
11
+
12
+ renders_one :footer, "FooterItem"
13
+
14
+ DEFAULT_TAG = :table
15
+
16
+ # @example Default
17
+ #
18
+ # <%= render(Ariadne::TableNavComponent.new) do |table| %>
19
+ # <%= table.header_row do |header_row| %>
20
+ # <% header_row.selection_cell do %>
21
+ # Status
22
+ # <% end %>
23
+ # <% header_row.main_cell do %>
24
+ # State
25
+ # <% end %>
26
+ # <% header_row.action_cell do %>
27
+ # Labels
28
+ # <% end %>
29
+ # <% end %>
30
+ # <%= table.row do |row| %>
31
+ # <% row.selection_cell do %>
32
+ # G
33
+ # <% end %>
34
+ # <% row.main_cell do %>
35
+ # "California"
36
+ # <% end %>
37
+ # <% row.metadata_cell do %>
38
+ # Labels
39
+ # <% end %>
40
+ # <% end %>
41
+ # <%= table.row do |row| %>
42
+ # <% row.selection_cell do %>
43
+ # V
44
+ # <% end %>
45
+ # <% row.main_cell do %>
46
+ # "New York"
47
+ # <% end %>
48
+ # <% row.metadata_cell do %>
49
+ # Labels
50
+ # <% end %>
51
+ # <% end %>
52
+ # <%= table.row do |row| %>
53
+ # <% row.cell do %>
54
+ # D
55
+ # <% end %>
56
+ # <% row.selection_cell do %>
57
+ # "Texas"
58
+ # <% end %>
59
+ # <% row.metadata_cell do %>
60
+ # Labels
61
+ # <% end %>
62
+ # <% end %>
63
+ # <% end %>
64
+ #
65
+ # @param classes [String] <%= link_to_classes_docs %>
66
+ # @param attributes [Hash] <%= link_to_attributes_docs %>
67
+ def initialize(classes: "", attributes: {})
68
+ @tag = DEFAULT_TAG
69
+ @classes = class_names(
70
+ DEFAULT_CLASSES,
71
+ classes,
72
+ )
73
+
74
+ @attributes = attributes
75
+ end
76
+
77
+ def has_header_row?
78
+ header_row.present?
79
+ end
80
+
81
+ def has_footer?
82
+ footer.present?
83
+ end
84
+
85
+ # This component is part of `TableNavComponent` and should not be
86
+ # used as a standalone component.
87
+ class BaseRowItem < Ariadne::TableNavComponent
88
+ BASE_ROW_CLASSES = ""
89
+
90
+ DEFAULT_TAG = :tr
91
+
92
+ BASE_SELECTION_CLASSES = ""
93
+ renders_one :selection_cell, lambda { |classes: "", attributes: {}|
94
+ actual_classes = class_names(BASE_SELECTION_CLASSES, classes)
95
+ if header?
96
+ Ariadne::TableNavComponent::BaseCellItem::HeaderCellItem.new(classes: actual_classes, attributes: attributes)
97
+ else
98
+ Ariadne::TableNavComponent::BaseCellItem::CellItem.new(classes: actual_classes, attributes: attributes)
99
+ end
100
+ }
101
+
102
+ BASE_MAIN_CLASSES = "ariadne-pr-5"
103
+ renders_one :main_cell, lambda { |classes: "", attributes: {}|
104
+ actual_classes = class_names(BASE_MAIN_CLASSES, classes)
105
+ if header?
106
+ Ariadne::TableNavComponent::BaseCellItem::HeaderCellItem.new(classes: actual_classes, attributes: attributes)
107
+ else
108
+ Ariadne::TableNavComponent::BaseCellItem::CellItem.new(classes: actual_classes, attributes: attributes)
109
+ end
110
+ }
111
+
112
+ attr_reader :classes, :attributes
113
+
114
+ def initialize(classes: "", attributes: {})
115
+ @tag = DEFAULT_TAG
116
+ @classes = class_names(BASE_ROW_CLASSES, classes)
117
+
118
+ @attributes = attributes
119
+ end
120
+
121
+ private def linked?
122
+ @href.present?
123
+ end
124
+
125
+ private def header?
126
+ @header.present?
127
+ end
128
+
129
+ def call
130
+ Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes)
131
+ end
132
+
133
+ # This component is part of `TableNavComponent` and should not be
134
+ # used as a standalone component.
135
+ class RowItem < Ariadne::TableNavComponent::BaseRowItem
136
+ DEFAULT_ROW_CLASSES = "ariadne-bg-white"
137
+ DEFAULT_METADATA_CLASSES = ""
138
+ renders_many :metadata_cells, lambda { |classes: "", attributes: {}|
139
+ actual_classes = class_names(DEFAULT_METADATA_CLASSES, classes)
140
+ Ariadne::TableNavComponent::BaseCellItem::CellItem.new(classes: actual_classes, attributes: attributes)
141
+ }
142
+
143
+ attr_reader :href
144
+
145
+ def initialize(classes: "", attributes: {})
146
+ @header = false
147
+
148
+ actual_classes = class_names(DEFAULT_ROW_CLASSES, classes)
149
+
150
+ super(classes: actual_classes, attributes: attributes)
151
+ end
152
+ end
153
+
154
+ # This component is part of `TableNavComponent` and should not be
155
+ # used as a standalone component.
156
+ class HeaderRowItem < Ariadne::TableNavComponent::BaseRowItem
157
+ DEFAULT_HEADER_ROW_CLASSES = "ariadne-bg-gray-50 ariadne-text-left"
158
+
159
+ renders_many :action_cells, lambda { |classes: "", attributes: {}|
160
+ Ariadne::TableNavComponent::BaseCellItem::HeaderCellItem.new(classes: classes, attributes: attributes)
161
+ }
162
+
163
+ def initialize(classes: "", attributes: {})
164
+ @header = true
165
+
166
+ actual_classes = class_names(
167
+ DEFAULT_HEADER_ROW_CLASSES,
168
+ classes,
169
+ )
170
+
171
+ super(classes: actual_classes, attributes: attributes)
172
+ end
173
+ end
174
+ end
175
+
176
+ # This component is part of `TableNavComponent` and should not be
177
+ # used as a standalone component.
178
+ class BaseCellItem < Ariadne::TableNavComponent
179
+ DEFAULT_CELL_CLASSES = "ariadne-py-3.5 ariadne-pl-4 ariadne-pr-3 ariadne-text-left ariadne-text-sm ariadne-text-gray-900"
180
+
181
+ attr_writer :first, :last
182
+
183
+ def initialize(classes: "", attributes: {})
184
+ @classes = class_names(
185
+ DEFAULT_CELL_CLASSES,
186
+ classes,
187
+ )
188
+
189
+ @attributes = attributes
190
+ end
191
+
192
+ def call
193
+ render(Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes)) do
194
+ content
195
+ end
196
+ end
197
+
198
+ # This component is part of `TableNavComponent` and should not be
199
+ # used as a standalone component.
200
+ class HeaderCellItem < Ariadne::TableNavComponent::BaseCellItem
201
+ DEFAULT_HEADER_CELL_CLASSES = "ariadne-py-3.5 ariadne-pl-4 ariadne-pr-3 ariadne-text-left ariadne-text-sm ariadne-font-semibold ariadne-text-gray-900 sm:ariadne-pl-6 md:ariadne-pl-0"
202
+
203
+ DEFAULT_TAG = :th
204
+
205
+ WIDTH_CLASSES = {
206
+ none: "ariadne-flex-none ariadne-w-14 ariadne-px-4",
207
+ default: "ariadne-flex-initial",
208
+ narrow: "ariadne-flex-initial ariadne-w-1/5 ariadne-text-right",
209
+ wide: "ariadne-flex-grow ariadne-w-3/5 sm:ariadne-pl-6",
210
+ }
211
+
212
+ # TODO: add one_of check for width
213
+ def initialize(classes: "", attributes: {})
214
+ @tag = DEFAULT_TAG
215
+ actual_classes = class_names(DEFAULT_HEADER_CELL_CLASSES, classes)
216
+ attributes["scope"] = "col"
217
+ super(classes: actual_classes, attributes: attributes)
218
+ end
219
+ end
220
+
221
+ # This component is part of `TableNavComponent` and should not be
222
+ # used as a standalone component.
223
+ class CellItem < Ariadne::TableNavComponent::BaseCellItem
224
+ DEFAULT_CELL_CLASSES = ""
225
+
226
+ DEFAULT_TAG = :td
227
+
228
+ # TODO: add one_of check for width
229
+ def initialize(classes: "", attributes: {})
230
+ @tag = DEFAULT_TAG
231
+ actual_classes = class_names(DEFAULT_CELL_CLASSES, classes)
232
+ super(classes: actual_classes, attributes: attributes)
233
+ end
234
+ end
235
+ end
236
+
237
+ # This component is part of `TableNavComponent` and should not be
238
+ # used as a standalone component.
239
+ class FooterItem < Ariadne::TableNavComponent
240
+ DEFAULT_FOOTER_CLASSES = "ariadne-border-none ariadne-flex ariadne-items-center ariadne-justify-between ariadne-px-4 ariadne-py-3 sm:ariadne-px-6"
241
+
242
+ DEFAULT_RESULT_CLASSES = "ariadne-text-sm ariadne-text-gray-700"
243
+ renders_one :records_info, lambda { |classes: "", attributes: {}|
244
+ actual_classes = class_names(DEFAULT_RESULT_CLASSES, classes)
245
+ Ariadne::BaseComponent.new(tag: :p, classes: actual_classes, attributes: attributes)
246
+ }
247
+
248
+ renders_one :pagination_bar, "Ariadne::TableNavComponent::PaginationBarItem"
249
+
250
+ attr_reader :classes, :attributes
251
+
252
+ def initialize(classes: "", attributes: {})
253
+ @classes = class_names(
254
+ DEFAULT_FOOTER_CLASSES,
255
+ classes,
256
+ )
257
+
258
+ @attributes = attributes
259
+ end
260
+
261
+ def call
262
+ render(Ariadne::BaseComponent.new(tag: :div, classes: @classes, attributes: @attributes)) do
263
+ records_info.to_s + pagination_bar.to_s
264
+ end
265
+ end
266
+ end
267
+
268
+ # This component is part of `TableNavComponent` and should not be
269
+ # used as a standalone component.
270
+ class PaginationBarItem < Ariadne::FooterComponent
271
+ DEFAULT_PREV_PAGE_CLASSES = "ariadne-relative ariadne-inline-flex ariadne-items-center ariadne-rounded-l-md ariadne-border ariadne-border-gray-300 ariadne-bg-white ariadne-px-2 ariadne-py-2 ariadne-text-sm ariadne-font-medium ariadne-text-gray-500 hover:ariadne-bg-gray-50 focus:ariadne-z-20"
272
+ renders_one :prev_page, lambda { |disabled: false, href:, classes: "", attributes: {}|
273
+ if disabled
274
+ actual_classes = class_names(DEFAULT_PREV_PAGE_CLASSES, "ariadne-bg-gray-50", classes)
275
+
276
+ render(Ariadne::BaseComponent.new(tag: :span, classes: actual_classes, attributes: attributes)) do
277
+ render(Ariadne::HeroiconComponent.new(icon: "chevron-left", size: :sm, variant: :mini, text_attributes: { "aria-hidden": true }, text_classes: "ariadne-sr-only"))
278
+ end
279
+ else
280
+ actual_classes = class_names(DEFAULT_PREV_PAGE_CLASSES, "hover:ariadne-bg-gray-50", classes)
281
+ attributes[:"aria-label"] = "previous"
282
+
283
+ render(Ariadne::LinkComponent.new(href: href, classes: actual_classes, attributes: attributes)) do
284
+ render(Ariadne::HeroiconComponent.new(icon: "chevron-left", size: :sm, variant: :mini, text_attributes: { "aria-hidden": true }, text_classes: "ariadne-sr-only"))
285
+ end
286
+ end
287
+ }
288
+
289
+ DEFAULT_PAGE_CLASSES = "ariadne-relative ariadne-inline-flex ariadne-items-center ariadne-border ariadne-border-gray-300 ariadne-bg-white ariadne-px-4 ariadne-py-2 ariadne-text-sm ariadne-font-medium ariadne-text-gray-500 hover:ariadne-bg-gray-50 focus:ariadne-z-20"
290
+ DEFAULT_CURRENT_PAGE_CLASSES = "ariadne-relative ariadne-z-10 ariadne-inline-flex ariadne-items-center ariadne-border ariadne-border-indigo-500 ariadne-bg-indigo-50 ariadne-px-4 ariadne-py-2 ariadne-text-sm ariadne-font-medium ariadne-text-indigo-600 focus:ariadne-z-20"
291
+ DEFAULT_GAP_CLASSES = " ariadne-relative ariadne-inline-flex ariadne-items-center ariadne-border ariadne-border-gray-300 ariadne-bg-white ariadne-px-4 ariadne-py-2 ariadne-text-sm ariadne-font-medium ariadne-text-gray-700"
292
+ renders_many :items, lambda { |link:, classes: "", attributes: {}|
293
+ page, href = link
294
+ if page.is_a?(Integer)
295
+ actual_classes = class_names(DEFAULT_PAGE_CLASSES, classes)
296
+ render(Ariadne::LinkComponent.new(href: href, classes: actual_classes, attributes: attributes)) { page.to_s }
297
+ elsif page.is_a?(String)
298
+ actual_classes = class_names(DEFAULT_CURRENT_PAGE_CLASSES, classes)
299
+ render(Ariadne::LinkComponent.new(href: href, classes: actual_classes, attributes: attributes)) { page.to_s }
300
+ elsif page == :gap
301
+ actual_classes = class_names(DEFAULT_GAP_CLASSES, classes)
302
+ render(Ariadne::BaseComponent.new(tag: :span, classes: actual_classes, attributes: attributes)) { h(href.to_s) }
303
+ end
304
+ }
305
+
306
+ DEFAULT_NEXT_PAGE_CLASSES = "ariadne-relative ariadne-inline-flex ariadne-items-center ariadne-rounded-r-md ariadne-border ariadne-border-gray-300 ariadne-bg-white ariadne-px-2 ariadne-py-2 ariadne-text-sm ariadne-font-medium ariadne-text-gray-500 hover:ariadne-bg-gray-50 focus:ariadne-z-20"
307
+ renders_one :next_page, lambda { |disabled: false, href:, classes: "", attributes: {}|
308
+ if disabled
309
+ actual_classes = class_names(DEFAULT_NEXT_PAGE_CLASSES, "ariadne-bg-gray-50", classes)
310
+
311
+ render(Ariadne::BaseComponent.new(tag: :span, classes: actual_classes, attributes: attributes)) do
312
+ render(Ariadne::HeroiconComponent.new(icon: "chevron-right", size: :sm, variant: :mini, text_attributes: { "aria-hidden": true }, text_classes: "ariadne-sr-only"))
313
+ end
314
+ else
315
+ actual_classes = class_names(DEFAULT_NEXT_PAGE_CLASSES, "hover:ariadne-bg-gray-50", classes)
316
+ attributes[:"aria-label"] = "next"
317
+
318
+ render(Ariadne::LinkComponent.new(href: href, classes: actual_classes, attributes: attributes)) do
319
+ render(Ariadne::HeroiconComponent.new(icon: "chevron-right", size: :sm, variant: :mini, text_attributes: { "aria-hidden": true }, text_classes: "ariadne-sr-only"))
320
+ end
321
+ end
322
+ }
323
+
324
+ attr_reader :classes, :attributes
325
+
326
+ DEFAULT_PAGINATOR_CLASSES = "ariadne-flex ariadne-items-center ariadne-justify-between ariadne-m-10"
327
+ def initialize(classes: "", attributes: {})
328
+ @classes = class_names(
329
+ DEFAULT_PAGINATOR_CLASSES,
330
+ classes,
331
+ )
332
+
333
+ @attributes = attributes
334
+ @attributes[:"aria-label"] ||= "paginator"
335
+ end
336
+ end
337
+ end
338
+ end
@@ -21,7 +21,7 @@ module Ariadne
21
21
  @tag = check_incoming_tag(DEFAULT_TAG, tag)
22
22
  @classes = class_names(
23
23
  DEFAULT_CLASSES,
24
- classes
24
+ classes,
25
25
  )
26
26
 
27
27
  @time = time
@@ -25,7 +25,7 @@ module Ariadne
25
25
  @tag = check_incoming_tag(DEFAULT_TAG, tag)
26
26
  @classes = class_names(
27
27
  DEFAULT_CLASSES,
28
- classes
28
+ classes,
29
29
  )
30
30
 
31
31
  @attributes = attributes
@@ -1,4 +1,4 @@
1
1
  <%= render Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes) do %>
2
2
  <span><%= @text %></span>
3
- <span class="tooltip-arrow ariadne-absolute ariadne-block" data-popper-arrow></span>
3
+ <span class="ariadne-tooltip-arrow ariadne-absolute ariadne-block" data-popper-arrow></span>
4
4
  <% end %>
@@ -28,13 +28,13 @@ module Ariadne
28
28
  DEFAULT_PLACEMENT = :top
29
29
  VALID_PLACEMENTS = [DEFAULT_PLACEMENT, :right, :bottom, :left].freeze
30
30
 
31
- DEFAULT_CLASSES = "ariadne-invisible ariadne-absolute ariadne-bg-slate-900 ariadne-text-white ariadne-font-semibold ariadne-max-w-xs ariadne-py-1 ariadne-px-2 ariadne-rounded z-max"
31
+ DEFAULT_CLASSES = "ariadne-invisible ariadne-absolute ariadne-bg-slate-900 ariadne-text-white ariadne-font-semibold ariadne-max-w-xs ariadne-py-1 ariadne-px-2 ariadne-rounded ariadne-z-max"
32
32
 
33
33
  DATA_CONTROLLER = "tooltip-component"
34
34
  DATA_ACTION = "mouseover->tooltip-component#show mouseout->tooltip-component#hide"
35
35
 
36
36
  TYPE_DEFAULT = :description
37
- TYPE_OPTIONS = [:label, TYPE_DEFAULT].freeze
37
+ VALID_TYPES = [:label, TYPE_DEFAULT].freeze
38
38
 
39
39
  # DEFAULT_DATA_ATTRIBUTES = {
40
40
  # "data-controller": DATA_CONTROLLER,
@@ -85,7 +85,7 @@ module Ariadne
85
85
  # @param tag [Symbol, String] The rendered tag name
86
86
  # @param for_id [String] The ID of the element that the tooltip should be attached to.
87
87
  # @param text [String] The text content of the tooltip. This should be brief and no longer than a sentence.
88
- # @param type [Symbol] <%= one_of(Ariadne::TooltipComponent::TYPE_OPTIONS) %>
88
+ # @param type [Symbol] <%= one_of(Ariadne::TooltipComponent::VALID_TYPES) %>
89
89
  # @param direction [Symbol] <%= one_of(Ariadne::TooltipComponent::VALID_PLACEMENTS) %>
90
90
  # @param classes [String] <%= link_to_classes_docs %>
91
91
  # @param attributes [Hash] <%= link_to_attributes_docs %>
@@ -101,7 +101,7 @@ module Ariadne
101
101
  @attributes[:for] = for_id
102
102
 
103
103
  @attributes[:"data-tooltip-component-placement"] = fetch_or_raise(VALID_PLACEMENTS, direction)
104
- @attributes[:"data-type"] = fetch_or_raise(TYPE_OPTIONS, type)
104
+ @attributes[:"data-type"] = fetch_or_raise(VALID_TYPES, type)
105
105
  @attributes[:"data-tooltip-component-target"] = "tooltip"
106
106
  end
107
107
  end
@@ -6,16 +6,30 @@ module Ariadne
6
6
  module FormHelper
7
7
  include ClassNameHelper
8
8
 
9
- DEFAULT_FORM_CLASSES = "space-y-8 divide-y divide-gray-200 sm:space-y-5"
10
- def ariadne_form_with(model: nil, scope: nil, url: nil, format: nil, classes: {}, attributes: {}, **options, &block)
9
+ DEFAULT_FORM_CLASSES = "ariadne-space-y-8 ariadne-divide-y ariadne-divide-gray-200 sm:ariadne-space-y-5"
10
+ def ariadne_form_with(model: nil, scope: nil, url: nil, format: nil, classes: "", attributes: {}, **options, &block)
11
11
  options[:class] = class_names(DEFAULT_FORM_CLASSES, options[:class])
12
12
  options[:builder] ||= Ariadne::FormBuilder
13
13
  options[:html] ||= {}
14
- options = options.merge(attributes)
15
- data = {
16
- controller: "ariadne-form",
17
- }
18
- form_with(model: model, scope: scope, url: url, format: format, data: data, **options, &block)
14
+
15
+ data = options.delete(:data) || {}
16
+ attributes = attributes.delete_if do |key, value|
17
+ key_name = key.to_s
18
+ if key_name.start_with?("data-")
19
+ data[key_name.sub(/^data-/, "").to_sym] = value
20
+ true
21
+ else
22
+ false
23
+ end
24
+ end
25
+
26
+ data[:controller] = if data.fetch(:controller, {}).present?
27
+ "#{data[:controller]} ariadne-form"
28
+ else
29
+ "ariadne-form"
30
+ end
31
+
32
+ form_with(model: model, scope: scope, url: url, format: format, data: data, attributes: attributes, **options, &block)
19
33
  end
20
34
  end
21
35
  end
@@ -22,14 +22,17 @@ module Ariadne
22
22
 
23
23
  InvalidValueError = Class.new(StandardError)
24
24
 
25
- TRUE_OR_FALSE = [true, false].freeze
25
+ TRUE_OR_FALSE = Set.new([true, false]).freeze
26
26
 
27
- def fetch_or_raise(allowed_values, given_value)
27
+ INTEGER_TYPES = Set.new(["Integer"]).freeze
28
+
29
+ def fetch_or_raise(allowed_values, given_value, against: nil)
28
30
  if !allowed_values.is_a?(Array) && !allowed_values.is_a?(Set)
29
31
  raise ArgumentError, "allowed_values must be an array or a set; it was #{allowed_values.class}"
30
32
  end
31
33
 
32
- if allowed_values.include?(given_value)
34
+ check_against_given_value = against || given_value
35
+ if allowed_values.include?(check_against_given_value)
33
36
  given_value
34
37
  else
35
38
  raise InvalidValueError, <<~MSG
@@ -41,10 +44,15 @@ module Ariadne
41
44
  end
42
45
  end
43
46
 
47
+ # TODO: use these two more
44
48
  def fetch_or_raise_boolean(given_value)
45
49
  fetch_or_raise(TRUE_OR_FALSE, given_value)
46
50
  end
47
51
 
52
+ def fetch_or_raise_integer(given_value)
53
+ fetch_or_raise(INTEGER_TYPES, given_value, against: given_value.class.name)
54
+ end
55
+
48
56
  # TODO: test this
49
57
  def check_incoming_tag(preferred_tag, given_tag)
50
58
  return preferred_tag if given_tag.blank? || preferred_tag == given_tag
@@ -27,7 +27,7 @@ module Ariadne
27
27
  end
28
28
 
29
29
  DEFAULT_LABEL_CLASSES = "ariadne-block ariadne-text-sm ariadne-font-medium ariadne-text-gray-700 ariadne-pl-2"
30
- def label(object_name, content, ptions = {}, &block)
30
+ def label(object_name, content, options = {}, &block)
31
31
  options[:class] = class_names(DEFAULT_LABEL_CLASSES, options.delete(:classes))
32
32
  super(object_name, content, options, &block)
33
33
  end
@@ -39,7 +39,7 @@ module Ariadne
39
39
  end
40
40
 
41
41
  DEFAULT_CHECKBOX_CLASSES = "focus:ariadne-ring-indigo-500 ariadne-h-4 ariadne-w-4 ariadne-text-indigo-600 ariadne-border-gray-300 ariadne-rounded"
42
- def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
42
+ def check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0")
43
43
  options[:class] = class_names(DEFAULT_CHECKBOX_CLASSES, options.delete(:classes))
44
44
  super(method, options, checked_value, unchecked_value)
45
45
  end
@@ -1,18 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Ariadne::FetchOrFallbackHelper
4
- # A little helper to enable graceful fallbacks
3
+ # Ariadne::IconHelper
4
+ # A helper that insists on certain values when
5
+ # checking herocions and their varients.
5
6
  #
6
- # Use this helper to quietly ensure a value is
7
- # one that you expect:
8
- #
9
- # allowed_values - allowed options for *value*
10
- # given_value - input being coerced
11
- # fallback - returned if *given_value* is not included in *allowed_values*
12
- #
13
- # fetch_or_raise([1,2,3], 5) => 2
14
- # fetch_or_raise([1,2,3], 1) => 1
15
- # fetch_or_raise([1,2,3], nil) => 2
7
+ # Use this helper to loudly ensure a value is
8
+ # one that you expect.
16
9
  module Ariadne
17
10
  # :nodoc:
18
11
  module IconHelper
@@ -23,11 +16,22 @@ module Ariadne
23
16
 
24
17
  icon_presence!(icon, variant)
25
18
  variant_presence!(icon, variant)
26
- fetch_or_raise(HeroiconsHelper::Icon::VALID_VARIANTS, variant)
19
+ ensure_valid_variant(variant)
27
20
 
28
21
  true
29
22
  end
30
23
 
24
+ def ensure_valid_variant(variant)
25
+ check_variant = if variant.blank? || !variant.respond_to?(:to_s)
26
+ ""
27
+ else
28
+ variant.to_s
29
+ end
30
+
31
+ fetch_or_raise(HeroiconsHelper::Icon::VALID_VARIANTS, check_variant)
32
+ end
33
+ module_function :ensure_valid_variant
34
+
31
35
  def has_partial_icon?(icon, variant)
32
36
  icon.present? || variant.present?
33
37
  end
@@ -8,8 +8,8 @@ module Ariadne
8
8
  class Constants
9
9
  CONSTANTS = JSON.parse(
10
10
  File.read(
11
- File.join(File.dirname(__FILE__), "../../../static/constants.json")
12
- )
11
+ File.join(File.dirname(__FILE__), "../../../static/constants.json"),
12
+ ),
13
13
  ).freeze
14
14
 
15
15
  class << self