ariadne_view_components 0.0.93.2 → 0.0.94.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/README.md +13 -4
  4. data/app/assets/javascripts/ariadne_view_components.js +14 -14
  5. data/app/assets/javascripts/ariadne_view_components.js.br +0 -0
  6. data/app/assets/javascripts/ariadne_view_components.js.gz +0 -0
  7. data/app/assets/javascripts/ariadne_view_components.js.map +1 -1
  8. data/app/assets/stylesheets/ariadne_view_components.css +1 -1
  9. data/app/assets/stylesheets/ariadne_view_components.css.br +0 -0
  10. data/app/assets/stylesheets/ariadne_view_components.css.gz +0 -0
  11. data/app/components/ariadne/base_component.rb +25 -22
  12. data/app/components/ariadne/behaviors/tooltipable.rb +12 -12
  13. data/app/components/ariadne/form/checkbox/component.rb +2 -2
  14. data/app/components/ariadne/form/group/component.rb +1 -1
  15. data/app/components/ariadne/form/radio_button/component.rb +2 -2
  16. data/app/components/ariadne/form/select/component.rb +1 -1
  17. data/app/components/ariadne/form/text_field/component.html.erb +2 -2
  18. data/app/components/ariadne/form/text_field/component.rb +14 -7
  19. data/app/components/ariadne/form/toggle/component.rb +2 -2
  20. data/app/components/ariadne/form/toggle_group/component.rb +1 -1
  21. data/app/components/ariadne/form/toggle_group/option/component.rb +1 -1
  22. data/app/components/ariadne/layout/grid/component.rb +1 -1
  23. data/app/components/ariadne/layout/grid/item/component.rb +2 -2
  24. data/app/components/ariadne/layout/label_block/component.rb +1 -1
  25. data/app/components/ariadne/layout/narrow/component.html.erb +5 -5
  26. data/app/components/ariadne/layout/narrow/component.rb +1 -1
  27. data/app/components/ariadne/ui/accordion/component.rb +3 -1
  28. data/app/components/ariadne/ui/accordion/item/component.html.erb +10 -10
  29. data/app/components/ariadne/ui/accordion/item/component.rb +12 -3
  30. data/app/components/ariadne/ui/avatar/component.html.erb +9 -7
  31. data/app/components/ariadne/ui/avatar/component.rb +55 -7
  32. data/app/components/ariadne/ui/badge/component.rb +35 -16
  33. data/app/components/ariadne/ui/banner/component.html.erb +23 -0
  34. data/app/components/ariadne/ui/banner/component.rb +226 -0
  35. data/app/components/ariadne/ui/banner/component.ts +46 -0
  36. data/app/components/ariadne/ui/blankslate/component.html.erb +2 -2
  37. data/app/components/ariadne/ui/blankslate/component.rb +12 -1
  38. data/app/components/ariadne/ui/button/component.rb +35 -24
  39. data/app/components/ariadne/ui/card/body/component.rb +1 -1
  40. data/app/components/ariadne/ui/card/component.rb +11 -7
  41. data/app/components/ariadne/ui/card/footer/component.rb +1 -1
  42. data/app/components/ariadne/ui/card/header/component.html.erb +2 -2
  43. data/app/components/ariadne/ui/card/header/component.rb +25 -16
  44. data/app/components/ariadne/ui/clipboard_copy/component.html.erb +1 -0
  45. data/app/components/ariadne/ui/clipboard_copy/component.rb +17 -21
  46. data/app/components/ariadne/ui/clipboard_copy/component.ts +15 -0
  47. data/app/components/ariadne/ui/color_dot/component.html.erb +5 -5
  48. data/app/components/ariadne/ui/color_dot/component.rb +19 -4
  49. data/app/components/ariadne/ui/combobox/component.html.erb +1 -1
  50. data/app/components/ariadne/ui/combobox/component.rb +54 -23
  51. data/app/components/ariadne/ui/combobox/component.ts +2 -0
  52. data/app/components/ariadne/ui/dialog/body/component.html.erb +3 -0
  53. data/app/components/ariadne/ui/dialog/body/component.rb +28 -0
  54. data/app/components/ariadne/ui/dialog/component.html.erb +25 -24
  55. data/app/components/ariadne/ui/dialog/component.rb +87 -18
  56. data/app/components/ariadne/ui/dialog/component.ts +5 -1
  57. data/app/components/ariadne/ui/dialog/footer/component.html.erb +3 -0
  58. data/app/components/ariadne/ui/dialog/footer/component.rb +34 -0
  59. data/app/components/ariadne/ui/heroicon/component.rb +21 -21
  60. data/app/components/ariadne/ui/image/component.rb +11 -23
  61. data/app/components/ariadne/ui/link/component.html.erb +1 -3
  62. data/app/components/ariadne/ui/link/component.rb +17 -4
  63. data/app/components/ariadne/ui/list/component.html.erb +5 -9
  64. data/app/components/ariadne/ui/list/component.rb +31 -7
  65. data/app/components/ariadne/ui/list/item/component.rb +6 -5
  66. data/app/components/ariadne/ui/pagination/component.rb +1 -2
  67. data/app/components/ariadne/ui/popover/component.html.erb +1 -1
  68. data/app/components/ariadne/ui/popover/component.rb +31 -26
  69. data/app/components/ariadne/ui/relative_time/component.html.erb +1 -0
  70. data/app/components/ariadne/ui/{time_ago → relative_time}/component.rb +15 -15
  71. data/app/components/ariadne/ui/{time_ago → relative_time}/component.ts +1 -1
  72. data/app/components/ariadne/ui/shortcut/component.html.erb +0 -1
  73. data/app/components/ariadne/ui/shortcut/component.rb +31 -5
  74. data/app/components/ariadne/ui/shortcut/component.ts +1 -1
  75. data/app/components/ariadne/ui/skeleton/component.rb +2 -8
  76. data/app/components/ariadne/ui/stats_panel/component.html.erb +3 -3
  77. data/app/components/ariadne/ui/stats_panel/component.rb +25 -1
  78. data/app/components/ariadne/ui/stats_panel/item/component.html.erb +3 -3
  79. data/app/components/ariadne/ui/stats_panel/item/component.rb +6 -6
  80. data/app/components/ariadne/ui/table/cell/component.rb +1 -1
  81. data/app/components/ariadne/ui/table/row/component.rb +1 -1
  82. data/app/components/ariadne/ui/typography/component.rb +3 -1
  83. data/app/frontend/controllers/tooltip_controller.ts +8 -3
  84. data/app/frontend/stylesheets/ariadne_view_components.css +1 -0
  85. data/app/frontend/stylesheets/theme.css +88 -0
  86. data/app/frontend/utils/createController.ts +9 -0
  87. data/app/helpers/ariadne/color_helper.rb +158 -0
  88. data/app/helpers/ariadne/form_helper.rb +1 -0
  89. data/app/helpers/ariadne/size_helper.rb +7 -0
  90. data/app/lib/ariadne/attributes_helper.rb +4 -4
  91. data/app/lib/ariadne/view_component/style_variants.rb +1 -1
  92. data/app/lib/ariadne/view_helper.rb +0 -6
  93. data/lib/ariadne/accessibility.rb +64 -0
  94. data/lib/ariadne/forms/dsl/form_object.rb +5 -1
  95. data/lib/ariadne/forms/dsl/input.rb +1 -1
  96. data/lib/ariadne/static/generate_arguments.rb +54 -0
  97. data/lib/ariadne/static/generate_audited_at.rb +17 -0
  98. data/lib/ariadne/static/generate_constants.rb +19 -0
  99. data/lib/ariadne/static/generate_previews.rb +53 -0
  100. data/lib/ariadne/static/generate_statuses.rb +17 -0
  101. data/lib/ariadne/static/generate_structure.rb +279 -0
  102. data/lib/ariadne/static.rb +68 -0
  103. data/lib/ariadne/view_components/constants.rb +2 -2
  104. data/lib/ariadne/view_components/version.rb +1 -1
  105. data/lib/ariadne/view_components.rb +0 -51
  106. data/lib/ariadne/yard/component_manifest.rb +81 -81
  107. data/lib/ariadne/yard/component_ref.rb +1 -1
  108. data/lib/ariadne/yard/docs_helper.rb +24 -16
  109. data/lib/ariadne/yard/dry_initializer/common_handler.rb +103 -0
  110. data/lib/ariadne/yard/dry_initializer/option_handler.rb +38 -0
  111. data/lib/ariadne/yard/dry_initializer/param_handler.rb +57 -0
  112. data/lib/ariadne/yard/registry.rb +2 -5
  113. data/lib/ariadne/yard/{info_arch_docs_helper.rb → structure_docs_helper.rb} +5 -5
  114. data/lib/ariadne/yard.rb +20 -8
  115. data/lib/rubocop/config/default.yml +0 -3
  116. metadata +34 -37
  117. data/app/components/ariadne/behaviors/captionable.rb +0 -55
  118. data/app/components/ariadne/turbo/frame/component.html.erb +0 -3
  119. data/app/components/ariadne/turbo/frame/component.rb +0 -16
  120. data/app/components/ariadne/turbo/stream_action/component.html.erb +0 -4
  121. data/app/components/ariadne/turbo/stream_action/component.rb +0 -25
  122. data/app/components/ariadne/ui/data_table/component.html.erb +0 -1
  123. data/app/components/ariadne/ui/data_table/component.rb +0 -11
  124. data/app/components/ariadne/ui/flash/component.html.erb +0 -18
  125. data/app/components/ariadne/ui/flash/component.rb +0 -151
  126. data/app/components/ariadne/ui/flash/component.ts +0 -56
  127. data/app/components/ariadne/ui/overlay/component.html.erb +0 -12
  128. data/app/components/ariadne/ui/overlay/component.rb +0 -54
  129. data/app/components/ariadne/ui/overlay/component.ts +0 -92
  130. data/app/components/ariadne/ui/time_ago/component.html.erb +0 -1
  131. data/lib/ariadne/view_components/commands.rb +0 -90
  132. data/lib/ariadne/view_components/statuses.rb +0 -14
  133. data/lib/ariadne/view_components/upstream.rb +0 -19
  134. data/lib/ariadne/yard/lookbook_pages_backend.rb +0 -235
  135. data/lib/rubocop/cop/ariadne/no_tag_memoize.rb +0 -44
  136. data/static/arguments.yml +0 -879
  137. data/static/assets/view-components.svg +0 -18
  138. data/static/classes.yml +0 -211
  139. data/static/constants.json +0 -743
  140. data/static/statuses.json +0 -58
  141. data/static/tailwindcss.yml +0 -727
  142. /data/app/components/ariadne/ui/{time_ago → relative_time}/en.yml +0 -0
