-
Notifications
You must be signed in to change notification settings - Fork 116
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
427 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<%= show_button %> | ||
<%= render Primer::BaseComponent.new(**@system_arguments) do %> | ||
<%= header %> | ||
<% if content.present? %> | ||
<%= content %> | ||
<% else %> | ||
<%= body %> | ||
<%= footer %> | ||
<% end %> | ||
<% end %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
# frozen_string_literal: true | ||
|
||
module Primer | ||
module Alpha | ||
# Overlay components codify design patterns related to floating surfaces such | ||
# as dialogs and menus. They are private components intended to be used by | ||
# specialized components, and mostly contain presentational logic and | ||
# behavior. | ||
# | ||
# @accessibility | ||
# - **Overlay Accessible Name**: A Overlay should have an accessible name, | ||
# so screen readers are aware of the purpose of the Overlay when it opens. | ||
# Give an accessible name setting `:title`. The accessible name will be | ||
# used as the main heading inside the Overlay. | ||
# - **Overlay unique id**: A Overlay should be unique. Give a unique id | ||
# setting `:Overlay_id`. If no `:Overlay_id` is given, a default randomize | ||
# hex id is generated. | ||
# | ||
# The combination of both `:title` and `:Overlay_id` establishes an | ||
# `aria-labelledby` relationship between the title and the unique id of | ||
# the Overlay. | ||
class Overlay < Primer::Component | ||
DEFAULT_SIZE = :auto | ||
SIZE_MAPPINGS = { | ||
DEFAULT_SIZE => "Overlay--size-auto", | ||
:small => "Overlay--size-small", | ||
:medium => "Overlay--size-medium", | ||
:medium_portrait => "Overlay--size-medium-portrait", | ||
:large => "Overlay--size-large", | ||
:xlarge => "Overlay--size-xlarge" | ||
}.freeze | ||
SIZE_OPTIONS = SIZE_MAPPINGS.keys | ||
|
||
DEFAULT_PLACEMENT = :anchored | ||
PLACEMENT_MAPPINGS = { | ||
DEFAULT_PLACEMENT => "Overlay--placement-anchored", | ||
:center => "Overlay--placement-center", | ||
:full => "Overlay--placement-full", | ||
:top => "Overlay--placement-top", | ||
:bottom => "Overlay--placement-bottom", | ||
:start => "Overlay--placement-start", | ||
:end => "Overlay--placement-end" | ||
}.freeze | ||
PLACEMENT_OPTIONS = [nil, *PLACEMENT_MAPPINGS.keys].freeze | ||
|
||
DEFAULT_ANCHOR_ALIGN = :start | ||
ANCHOR_ALIGN_MAPPINGS = { | ||
DEFAULT_ANCHOR_ALIGN => "Overlay--anchorAlign-start", | ||
:center => "Overlay--anchorAlign-center", | ||
:end => "Overlay--anchorAlign-end", | ||
}.freeze | ||
ANCHOR_ALIGN_OPTIONS = ANCHOR_ALIGN_MAPPINGS.keys | ||
|
||
DEFAULT_ANCHOR_SIDE = :outside_bottom | ||
ANCHOR_SIDE_MAPPINGS = { | ||
:inside_top => "Overlay--anchorSide-insideTop", | ||
:inside_bottom => "Overlay--anchorSide-insideBottom", | ||
:inside_left => "Overlay--anchorSide-insideLeft", | ||
:inside_right => "Overlay--anchorSide-insideRight", | ||
:inside_center => "Overlay--anchorSide-insideCenter", | ||
:outside_top => "Overlay--anchorSide-outsideTop", | ||
DEFAULT_ANCHOR_SIDE => "Overlay--anchorSide-outsideBottom", | ||
:outside_left => "Overlay--anchorSide-outsideLeft", | ||
:outside_right => "Overlay--anchorSide-outsideRight", | ||
}.freeze | ||
ANCHOR_SIDE_OPTIONS = ANCHOR_SIDE_MAPPINGS.keys | ||
|
||
DEFAULT_POPUP = :auto | ||
POPUP_OPTIONS = [ DEFAULT_POPUP, :hint, :manual ].freeze | ||
|
||
ROLE_OPTIONS = [ :dialog, :menu ].freeze | ||
|
||
# Optional button to open the Overlay. | ||
# | ||
# @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] = "overlay-show-#{@system_arguments[:id]}" | ||
system_arguments["popuptoggletarget"] = @system_arguments[:id] | ||
system_arguments[:data] = (system_arguments[:data] || {}).merge({ "show-dialog-id": @system_arguments[:id] }) | ||
Primer::ButtonComponent.new(**system_arguments) | ||
} | ||
|
||
# Header content. | ||
# | ||
# @param 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 { |divider: false, size: :medium, visually_hide_title: @visually_hide_title, **system_arguments| | ||
Primer::Alpha::Overlay::Header.new( | ||
id: @id, | ||
title: @title, | ||
subtitle: @subtitle, | ||
size: size, | ||
divider: divider, | ||
visually_hide_title: visually_hide_title, | ||
**system_arguments | ||
) | ||
} | ||
|
||
# Required body content. | ||
# | ||
# @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 Overlay with Cancel and Submit buttons | ||
# @description | ||
# An ID is provided which enables wiring of the open and close buttons to the Overlay. | ||
# @code | ||
# <%= render(Primer::Alpha::Overlay.new( | ||
# title: "Overlay Example", | ||
# id: "my-Overlay", | ||
# )) do |d| %> | ||
# <% d.with_show_button { "Show Overlay" } %> | ||
# <% d.with_body do %> | ||
# <p>Some content</p> | ||
# <% end %> | ||
# <% d.footer do %> | ||
# <%= render(Primer::ButtonComponent.new(data: { "close-Overlay-id": "my-Overlay" })) { "Cancel" } %> | ||
# <%= render(Primer::ButtonComponent.new(scheme: :primary)) { "Submit" } %> | ||
# <% end %> | ||
# <% end %> | ||
# @param id [String] The id of the Overlay. | ||
# @param title [String] Describes the content of the Overlay. | ||
# @param subtitle [String] Provides dditional context for the Overlay, also setting the `aria-describedby` attribute. | ||
# @param size [Symbol] The size of the Overlay. <%= one_of(Primer::Alpha::Overlay::SIZE_OPTIONS) %> | ||
# @param placement [Symbol] The placement of the Overlay. <%= one_of(Primer::Alpha::Overlay::PLACEMENT_OPTIONS) %> | ||
# @param anchor_align [Symbol] The anchor alignment of the Overlay. <%= one_of(Primer::Alpha::Overlay::ANCHOR_ALIGN_OPTIONS) %> | ||
# @param anchor_side [Symbol] The side to anchor the Overlay to. <%= one_of(Primer::Alpha::Overlay::ANCHOR_SIDE_OPTIONS) %> | ||
# @param allow_out_of_bounds [Boolean] Allow the Overlay to overflow its container. | ||
# @param visually_hide_title [Boolean] If true will hide the heading title, while still making it available to Screen Readers. | ||
# @param role [String] The ARIA role. <%= one_of(Primer::Alpha::Overlay::ROLE_OPTIONS) %> | ||
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %> | ||
def initialize( | ||
title:, | ||
subtitle: nil, | ||
popup: DEFAULT_POPUP, | ||
defaultopen: false, | ||
size: DEFAULT_SIZE, | ||
placement: DEFAULT_PLACEMENT, | ||
anchor_align: DEFAULT_ANCHOR_ALIGN, | ||
anchor_side: DEFAULT_ANCHOR_SIDE, | ||
allow_out_of_bounds: false, | ||
visually_hide_title: false, | ||
role:, | ||
id: "Overlay-#{(36**3 + rand(36**4)).to_s(36)}", | ||
**system_arguments | ||
) | ||
@system_arguments = deny_tag_argument(**system_arguments) | ||
|
||
@system_arguments[:tag] = "primer-overlay" | ||
@system_arguments[:role] = fetch_or_fallback(ROLE_OPTIONS, role) | ||
|
||
@system_arguments[:id] = id.to_s | ||
@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( | ||
"Overlay-backdrop", | ||
PLACEMENT_MAPPINGS[fetch_or_fallback(PLACEMENT_OPTIONS, placement, nil)], | ||
ANCHOR_ALIGN_MAPPINGS[fetch_or_fallback(ANCHOR_ALIGN_OPTIONS, anchor_align, DEFAULT_ANCHOR_ALIGN)], | ||
ANCHOR_SIDE_MAPPINGS[fetch_or_fallback(ANCHOR_SIDE_OPTIONS, anchor_side, DEFAULT_ANCHOR_SIDE)] | ||
) | ||
|
||
@id = id.to_s | ||
@title = title | ||
@subtitle = subtitle | ||
@visually_hide_title = visually_hide_title | ||
|
||
@system_arguments[:popup] = popup | ||
@system_arguments[:defaultopen] = "" if defaultopen | ||
@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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# frozen_string_literal: true | ||
|
||
module Primer | ||
module Alpha | ||
class Overlay | ||
# A `Overlay::Body` is a compositional component, used to render the | ||
# Body of an overlay. See <%= link_to_component(Primer::Alpha::Overlay) %>. | ||
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# frozen_string_literal: true | ||
|
||
module Primer | ||
module Alpha | ||
class Overlay | ||
# A `Overlay::Footer` is a compositional component, used to render the | ||
# Footer of an overlay. See <%= link_to_component(Primer::Alpha::Overlay) %>. | ||
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# frozen_string_literal: true | ||
|
||
module Primer | ||
module Alpha | ||
class Overlay | ||
# A `Overlay::Header` is a compositional component, used to render the | ||
# Header of an overlay. See <%= link_to_component(Primer::Alpha::Overlay) %>. | ||
class Header < Primer::Component | ||
DEFAULT_SIZE = :medium | ||
SIZE_MAPPINGS = { | ||
DEFAULT_SIZE => nil, | ||
:large => "Overlay-header--large", | ||
}.freeze | ||
SIZE_OPTIONS = SIZE_MAPPINGS.keys | ||
|
||
# @param title [String] Describes the content of the Overlay. | ||
# @param subtitle [String] Provides dditional context for the Overlay, also setting the `aria-describedby` attribute. | ||
# @param 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:, | ||
subtitle: nil, | ||
size: DEFAULT_SIZE, | ||
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": divider }, | ||
SIZE_MAPPINGS[fetch_or_fallback(SIZE_OPTIONS, size, DEFAULT_SIZE)], | ||
system_arguments[:classes] | ||
) | ||
end | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.