summaryrefslogtreecommitdiff
path: root/app/components/pajamas
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-06-20 11:10:13 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-06-20 11:10:13 +0000
commit0ea3fcec397b69815975647f5e2aa5fe944a8486 (patch)
tree7979381b89d26011bcf9bdc989a40fcc2f1ed4ff /app/components/pajamas
parent72123183a20411a36d607d70b12d57c484394c8e (diff)
downloadgitlab-ce-0ea3fcec397b69815975647f5e2aa5fe944a8486.tar.gz
Add latest changes from gitlab-org/gitlab@15-1-stable-eev15.1.0-rc42
Diffstat (limited to 'app/components/pajamas')
-rw-r--r--app/components/pajamas/alert_component.html.haml9
-rw-r--r--app/components/pajamas/alert_component.rb14
-rw-r--r--app/components/pajamas/banner_component.html.haml23
-rw-r--r--app/components/pajamas/banner_component.rb61
-rw-r--r--app/components/pajamas/button_component.html.haml8
-rw-r--r--app/components/pajamas/button_component.rb118
-rw-r--r--app/components/pajamas/card_component.html.haml9
-rw-r--r--app/components/pajamas/card_component.rb21
-rw-r--r--app/components/pajamas/checkbox_component.html.haml6
-rw-r--r--app/components/pajamas/checkbox_component.rb56
-rw-r--r--app/components/pajamas/component.rb12
-rw-r--r--app/components/pajamas/concerns/checkbox_radio_label_with_help_text.rb30
-rw-r--r--app/components/pajamas/concerns/checkbox_radio_options.rb11
-rw-r--r--app/components/pajamas/radio_component.html.haml5
-rw-r--r--app/components/pajamas/radio_component.rb51
15 files changed, 417 insertions, 17 deletions
diff --git a/app/components/pajamas/alert_component.html.haml b/app/components/pajamas/alert_component.html.haml
index 782ac8b9ca2..13c458f05e9 100644
--- a/app/components/pajamas/alert_component.html.haml
+++ b/app/components/pajamas/alert_component.html.haml
@@ -1,11 +1,10 @@
-.gl-alert{ role: 'alert', class: [base_class, @alert_class], data: @alert_data }
+.gl-alert{ @alert_options, role: 'alert', class: base_class }
- if @show_icon
= sprite_icon(icon, css_class: icon_classes)
- if @dismissible
- %button.btn.gl-dismiss-btn.btn-default.btn-sm.gl-button.btn-default-tertiary.btn-icon.js-close{ type: 'button',
- aria: { label: _('Dismiss') },
- class: @close_button_class,
- data: @close_button_data }
+ %button.btn.gl-dismiss-btn.btn-default.btn-sm.gl-button.btn-default-tertiary.btn-icon.js-close{ @close_button_options,
+ type: 'button',
+ aria: { label: _('Dismiss') } }
= sprite_icon('close')
.gl-alert-content{ role: 'alert' }
- if @title
diff --git a/app/components/pajamas/alert_component.rb b/app/components/pajamas/alert_component.rb
index c1b2132da29..cfab34f537e 100644
--- a/app/components/pajamas/alert_component.rb
+++ b/app/components/pajamas/alert_component.rb
@@ -7,21 +7,17 @@ module Pajamas
# @param [Symbol] variant
# @param [Boolean] dismissible
# @param [Boolean] show_icon
- # @param [String] alert_class
- # @param [Hash] alert_data
- # @param [String] close_button_class
- # @param [Hash] close_button_data
+ # @param [Hash] alert_options
+ # @param [Hash] close_button_options
def initialize(
title: nil, variant: :info, dismissible: true, show_icon: true,
- alert_class: nil, alert_data: {}, close_button_class: nil, close_button_data: {})
+ alert_options: {}, close_button_options: {})
@title = title
@variant = variant
@dismissible = dismissible
@show_icon = show_icon
- @alert_class = alert_class
- @alert_data = alert_data
- @close_button_class = close_button_class
- @close_button_data = close_button_data
+ @alert_options = alert_options
+ @close_button_options = close_button_options
end
def base_class
diff --git a/app/components/pajamas/banner_component.html.haml b/app/components/pajamas/banner_component.html.haml
new file mode 100644
index 00000000000..4fa2ed09cd3
--- /dev/null
+++ b/app/components/pajamas/banner_component.html.haml
@@ -0,0 +1,23 @@
+%section.gl-banner{ @banner_options, class: banner_class }
+ - if illustration?
+ .gl-banner-illustration
+ = illustration
+ - elsif @svg_path.present?
+ .gl-banner-illustration
+ = image_tag @svg_path, alt: ""
+
+ .gl-banner-content
+ %h1.gl-banner-title= title
+
+ = content
+
+ - if primary_action?
+ = primary_action
+ - else
+ = link_to @button_text, @button_link, { **@button_options, class: 'btn btn-md btn-confirm gl-button js-close-callout' }
+
+ - actions.each do |action|
+ = action
+
+ %button.gl-button.gl-banner-close.btn-sm.btn-icon.js-close{ @close_options, class: close_class, type: 'button' }
+ = sprite_icon('close', size: 16, css_class: 'dismiss-icon')
diff --git a/app/components/pajamas/banner_component.rb b/app/components/pajamas/banner_component.rb
new file mode 100644
index 00000000000..9b6343b47c9
--- /dev/null
+++ b/app/components/pajamas/banner_component.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+module Pajamas
+ class BannerComponent < Pajamas::Component
+ # @param [String] button_text
+ # @param [String] button_link
+ # @param [Boolean] embedded
+ # @param [Symbol] variant
+ # @param [String] svg_path
+ # @param [Hash] banner_options
+ # @param [Hash] button_options
+ # @param [Hash] close_options
+ def initialize(
+ button_text: 'OK',
+ button_link: '#',
+ embedded: false,
+ variant: :promotion,
+ svg_path: nil,
+ banner_options: {},
+ button_options: {},
+ close_options: {}
+ )
+ @button_text = button_text
+ @button_link = button_link
+ @embedded = embedded
+ @variant = variant.to_sym
+ @svg_path = svg_path.to_s
+ @banner_options = banner_options
+ @button_options = button_options
+ @close_options = close_options
+ end
+
+ private
+
+ def banner_class
+ classes = []
+ classes.push('gl-border-none') if @embedded
+ classes.push('gl-banner-introduction') if introduction?
+ classes.join(' ')
+ end
+
+ def close_class
+ if introduction?
+ 'btn-confirm btn-confirm-tertiary'
+ else
+ 'btn-default btn-default-tertiary'
+ end
+ end
+
+ delegate :sprite_icon, to: :helpers
+
+ renders_one :title
+ renders_one :illustration
+ renders_one :primary_action
+ renders_many :actions
+
+ def introduction?
+ @variant == :introduction
+ end
+ end
+end
diff --git a/app/components/pajamas/button_component.html.haml b/app/components/pajamas/button_component.html.haml
new file mode 100644
index 00000000000..8ce7d9e0315
--- /dev/null
+++ b/app/components/pajamas/button_component.html.haml
@@ -0,0 +1,8 @@
+= content_tag tag, {**@button_options, **base_attributes, class: button_class, href: @href, target: @target } do
+ - if @loading
+ = gl_loading_icon(inline: true, css_class: 'gl-button-icon gl-button-loading-indicator')
+ - if @icon && (!@loading || content)
+ = sprite_icon(@icon, css_class: "gl-icon gl-button-icon #{@icon_classes}")
+ - if content
+ %span.gl-button-text{ class: @button_text_classes }
+ = content
diff --git a/app/components/pajamas/button_component.rb b/app/components/pajamas/button_component.rb
new file mode 100644
index 00000000000..c6193d1ae05
--- /dev/null
+++ b/app/components/pajamas/button_component.rb
@@ -0,0 +1,118 @@
+# frozen_string_literal: true
+
+module Pajamas
+ class ButtonComponent < Pajamas::Component
+ # @param [Symbol] category
+ # @param [Symbol] variant
+ # @param [Symbol] size
+ # @param [Symbol] type
+ # @param [Boolean] disabled
+ # @param [Boolean] loading
+ # @param [Boolean] block
+ # @param [Boolean] selected
+ # @param [String] icon
+ # @param [String] href
+ # @param [String] target
+ # @param [Hash] button_options
+ # @param [String] button_text_classes
+ # @param [String] icon_classes
+ def initialize(
+ category: :primary,
+ variant: :default,
+ size: :medium,
+ type: :button,
+ disabled: false,
+ loading: false,
+ block: false,
+ selected: false,
+ icon: nil,
+ href: nil,
+ target: nil,
+ button_options: {},
+ button_text_classes: nil,
+ icon_classes: nil
+ )
+ @category = filter_attribute(category.to_sym, CATEGORY_OPTIONS)
+ @variant = filter_attribute(variant.to_sym, VARIANT_OPTIONS)
+ @size = filter_attribute(size.to_sym, SIZE_OPTIONS)
+ @type = filter_attribute(type.to_sym, TYPE_OPTIONS, default: :button)
+ @disabled = disabled
+ @loading = loading
+ @block = block
+ @selected = selected
+ @icon = icon
+ @href = href
+ @target = filter_attribute(target, TARGET_OPTIONS)
+ @button_options = button_options
+ @button_text_classes = button_text_classes
+ @icon_classes = icon_classes
+ end
+
+ private
+
+ def button_class
+ classes = ['gl-button btn']
+ classes.push('disabled') if @disabled || @loading
+ classes.push('selected') if @selected
+ classes.push('btn-block') if @block
+ classes.push('btn-icon') if @icon && !content
+
+ classes.push(SIZE_CLASSES[@size])
+
+ classes.push(VARIANT_CLASSES[@variant])
+
+ unless NON_CATEGORY_VARIANTS.include?(@variant) || @category == :primary
+ classes.push(VARIANT_CLASSES[@variant] + '-' + CATEGORY_CLASSES[@category])
+ end
+
+ classes.push(@button_options[:class])
+
+ classes.join(' ')
+ end
+
+ CATEGORY_OPTIONS = [:primary, :secondary, :tertiary].freeze
+ VARIANT_OPTIONS = [:default, :confirm, :danger, :dashed, :link, :reset].freeze
+ SIZE_OPTIONS = [:small, :medium].freeze
+ TYPE_OPTIONS = [:button, :reset, :submit].freeze
+ TARGET_OPTIONS = %w[_self _blank _parent _top].freeze
+
+ CATEGORY_CLASSES = {
+ primary: '',
+ secondary: 'secondary',
+ tertiary: 'tertiary'
+ }.freeze
+
+ VARIANT_CLASSES = {
+ default: 'btn-default',
+ confirm: 'btn-confirm',
+ danger: 'btn-danger',
+ dashed: 'btn-dashed',
+ link: 'btn-link',
+ reset: 'btn-gl-reset'
+ }.freeze
+
+ NON_CATEGORY_VARIANTS = [:dashed, :link, :reset].freeze
+
+ SIZE_CLASSES = {
+ small: 'btn-sm',
+ medium: 'btn-md'
+ }.freeze
+
+ delegate :sprite_icon, to: :helpers
+ delegate :gl_loading_icon, to: :helpers
+
+ def tag
+ @href ? 'a' : 'button'
+ end
+
+ def base_attributes
+ attributes = {}
+
+ attributes['disabled'] = '' if @disabled || @loading
+ attributes['aria-disabled'] = true if @disabled || @loading
+ attributes['type'] = @type unless @href
+
+ attributes
+ end
+ end
+end
diff --git a/app/components/pajamas/card_component.html.haml b/app/components/pajamas/card_component.html.haml
new file mode 100644
index 00000000000..007229cc69f
--- /dev/null
+++ b/app/components/pajamas/card_component.html.haml
@@ -0,0 +1,9 @@
+.gl-card{ @card_options }
+ - if header?
+ .gl-card-header{ @header_options }
+ = header
+ .gl-card-body{ @body_options }
+ = body
+ - if footer?
+ .gl-card-footer{ @footer_options }
+ = footer
diff --git a/app/components/pajamas/card_component.rb b/app/components/pajamas/card_component.rb
new file mode 100644
index 00000000000..bcc71db1c34
--- /dev/null
+++ b/app/components/pajamas/card_component.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+# Renders a GlCard root element
+module Pajamas
+ class CardComponent < Pajamas::Component
+ # @param [Hash] card_options
+ # @param [Hash] header_options
+ # @param [Hash] body_options
+ # @param [Hash] footer_options
+ def initialize(card_options: {}, header_options: {}, body_options: {}, footer_options: {})
+ @card_options = card_options
+ @header_options = header_options
+ @body_options = body_options
+ @footer_options = footer_options
+ end
+
+ renders_one :header
+ renders_one :body
+ renders_one :footer
+ end
+end
diff --git a/app/components/pajamas/checkbox_component.html.haml b/app/components/pajamas/checkbox_component.html.haml
new file mode 100644
index 00000000000..9e3d4e68a42
--- /dev/null
+++ b/app/components/pajamas/checkbox_component.html.haml
@@ -0,0 +1,6 @@
+.gl-form-checkbox.custom-control.custom-checkbox
+ = form.check_box(method,
+ formatted_input_options,
+ checked_value,
+ unchecked_value)
+ = render_label_with_help_text
diff --git a/app/components/pajamas/checkbox_component.rb b/app/components/pajamas/checkbox_component.rb
new file mode 100644
index 00000000000..ae78d0453f8
--- /dev/null
+++ b/app/components/pajamas/checkbox_component.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+# Renders a Pajamas compliant checkbox element
+# Must be used in an instance of `ActionView::Helpers::FormBuilder`
+module Pajamas
+ class CheckboxComponent < Pajamas::Component
+ include Pajamas::Concerns::CheckboxRadioLabelWithHelpText
+ include Pajamas::Concerns::CheckboxRadioOptions
+
+ renders_one :label
+ renders_one :help_text
+
+ def initialize(
+ form:,
+ method:,
+ label: nil,
+ help_text: nil,
+ label_options: {},
+ checkbox_options: {},
+ checked_value: '1',
+ unchecked_value: '0'
+ )
+ @form = form
+ @method = method
+ @label_argument = label
+ @help_text_argument = help_text
+ @label_options = label_options
+ @input_options = checkbox_options
+ @checked_value = checked_value
+ @unchecked_value = unchecked_value
+ @value = checked_value if checkbox_options[:multiple]
+ end
+
+ attr_reader(
+ :form,
+ :method,
+ :label_argument,
+ :help_text_argument,
+ :label_options,
+ :input_options,
+ :checked_value,
+ :unchecked_value,
+ :value
+ )
+
+ private
+
+ def label_content
+ label? ? label : label_argument
+ end
+
+ def help_text_content
+ help_text? ? help_text : help_text_argument
+ end
+ end
+end
diff --git a/app/components/pajamas/component.rb b/app/components/pajamas/component.rb
index b05d93b680e..3b1826a646c 100644
--- a/app/components/pajamas/component.rb
+++ b/app/components/pajamas/component.rb
@@ -4,8 +4,6 @@ module Pajamas
class Component < ViewComponent::Base
private
- # :nocov:
-
# Filter a given a value against a list of allowed values
# If no value is given or value is not allowed return default one
#
@@ -18,6 +16,14 @@ module Pajamas
default
end
- # :nocov:
+
+ # Add CSS classes and additional options to an existing options hash
+ #
+ # @param [Hash] options
+ # @param [Array] css_classes
+ # @param [Hash] additional_option
+ def format_options(options:, css_classes: [], additional_options: {})
+ options.merge({ class: [*css_classes, options[:class]].flatten.compact }, additional_options)
+ end
end
end
diff --git a/app/components/pajamas/concerns/checkbox_radio_label_with_help_text.rb b/app/components/pajamas/concerns/checkbox_radio_label_with_help_text.rb
new file mode 100644
index 00000000000..4ece904fb85
--- /dev/null
+++ b/app/components/pajamas/concerns/checkbox_radio_label_with_help_text.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Pajamas
+ module Concerns
+ module CheckboxRadioLabelWithHelpText
+ def render_label_with_help_text
+ form.label(method, formatted_label_options) { label_entry }
+ end
+
+ private
+
+ def label_entry
+ if help_text_content
+ content_tag(:span, label_content) +
+ content_tag(:p, help_text_content, class: 'help-text', data: { testid: 'pajamas-component-help-text' })
+ else
+ content_tag(:span, label_content)
+ end
+ end
+
+ def formatted_label_options
+ format_options(
+ options: label_options,
+ css_classes: ['custom-control-label'],
+ additional_options: { value: value }
+ )
+ end
+ end
+ end
+end
diff --git a/app/components/pajamas/concerns/checkbox_radio_options.rb b/app/components/pajamas/concerns/checkbox_radio_options.rb
new file mode 100644
index 00000000000..e79fdb7b601
--- /dev/null
+++ b/app/components/pajamas/concerns/checkbox_radio_options.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Pajamas
+ module Concerns
+ module CheckboxRadioOptions
+ def formatted_input_options
+ format_options(options: input_options, css_classes: ['custom-control-input'])
+ end
+ end
+ end
+end
diff --git a/app/components/pajamas/radio_component.html.haml b/app/components/pajamas/radio_component.html.haml
new file mode 100644
index 00000000000..6bf57b0b187
--- /dev/null
+++ b/app/components/pajamas/radio_component.html.haml
@@ -0,0 +1,5 @@
+.gl-form-radio.custom-control.custom-radio
+ = form.radio_button(method,
+ value,
+ formatted_input_options)
+ = render_label_with_help_text
diff --git a/app/components/pajamas/radio_component.rb b/app/components/pajamas/radio_component.rb
new file mode 100644
index 00000000000..52a761b9d7d
--- /dev/null
+++ b/app/components/pajamas/radio_component.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+# Renders a Pajamas compliant radio button element
+# Must be used in an instance of `ActionView::Helpers::FormBuilder`
+module Pajamas
+ class RadioComponent < Pajamas::Component
+ include Pajamas::Concerns::CheckboxRadioLabelWithHelpText
+ include Pajamas::Concerns::CheckboxRadioOptions
+
+ renders_one :label
+ renders_one :help_text
+
+ def initialize(
+ form:,
+ method:,
+ label: nil,
+ help_text: nil,
+ label_options: {},
+ radio_options: {},
+ value: nil
+ )
+ @form = form
+ @method = method
+ @label_argument = label
+ @help_text_argument = help_text
+ @label_options = label_options
+ @input_options = radio_options
+ @value = value
+ end
+
+ attr_reader(
+ :form,
+ :method,
+ :label_argument,
+ :help_text_argument,
+ :label_options,
+ :input_options,
+ :value
+ )
+
+ private
+
+ def label_content
+ label? ? label : label_argument
+ end
+
+ def help_text_content
+ help_text? ? help_text : help_text_argument
+ end
+ end
+end