@@ -0,0 +1,226 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ module Ariadne
5
+ module UI
6
+ module Banner
7
+ # Use this component to draw attention to important information.
8
+ #
9
+ # ### Events
10
+ #
11
+ # |Name |Type |Bubbles |Cancelable |
12
+ # |:---------|:-------------------|:-------|:----------|
13
+ # |`dismiss` |`CustomEvent<void>` |No |No |
14
+ #
15
+ #
16
+ # @accessibility
17
+ # ### Improve discoverability with a heading and landmark
18
+ # Banners are made visually prominent with icons and colors to immediately draw attention.
19
+ #
20
+ # To ensure the Banner is also easily discoverable for assistive technology users, you must provide a heading inside of the Banner that describes the purpose of the Banner.
21
+ class Component < Ariadne::BaseComponent
22
+ # @param [Boolean] dismissible Whether the component can be dismissed with an "x" button.
23
+ option :dismissible, default: -> { false }
24
+ # @param [String] dismiss_label The aria-label text of the dismiss "x" button
25
+ option :dismiss_label, optional: true
26
+
27
+ DEFAULT_SCHEME = :default
28
+ VALID_SCHEMES = [DEFAULT_SCHEME, :danger, :warning, :info, :success].freeze
29
+
30
+ # @param [Symbol] scheme (:default) The scheme design to use. <%= one_of(Ariadne::UI::Banner::Component::VALID_SCHEMES) %>
31
+ option :scheme, default: -> { DEFAULT_SCHEME }
32
+
33
+ # @param [Symbol] width (:base) Indicates the width of the button. Can be either `:base` or `:full`.
34
+ option :width, default: proc { :base }
35
+
36
+ # @param [Boolean, String] autohide (false) Autohides the banner after a set amount of time. If `true`, uses the default timeout;
37
+ # otherwise, provide a value to use.
38
+ option :autohide, default: -> { false }
39
+
40
+ # @param [String] title A header announcing the banner.
41
+ option :title
42
+
43
+ # Content that will render on the right-hand side of the component.
44
+ #
45
+ # To render a button, call the `with_action_button` method, which accepts the arguments accepted by <%= link_to_component(Ariadne::UI::Button::Component) %>.
46
+ #
47
+ # To render custom content, call the `with_action_content` method and pass a block that returns HTML.
48
+ renders_one :action, types: {
49
+ button: Ariadne::UI::Button::Component,
50
+ content: Ariadne::BaseComponent::ACCEPT_ANYTHING,
51
+ }
52
+
53
+ # @param [Symbol] heroicon The name of a <%= link_to_heroicons %> icon to show on the left-hand side of the component. If no icon is provided, one will be chosen based on the scheme.
54
+ renders_one :heroicon, Ariadne::UI::Heroicon::Component
55
+
56
+ def icon
57
+ heroicon || infer_icon
58
+ end
59
+
60
+ accepts_html_attributes do |html_attrs|
61
+ autohide_value = if @autohide == true
62
+ 4000
63
+ else
64
+ @autohide.presence || 0
65
+ end
66
+
67
+ component_data_attrs = {
68
+ controller: stimulus_name,
69
+ "#{stimulus_name}-target": "banner",
70
+ "#{stimulus_name}-autohide-value": autohide_value,
71
+ }
72
+ html_attrs[:data] = merge_data_attributes(html_attrs, component_data_attrs)
73
+
74
+ html_attrs[:class] = merge_tailwind_classes([
75
+ style(scheme:, width:),
76
+ html_attrs[:class],
77
+ ])
78
+ end
79
+
80
+ def before_render
81
+ raise ArgumentError, "Requires `dismiss_label`" if dismissible && dismiss_label.nil?
82
+
83
+ @header_id = self.class.generate_id
84
+ end
85
+
86
+ def heroicon_or_default
87
+ if heroicon?
88
+ heroicon
89
+ else
90
+ icon = case scheme
91
+ when :danger
92
+ :"exclamation-circle"
93
+ when :warning
94
+ :"exclamation-triangle"
95
+ when :info
96
+ :"information-circle"
97
+ when :success
98
+ :"check-circle"
99
+ else
100
+ :"chat-bubble-bottom-center"
101
+ end
102
+
103
+ Ariadne::UI::Heroicon::Component.new(icon: icon, variant: :outline)
104
+ end
105
+ end
106
+
107
+ style do
108
+ base do
109
+ [
110
+ "ariadne-border",
111
+ "ariadne-pointer-events-auto",
112
+ "ariadne-overflow-hidden",
113
+ "ariadne-rounded-lg",
114
+ "ariadne-shadow-lg",
115
+ "ariadne-ring-1",
116
+ "ariadne-ring-slate-950",
117
+ "ariadne-ring-opacity-5",
118
+ "ariadne-z-50",
119
+ ]
120
+ end
121
+
122
+ variants do
123
+ width do
124
+ base do
125
+ [
126
+ "ariadne-w-full",
127
+ "ariadne-max-w-lg",
128
+ ]
129
+ end
130
+
131
+ full do
132
+ [
133
+ "ariadne-w-full",
134
+ ]
135
+ end
136
+ end
137
+
138
+ scheme do
139
+ default do
140
+ []
141
+ end
142
+ danger do
143
+ [
144
+ "ariadne-border-danger",
145
+ "ariadne-bg-red-50",
146
+ ]
147
+ end
148
+ warning do
149
+ [
150
+ "ariadne-border-warning",
151
+ "ariadne-bg-yellow-50",
152
+ ]
153
+ end
154
+ info do
155
+ [
156
+ "ariadne-border-info",
157
+ "ariadne-bg-blue-50",
158
+ ]
159
+ end
160
+ success do
161
+ [
162
+ "ariadne-border-success",
163
+ "ariadne-bg-green-50",
164
+ ]
165
+ end
166
+ end
167
+ end
168
+ end
169
+
170
+ style(:text) do
171
+ variants do
172
+ scheme do
173
+ danger do
174
+ [
175
+ "ariadne-text-red-700",
176
+ ]
177
+ end
178
+ warning do
179
+ [
180
+ "ariadne-text-yellow-700",
181
+ ]
182
+ end
183
+ info do
184
+ [
185
+ "ariadne-text-blue-700",
186
+ ]
187
+ end
188
+ success do
189
+ [
190
+ "ariadne-text-green-700",
191
+ ]
192
+ end
193
+ end
194
+ end
195
+ end
196
+
197
+ style(:dismissable) do
198
+ variants do
199
+ scheme do
200
+ danger do
201
+ [
202
+ "ariadne-text-red-700",
203
+ ]
204
+ end
205
+ warning do
206
+ [
207
+ "ariadne-text-yellow-700",
208
+ ]
209
+ end
210
+ info do
211
+ [
212
+ "ariadne-text-blue-700",
213
+ ]
214
+ end
215
+ success do
216
+ [
217
+ "ariadne-text-green-700",
218
+ ]
219
+ end
220
+ end
221
+ end
222
+ end
223
+ end
224
+ end
225
+ end
226
+ end
@@ -0,0 +1,46 @@
1
+ import {controllerFactory} from '@utils/createController'
2
+
3
+ export default class Controller extends controllerFactory()({
4
+ targets: {
5
+ banner: HTMLDivElement,
6
+ },
7
+ values: {
8
+ open: Boolean,
9
+ autohide: {
10
+ default: 4000,
11
+ type: Number,
12
+ },
13
+ },
14
+ }) {
15
+ connect() {
16
+ if (this.autohideValue != 0) {
17
+ const noop = (): void => {};
18
+
19
+ // Set a timer for it to be removed from the dom automatically
20
+ setTimeout(() => {
21
+ this.hide().then(noop).catch(noop);
22
+ }, this.autohideValue);
23
+ }
24
+ }
25
+
26
+ dismiss() {
27
+ this.remove();
28
+ // this.hide()
29
+
30
+ this.dispatchEvent(this.bannerTarget, 'ariadne-banner:dismiss')
31
+ }
32
+
33
+ show() {
34
+ this.bannerTarget.style.setProperty('display', 'initial')
35
+ }
36
+
37
+ remove() {
38
+ const parentElement = this.bannerTarget.parentElement
39
+ if (!parentElement) return
40
+
41
+ parentElement.removeChild(this.bannerTarget)
42
+ }
43
+ hide() {
44
+ this.bannerTarget.style.setProperty('display', 'none')
45
+ }
46
+ }
@@ -1,7 +1,7 @@
1
1
  <div class="ariadne-grow ariadne-flex ariadne-flex-col ariadne-justify-center ariadne-items-center ariadne-gap-1">
