Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dialog Component #1214

Merged
merged 31 commits into from
Aug 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
112dbd5
initial dialog implementation
keithamus Jul 22, 2022
e5157cc
docs: build docs
actions-user Aug 18, 2022
e5dcc09
auto-correcting rubocop spacing violations
jonrohan Aug 23, 2022
9162304
add prettier to devdeps to hoist 2.7.1 version
keithamus Aug 24, 2022
b61a051
fix all prettier issues
keithamus Aug 24, 2022
18b5760
flip hide_divider to show_divider
keithamus Aug 24, 2022
fb5c827
clean up modal-dialog code a little#
keithamus Aug 24, 2022
f8cf3d1
clean up if block
keithamus Aug 24, 2022
ae81e10
drop unused argument
keithamus Aug 24, 2022
b5f756d
migrate to beta closebutton
keithamus Aug 24, 2022
0a2aca8
Merge remote-tracking branch 'origin/main' into initial-dialog-implem…
keithamus Aug 24, 2022
22aadb6
Merge branch 'main' into initial-dialog-implementation
keithamus Aug 25, 2022
8591622
Merge branch 'main' into initial-dialog-implementation
langermank Aug 26, 2022
5928bfe
Update sizing and position (#1341)
langermank Aug 30, 2022
aec9297
make small dialog default to portrait
keithamus Aug 31, 2022
4a4a9d8
pass through visually_hide_title to header
keithamus Aug 31, 2022
519ac41
allow content to override title/subtitle in header
keithamus Aug 31, 2022
384f5dd
upgrade primer/css
keithamus Aug 31, 2022
48c9216
allow configuring body_text in dialog default preview
keithamus Aug 31, 2022
d65eb7b
add custom header dialog preview
keithamus Aug 31, 2022
5ee01d9
Merge remote-tracking branch 'origin/main' into initial-dialog-implem…
keithamus Aug 31, 2022
20fe3e2
add missing Yard types
keithamus Aug 31, 2022
2f0ce6d
fix up dialog header component test
keithamus Aug 31, 2022
c7dbe6a
fix lint
keithamus Aug 31, 2022
4edecc3
docs: build docs
actions-user Aug 31, 2022
a552a84
remove uneeded files
keithamus Aug 31, 2022
1434aab
remove blank line
keithamus Aug 31, 2022
0ec0793
Create clever-crabs-raise.md
jonrohan Aug 31, 2022
d2f8ced
remove useless tests
keithamus Aug 31, 2022
30fb2ff
Fix component test
jonrohan Aug 31, 2022
7ad9af3
Fixing dialog_test
jonrohan Aug 31, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/clever-crabs-raise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@primer/view-components": patch
---

Adding Primer Dialog Component
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 <%= @backdrop_classes %>" data-modal-dialog-overlay>
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
<%= header %>
<% if content.present? %>
<%= content %>
<% else %>
<%= body %>
<%= footer %>
<% end %>
<% end %>
</div>
160 changes: 160 additions & 0 deletions app/components/primer/alpha/dialog.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# 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_SIZE = :medium
SIZE_MAPPINGS = {
:small => "Overlay--size-small-portrait",
:medium_portrait => "Overlay--size-medium-portrait",
DEFAULT_SIZE => "Overlay--size-medium",
:large => "Overlay--size-large",
:xlarge => "Overlay--size-xlarge"
}.freeze
SIZE_OPTIONS = SIZE_MAPPINGS.keys

DEFAULT_POSITION = :center
POSITION_MAPPINGS = {
DEFAULT_POSITION => "Overlay-backdrop--center",
:left => "Overlay-backdrop--side Overlay-backdrop--placement-left",
:right => "Overlay-backdrop--side Overlay-backdrop--placement-right"
}.freeze
POSITION_OPTIONS = POSITION_MAPPINGS.keys

DEFAULT_POSITION_NARROW = :inherit
POSITION_NARROW_MAPPINGS = {
DEFAULT_POSITION_NARROW => "",
:bottom => "Overlay-backdrop--side-whenNarrow Overlay-backdrop--placement-bottom-whenNarrow",
:fullscreen => "Overlay-backdrop--full-whenNarrow",
:left => "Overlay-backdrop--side-whenNarrow Overlay-backdrop--placement-left-whenNarrow",
:right => "Overlay-backdrop--side-whenNarrow Overlay-backdrop--placement-right-whenNarrow"
}.freeze
POSITION_NARROW_OPTIONS = POSITION_NARROW_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 show_divider [Boolean] Show a divider between the header and body.
# @param visually_hide_title [Boolean] Visually hide the `title` while maintaining a label for assistive technologies.
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
renders_one :header, lambda { |show_divider: false, visually_hide_title: @visually_hide_title, **system_arguments|
Primer::Alpha::Dialog::Header.new(
id: @id,
title: @title,
subtitle: @subtitle,
show_divider: show_divider,
visually_hide_title: visually_hide_title,
**system_arguments
)
}

# Required body content.
keithamus marked this conversation as resolved.
Show resolved Hide resolved
#
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
renders_one :body, "Body"

# Footer content.
#
# @param show_divider [Boolean] Show a divider between the footer and body.
# @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.with_show_button { "Show Dialog" } %>
# <% d.with_body do %>
# <p>Some content</p>
# <% end %>
# <% d.footer do %>
# <%= render(Primer::ButtonComponent.new(data: { "close-dialog-id": "my-dialog" })) { "Cancel" } %>
keithamus marked this conversation as resolved.
Show resolved Hide resolved
# <%= render(Primer::ButtonComponent.new(scheme: :primary)) { "Submit" } %>
# <% end %>
# <% end %>
# @param id [String] The id of the dialog.
# @param title [String] Describes the content of the dialog.
# @param subtitle [String] Provides dditional context for the dialog, also setting the `aria-describedby` attribute.
# @param size [Symbol] The size of the dialog. <%= one_of(Primer::Alpha::Dialog::SIZE_OPTIONS) %>
# @param position [Symbol] The size of the dialog. <%= one_of(Primer::Alpha::Dialog::POSITION_OPTIONS) %>
# @param position_narrow [Symbol] The size of the dialog. <%= one_of(Primer::Alpha::Dialog::POSITION_NARROW_OPTIONS) %>
# @param visually_hide_title [Boolean] If true will hide the heading title, while still making it available to Screen Readers.
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
def initialize(
keithamus marked this conversation as resolved.
Show resolved Hide resolved
title:,
subtitle: nil,
size: DEFAULT_SIZE,
position: DEFAULT_POSITION,
position_narrow: DEFAULT_POSITION_NARROW,
visually_hide_title: false,
id: "dialog-#{(36**3 + rand(36**4)).to_s(36)}",
**system_arguments
)
@system_arguments = deny_tag_argument(**system_arguments)

@system_arguments[:tag] = "modal-dialog"
keithamus marked this conversation as resolved.
Show resolved Hide resolved
@system_arguments[:role] = "dialog"
@system_arguments[:id] = id.to_s
@system_arguments[:aria] = { modal: true }
@system_arguments[:classes] = class_names(
"Overlay",
"Overlay-whenNarrow",
SIZE_MAPPINGS[fetch_or_fallback(SIZE_OPTIONS, size, DEFAULT_SIZE)],
"Overlay--motion-scaleFade",
system_arguments[:classes]
)
@backdrop_classes = class_names(
POSITION_MAPPINGS[fetch_or_fallback(POSITION_OPTIONS, position, DEFAULT_POSITION)],
POSITION_NARROW_MAPPINGS[fetch_or_fallback(POSITION_NARROW_MAPPINGS, position_narrow, DEFAULT_POSITION_NARROW)]
)

@id = id.to_s
@title = title
@position = position
@position_narrow = position_narrow
@visually_hide_title = visually_hide_title

@subtitle = subtitle

@system_arguments[:aria] ||= {}
@system_arguments[:aria][:describedby] ||= "#{@id}-description"
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 show_divider [Boolean] Show a divider between the footer and body.
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
def initialize(
show_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": show_divider },
system_arguments[:classes]
)
end

def call
render(Primer::BaseComponent.new(**@system_arguments)) { content }
end
end
end
end
end
15 changes: 15 additions & 0 deletions app/components/primer/alpha/dialog/header.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
<div class="Overlay-headerContentWrap">
<div class="Overlay-titleWrap">
<h1 class="Overlay-title <% if @visually_hide_title || content.present? %>sr-only<% end %>"><%= @title %></h1>
<% if content.present? %>
<%= content %>
<% elsif @subtitle.present? %>
<h2 id="<%= @id %>-description" class="Overlay-description"><%= @subtitle %></h2>
<% end %>
</div>
<div class="Overlay-actionWrap">
<%= render Primer::Beta::CloseButton.new(classes: "Overlay-closeButton", "data-close-dialog-id": @id) %>
</div>
</div>
<% end %>
37 changes: 37 additions & 0 deletions app/components/primer/alpha/dialog/header.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# 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] Describes the content of the dialog.
# @param subtitle [String] Provides dditional context for the dialog, also setting the `aria-describedby` attribute.
# @param show_divider [Boolean] Show a divider between the header and body.
# @param visually_hide_title [Boolean] Visually hide the `title` while maintaining a label for assistive technologies.
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
def initialize(
id:,
title:,
keithamus marked this conversation as resolved.
Show resolved Hide resolved
subtitle: nil,
show_divider: false,
visually_hide_title: false,
**system_arguments
)
@id = id
@title = title
@subtitle = subtitle
@visually_hide_title = visually_hide_title
@system_arguments = deny_tag_argument(**system_arguments)
@system_arguments[:tag] = :header
@system_arguments[:classes] = class_names(
"Overlay-header",
{ "Overlay-header--divided": show_divider },
system_arguments[:classes]
)
end
end
end
end
end
Loading