primer_view_components 0.0.123 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/app/assets/javascripts/primer_view_components.js +1 -1
- data/app/assets/javascripts/primer_view_components.js.map +1 -1
- data/app/assets/styles/primer_view_components.css +2 -2
- data/app/assets/styles/primer_view_components.css.map +1 -1
- data/app/components/primer/alpha/action_list/item.rb +4 -0
- data/app/components/primer/alpha/action_list.css.json +41 -0
- data/app/components/primer/alpha/auto_complete.css.json +11 -0
- data/app/components/primer/alpha/banner.css.json +14 -0
- data/app/components/primer/alpha/button_marketing.css.json +10 -0
- data/app/components/primer/alpha/dialog.css.json +63 -0
- data/app/components/primer/alpha/dropdown.css.json +21 -0
- data/app/components/primer/alpha/layout.css.json +27 -0
- data/app/components/primer/alpha/menu.css.json +11 -0
- data/app/components/primer/alpha/nav_list/item.rb +3 -1
- data/app/components/primer/alpha/nav_list/section.rb +4 -4
- data/app/components/primer/alpha/nav_list.js +3 -0
- data/app/components/primer/alpha/nav_list.rb +2 -2
- data/app/components/primer/alpha/nav_list.ts +4 -0
- data/app/components/primer/alpha/overlay/body.rb +26 -0
- data/app/components/primer/alpha/overlay/footer.rb +41 -0
- data/app/components/primer/alpha/overlay/header.html.erb +15 -0
- data/app/components/primer/alpha/overlay/header.rb +47 -0
- data/app/components/primer/alpha/overlay.css +1 -0
- data/app/components/primer/alpha/overlay.css.json +11 -0
- data/app/components/primer/alpha/overlay.css.map +1 -0
- data/app/components/primer/alpha/overlay.html.erb +11 -0
- data/app/components/primer/alpha/overlay.pcss +14 -0
- data/app/components/primer/alpha/overlay.rb +194 -0
- data/app/components/primer/alpha/segmented_control.css.json +15 -0
- data/app/components/primer/alpha/tab_nav.css.json +10 -0
- data/app/components/primer/alpha/text_field.css.json +38 -0
- data/app/components/primer/alpha/toggle_switch.css.json +16 -0
- data/app/components/primer/alpha/underline_nav.css.json +13 -0
- data/app/components/primer/anchored_position.d.ts +27 -0
- data/app/components/primer/anchored_position.js +149 -0
- data/app/components/primer/anchored_position.ts +167 -0
- data/app/components/primer/beta/avatar.css.json +14 -0
- data/app/components/primer/beta/avatar_stack.css.json +9 -0
- data/app/components/primer/beta/blankslate.css.json +12 -0
- data/app/components/primer/beta/border_box.css.json +32 -0
- data/app/components/primer/beta/breadcrumbs.css.json +4 -0
- data/app/components/primer/beta/button.css.json +22 -0
- data/app/components/primer/beta/counter.css.json +6 -0
- data/app/components/primer/beta/flash.css.json +15 -0
- data/app/components/primer/beta/flash.html.erb +1 -2
- data/app/components/primer/beta/label.css.json +20 -0
- data/app/components/primer/beta/link.css.json +8 -0
- data/app/components/primer/beta/popover.css.json +18 -0
- data/app/components/primer/beta/progress_bar.css.json +6 -0
- data/app/components/primer/beta/state.css.json +10 -0
- data/app/components/primer/beta/subhead.css.json +8 -0
- data/app/components/primer/beta/timeline_item.css.json +9 -0
- data/app/components/primer/beta/truncate.css.json +6 -0
- data/app/components/primer/primer.d.ts +2 -0
- data/app/components/primer/primer.js +2 -0
- data/app/components/primer/primer.pcss +3 -0
- data/app/components/primer/primer.ts +2 -0
- data/app/components/primer/truncate.css.json +7 -0
- data/app/lib/primer/css/layout.css.json +263 -0
- data/app/lib/primer/css/utilities.css.json +1636 -0
- data/lib/primer/view_components/linters/base_linter.rb +1 -1
- data/lib/primer/view_components/linters/disallow_component_css_counter.rb +30 -0
- data/lib/primer/view_components/version.rb +2 -2
- data/lib/primer/yard/component_manifest.rb +1 -0
- data/previews/primer/alpha/overlay_preview/middle_of_page.html.erb +17 -0
- data/previews/primer/alpha/overlay_preview.rb +107 -0
- data/static/arguments.json +104 -0
- data/static/audited_at.json +4 -0
- data/static/classes.json +311 -0
- data/static/constants.json +102 -0
- data/static/previews.json +21 -0
- data/static/statuses.json +4 -0
- metadata +19 -2
@@ -0,0 +1,194 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Primer
|
4
|
+
module Alpha
|
5
|
+
# Overlay components codify design patterns related to floating surfaces such
|
6
|
+
# as dialogs and menus. They are private components intended to be used by
|
7
|
+
# specialized components, and mostly contain presentational logic and
|
8
|
+
# behavior.
|
9
|
+
#
|
10
|
+
# @accessibility
|
11
|
+
# - **Overlay Accessible Name**: An overlay should have an accessible name,
|
12
|
+
# so screen readers are aware of the purpose of the Overlay when it opens.
|
13
|
+
# Give an accessible name setting `:title`. The accessible name will be
|
14
|
+
# used as the main heading inside the Overlay.
|
15
|
+
# - **Overlay unique id**: A Overlay should be unique. Give a unique id
|
16
|
+
# setting `:id`. If no `:id` is given, a default randomize hex id is
|
17
|
+
# generated.
|
18
|
+
#
|
19
|
+
# The combination of both `:title` and `:id` establishes an
|
20
|
+
# `aria-labelledby` relationship between the title and the unique id
|
21
|
+
# of the Overlay.
|
22
|
+
class Overlay < Primer::Component
|
23
|
+
DEFAULT_PADDING = :normal
|
24
|
+
PADDING_MAPPINGS = {
|
25
|
+
DEFAULT_PADDING => nil,
|
26
|
+
:condensed => "Overlay-body--paddingCondensed",
|
27
|
+
:none => "Overlay-body--paddingNone"
|
28
|
+
}.freeze
|
29
|
+
|
30
|
+
PADDING_OPTIONS = PADDING_MAPPINGS.keys
|
31
|
+
|
32
|
+
DEFAULT_SIZE = :auto
|
33
|
+
SIZE_MAPPINGS = {
|
34
|
+
DEFAULT_SIZE => "Overlay--size-auto",
|
35
|
+
:small => "Overlay--size-small",
|
36
|
+
:medium => "Overlay--size-medium",
|
37
|
+
:medium_portrait => "Overlay--size-medium-portrait",
|
38
|
+
:large => "Overlay--size-large",
|
39
|
+
:xlarge => "Overlay--size-xlarge"
|
40
|
+
}.freeze
|
41
|
+
SIZE_OPTIONS = SIZE_MAPPINGS.keys
|
42
|
+
|
43
|
+
DEFAULT_ANCHOR_ALIGN = :start
|
44
|
+
ANCHOR_ALIGN_OPTIONS = [DEFAULT_ANCHOR_ALIGN, :center, :end].freeze
|
45
|
+
|
46
|
+
DEFAULT_ANCHOR_OFFSET = :normal
|
47
|
+
ANCHOR_OFFSET_OPTIONS = [DEFAULT_ANCHOR_OFFSET, :spacious].freeze
|
48
|
+
|
49
|
+
DEFAULT_ANCHOR_SIDE = :outside_bottom
|
50
|
+
ANCHOR_SIDE_MAPPINGS = {
|
51
|
+
:inside_top => "inside-top",
|
52
|
+
:inside_bottom => "inside-bottom",
|
53
|
+
:inside_left => "inside-left",
|
54
|
+
:inside_right => "inside-right",
|
55
|
+
:inside_center => "inside-center",
|
56
|
+
:outside_top => "outside-top",
|
57
|
+
DEFAULT_ANCHOR_SIDE => "outside-bottom",
|
58
|
+
:outside_left => "outside-left",
|
59
|
+
:outside_right => "outside-right"
|
60
|
+
}.freeze
|
61
|
+
ANCHOR_SIDE_OPTIONS = ANCHOR_SIDE_MAPPINGS.keys
|
62
|
+
|
63
|
+
DEFAULT_POPOVER = :auto
|
64
|
+
POPOVER_OPTIONS = [DEFAULT_POPOVER, :manual].freeze
|
65
|
+
|
66
|
+
ROLE_OPTIONS = [:dialog, :menu].freeze
|
67
|
+
|
68
|
+
# Optional button to open the Overlay.
|
69
|
+
#
|
70
|
+
# @param system_arguments [Hash] The same arguments as <%= link_to_component(Primer::ButtonComponent) %>.
|
71
|
+
renders_one :show_button, lambda { |**system_arguments|
|
72
|
+
system_arguments[:classes] = class_names(
|
73
|
+
system_arguments[:classes]
|
74
|
+
)
|
75
|
+
system_arguments[:id] = "overlay-show-#{@system_arguments[:id]}"
|
76
|
+
system_arguments["popovertoggletarget"] = @system_arguments[:id]
|
77
|
+
system_arguments[:data] = (system_arguments[:data] || {}).merge({ "show-dialog-id": @system_arguments[:id] })
|
78
|
+
Primer::Beta::Button.new(**system_arguments)
|
79
|
+
}
|
80
|
+
|
81
|
+
# Header content.
|
82
|
+
#
|
83
|
+
# @param divider [Boolean] Show a divider between the header and body.
|
84
|
+
# @param visually_hide_title [Boolean] Visually hide the `title` while maintaining a label for assistive technologies.
|
85
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
86
|
+
renders_one :header, lambda { |divider: false, size: :medium, visually_hide_title: @visually_hide_title, **system_arguments|
|
87
|
+
Primer::Alpha::Overlay::Header.new(
|
88
|
+
id: @id,
|
89
|
+
title: @title,
|
90
|
+
subtitle: @subtitle,
|
91
|
+
size: size,
|
92
|
+
divider: divider,
|
93
|
+
visually_hide_title: visually_hide_title,
|
94
|
+
**system_arguments
|
95
|
+
)
|
96
|
+
}
|
97
|
+
|
98
|
+
# Required body content.
|
99
|
+
#
|
100
|
+
# @param padding [Symbol] The padding. <%= one_of(Primer::Alpha::Overlay::PADDING_OPTIONS) %>
|
101
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
102
|
+
renders_one :body, lambda { |padding: @padding, **system_arguments|
|
103
|
+
Primer::Alpha::Overlay::Body.new(
|
104
|
+
padding: padding,
|
105
|
+
**system_arguments
|
106
|
+
)
|
107
|
+
}
|
108
|
+
|
109
|
+
# Footer content.
|
110
|
+
#
|
111
|
+
# @param show_divider [Boolean] Show a divider between the footer and body.
|
112
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
113
|
+
renders_one :footer, "Footer"
|
114
|
+
|
115
|
+
# @example Overlay with Cancel and Submit buttons
|
116
|
+
# @description
|
117
|
+
# An ID is provided which enables wiring of the open and close buttons to the Overlay.
|
118
|
+
# @code
|
119
|
+
# <%= render(Primer::Alpha::Overlay.new(
|
120
|
+
# title: "Overlay Example",
|
121
|
+
# id: "my-Overlay",
|
122
|
+
# role: :dialog,
|
123
|
+
# )) do |d| %>
|
124
|
+
# <% d.with_show_button { "Show Overlay" } %>
|
125
|
+
# <% d.with_body do %>
|
126
|
+
# <p>Some content</p>
|
127
|
+
# <% end %>
|
128
|
+
# <% end %>
|
129
|
+
# @param id [String] The id of the Overlay.
|
130
|
+
# @param title [String] Describes the content of the Overlay.
|
131
|
+
# @param subtitle [String] Provides dditional context for the Overlay, also setting the `aria-describedby` attribute.
|
132
|
+
# @param popover [Symbol] The popover behaviour. <%= one_of(Primer::Alpha::Overlay::POPOVER_OPTIONS) %>
|
133
|
+
# @param popover [Symbol] The popover behaviour. <%= one_of(Primer::Alpha::Overlay::POPOVER_OPTIONS) %>
|
134
|
+
# @param size [Symbol] The size of the Overlay. <%= one_of(Primer::Alpha::Overlay::SIZE_OPTIONS) %>
|
135
|
+
# @param padding [Symbol] The padding given to the Overlay body. <%= one_of(Primer::Alpha::Overlay::PADDING_OPTIONS) %>
|
136
|
+
# @param anchor [String] An ID of the element to anchor onto. Defaults to the `show_button`.
|
137
|
+
# @param anchor_align [Symbol] The anchor alignment of the Overlay. <%= one_of(Primer::Alpha::Overlay::ANCHOR_ALIGN_OPTIONS) %>
|
138
|
+
# @param anchor_side [Symbol] The side to anchor the Overlay to. <%= one_of(Primer::Alpha::Overlay::ANCHOR_SIDE_OPTIONS) %>
|
139
|
+
# @param anchor_offset [Symbol] The anchor offset to give the Overlay. <%= one_of(Primer::Alpha::Overlay::ANCHOR_OFFSET_OPTIONS) %>
|
140
|
+
# @param allow_out_of_bounds [Boolean] Allow the Overlay to overflow its container.
|
141
|
+
# @param visually_hide_title [Boolean] If true will hide the heading title, while still making it available to Screen Readers.
|
142
|
+
# @param role [String] The ARIA role. <%= one_of(Primer::Alpha::Overlay::ROLE_OPTIONS) %>
|
143
|
+
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
144
|
+
def initialize(
|
145
|
+
title:,
|
146
|
+
role:,
|
147
|
+
subtitle: nil,
|
148
|
+
popover: DEFAULT_POPOVER,
|
149
|
+
size: DEFAULT_SIZE,
|
150
|
+
padding: DEFAULT_PADDING,
|
151
|
+
anchor: nil,
|
152
|
+
anchor_align: DEFAULT_ANCHOR_ALIGN,
|
153
|
+
anchor_offset: DEFAULT_ANCHOR_OFFSET,
|
154
|
+
anchor_side: DEFAULT_ANCHOR_SIDE,
|
155
|
+
allow_out_of_bounds: false,
|
156
|
+
visually_hide_title: false,
|
157
|
+
id: self.class.generate_id,
|
158
|
+
**system_arguments
|
159
|
+
)
|
160
|
+
@system_arguments = deny_tag_argument(**system_arguments)
|
161
|
+
|
162
|
+
@system_arguments[:role] = fetch_or_fallback(ROLE_OPTIONS, role)
|
163
|
+
|
164
|
+
@system_arguments[:id] = id.to_s
|
165
|
+
@system_arguments[:classes] = class_names(
|
166
|
+
"Overlay",
|
167
|
+
SIZE_MAPPINGS[fetch_or_fallback(SIZE_OPTIONS, size, DEFAULT_SIZE)],
|
168
|
+
"Overlay--motion-scaleFade",
|
169
|
+
system_arguments[:classes]
|
170
|
+
)
|
171
|
+
@system_arguments[:tag] = "anchored-position"
|
172
|
+
@system_arguments[:anchor] = anchor || "overlay-show-#{@system_arguments[:id]}"
|
173
|
+
@system_arguments[:align] = fetch_or_fallback(ANCHOR_ALIGN_OPTIONS, anchor_align, DEFAULT_ANCHOR_ALIGN)
|
174
|
+
@system_arguments[:side] = ANCHOR_SIDE_MAPPINGS[fetch_or_fallback(ANCHOR_SIDE_OPTIONS, anchor_side, DEFAULT_ANCHOR_SIDE)]
|
175
|
+
@system_arguments["anchor-offset"] = fetch_or_fallback(ANCHOR_OFFSET_OPTIONS, anchor_offset, DEFAULT_ANCHOR_OFFSET)
|
176
|
+
@system_arguments["allow-out-of-bounds"] = true if allow_out_of_bounds
|
177
|
+
@id = id.to_s
|
178
|
+
@title = title
|
179
|
+
@subtitle = subtitle
|
180
|
+
@visually_hide_title = visually_hide_title
|
181
|
+
@padding = padding
|
182
|
+
|
183
|
+
@system_arguments[:popover] = popover
|
184
|
+
@system_arguments[:aria] ||= {}
|
185
|
+
@system_arguments[:aria][:describedby] ||= "#{@id}-description"
|
186
|
+
end
|
187
|
+
|
188
|
+
def before_render
|
189
|
+
with_header unless header?
|
190
|
+
with_body unless body?
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
@@ -27,5 +27,20 @@
|
|
27
27
|
".SegmentedControl--fullWidth .SegmentedControl-item",
|
28
28
|
".SegmentedControl--fullWidth .Button--iconOnly",
|
29
29
|
".SegmentedControl--fullWidth .Button-withTooltip"
|
30
|
+
],
|
31
|
+
"classes": [
|
32
|
+
"SegmentedControl",
|
33
|
+
"SegmentedControl-item",
|
34
|
+
"SegmentedControl-item--selected",
|
35
|
+
"Button",
|
36
|
+
"Button-label",
|
37
|
+
"Button--small",
|
38
|
+
"Button--iconOnly",
|
39
|
+
"Button--medium",
|
40
|
+
"Button--large",
|
41
|
+
"Button--invisible",
|
42
|
+
"Button--invisible-noVisuals",
|
43
|
+
"SegmentedControl--fullWidth",
|
44
|
+
"Button-withTooltip"
|
30
45
|
]
|
31
46
|
}
|
@@ -130,5 +130,43 @@
|
|
130
130
|
"input.FormControl-radio[type=radio]:checked",
|
131
131
|
"input.FormControl-radio[type=radio]:checked:disabled",
|
132
132
|
"input.FormControl-radio[type=radio]:focus-visible"
|
133
|
+
],
|
134
|
+
"classes": [
|
135
|
+
"FormControl",
|
136
|
+
"FormControl--fullWidth",
|
137
|
+
"FormControl-label",
|
138
|
+
"FormControl-caption",
|
139
|
+
"FormControl-inlineValidation",
|
140
|
+
"FormControl-spacingWrapper",
|
141
|
+
"FormControl-horizontalGroup",
|
142
|
+
"FormControl-input",
|
143
|
+
"FormControl-select",
|
144
|
+
"FormControl-textarea",
|
145
|
+
"FormControl-small",
|
146
|
+
"FormControl-medium",
|
147
|
+
"FormControl-large",
|
148
|
+
"FormControl-inset",
|
149
|
+
"FormControl-monospace",
|
150
|
+
"FormControl-error",
|
151
|
+
"FormControl-success",
|
152
|
+
"FormControl-warning",
|
153
|
+
"FormControl-toggleSwitchInput",
|
154
|
+
"FormControl-input-wrap",
|
155
|
+
"FormControl-input-leadingVisualWrap",
|
156
|
+
"FormControl-input-leadingVisual",
|
157
|
+
"FormControl-input-trailingAction",
|
158
|
+
"FormControl-input-trailingAction--divider",
|
159
|
+
"FormControl-input-wrap--leadingVisual",
|
160
|
+
"FormControl-input-wrap--trailingAction",
|
161
|
+
"FormControl-input-wrap-trailingAction--divider",
|
162
|
+
"FormControl-select-wrap",
|
163
|
+
"FormControl-checkbox-wrap",
|
164
|
+
"FormControl-radio-wrap",
|
165
|
+
"FormControl-checkbox-labelWrap",
|
166
|
+
"FormControl-radio-labelWrap",
|
167
|
+
"FormControl-check-group-wrap",
|
168
|
+
"FormControl-radio-group-wrap",
|
169
|
+
"FormControl-checkbox",
|
170
|
+
"FormControl-radio"
|
133
171
|
]
|
134
172
|
}
|
@@ -36,5 +36,21 @@
|
|
36
36
|
".ToggleSwitch-statusOff",
|
37
37
|
".ToggleSwitch--statusAtEnd",
|
38
38
|
".ToggleSwitch--statusAtEnd .ToggleSwitch-status"
|
39
|
+
],
|
40
|
+
"classes": [
|
41
|
+
"ToggleSwitch",
|
42
|
+
"ToggleSwitch--checked",
|
43
|
+
"ToggleSwitch-statusOn",
|
44
|
+
"ToggleSwitch-statusOff",
|
45
|
+
"ToggleSwitch-track",
|
46
|
+
"ToggleSwitch-knob",
|
47
|
+
"ToggleSwitch-lineIcon",
|
48
|
+
"ToggleSwitch-circleIcon",
|
49
|
+
"ToggleSwitch-icons",
|
50
|
+
"ToggleSwitch-status",
|
51
|
+
"ToggleSwitch-statusIcon",
|
52
|
+
"ToggleSwitch--small",
|
53
|
+
"ToggleSwitch--disabled",
|
54
|
+
"ToggleSwitch--statusAtEnd"
|
39
55
|
]
|
40
56
|
}
|
@@ -24,5 +24,18 @@
|
|
24
24
|
".UnderlineNav--full .UnderlineNav-body",
|
25
25
|
".UnderlineNav-octicon",
|
26
26
|
".UnderlineNav-container"
|
27
|
+
],
|
28
|
+
"classes": [
|
29
|
+
"UnderlineNav",
|
30
|
+
"Counter",
|
31
|
+
"Counter--primary",
|
32
|
+
"UnderlineNav-body",
|
33
|
+
"UnderlineNav-item",
|
34
|
+
"selected",
|
35
|
+
"UnderlineNav--right",
|
36
|
+
"UnderlineNav-actions",
|
37
|
+
"UnderlineNav--full",
|
38
|
+
"UnderlineNav-octicon",
|
39
|
+
"UnderlineNav-container"
|
27
40
|
]
|
28
41
|
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import type { AnchorAlignment, AnchorSide, PositionSettings } from '@primer/behaviors';
|
2
|
+
export default class AnchoredPositionElement extends HTMLElement implements PositionSettings {
|
3
|
+
#private;
|
4
|
+
get align(): AnchorAlignment;
|
5
|
+
set align(value: AnchorAlignment);
|
6
|
+
get side(): AnchorSide;
|
7
|
+
set side(value: AnchorSide);
|
8
|
+
get anchorOffset(): number;
|
9
|
+
set anchorOffset(value: number | 'normal' | 'spacious');
|
10
|
+
get anchor(): string;
|
11
|
+
set anchor(value: string);
|
12
|
+
get anchorElement(): HTMLElement | null;
|
13
|
+
set anchorElement(value: HTMLElement | null);
|
14
|
+
get alignmentOffset(): number;
|
15
|
+
set alignmentOffset(value: number);
|
16
|
+
get allowOutOfBounds(): boolean;
|
17
|
+
set allowOutOfBounds(value: boolean);
|
18
|
+
connectedCallback(): void;
|
19
|
+
static observedAttributes: string[];
|
20
|
+
attributeChangedCallback(): void;
|
21
|
+
update(): void;
|
22
|
+
}
|
23
|
+
declare global {
|
24
|
+
interface Window {
|
25
|
+
AnchoredPositionElement: typeof AnchoredPositionElement;
|
26
|
+
}
|
27
|
+
}
|
@@ -0,0 +1,149 @@
|
|
1
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
2
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
3
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
4
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
5
|
+
};
|
6
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
7
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
10
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
11
|
+
};
|
12
|
+
var _AnchoredPositionElement_anchorElement, _AnchoredPositionElement_animationFrame;
|
13
|
+
import { getAnchoredPosition } from '@primer/behaviors';
|
14
|
+
const updateWhenVisible = (() => {
|
15
|
+
const anchors = new Set();
|
16
|
+
let intersectionObserver = null;
|
17
|
+
let resizeObserver = null;
|
18
|
+
function updateVisibleAnchors() {
|
19
|
+
for (const anchor of anchors) {
|
20
|
+
anchor.update();
|
21
|
+
}
|
22
|
+
}
|
23
|
+
return (el) => {
|
24
|
+
// eslint-disable-next-line github/prefer-observers
|
25
|
+
window.addEventListener('resize', updateVisibleAnchors);
|
26
|
+
intersectionObserver || (intersectionObserver = new IntersectionObserver(entries => {
|
27
|
+
for (const entry of entries) {
|
28
|
+
const target = entry.target;
|
29
|
+
if (entry.isIntersecting) {
|
30
|
+
target.update();
|
31
|
+
anchors.add(target);
|
32
|
+
}
|
33
|
+
else {
|
34
|
+
anchors.delete(target);
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}));
|
38
|
+
resizeObserver || (resizeObserver = new ResizeObserver(() => {
|
39
|
+
for (const anchor of anchors) {
|
40
|
+
anchor.update();
|
41
|
+
}
|
42
|
+
}));
|
43
|
+
resizeObserver.observe(el.ownerDocument.documentElement);
|
44
|
+
intersectionObserver.observe(el);
|
45
|
+
};
|
46
|
+
})();
|
47
|
+
export default class AnchoredPositionElement extends HTMLElement {
|
48
|
+
constructor() {
|
49
|
+
super(...arguments);
|
50
|
+
_AnchoredPositionElement_anchorElement.set(this, null);
|
51
|
+
_AnchoredPositionElement_animationFrame.set(this, void 0);
|
52
|
+
}
|
53
|
+
get align() {
|
54
|
+
const value = this.getAttribute('align');
|
55
|
+
if (value === 'center' || value === 'end')
|
56
|
+
return value;
|
57
|
+
return 'start';
|
58
|
+
}
|
59
|
+
set align(value) {
|
60
|
+
this.setAttribute('align', `${value}`);
|
61
|
+
}
|
62
|
+
get side() {
|
63
|
+
const value = this.getAttribute('side');
|
64
|
+
if (value === 'inside-top' ||
|
65
|
+
value === 'inside-bottom' ||
|
66
|
+
value === 'inside-left' ||
|
67
|
+
value === 'inside-right' ||
|
68
|
+
value === 'inside-center' ||
|
69
|
+
value === 'outside-top' ||
|
70
|
+
value === 'outside-left' ||
|
71
|
+
value === 'outside-right') {
|
72
|
+
return value;
|
73
|
+
}
|
74
|
+
return 'outside-bottom';
|
75
|
+
}
|
76
|
+
set side(value) {
|
77
|
+
this.setAttribute('side', `${value}`);
|
78
|
+
}
|
79
|
+
get anchorOffset() {
|
80
|
+
const alias = this.getAttribute('anchor-offset');
|
81
|
+
if (alias === 'spacious' || alias === '8')
|
82
|
+
return 8;
|
83
|
+
return 4;
|
84
|
+
}
|
85
|
+
set anchorOffset(value) {
|
86
|
+
this.setAttribute('anchor-offset', `${value}`);
|
87
|
+
}
|
88
|
+
get anchor() {
|
89
|
+
return this.getAttribute('anchor') || '';
|
90
|
+
}
|
91
|
+
set anchor(value) {
|
92
|
+
this.setAttribute('anchor', `${value}`);
|
93
|
+
}
|
94
|
+
get anchorElement() {
|
95
|
+
if (__classPrivateFieldGet(this, _AnchoredPositionElement_anchorElement, "f"))
|
96
|
+
return __classPrivateFieldGet(this, _AnchoredPositionElement_anchorElement, "f");
|
97
|
+
const idRef = this.anchor;
|
98
|
+
if (!idRef)
|
99
|
+
return null;
|
100
|
+
return this.ownerDocument.getElementById(idRef);
|
101
|
+
}
|
102
|
+
set anchorElement(value) {
|
103
|
+
__classPrivateFieldSet(this, _AnchoredPositionElement_anchorElement, value, "f");
|
104
|
+
if (!__classPrivateFieldGet(this, _AnchoredPositionElement_anchorElement, "f")) {
|
105
|
+
this.removeAttribute('anchor');
|
106
|
+
}
|
107
|
+
}
|
108
|
+
get alignmentOffset() {
|
109
|
+
return Number(this.getAttribute('alignment-offset'));
|
110
|
+
}
|
111
|
+
set alignmentOffset(value) {
|
112
|
+
this.setAttribute('alignment-offset', `${value}`);
|
113
|
+
}
|
114
|
+
get allowOutOfBounds() {
|
115
|
+
return this.hasAttribute('allow-out-of-bounds');
|
116
|
+
}
|
117
|
+
set allowOutOfBounds(value) {
|
118
|
+
this.toggleAttribute('allow-out-of-bounds', value);
|
119
|
+
}
|
120
|
+
connectedCallback() {
|
121
|
+
this.update();
|
122
|
+
this.addEventListener('beforetoggle', () => this.update());
|
123
|
+
updateWhenVisible(this);
|
124
|
+
}
|
125
|
+
attributeChangedCallback() {
|
126
|
+
this.update();
|
127
|
+
}
|
128
|
+
update() {
|
129
|
+
if (!this.isConnected)
|
130
|
+
return;
|
131
|
+
cancelAnimationFrame(__classPrivateFieldGet(this, _AnchoredPositionElement_animationFrame, "f"));
|
132
|
+
__classPrivateFieldSet(this, _AnchoredPositionElement_animationFrame, requestAnimationFrame(() => {
|
133
|
+
const anchor = this.anchorElement;
|
134
|
+
if (!anchor)
|
135
|
+
return;
|
136
|
+
const { left, top, anchorSide, anchorAlign } = getAnchoredPosition(this, anchor, this);
|
137
|
+
this.style.top = `${top}px`;
|
138
|
+
this.style.left = `${left}px`;
|
139
|
+
this.classList.remove('Overlay--anchorAlign-start', 'Overlay--anchorAlign-center', 'Overlay--anchorAlign-end', 'Overlay--anchorSide-insideTop', 'Overlay--anchorSide-insideBottom', 'Overlay--anchorSide-insideLeft', 'Overlay--anchorSide-insideRight', 'Overlay--anchorSide-insideCenter', 'Overlay--anchorSide-outsideTop', 'Overlay--anchorSide-outsideLeft', 'Overlay--anchorSide-outsideRight');
|
140
|
+
this.classList.add(`Overlay--anchorAlign-${anchorAlign}`, `Overlay--anchorSide-${anchorSide}`);
|
141
|
+
}), "f");
|
142
|
+
}
|
143
|
+
}
|
144
|
+
_AnchoredPositionElement_anchorElement = new WeakMap(), _AnchoredPositionElement_animationFrame = new WeakMap();
|
145
|
+
AnchoredPositionElement.observedAttributes = ['align', 'side', 'anchor', 'alignment-offset', 'allow-out-of-bounds'];
|
146
|
+
if (!customElements.get('anchored-position')) {
|
147
|
+
window.AnchoredPositionElement = AnchoredPositionElement;
|
148
|
+
customElements.define('anchored-position', AnchoredPositionElement);
|
149
|
+
}
|
@@ -0,0 +1,167 @@
|
|
1
|
+
import type {AnchorAlignment, AnchorSide, PositionSettings} from '@primer/behaviors'
|
2
|
+
import {getAnchoredPosition} from '@primer/behaviors'
|
3
|
+
|
4
|
+
const updateWhenVisible = (() => {
|
5
|
+
const anchors = new Set<AnchoredPositionElement>()
|
6
|
+
let intersectionObserver: IntersectionObserver | null = null
|
7
|
+
let resizeObserver: ResizeObserver | null = null
|
8
|
+
function updateVisibleAnchors() {
|
9
|
+
for (const anchor of anchors) {
|
10
|
+
anchor.update()
|
11
|
+
}
|
12
|
+
}
|
13
|
+
return (el: AnchoredPositionElement) => {
|
14
|
+
// eslint-disable-next-line github/prefer-observers
|
15
|
+
window.addEventListener('resize', updateVisibleAnchors)
|
16
|
+
intersectionObserver ||= new IntersectionObserver(entries => {
|
17
|
+
for (const entry of entries) {
|
18
|
+
const target = entry.target as AnchoredPositionElement
|
19
|
+
if (entry.isIntersecting) {
|
20
|
+
target.update()
|
21
|
+
anchors.add(target)
|
22
|
+
} else {
|
23
|
+
anchors.delete(target)
|
24
|
+
}
|
25
|
+
}
|
26
|
+
})
|
27
|
+
resizeObserver ||= new ResizeObserver(() => {
|
28
|
+
for (const anchor of anchors) {
|
29
|
+
anchor.update()
|
30
|
+
}
|
31
|
+
})
|
32
|
+
resizeObserver.observe(el.ownerDocument.documentElement)
|
33
|
+
intersectionObserver.observe(el)
|
34
|
+
}
|
35
|
+
})()
|
36
|
+
|
37
|
+
export default class AnchoredPositionElement extends HTMLElement implements PositionSettings {
|
38
|
+
get align(): AnchorAlignment {
|
39
|
+
const value = this.getAttribute('align')
|
40
|
+
if (value === 'center' || value === 'end') return value
|
41
|
+
return 'start'
|
42
|
+
}
|
43
|
+
|
44
|
+
set align(value: AnchorAlignment) {
|
45
|
+
this.setAttribute('align', `${value}`)
|
46
|
+
}
|
47
|
+
|
48
|
+
get side(): AnchorSide {
|
49
|
+
const value = this.getAttribute('side')
|
50
|
+
if (
|
51
|
+
value === 'inside-top' ||
|
52
|
+
value === 'inside-bottom' ||
|
53
|
+
value === 'inside-left' ||
|
54
|
+
value === 'inside-right' ||
|
55
|
+
value === 'inside-center' ||
|
56
|
+
value === 'outside-top' ||
|
57
|
+
value === 'outside-left' ||
|
58
|
+
value === 'outside-right'
|
59
|
+
) {
|
60
|
+
return value
|
61
|
+
}
|
62
|
+
return 'outside-bottom'
|
63
|
+
}
|
64
|
+
|
65
|
+
set side(value: AnchorSide) {
|
66
|
+
this.setAttribute('side', `${value}`)
|
67
|
+
}
|
68
|
+
|
69
|
+
get anchorOffset(): number {
|
70
|
+
const alias = this.getAttribute('anchor-offset')
|
71
|
+
if (alias === 'spacious' || alias === '8') return 8
|
72
|
+
return 4
|
73
|
+
}
|
74
|
+
|
75
|
+
set anchorOffset(value: number | 'normal' | 'spacious') {
|
76
|
+
this.setAttribute('anchor-offset', `${value}`)
|
77
|
+
}
|
78
|
+
|
79
|
+
get anchor() {
|
80
|
+
return this.getAttribute('anchor') || ''
|
81
|
+
}
|
82
|
+
|
83
|
+
set anchor(value: string) {
|
84
|
+
this.setAttribute('anchor', `${value}`)
|
85
|
+
}
|
86
|
+
|
87
|
+
#anchorElement: HTMLElement | null = null
|
88
|
+
get anchorElement(): HTMLElement | null {
|
89
|
+
if (this.#anchorElement) return this.#anchorElement
|
90
|
+
const idRef = this.anchor
|
91
|
+
if (!idRef) return null
|
92
|
+
return this.ownerDocument.getElementById(idRef)
|
93
|
+
}
|
94
|
+
|
95
|
+
set anchorElement(value: HTMLElement | null) {
|
96
|
+
this.#anchorElement = value
|
97
|
+
if (!this.#anchorElement) {
|
98
|
+
this.removeAttribute('anchor')
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
get alignmentOffset(): number {
|
103
|
+
return Number(this.getAttribute('alignment-offset'))
|
104
|
+
}
|
105
|
+
|
106
|
+
set alignmentOffset(value: number) {
|
107
|
+
this.setAttribute('alignment-offset', `${value}`)
|
108
|
+
}
|
109
|
+
|
110
|
+
get allowOutOfBounds() {
|
111
|
+
return this.hasAttribute('allow-out-of-bounds')
|
112
|
+
}
|
113
|
+
|
114
|
+
set allowOutOfBounds(value: boolean) {
|
115
|
+
this.toggleAttribute('allow-out-of-bounds', value)
|
116
|
+
}
|
117
|
+
|
118
|
+
connectedCallback() {
|
119
|
+
this.update()
|
120
|
+
this.addEventListener('beforetoggle', () => this.update())
|
121
|
+
updateWhenVisible(this)
|
122
|
+
}
|
123
|
+
|
124
|
+
static observedAttributes = ['align', 'side', 'anchor', 'alignment-offset', 'allow-out-of-bounds']
|
125
|
+
attributeChangedCallback() {
|
126
|
+
this.update()
|
127
|
+
}
|
128
|
+
|
129
|
+
#animationFrame: ReturnType<typeof requestAnimationFrame>
|
130
|
+
update() {
|
131
|
+
if (!this.isConnected) return
|
132
|
+
cancelAnimationFrame(this.#animationFrame)
|
133
|
+
|
134
|
+
this.#animationFrame = requestAnimationFrame(() => {
|
135
|
+
const anchor = this.anchorElement
|
136
|
+
if (!anchor) return
|
137
|
+
const {left, top, anchorSide, anchorAlign} = getAnchoredPosition(this, anchor, this)
|
138
|
+
this.style.top = `${top}px`
|
139
|
+
this.style.left = `${left}px`
|
140
|
+
this.classList.remove(
|
141
|
+
'Overlay--anchorAlign-start',
|
142
|
+
'Overlay--anchorAlign-center',
|
143
|
+
'Overlay--anchorAlign-end',
|
144
|
+
'Overlay--anchorSide-insideTop',
|
145
|
+
'Overlay--anchorSide-insideBottom',
|
146
|
+
'Overlay--anchorSide-insideLeft',
|
147
|
+
'Overlay--anchorSide-insideRight',
|
148
|
+
'Overlay--anchorSide-insideCenter',
|
149
|
+
'Overlay--anchorSide-outsideTop',
|
150
|
+
'Overlay--anchorSide-outsideLeft',
|
151
|
+
'Overlay--anchorSide-outsideRight'
|
152
|
+
)
|
153
|
+
this.classList.add(`Overlay--anchorAlign-${anchorAlign}`, `Overlay--anchorSide-${anchorSide}`)
|
154
|
+
})
|
155
|
+
}
|
156
|
+
}
|
157
|
+
|
158
|
+
if (!customElements.get('anchored-position')) {
|
159
|
+
window.AnchoredPositionElement = AnchoredPositionElement
|
160
|
+
customElements.define('anchored-position', AnchoredPositionElement)
|
161
|
+
}
|
162
|
+
|
163
|
+
declare global {
|
164
|
+
interface Window {
|
165
|
+
AnchoredPositionElement: typeof AnchoredPositionElement
|
166
|
+
}
|
167
|
+
}
|
@@ -13,5 +13,19 @@
|
|
13
13
|
".avatar-6",
|
14
14
|
".avatar-7",
|
15
15
|
".avatar-8"
|
16
|
+
],
|
17
|
+
"classes": [
|
18
|
+
"avatar",
|
19
|
+
"avatar-link",
|
20
|
+
"avatar-group-item",
|
21
|
+
"avatar-1",
|
22
|
+
"avatar-2",
|
23
|
+
"avatar-small",
|
24
|
+
"avatar-3",
|
25
|
+
"avatar-4",
|
26
|
+
"avatar-5",
|
27
|
+
"avatar-6",
|
28
|
+
"avatar-7",
|
29
|
+
"avatar-8"
|
16
30
|
]
|
17
31
|
}
|