2
- <%= visual_icon %>
2
+ <%= visual_heroicon %>
3
3
  <div class="ariadne-pt-5">
4
- <%= render(Ariadne::UI::Typography::Component.new(type: :ann)) { title } %>
4
+ <%= render(Ariadne::UI::Typography::Component.new(type: :ann)) { title } %>
5
5
  </div>
6
6
  <div class="ariadne-space-y-2">
7
7
  <%= render(Ariadne::UI::Typography::Component.new(type: :lede)) { description } %>
@@ -4,11 +4,22 @@
4
4
  module Ariadne
5
5
  module UI
6
6
  module Blankslate
7
+ # Blankslate is used as placeholder to tell users why content is missing.
7
8
  class Component < Ariadne::BaseComponent
9
+ # @param [String] title The blank slate's title.
8
10
  option :title
11
+ # @param [String] description A description of why content is missing.
9
12
  option :description, optional: true
10
13
 
11
- renders_one :visual_icon, Ariadne::UI::Heroicon::Component
14
+ # Optional visual that appears at the center of the blankslate.
15
+ #
16
+ # Use:
17
+ #
18
+ # - `visual_heroicon` for a <%= link_to_component(Ariadne::UI::Heroicon::Component) %>.
19
+ #
20
+ # @param options [Hash] Same arguments as <%= link_to_component(Ariadne::UI::Heroicon::Component) %>.
21
+
22
+ renders_one :visual_heroicon, Ariadne::UI::Heroicon::Component
12
23
  end
