ariadne_view_components 0.0.93.2 → 0.0.94

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -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.rb +1 -1
  26. data/app/components/ariadne/ui/accordion/component.rb +3 -1
  27. data/app/components/ariadne/ui/accordion/item/component.html.erb +10 -10
  28. data/app/components/ariadne/ui/accordion/item/component.rb +12 -3
  29. data/app/components/ariadne/ui/avatar/component.html.erb +9 -7
  30. data/app/components/ariadne/ui/avatar/component.rb +55 -7
  31. data/app/components/ariadne/ui/badge/component.rb +35 -16
  32. data/app/components/ariadne/ui/banner/component.html.erb +23 -0
  33. data/app/components/ariadne/ui/banner/component.rb +226 -0
  34. data/app/components/ariadne/ui/banner/component.ts +46 -0
  35. data/app/components/ariadne/ui/blankslate/component.html.erb +2 -2
  36. data/app/components/ariadne/ui/blankslate/component.rb +12 -1
  37. data/app/components/ariadne/ui/button/component.rb +35 -24
  38. data/app/components/ariadne/ui/card/body/component.rb +1 -1
  39. data/app/components/ariadne/ui/card/component.rb +11 -7
  40. data/app/components/ariadne/ui/card/footer/component.rb +1 -1
  41. data/app/components/ariadne/ui/card/header/component.html.erb +2 -2
  42. data/app/components/ariadne/ui/card/header/component.rb +25 -16
  43. data/app/components/ariadne/ui/clipboard_copy/component.html.erb +1 -0
  44. data/app/components/ariadne/ui/clipboard_copy/component.rb +17 -21
  45. data/app/components/ariadne/ui/clipboard_copy/component.ts +15 -0
  46. data/app/components/ariadne/ui/color_dot/component.html.erb +5 -5
  47. data/app/components/ariadne/ui/color_dot/component.rb +19 -4
  48. data/app/components/ariadne/ui/combobox/component.html.erb +1 -1
  49. data/app/components/ariadne/ui/combobox/component.rb +54 -23
  50. data/app/components/ariadne/ui/combobox/component.ts +2 -0
  51. data/app/components/ariadne/ui/dialog/body/component.html.erb +3 -0
  52. data/app/components/ariadne/ui/dialog/body/component.rb +28 -0
  53. data/app/components/ariadne/ui/dialog/component.html.erb +25 -24
  54. data/app/components/ariadne/ui/dialog/component.rb +87 -18
  55. data/app/components/ariadne/ui/dialog/component.ts +5 -1
  56. data/app/components/ariadne/ui/dialog/footer/component.html.erb +3 -0
  57. data/app/components/ariadne/ui/dialog/footer/component.rb +34 -0
  58. data/app/components/ariadne/ui/heroicon/component.rb +21 -21
  59. data/app/components/ariadne/ui/image/component.rb +11 -23
  60. data/app/components/ariadne/ui/link/component.html.erb +1 -3
  61. data/app/components/ariadne/ui/link/component.rb +17 -4
  62. data/app/components/ariadne/ui/list/component.html.erb +5 -9
  63. data/app/components/ariadne/ui/list/component.rb +31 -7
  64. data/app/components/ariadne/ui/list/item/component.rb +6 -5
  65. data/app/components/ariadne/ui/pagination/component.rb +1 -2
  66. data/app/components/ariadne/ui/popover/component.html.erb +1 -1
  67. data/app/components/ariadne/ui/popover/component.rb +31 -26
  68. data/app/components/ariadne/ui/relative_time/component.html.erb +1 -0
  69. data/app/components/ariadne/ui/{time_ago → relative_time}/component.rb +15 -15
  70. data/app/components/ariadne/ui/{time_ago → relative_time}/component.ts +1 -1
  71. data/app/components/ariadne/ui/shortcut/component.html.erb +0 -1
  72. data/app/components/ariadne/ui/shortcut/component.rb +31 -5
  73. data/app/components/ariadne/ui/shortcut/component.ts +1 -1
  74. data/app/components/ariadne/ui/skeleton/component.rb +2 -8
  75. data/app/components/ariadne/ui/stats_panel/component.html.erb +3 -3
  76. data/app/components/ariadne/ui/stats_panel/component.rb +25 -1
  77. data/app/components/ariadne/ui/stats_panel/item/component.html.erb +3 -3
  78. data/app/components/ariadne/ui/stats_panel/item/component.rb +6 -6
  79. data/app/components/ariadne/ui/table/cell/component.rb +1 -1
  80. data/app/components/ariadne/ui/table/row/component.rb +1 -1
  81. data/app/components/ariadne/ui/typography/component.rb +3 -1
  82. data/app/frontend/controllers/tooltip_controller.ts +8 -3
  83. data/app/frontend/stylesheets/ariadne_view_components.css +1 -0
  84. data/app/frontend/stylesheets/theme.css +88 -0
  85. data/app/frontend/utils/createController.ts +9 -0
  86. data/app/helpers/ariadne/color_helper.rb +158 -0
  87. data/app/helpers/ariadne/form_helper.rb +1 -0
  88. data/app/helpers/ariadne/size_helper.rb +7 -0
  89. data/app/lib/ariadne/attributes_helper.rb +4 -4
  90. data/app/lib/ariadne/view_component/style_variants.rb +1 -1
  91. data/app/lib/ariadne/view_helper.rb +0 -6
  92. data/lib/ariadne/accessibility.rb +64 -0
  93. data/lib/ariadne/forms/dsl/form_object.rb +5 -1
  94. data/lib/ariadne/forms/dsl/input.rb +1 -1
  95. data/lib/ariadne/static/generate_arguments.rb +54 -0
  96. data/lib/ariadne/static/generate_audited_at.rb +17 -0
  97. data/lib/ariadne/static/generate_constants.rb +19 -0
  98. data/lib/ariadne/static/generate_previews.rb +53 -0
  99. data/lib/ariadne/static/generate_statuses.rb +17 -0
  100. data/lib/ariadne/static/generate_structure.rb +279 -0
  101. data/lib/ariadne/static.rb +68 -0
  102. data/lib/ariadne/view_components/constants.rb +2 -2
  103. data/lib/ariadne/view_components/version.rb +1 -1
  104. data/lib/ariadne/view_components.rb +0 -51
  105. data/lib/ariadne/yard/component_manifest.rb +81 -81
  106. data/lib/ariadne/yard/component_ref.rb +1 -1
  107. data/lib/ariadne/yard/docs_helper.rb +24 -16
  108. data/lib/ariadne/yard/dry_initializer/common_handler.rb +103 -0
  109. data/lib/ariadne/yard/dry_initializer/option_handler.rb +38 -0
  110. data/lib/ariadne/yard/dry_initializer/param_handler.rb +57 -0
  111. data/lib/ariadne/yard/registry.rb +2 -5
  112. data/lib/ariadne/yard/{info_arch_docs_helper.rb → structure_docs_helper.rb} +5 -5
  113. data/lib/ariadne/yard.rb +20 -8
  114. data/lib/rubocop/config/default.yml +0 -3
  115. metadata +34 -37
  116. data/app/components/ariadne/behaviors/captionable.rb +0 -55
  117. data/app/components/ariadne/turbo/frame/component.html.erb +0 -3
  118. data/app/components/ariadne/turbo/frame/component.rb +0 -16
  119. data/app/components/ariadne/turbo/stream_action/component.html.erb +0 -4
  120. data/app/components/ariadne/turbo/stream_action/component.rb +0 -25
  121. data/app/components/ariadne/ui/data_table/component.html.erb +0 -1
  122. data/app/components/ariadne/ui/data_table/component.rb +0 -11
  123. data/app/components/ariadne/ui/flash/component.html.erb +0 -18
  124. data/app/components/ariadne/ui/flash/component.rb +0 -151
  125. data/app/components/ariadne/ui/flash/component.ts +0 -56
  126. data/app/components/ariadne/ui/overlay/component.html.erb +0 -12
  127. data/app/components/ariadne/ui/overlay/component.rb +0 -54
  128. data/app/components/ariadne/ui/overlay/component.ts +0 -92
  129. data/app/components/ariadne/ui/time_ago/component.html.erb +0 -1
  130. data/lib/ariadne/view_components/commands.rb +0 -90
  131. data/lib/ariadne/view_components/statuses.rb +0 -14
  132. data/lib/ariadne/view_components/upstream.rb +0 -19
  133. data/lib/ariadne/yard/lookbook_pages_backend.rb +0 -235
  134. data/lib/rubocop/cop/ariadne/no_tag_memoize.rb +0 -44
  135. data/static/arguments.yml +0 -879
  136. data/static/assets/view-components.svg +0 -18
  137. data/static/classes.yml +0 -211
  138. data/static/constants.json +0 -743
  139. data/static/statuses.json +0 -58
  140. data/static/tailwindcss.yml +0 -727
  141. /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>