Skip to content

Commit

Permalink
initial dialog implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
keithamus committed Aug 18, 2022
1 parent c539291 commit 9469ea0
Show file tree
Hide file tree
Showing 26 changed files with 680 additions and 7 deletions.
2 changes: 1 addition & 1 deletion app/assets/javascripts/primer_view_components.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion app/assets/javascripts/primer_view_components.js.map

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions app/components/primer/alpha/dialog.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<%= show_button %>
<div class="Overlay--hidden Overlay-backdrop--center Overlay-backdrop--full-whenNarrow" data-modal-dialog-overlay>
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
<%= header %>
<% if content.present? %>
<%= content %>
<% else %>
<%= body %>
<%= footer %>
<% end %>
<% end %>
</div>
141 changes: 141 additions & 0 deletions app/components/primer/alpha/dialog.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# frozen_string_literal: true

module Primer
module Alpha
# A `Dialog` is used to remove the user from the main application flow,
# to confirm actions, ask for disambiguation or to present small forms.
#
# @accessibility
# - **Dialog Accessible Name**: A dialog should have an accessible name,
# so screen readers are aware of the purpose of the dialog when it opens.
# Give an accessible name setting `:title`. The accessible name will be
# used as the main heading inside the dialog.
# - **Dialog unique id**: A dialog should be unique. Give a unique id
# setting `:dialog_id`. If no `:dialog_id` is given, a default randomize
# hex id is generated.
#
# The combination of both `:title` and `:dialog_id` establishes an
# `aria-labelledby` relationship between the title and the unique id of
# the dialog.
class Dialog < Primer::Component
DEFAULT_WIDTH = :medium
WIDTH_MAPPINGS = {
:small => "Overlay--width-small",
DEFAULT_WIDTH => "Overlay--width-medium",
:large => "Overlay--width-large",
:xlarge => "Overlay--width-xlarge",
:xxlarge => "Overlay--width-xxlarge"
}.freeze
WIDTH_OPTIONS = WIDTH_MAPPINGS.keys

DEFAULT_HEIGHT = :auto
HEIGHT_MAPPINGS = {
:small => "Overlay--height-small",
DEFAULT_HEIGHT => "Overlay--height-auto",
:large => "Overlay--height-large",
:xlarge => "Overlay--height-xlarge",
}.freeze
HEIGHT_OPTIONS = HEIGHT_MAPPINGS.keys

# Optional button to open the dialog.
#
# @param system_arguments [Hash] The same arguments as <%= link_to_component(Primer::ButtonComponent) %>.
renders_one :show_button, lambda { |**system_arguments|
system_arguments[:classes] = class_names(
system_arguments[:classes]
)
system_arguments[:id] = "dialog-show-#{@system_arguments[:id]}"
system_arguments["data-show-dialog-id"] = @system_arguments[:id]
system_arguments[:data] = (system_arguments[:data] || {}).merge({ "show-dialog-id": @system_arguments[:id] })
Primer::ButtonComponent.new(**system_arguments)
}

# Header content.
#
# @param hide_divider [Boolean] If true the visual dividing line between the header and body will be hidden
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
renders_one :header, lambda { |hide_divider: false, **system_arguments|
Primer::Alpha::Dialog::Header.new(
id: @id,
title: @title,
subtitle: @subtitle,
hide_divider: hide_divider,
**system_arguments
)
}

# Required body content.
#
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
renders_one :body, "Body"

# Footer content.
#
# @param hide_divider [Boolean] If true the visual dividing line between the body and footer will be hidden
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
renders_one :footer, "Footer"

# @example Dialog with Cancel and Submit buttons
# @description
# An ID is provided which enables wiring of the open and close buttons to the dialog.
# @code
# <%= render(Primer::Alpha::Dialog.new(
# title: "Dialog Example",
# id: "my-dialog",
# )) do |d| %>
# <% d.show_button { "Show Dialog" } %>
# <% d.body do %>
# <p>Some content</p>
# <% end %>
# <% d.footer do %>
# <%= render(Primer::ButtonComponent.new(data: { "close-dialog-id": "my-dialog" })) { "Cancel" } %>
# <%= render(Primer::ButtonComponent.new(scheme: :primary)) { "Submit" } %>
# <% end %>
# <% end %>
# @param id [String] The id of the dialog.
# @param title [String] The title of the dialog.
# @param subtitle [String] The subtitle of the dialog. This will also set the `aria-describedby` attribute.
# @param width [Symbol] The width of the dialog. <%= one_of(Primer::Alpha::Dialog::WIDTH_OPTIONS) %>
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
def initialize(
title:,
subtitle: nil,
width: DEFAULT_WIDTH,
height: DEFAULT_HEIGHT,
id: "dialog-#{(36**3 + rand(36**4)).to_s(36)}",
**system_arguments
)
@system_arguments = deny_tag_argument(**system_arguments)