13
24
  end
14
25
  end
@@ -4,19 +4,38 @@
4
4
  module Ariadne
5
5
  module UI
6
6
  module Button
7
+ # Used to initiate actions on a page or form.
8
+ #
9
+ # You can call `as_icon` to render a button with only an icon.
10
+ #
11
+ # @accessibility If `as_icon` is called, you must provide an `aria-label` or `aria-description` to the button.
12
+ #
13
+ # @behaviors <%= link_to_component(Ariadne::Behaviors::Tooltipable) %>
7
14
  class Component < Ariadne::BaseComponent
8
15
  attr_reader :icon_only
9
16
 
10
- include Ariadne::Behaviors::Captionable
11
17
  include Ariadne::Behaviors::Tooltipable
12
18
 
13
- option :as, default: proc { :button }
14
- option :href, default: proc { nil }
19
+ # @param [Symbol] as (:button) One of `:button` or :link. Indicates how to render the button: as a `button` or `a` tag.
20
+ option :as, default: -> { :button }
15
21
 
22
+ # @param [Symbol] href If `as: == :link`, this indicates where the `a` should go.
23
+ option :href, default: -> { nil }
24
+
25
+ # @param [String] type (button) Indicates the button's type, e.g. `submit`.
16
26
  option :type, default: proc { "button" }
