Class: NitroKit::Button

Inherits:
Component
  • Object
show all
Defined in:
app/components/nitro_kit/button.rb

Constant Summary collapse

VARIANTS =
%i[default primary destructive ghost].freeze
SIZES =
%i[xs sm md lg xl].freeze
TYPES =
%i[button submit reset].freeze
SUBMISSION_INDICATORS =
%i[spinner].freeze
DEFAULT_TYPE =
:button

Constants inherited from Component

Component::ADDITIVE_DATA_ATTRIBUTES, Component::COMPONENT_OWNED_DATA_ATTRIBUTES, Component::FORBIDDEN_ATTRIBUTES, Component::RESERVED_DATA_ATTRIBUTES

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(text = nil, href: nil, variant: :default, size: :md, icon: nil, icon_end: nil, label: nil, id: nil, type: UNSET_TYPE, name: nil, value: nil, form: nil, target: nil, rel: nil, download: nil, disabled: false, loading: false, submission_indicator: nil, html: {}, aria: {}, data: {}, desperately_need_a_class: nil) ⇒ Button

Returns a new instance of Button.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'app/components/nitro_kit/button.rb', line 13

def initialize(
  text = nil,
  href: nil,
  variant: :default,
  size: :md,
  icon: nil,
  icon_end: nil,
  label: nil,
  id: nil,
  type: UNSET_TYPE,
  name: nil,
  value: nil,
  form: nil,
  target: nil,
  rel: nil,
  download: nil,
  disabled: false,
  loading: false,
  submission_indicator: nil,
  html: {},
  aria: {},
  data: {},
  desperately_need_a_class: nil
)
  if !href.nil? && (!href.is_a?(String) || href.empty?)
    raise ArgumentError, "Button href must be nil or a non-blank String"
  end
  if href && !type.equal?(UNSET_TYPE)
    raise ArgumentError, "Link Buttons do not accept type; type: applies to native button elements"
  end
  if href && [ name, value, form ].any? { |option| !option.nil? }
    raise ArgumentError, "Link Buttons do not accept name, value, or form"
  end
  if !href && [ target, rel, download ].any? { |option| !option.nil? }
    raise ArgumentError, "Button elements do not accept target, rel, or download"
  end
  if !label.nil? && (!label.is_a?(String) || label.strip.empty?)
    raise ArgumentError, "Button label: must be a non-blank String"
  end
  if text.is_a?(String) && text.strip.empty?
    raise ArgumentError, "Button text must be non-blank"
  end

  @text = text
  @href = href
  @icon = icon
  @icon_end = icon_end
  @label = label
  @variant = validate_choice!(:variant, variant, VARIANTS)
  @size = validate_choice!(:size, size, SIZES)
  @type = validate_choice!(:type, resolved_type(type), TYPES)
  @loading = validate_boolean!(:loading, loading)
  @disabled = validate_boolean!(:disabled, disabled) || @loading
  @aria = aria
  @submission_feedback = submission_feedback(data)
  @submission_indicator = if submission_indicator.nil?
    nil
  else
    validate_choice!(:submission_indicator, submission_indicator, SUBMISSION_INDICATORS)
  end
  if @submission_indicator && (href || @type != :submit)
    raise ArgumentError, "submission_indicator: applies only to native submit Buttons"
  end
  if @submission_indicator && @loading
    raise ArgumentError, "submission_indicator: and loading: cannot be combined"
  end

  owned_aria = {
    label: @label,
    busy: @loading ? true : nil
  }.compact

  native_attributes = if href
    {
      id:,
      href: @disabled ? nil : href,
      target:,
      rel:,
      download:,
      tabindex: @disabled ? -1 : nil,
      aria: owned_aria
    }.compact.tap do |attributes|
      if @disabled
        attributes[:href] = nil
        attributes[:aria] = attributes[:aria].merge(disabled: true)
      end
      attributes.delete(:aria) if attributes[:aria].empty?
    end
  else
    {
      id:,
      type: @type,
      name:,
      value:,
      form:,
      disabled: @disabled,
      aria: owned_aria.presence,
      data: submission_data
    }.compact
  end

  super(
    component: :button,
    attributes: native_attributes,
    html:,
    aria:,
    data:,
    variant:,
    size:,
    desperately_need_a_class:
  )
end

Instance Attribute Details

#hrefObject (readonly)

Returns the value of attribute href.



126
127
128
# File 'app/components/nitro_kit/button.rb', line 126

def href
  @href
end

#iconObject (readonly)

Returns the value of attribute icon.



126
127
128
# File 'app/components/nitro_kit/button.rb', line 126

def icon
  @icon
end

#icon_endObject (readonly)

Returns the value of attribute icon_end.



126
127
128
# File 'app/components/nitro_kit/button.rb', line 126

def icon_end
  @icon_end
end

#labelObject (readonly)

Returns the value of attribute label.



126
127
128
# File 'app/components/nitro_kit/button.rb', line 126

def label
  @label
end

#sizeObject (readonly)

Returns the value of attribute size.



126
127
128
# File 'app/components/nitro_kit/button.rb', line 126

def size
  @size
end

#textObject (readonly)

Returns the value of attribute text.



126
127
128
# File 'app/components/nitro_kit/button.rb', line 126

def text
  @text
end

#variantObject (readonly)

Returns the value of attribute variant.



126
127
128
# File 'app/components/nitro_kit/button.rb', line 126

def variant
  @variant
end

Instance Method Details

#loading?Boolean

Returns:

  • (Boolean)


128
# File 'app/components/nitro_kit/button.rb', line 128

def loading? = @loading

#view_template(&block) ⇒ Object

Raises:

  • (ArgumentError)


130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'app/components/nitro_kit/button.rb', line 130

def view_template(&block)
  raise ArgumentError, "Button accepts text or a block, not both" if !text.nil? && block
  unless !text.nil? || block || icon || icon_end
    raise ArgumentError, "Button requires text, a block, or an icon"
  end
  # Only render time knows whether a block supplies the visible label.
  if text.nil? && !block && !accessible_label?
    raise ArgumentError, "Icon-only Button requires label:, aria: { label: }, or aria: { labelledby: }"
  end

  tag = href ? :a : :button
  public_send(tag, **root_attributes) { contents(&block) }
end