@system_arguments[:tag] = "modal-dialog"
@system_arguments[:role] = "dialog"
@system_arguments[:id] = id.to_s
@system_arguments[:aria] = { modal: true }
@system_arguments[:classes] = class_names(
"Overlay",
WIDTH_MAPPINGS[fetch_or_fallback(WIDTH_OPTIONS, width, DEFAULT_WIDTH)],
HEIGHT_MAPPINGS[fetch_or_fallback(HEIGHT_OPTIONS, height, DEFAULT_HEIGHT)],
"Overlay--motion-scaleFade",
system_arguments[:classes]
)

@id = id.to_s
@title = title

@subtitle = subtitle
if subtitle.present?
@system_arguments[:aria] ||= {}
@system_arguments[:aria][:describedby] ||= "#{@id}-description"
end

end

def before_render
with_header() unless header?
with_body() unless body?
end

end
end
end

25 changes: 25 additions & 0 deletions app/components/primer/alpha/dialog/body.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

module Primer
module Alpha
class Dialog
# A `Dialog::Body` is a compositional component, used to render the
# Body of a dialog. See <%= link_to_component(Primer::Alpha::Dialog) %>.
class Body < Primer::Component
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
def initialize(**system_arguments)
@system_arguments = deny_tag_argument(**system_arguments)
@system_arguments[:tag] = :div
@system_arguments[:classes] = class_names(
"Overlay-body",
system_arguments[:classes]
)
end

def call
render(Primer::BaseComponent.new(**@system_arguments)) { content }
end
end
end
end
end
31 changes: 31 additions & 0 deletions app/components/primer/alpha/dialog/footer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

module Primer
module Alpha
class Dialog
# A `Dialog::Footer` is a compositional component, used to render the
# Footer of a dialog. See <%= link_to_component(Primer::Alpha::Dialog) %>.
class Footer < Primer::Component
# @param hide_divider [Boolean] If true the visual dividing line between the body and footer will be hidden
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
def initialize(
hide_divider: false,
**system_arguments
)
@system_arguments = deny_tag_argument(**system_arguments)
@system_arguments[:tag] = :div
@system_arguments[:classes] = class_names(
"Overlay-footer",
"Overlay-footer--alignEnd",
{ "Overlay-footer--divided": !hide_divider },
system_arguments[:classes]
)
end

def call
render(Primer::BaseComponent.new(**@system_arguments)) { content }
end
end
end
end
end
13 changes: 13 additions & 0 deletions app/components/primer/alpha/dialog/header.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
<div class="Overlay-headerContentWrap">
<div class="Overlay-titleWrap">
<h1 class="Overlay-title"><%= @title %></h1>
<% if @subtitle.present? %>
<h2 id="<%= @id %>-description" class="Overlay-description"><%= @subtitle %></h2>
<% end %>
</div>
<div class="Overlay-actionWrap">
<%= render Primer::CloseButton.new(classes: "Overlay-closeButton", "data-close-dialog-id": @id) %>
</div>
</div>
<% end %>
35 changes: 35 additions & 0 deletions app/components/primer/alpha/dialog/header.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# frozen_string_literal: true

module Primer
module Alpha
class Dialog
# A `Dialog::Header` is a compositional component, used to render the
# Header of a dialog. See <%= link_to_component(Primer::Alpha::Dialog) %>.
class Header < Primer::Component
# @param title [String] The title of the dialog.
# @param subtitle [String] The subtitle of the dialog. This will also set the `aria-describedby` attribute.
# @param hide_divider [Boolean] If true the visual dividing line between the body and footer will be hidden
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
def initialize(
id:,
title:,
subtitle: nil,
subtitle_id: nil,
hide_divider: false,
**system_arguments
)
@id = id
@title = title
@subtitle = subtitle
@system_arguments = deny_tag_argument(**system_arguments)
@system_arguments[:tag] = :header
@system_arguments[:classes] = class_names(
"Overlay-header",
{ "Overlay-header--divided": !hide_divider },
system_arguments[:classes]
)
end
end
end
end
end
Loading

0 comments on commit 9469ea0

Please sign in to comment.