17
- option :state, default: proc { "" }
18
- option :theme, default: proc { :primary }
19
- option :size, default: proc { :md }
27
+
28
+ DEFAULT_SCHEME = :primary
29
+ SCHEME_OPTIONS = [DEFAULT_SCHEME, :secondary, :nude, :danger].freeze
30
+
31
+ # @param [Symbol] scheme (:primary) Indicates the button's scheme. <%= one_of(Ariadne::UI::Button::Component::SCHEME_OPTIONS) %>
32
+ option :scheme, default: proc { DEFAULT_SCHEME }
33
+
34
+ DEFAULT_SIZE = :md
35
+ # @param [Symbol] size (Ariadne::UI::Button::DEFAULT_SIZE) Indicates the button's size. <%= one_of(Ariadne::SizeHelper::VALID_SIZES) %>
36
+ option :size, default: proc { DEFAULT_SIZE }
37
+
38
+ # @param [Symbol] width (:narrow) Indicates the width of the button. Can be either `:narrow` or `:full`.
20
39
  option :width, default: proc { :narrow }
21
40
 
22
41
  # Leading visuals appear to the left of the button text.
@@ -24,11 +43,10 @@ module Ariadne
24
43
  # Use:
25
44
  #
26
45
  # - `leading_visual_heroicon` for a <%= link_to_component(Ariadne::UI::Heroicon::Component) %>.
46
+ #
47
+ # @param options [Hash] Same arguments as the chosen visual.
27
48
  renders_one :leading_visual, types: {
28
- heroicon: lambda { |**options|
29
- options[:size] = @size
30
- Ariadne::UI::Heroicon::Component.new(**options)
31
- },
49
+ heroicon: Ariadne::UI::Heroicon::Component,
32
50
  }
33
51
 
34
52
  # Trailing visuals appear to the right of the button text.
@@ -36,15 +54,14 @@ module Ariadne
36
54
  # Use:
37
55
  #
38
56
  # - `trailing_visual_heroicon` for a <%= link_to_component(Ariadne::UI::Heroicon::Component) %>.
57
+ #
58
+ # @param options [Hash] Same arguments as the chosen visual.
39
59
  renders_one :trailing_visual, types: {
40
- heroicon: lambda { |**options|
41
- options[:size] = @size
42
- Ariadne::UI::Heroicon::Component.new(**options)
43
- },
60
+ heroicon: Ariadne::UI::Heroicon::Component,
44
61
  }
45
62
 
46
63
  accepts_html_attributes do |html_attrs|
47
- html_attrs[:class] = Ariadne::ViewComponents.tailwind_merger.merge([style(theme:, size:, icon_only:, width:), html_attrs[:class]].join(" "))
64
+ html_attrs[:class] = merge_tailwind_classes([style(scheme:, size:, icon_only:, width:), html_attrs[:class]].join(" "))
48
65
 
49
66
  if link?
50
67
  raise ArgumentError, "Button needs an `href` defined when using `as: :link`" if href.blank?
@@ -57,10 +74,6 @@ module Ariadne
57
74
  end
58
75
  end
59
76
 
60
- def initialize(**options)
61
- super
62
- end
63
-
64
77
  def as_icon(**options)
65
78
  validate_aria_label!(html_attrs)
66
79
 
@@ -109,17 +122,15 @@ module Ariadne
109
122
  end
110
123
 
111
124
  variants do
112
- theme do
125
+ scheme do
113
126
  primary do
114
127
  [
115
128
  "ariadne-bg-primary",
116
129
  "ariadne-text-primary-foreground",
117
130
 
118
- "hover:ariadne-bg-primary-hover",
119
- "active:ariadne-bg-primary-active",
131
+ "hover:enabled:ariadne-bg-primary/90",
120
132
 
121
- "disabled:ariadne-bg-primary-disabled-dark",
122
- "disabled:ariadne-text-primary-disabled-foreground-dark",
133
+ "disabled:ariadne-opacity-50",
123
134
  ]
124
135
  end
125
136
 
@@ -7,7 +7,7 @@ module Ariadne
7
7
  module Body
8
8
  class Component < Ariadne::BaseComponent
9
9
  accepts_html_attributes do |html_attrs|
10
- html_attrs[:class] = Ariadne::ViewComponents.tailwind_merger.merge([style, html_attrs[:class]].join(" "))
10
+ html_attrs[:class] = merge_tailwind_classes([style, html_attrs[:class]].join(" "))
11
11
  end
12
12
 
13
13
  style do
@@ -5,26 +5,30 @@ module Ariadne
5
5
  module UI
6
6
  module Card
7
7
  class Component < Ariadne::BaseComponent
8
- option :href, default: -> { nil }
8
+ # @param [String] href If provided, renders the entire card as a link.
9
+ option :href, optional: true
9
10
 
11
+ # Represent the card's header.
10
12
  renders_one :header, Ariadne::UI::Card::Header::Component
11
13
 
12
14
  accepts_html_attributes do |html_attrs|
13
- html_attrs[:class] = Ariadne::ViewComponents.tailwind_merger.merge([style(link: href.present? ? :yes : :no), html_attrs[:class]].join(" "))
15
+ html_attrs[:class] = merge_tailwind_classes([style(link: href.present? ? :yes : :no), html_attrs[:class]].join(" "))
14
16
  end
15
17
 
18
+ # The card's body.
16
19
  renders_one :body, Ariadne::UI::Card::Body::Component
20
+
21
+ # Represent the card's footer
17
22
  renders_one :footer, Ariadne::UI::Card::Footer::Component
18
23
 
19
24
  style do
20
25
  base do
21
26
  [
22
- "ariadne-rounded-lg",
27
+ "ariadne-rounded-xl",
23
28
  "ariadne-border",
24
- "ariadne-bg-foreground",
25
- "dark:ariadne-bg-foreground-dark",
26
- "ariadne-text-content",
27
- "dark:ariadne-text-content-dark",
29
+ "ariadne-bg-card",
30
+ "ariadne-text-card-foreground",
31
+ "ariadne-shadow",
28
32
  ]
29
33
  end
30
34
 
@@ -7,7 +7,7 @@ module Ariadne
7
7
  module Footer
8
8
  class Component < Ariadne::BaseComponent
9
9
  accepts_html_attributes do |html_attrs|
10
- html_attrs[:class] = Ariadne::ViewComponents.tailwind_merger.merge([style, html_attrs[:class]].join(" "))
10
+ html_attrs[:class] = merge_tailwind_classes([style, html_attrs[:class]].join(" "))
11
11
  end
12
12
 
13
13
  style do
@@ -1,6 +1,6 @@
1
1
  <div class="<%= html_attrs[:class] %>" <%= html_attributes %>>
2
- <%= title %>
2
+ <span class="<%= style(:title) %>"><%= title %></span>
3
3
  <% if description %>
4
- <%= description %>
4
+ <span class="<%= style(:description) %>"><%= description %></span>
5
5
  <% end %>
6
6
  </div>
@@ -5,26 +5,16 @@ module Ariadne
5
5
  module UI
6
6
  module Card
7
7
  module Header
8
+ # The header of a card.
8
9
  class Component < Ariadne::BaseComponent
9
- renders_one :title, lambda { |type: :subheading, **options|
10
- options[:type] ||= type
11
- options[:html_attrs] ||= {}
12
- options[:html_attrs][:class] ||= ""
13
- options[:html_attrs][:class] = [
14
- "ariadne-grow",
15
- "ariadne-leading-none",
16
- options[:html_attrs][:class],
17
- ]
18
- Ariadne::UI::Typography::Component.new(**options)
19
- }
10
+ # @param [String] title If provided, serves as the title of the card.
11
+ option :title, optional: true
20
12
 
21
- renders_one :description, lambda { |type: :muted, **options|
22
- options[:type] ||= type
23
- Ariadne::UI::Typography::Component.new(**options)
24
- }
13
+ # @param [String] description If provided, serves as the description of the card.
14
+ option :description, optional: true
25
15
 
26
16
  accepts_html_attributes do |html_attrs|
27
- html_attrs[:class] = Ariadne::ViewComponents.tailwind_merger.merge([style, html_attrs[:class]].join(" "))
17
+ html_attrs[:class] = merge_tailwind_classes([style, html_attrs[:class]].join(" "))
28
18
  end
29
19
 
30
20
  style do
@@ -37,6 +27,25 @@ module Ariadne
37
27
  ]
38
28
  end
39
29
  end
30
+
31
+ style(:title) do
32
+ base do
33
+ [
34
+ "ariadne-font-semibold",
35
+ "ariadne-leading-none",
36
+ "ariadne-tracking-tight",
37
+ ]
38
+ end
39
+ end
40
+
41
+ style(:description) do
42
+ base do
43
+ [
44
+ "araidne-text-sm",
45
+ "ariadne-text-muted-foreground",
46
+ ]
47
+ end
48
+ end
40
49
  end
41
50
  end
42
51
  end
@@ -6,3 +6,4 @@
6
6
  <%= render Ariadne::UI::Heroicon::Component.new(icon: :check, variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, html_attrs: { class: "ariadne-text-green-600 ariadne-hidden", data: { "ariadne-ui-clipboard-copy-target" => "confirmed" }}) %>
7
7
  <% end %>
8
8
  </clipboard-copy>
9
+ <div aria-live="polite" aria-atomic="true" class="ariadne-sr-only" data-clipboard-copy-feedback></div>
@@ -4,28 +4,24 @@
4
4
  module Ariadne
5
5
  module UI
6
6
  module ClipboardCopy
7
- # Use `ClipboardCopy` to copy element text content or input values to the clipboard.
8
- #
9
- # @example Default
10
- # <%= render(Ariadne::UI::ClipboardCopy::Component.new(value: "Text to copy", aria_label: "Copy text to the system clipboard" )) %>
11
- #
12
- # @example With text instead of icons
13
- # <%= render(Ariadne::UI::ClipboardCopy::Component.new(value: "Text to copy", aria_label: "Copy text to the system clipboard" )) do %>
14
- # Click to copy!
15
- # <% end %>
16
- #
17
- # @example Copying from an element
18
- # <%= render(Ariadne::UI::ClipboardCopy::Component.new(for_id: "blob-path", aria_label: "Copy text to the system clipboard" )) %>
19
- # <div id="blob-path">src/index.js</div>
7
+ # Use this to copy element text content or input values to the clipboard.
20
8
  #
21
9
  # @accessibility
22
- # Always set an accessible label to help the user interact with the component.
23
- class Component < Ariadne::UI::Button::Component
24
- # @param value [Strinulus_g] Text to copy when the component is clicked.
10
+ # Always set an accessible label (through `aria-label`) to help the user interact with the component.
11
+ #
12
+ # This component has a built-in `aria-live` region that announces "Copied!" when the copy element is pressed.
13
+ class Component < Ariadne::BaseComponent
14
+ # @param [String] value Text to copy when the component is clicked.
25
15
  option :value, optional: true
26
- # @param for [String] If `value` is not provided, the element with this id will be copied.
16
+ # @param [String] for If `value` is not provided, the element with this id will be copied.
27
17
  option :for, optional: true
28
18
 
19
+ DEFAULT_SIZE = :md
20
+ # @param [Symbol] size (Ariadne::UI::ClipboardCopy::DEFAULT_SIZE) Indicates the button's size. <%= one_of(Ariadne::SizeHelper::VALID_SIZES) %>
21
+ option :size, default: proc { DEFAULT_SIZE }
22
+
23
+ include Ariadne::Behaviors::Tooltipable
24
+
29
25
  def initialize(**options)
30
26
  super
31
27
  validate!
@@ -37,7 +33,7 @@ module Ariadne
37
33
  html_attrs[:value] = @value if @value.present?
38
34
  html_attrs[:for] = @for if @for.present?
39
35
 
40
- html_attrs[:class] = Ariadne::ViewComponents.tailwind_merger.merge([style(size:), html_attrs[:class]].join(" "))
36
+ html_attrs[:class] = merge_tailwind_classes([style(size:), html_attrs[:class]].join(" "))
41
37
 
42
38
  html_attrs[:data]["#{stimulus_name}-hidden-class-value"] = "ariadne-hidden"
43
39
  html_attrs[:data]["#{stimulus_name}-show-class-value"] = "ariadne-inline-block"
@@ -86,9 +82,6 @@ module Ariadne
86
82
  "[&>svg]:ariadne-size-4",
87
83
  ]
88
84
  end
89
- base do
90
- ["ariadne-gap-1", "ariadne-text-base", "ariadne-rounded-md"]
91
- end
92
85
  md do
93
86
  [
94
87
  "ariadne-gap-1",
@@ -100,6 +93,9 @@ module Ariadne
100
93
  lg do
101
94
  ["ariadne-gap-1", "ariadne-text-lg", "ariadne-rounded-lg"]
102
95
  end
96
+ xl do
97
+ ["ariadne-gap-1", "ariadne-text-xl", "ariadne-rounded-xl"]
98
+ end
103
99
  end
104
100
  end
105
101
  end
@@ -23,12 +23,27 @@ export default class ClipboardCopyController extends controllerFactory<HTMLDetai
23
23
  copy(event: Event) {
24
24
  const target = event.target as HTMLElement
25
25
  const currentTimeout = this.clipboardCopyElementTimers.get(target)
26
+ const clipboardCopyLiveRegion = target.parentNode?.querySelector<HTMLElement>('[data-clipboard-copy-feedback]')
27
+ const copiedAnnouncement = 'Copied!'
26
28
 
27
29
  if (currentTimeout) {
28
30
  clearTimeout(currentTimeout)
29
31
  this.clipboardCopyElementTimers.delete(target)
30
32
  } else {
31
33
  this.showConfirm()
34
+
35
+ if (clipboardCopyLiveRegion) {
36
+ if (clipboardCopyLiveRegion.textContent === copiedAnnouncement) {
37
+ /* This is a hack due to the way the aria live API works.
38
+ A screen reader will not read a live region again
39
+ if the text is the same. Adding a space character tells
40
+ the browser that the live region has updated,
41
+ which will cause it to read again, but with no audible difference. */
42
+ clipboardCopyLiveRegion.textContent = `${copiedAnnouncement}\u00A0`
43
+ } else {
44
+ clipboardCopyLiveRegion.textContent = copiedAnnouncement
45
+ }
46
+ }
32
47
  }
33
48
 
34
49
  this.clipboardCopyElementTimers.set(
@@ -1,7 +1,7 @@
1
1
  <span class="<%= style(size:) %>">
2
- <span class="ariadne-px-0.5 ariadne-p-1 ariadne-shrink-0">
3
- <svg class="<%= style(:svg, size:) %>" viewBox="0 0 1 1" xmlns="http://www.w3.org/2000/svg">
4
- <circle cx="0.5" cy="0.5" r="0.5" fill="<%= "rgba(#{color.join(',')})" %>" />
5
- </svg>
2
+ <span class="ariadne-px-0.5 ariadne-p-1 ariadne-shrink-0">
3
+ <svg class="<%= style(:svg, size:) %>" viewBox="0 0 1 1" xmlns="http://www.w3.org/2000/svg">
4
+ <circle cx="0.5" cy="0.5" r="0.5" fill="#<%= color %>" />
5
+ </svg>
6
6
  </span>
7
- </span>
7
+ </span>