primer_view_components 0.1.8 → 0.1.9
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 +28 -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 +1 -1
- data/app/assets/styles/primer_view_components.css.map +1 -1
- data/app/components/primer/alpha/action_list/item.rb +1 -3
- data/app/components/primer/alpha/action_menu.rb +1 -1
- data/app/components/primer/alpha/modal_dialog.js +6 -0
- data/app/components/primer/alpha/modal_dialog.ts +6 -0
- data/app/components/primer/alpha/overlay/header.html.erb +5 -3
- data/app/components/primer/alpha/overlay/header.rb +4 -1
- data/app/components/primer/alpha/overlay.css +1 -1
- data/app/components/primer/alpha/overlay.css.json +1 -1
- data/app/components/primer/alpha/overlay.css.map +1 -1
- data/app/components/primer/alpha/overlay.pcss +1 -1
- data/app/components/primer/alpha/overlay.rb +1 -0
- data/app/components/primer/alpha/toggle_switch.css +1 -1
- data/app/components/primer/alpha/toggle_switch.css.json +11 -11
- data/app/components/primer/alpha/toggle_switch.css.map +1 -1
- data/app/components/primer/alpha/toggle_switch.d.ts +1 -1
- data/app/components/primer/alpha/toggle_switch.html.erb +2 -2
- data/app/components/primer/alpha/toggle_switch.js +44 -42
- data/app/components/primer/alpha/toggle_switch.pcss +4 -4
- data/app/components/primer/alpha/toggle_switch.rb +7 -0
- data/app/components/primer/alpha/toggle_switch.ts +50 -41
- data/app/components/primer/beta/auto_complete.rb +1 -1
- data/app/components/primer/focus_group.js +10 -6
- data/app/components/primer/focus_group.ts +10 -5
- data/lib/primer/forms/dsl/input.rb +4 -8
- data/lib/primer/forms/dsl/text_field_input.rb +0 -4
- data/lib/primer/forms/dsl/toggle_switch_input.rb +4 -0
- data/lib/primer/forms/form_control.html.erb +3 -5
- data/lib/primer/forms/primer_base_component_wrapper.html.erb +3 -0
- data/lib/primer/forms/primer_base_component_wrapper.rb +24 -0
- data/lib/primer/forms/toggle_switch.html.erb +3 -3
- data/lib/primer/forms/toggle_switch.rb +6 -2
- data/lib/primer/forms/toggle_switch_input.js +7 -2
- data/lib/primer/forms/toggle_switch_input.ts +9 -2
- data/lib/primer/static/generate_info_arch.rb +3 -0
- data/lib/primer/view_components/version.rb +1 -1
- data/lib/primer/yard/component_manifest.rb +1 -1
- data/lib/primer/yard/lookbook_pages_backend.rb +7 -1
- data/lib/primer/yard/registry.rb +4 -0
- data/previews/primer/alpha/overlay_preview/middle_of_page_with_relative_container.html.erb +19 -0
- data/previews/primer/alpha/overlay_preview.rb +31 -0
- data/static/arguments.json +7 -1
- data/static/info_arch.json +312 -1
- data/static/previews.json +5 -0
- metadata +5 -9
- data/lib/tasks/docs.rake +0 -185
- data/lib/tasks/helpers/ast_processor.rb +0 -44
- data/lib/tasks/helpers/ast_traverser.rb +0 -77
- data/lib/tasks/primer_view_components.rake +0 -47
- data/lib/tasks/static.rake +0 -29
- data/lib/tasks/test.rake +0 -83
- data/lib/tasks/utilities.rake +0 -109
@@ -42,9 +42,7 @@ module Primer
|
|
42
42
|
#
|
43
43
|
# To render custom content, call the `with_leading_visual_content` method and pass a block that returns a string.
|
44
44
|
renders_one :leading_visual, types: {
|
45
|
-
icon:
|
46
|
-
Primer::Beta::Octicon.new(classes: "ActionListItem-visual ActionListItem-visual--leading", **system_arguments)
|
47
|
-
},
|
45
|
+
icon: Primer::Beta::Octicon,
|
48
46
|
avatar: ->(**kwargs) { Primer::Beta::Avatar.new(**{ **kwargs, size: 16 }) },
|
49
47
|
svg: lambda { |**system_arguments|
|
50
48
|
Primer::BaseComponent.new(tag: :svg, width: "16", height: "16", **system_arguments)
|
@@ -105,7 +105,7 @@ module Primer
|
|
105
105
|
# <% c.with_item(tag: :"clipboard-copy", value: "Text to copy") do %>
|
106
106
|
# Copy Text
|
107
107
|
# <% end %>
|
108
|
-
# <% c.with_item(tag: :button, type: "button",
|
108
|
+
# <% c.with_item(tag: :button, type: "button", scheme: :danger) do %>
|
109
109
|
# Delete
|
110
110
|
# <% end %>
|
111
111
|
# <% end %>
|
@@ -31,6 +31,10 @@ function clickHandler(event) {
|
|
31
31
|
if (dialog instanceof ModalDialogElement) {
|
32
32
|
dialog.openButton = button;
|
33
33
|
dialog.show();
|
34
|
+
// A buttons default behaviour in some browsers it to send a pointer event
|
35
|
+
// If the behaviour is allowed through the dialog will be shown but then
|
36
|
+
// quickly hidden- as if it were never shown. This prevents that.
|
37
|
+
event.preventDefault();
|
34
38
|
return;
|
35
39
|
}
|
36
40
|
}
|
@@ -96,6 +100,7 @@ export class ModalDialogElement extends HTMLElement {
|
|
96
100
|
if (this.open)
|
97
101
|
return;
|
98
102
|
this.setAttribute('open', '');
|
103
|
+
this.setAttribute('aria-disabled', 'false');
|
99
104
|
(_a = __classPrivateFieldGet(this, _ModalDialogElement_instances, "a", _ModalDialogElement_overlayBackdrop_get)) === null || _a === void 0 ? void 0 : _a.classList.remove('Overlay--hidden');
|
100
105
|
document.body.style.paddingRight = `${window.innerWidth - document.body.clientWidth}px`;
|
101
106
|
document.body.style.overflow = 'hidden';
|
@@ -109,6 +114,7 @@ export class ModalDialogElement extends HTMLElement {
|
|
109
114
|
if (!this.open)
|
110
115
|
return;
|
111
116
|
this.removeAttribute('open');
|
117
|
+
this.setAttribute('aria-disabled', 'true');
|
112
118
|
(_b = __classPrivateFieldGet(this, _ModalDialogElement_instances, "a", _ModalDialogElement_overlayBackdrop_get)) === null || _b === void 0 ? void 0 : _b.classList.add('Overlay--hidden');
|
113
119
|
document.body.style.paddingRight = '0';
|
114
120
|
document.body.style.overflow = 'initial';
|
@@ -23,6 +23,10 @@ function clickHandler(event: Event) {
|
|
23
23
|
if (dialog instanceof ModalDialogElement) {
|
24
24
|
dialog.openButton = button
|
25
25
|
dialog.show()
|
26
|
+
// A buttons default behaviour in some browsers it to send a pointer event
|
27
|
+
// If the behaviour is allowed through the dialog will be shown but then
|
28
|
+
// quickly hidden- as if it were never shown. This prevents that.
|
29
|
+
event.preventDefault()
|
26
30
|
return
|
27
31
|
}
|
28
32
|
}
|
@@ -96,6 +100,7 @@ export class ModalDialogElement extends HTMLElement {
|
|
96
100
|
if (value) {
|
97
101
|
if (this.open) return
|
98
102
|
this.setAttribute('open', '')
|
103
|
+
this.setAttribute('aria-disabled', 'false')
|
99
104
|
this.#overlayBackdrop?.classList.remove('Overlay--hidden')
|
100
105
|
document.body.style.paddingRight = `${window.innerWidth - document.body.clientWidth}px`
|
101
106
|
document.body.style.overflow = 'hidden'
|
@@ -107,6 +112,7 @@ export class ModalDialogElement extends HTMLElement {
|
|
107
112
|
} else {
|
108
113
|
if (!this.open) return
|
109
114
|
this.removeAttribute('open')
|
115
|
+
this.setAttribute('aria-disabled', 'true')
|
110
116
|
this.#overlayBackdrop?.classList.add('Overlay--hidden')
|
111
117
|
document.body.style.paddingRight = '0'
|
112
118
|
document.body.style.overflow = 'initial'
|
@@ -8,8 +8,10 @@
|
|
8
8
|
<h2 class="Overlay-description"><%= @subtitle %></h2>
|
9
9
|
<% end %>
|
10
10
|
</div>
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
<% if @overlay_id %>
|
12
|
+
<div class="Overlay-actionWrap">
|
13
|
+
<%= render Primer::Beta::CloseButton.new(classes: "Overlay-closeButton", "popovertarget": @overlay_id, "popovertargetaction": "hide") %>
|
14
|
+
</div>
|
15
|
+
<% end %>
|
14
16
|
</div>
|
15
17
|
<% end %>
|
@@ -14,7 +14,8 @@ module Primer
|
|
14
14
|
SIZE_OPTIONS = SIZE_MAPPINGS.keys
|
15
15
|
|
16
16
|
# @param title [String] Describes the content of the Overlay.
|
17
|
-
# @param subtitle [String] Provides
|
17
|
+
# @param subtitle [String] Provides additional context for the Overlay, also setting the `aria-describedby` attribute.
|
18
|
+
# @param overlay_id [String] Provides the id of the overlay element so the close button can close it
|
18
19
|
# @param size [Symbol] The size of the Header. <%= one_of(Primer::Alpha::Overlay::Header::SIZE_OPTIONS) %>
|
19
20
|
# @param divider [Boolean] Show a divider between the header and body.
|
20
21
|
# @param visually_hide_title [Boolean] Visually hide the `title` while maintaining a label for assistive technologies.
|
@@ -22,12 +23,14 @@ module Primer
|
|
22
23
|
def initialize(
|
23
24
|
id:,
|
24
25
|
title:,
|
26
|
+
overlay_id: nil,
|
25
27
|
subtitle: nil,
|
26
28
|
size: DEFAULT_SIZE,
|
27
29
|
divider: false,
|
28
30
|
visually_hide_title: false,
|
29
31
|
**system_arguments
|
30
32
|
)
|
33
|
+
@overlay_id = overlay_id
|
31
34
|
@id = id
|
32
35
|
@title = title
|
33
36
|
@subtitle = subtitle
|
@@ -1 +1 @@
|
|
1
|
-
.Overlay[popover]{border-width:0;min-width:192px;padding:0;position:absolute}.Overlay[popover]:not(:open){display:none}anchored-position{display:block}
|
1
|
+
.Overlay[popover]{border-width:0;min-width:192px;padding:0;position:absolute}.Overlay[popover]:not(:popover-open){display:none}anchored-position{display:block}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["overlay.pcss"],"names":[],"mappings":"AAAA,kBACE,cAAe,CAGf,eAAgB,CAFhB,SAAU,CACV,iBAEF,CAGA,
|
1
|
+
{"version":3,"sources":["overlay.pcss"],"names":[],"mappings":"AAAA,kBACE,cAAe,CAGf,eAAgB,CAFhB,SAAU,CACV,iBAEF,CAGA,qCACE,YACF,CAEA,kBACE,aACF","file":"overlay.css","sourcesContent":[".Overlay[popover] {\n border-width: 0;\n padding: 0;\n position: absolute;\n min-width: 192px;\n}\n\n/* stylelint-disable-next-line selector-pseudo-class-no-unknown */\n.Overlay[popover]:not(:popover-open) {\n display: none;\n}\n\nanchored-position {\n display: block;\n}\n"]}
|
@@ -94,6 +94,7 @@ module Primer
|
|
94
94
|
# @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
|
95
95
|
renders_one :header, lambda { |divider: false, size: :medium, visually_hide_title: @visually_hide_title, **system_arguments|
|
96
96
|
Primer::Alpha::Overlay::Header.new(
|
97
|
+
overlay_id: @id,
|
97
98
|
id: title_id,
|
98
99
|
title: @title,
|
99
100
|
subtitle: @subtitle,
|
@@ -1 +1 @@
|
|
1
|
-
.ToggleSwitch,.ToggleSwitch.ToggleSwitch{display:inline-flex}.ToggleSwitch{align-items:center;gap:var(--controlStack-medium-gap-condensed,8px)}.ToggleSwitch--checked .ToggleSwitch-statusOn{height:auto;visibility:visible}.ToggleSwitch--checked .ToggleSwitch-statusOff{height:0;visibility:hidden}.ToggleSwitch-track{-webkit-appearance:none;appearance:none;background-color:var(--color-switch-track-bg);border:var(--borderWidth-thin,1px) solid var(--color-switch-track-border);border-radius:var(--borderRadius-medium,6px);cursor:pointer;display:block;height:var(--control-medium-size,32px);overflow:hidden;padding:0;position:relative;text-decoration:none;transition-duration:80ms;transition-property:background-color,border-color;transition-timing-function:cubic-bezier(.5,1,.89,1);-webkit-user-select:none;user-select:none;width:var(--base-size-64,64px)}.ToggleSwitch-track:focus,.ToggleSwitch-track:focus-visible{outline-offset:1px}.ToggleSwitch-track:hover{background-color:var(--color-switch-track-hover-bg)}.ToggleSwitch-track:active{background-color:var(--color-switch-track-active-bg)}@media (pointer:coarse){.ToggleSwitch-track:before{content:"";height:100%;left:50%;min-height:44px;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:100%}}@media (prefers-reduced-motion){.ToggleSwitch-track,.ToggleSwitch-track *{transition:none}}.ToggleSwitch-track[aria-
|
1
|
+
.ToggleSwitch,.ToggleSwitch.ToggleSwitch{display:inline-flex}.ToggleSwitch{align-items:center;gap:var(--controlStack-medium-gap-condensed,8px)}.ToggleSwitch--checked .ToggleSwitch-statusOn{height:auto;visibility:visible}.ToggleSwitch--checked .ToggleSwitch-statusOff{height:0;visibility:hidden}.ToggleSwitch-track{-webkit-appearance:none;appearance:none;background-color:var(--color-switch-track-bg);border:var(--borderWidth-thin,1px) solid var(--color-switch-track-border);border-radius:var(--borderRadius-medium,6px);cursor:pointer;display:block;height:var(--control-medium-size,32px);overflow:hidden;padding:0;position:relative;text-decoration:none;transition-duration:80ms;transition-property:background-color,border-color;transition-timing-function:cubic-bezier(.5,1,.89,1);-webkit-user-select:none;user-select:none;width:var(--base-size-64,64px)}.ToggleSwitch-track:focus,.ToggleSwitch-track:focus-visible{outline-offset:1px}.ToggleSwitch-track:hover{background-color:var(--color-switch-track-hover-bg)}.ToggleSwitch-track:active{background-color:var(--color-switch-track-active-bg)}@media (pointer:coarse){.ToggleSwitch-track:before{content:"";height:100%;left:50%;min-height:44px;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:100%}}@media (prefers-reduced-motion){.ToggleSwitch-track,.ToggleSwitch-track *{transition:none}}.ToggleSwitch-track[aria-pressed=true][disabled]{background-color:var(--color-switch-track-disabled-bg);border-color:#0000;color:var(--color-switch-track-checked-disabled-fg)}.ToggleSwitch-track[aria-pressed=true]{background-color:var(--color-switch-track-checked-bg);border-color:var(--color-switch-track-checked-border)}.ToggleSwitch-track[aria-pressed=true]:not([disabled]):hover{background-color:var(--color-switch-track-checked-hover-bg)}.ToggleSwitch-track[aria-pressed=true]:not([disabled]):active{background-color:var(--color-switch-track-checked-active-bg)}.ToggleSwitch-track[aria-pressed=true] .ToggleSwitch-knob{background-color:var(--color-switch-knob-checked-bg);border-color:var(--color-switch-knob-checked-border);transform:translateX(100%)}.ToggleSwitch-track[aria-pressed=true] .ToggleSwitch-lineIcon{transform:translateX(0)}.ToggleSwitch-track[aria-pressed=true] .ToggleSwitch-circleIcon{transform:translateX(100%)}.ToggleSwitch-track[disabled]{background-color:var(--color-switch-track-disabled-bg);border-color:#0000;cursor:not-allowed;transition-property:none}.ToggleSwitch-track[disabled] .ToggleSwitch-knob{border-color:var(--color-border-default);box-shadow:none}.ToggleSwitch-track[disabled] .ToggleSwitch-circleIcon,.ToggleSwitch-track[disabled] .ToggleSwitch-lineIcon{color:var(--color-switch-track-disabled-fg)}.ToggleSwitch-icons{align-items:center;display:flex;height:100%;overflow:hidden;width:100%}.ToggleSwitch-lineIcon{color:var(--color-switch-track-checked-fg);transform:translateX(-100%)}.ToggleSwitch-circleIcon,.ToggleSwitch-lineIcon{flex:1 0 50%;line-height:0;transition-duration:80ms;transition-property:transform}.ToggleSwitch-circleIcon{color:var(--color-switch-track-fg);transform:translateX(0)}.ToggleSwitch-knob{background-color:var(--color-switch-knob-bg);border:var(--borderWidth-thin,1px) solid var(--color-switch-knob-border);border-radius:var(--borderRadius-medium,6px);bottom:0;box-shadow:var(--color-shadow-medium),var(--color-btn-inset-shadow);position:absolute;top:0;transition-duration:80ms;transition-property:transform;transition-timing-function:cubic-bezier(.5,1,.89,1);width:50%;z-index:1}@media (prefers-reduced-motion){.ToggleSwitch-knob{transition:none}}.ToggleSwitch-status{color:var(--color-fg-default);font-size:var(--text-body-size-medium,14px);line-height:1.5;position:relative;text-align:right}.ToggleSwitch-statusIcon{display:flex;margin-top:.063rem;width:var(--base-size-16,16px)}.ToggleSwitch--small .ToggleSwitch-status{font-size:var(--text-body-size-small,12px)}.ToggleSwitch--small .ToggleSwitch-track{height:var(--control-xsmall-size,24px);width:var(--base-size-48,48px)}.ToggleSwitch--disabled .ToggleSwitch-status{color:var(--color-fg-muted)}.ToggleSwitch-statusOn{height:0;visibility:hidden}.ToggleSwitch-statusOff{height:auto;visibility:visible}.ToggleSwitch--statusAtEnd{flex-direction:row-reverse}.ToggleSwitch--statusAtEnd .ToggleSwitch-status{text-align:left}
|
@@ -12,17 +12,17 @@
|
|
12
12
|
".ToggleSwitch-track:active",
|
13
13
|
".ToggleSwitch-track:before",
|
14
14
|
".ToggleSwitch-track *",
|
15
|
-
".ToggleSwitch-track[aria-
|
16
|
-
".ToggleSwitch-track[aria-
|
17
|
-
".ToggleSwitch-track[aria-
|
18
|
-
".ToggleSwitch-track[aria-
|
19
|
-
".ToggleSwitch-track[aria-
|
20
|
-
".ToggleSwitch-track[aria-
|
21
|
-
".ToggleSwitch-track[aria-
|
22
|
-
".ToggleSwitch-track[
|
23
|
-
".ToggleSwitch-track[
|
24
|
-
".ToggleSwitch-track[
|
25
|
-
".ToggleSwitch-track[
|
15
|
+
".ToggleSwitch-track[aria-pressed=true][disabled]",
|
16
|
+
".ToggleSwitch-track[aria-pressed=true]",
|
17
|
+
".ToggleSwitch-track[aria-pressed=true]:not([disabled]):hover",
|
18
|
+
".ToggleSwitch-track[aria-pressed=true]:not([disabled]):active",
|
19
|
+
".ToggleSwitch-track[aria-pressed=true] .ToggleSwitch-knob",
|
20
|
+
".ToggleSwitch-track[aria-pressed=true] .ToggleSwitch-lineIcon",
|
21
|
+
".ToggleSwitch-track[aria-pressed=true] .ToggleSwitch-circleIcon",
|
22
|
+
".ToggleSwitch-track[disabled]",
|
23
|
+
".ToggleSwitch-track[disabled] .ToggleSwitch-knob",
|
24
|
+
".ToggleSwitch-track[disabled] .ToggleSwitch-circleIcon",
|
25
|
+
".ToggleSwitch-track[disabled] .ToggleSwitch-lineIcon",
|
26
26
|
".ToggleSwitch-icons",
|
27
27
|
".ToggleSwitch-lineIcon",
|
28
28
|
".ToggleSwitch-circleIcon",
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["toggle_switch.pcss","<no source>"],"names":[],"mappings":"AAQA,yCAHE,mBAOF,CAJA,cACE,kBAAmB,CAEnB,gDACF,CAGE,8CACE,WAAY,CACZ,kBACF,CAEA,+CACE,QAAS,CACT,iBACF,CAGF,oBAgBE,uBAAgB,CAAhB,eAAgB,CANhB,6CAA8C,CAC9C,yEAA2E,CAC3E,4CAA8C,CAJ9C,cAAe,CANf,aAAc,CAEd,sCAAwC,CAExC,eAAgB,CADhB,SAAU,CAJV,iBAAkB,CAMlB,oBAAqB,CAOrB,wBAAyB,CACzB,iDAAmD,CAFnD,mDAAyD,CAJzD,wBAAiB,CAAjB,gBAAiB,CANjB,8BAyCF,CA1BE,4DAEE,kBACF,CAEA,0BACE,mDACF,CAEA,2BACE,oDACF,CAEA,wBAEI,2BC3DN,WAAA,YAAA,SAAA,gBAAA,kBAAA,QAAA,4CAAA,UD2DgC,CAE9B,CAEA,gCAGE,0CACE,eACF,CACF,CAGF,
|
1
|
+
{"version":3,"sources":["toggle_switch.pcss","<no source>"],"names":[],"mappings":"AAQA,yCAHE,mBAOF,CAJA,cACE,kBAAmB,CAEnB,gDACF,CAGE,8CACE,WAAY,CACZ,kBACF,CAEA,+CACE,QAAS,CACT,iBACF,CAGF,oBAgBE,uBAAgB,CAAhB,eAAgB,CANhB,6CAA8C,CAC9C,yEAA2E,CAC3E,4CAA8C,CAJ9C,cAAe,CANf,aAAc,CAEd,sCAAwC,CAExC,eAAgB,CADhB,SAAU,CAJV,iBAAkB,CAMlB,oBAAqB,CAOrB,wBAAyB,CACzB,iDAAmD,CAFnD,mDAAyD,CAJzD,wBAAiB,CAAjB,gBAAiB,CANjB,8BAyCF,CA1BE,4DAEE,kBACF,CAEA,0BACE,mDACF,CAEA,2BACE,oDACF,CAEA,wBAEI,2BC3DN,WAAA,YAAA,SAAA,gBAAA,kBAAA,QAAA,4CAAA,UD2DgC,CAE9B,CAEA,gCAGE,0CACE,eACF,CACF,CAGF,iDACE,sDAAuD,CAEvD,kBAAyB,CADzB,mDAEF,CAEA,uCACE,qDAAsD,CACtD,qDAyBF,CAtBI,6DACE,2DACF,CAEA,8DACE,4DACF,CAGF,0DACE,oDAAqD,CACrD,oDAAqD,CACrD,0BACF,CAEA,8DACE,uBACF,CAEA,gEACE,0BACF,CAGF,8BAEE,sDAAuD,CACvD,kBAAyB,CAFzB,kBAAmB,CAGnB,wBAcF,CAZE,iDACE,wCAAyC,CACzC,eACF,CAMA,4GACE,2CACF,CAGF,oBAEE,kBAAmB,CADnB,YAAa,CAGb,WAAY,CACZ,eAAgB,CAFhB,UAGF,CAEA,uBAEE,0CAA2C,CAG3C,2BAEF,CAEA,gDAHE,YAAa,CALb,aAAc,CAEd,wBAAyB,CACzB,6BAYF,CAPA,yBAEE,kCAAmC,CAGnC,uBAEF,CAEA,mBAME,4CAA6C,CAC7C,wEAA0E,CAC1E,4CAA8C,CAL9C,QAAS,CAMT,mEAAqE,CARrE,iBAAkB,CAClB,KAAM,CASN,wBAAyB,CACzB,6BAA8B,CAF9B,mDAAyD,CALzD,SAAU,CADV,SAaF,CAHE,gCAdF,mBAeI,eAEJ,CADE,CAGF,qBAIE,6BAA8B,CAF9B,2CAA6C,CAC7C,eAAgB,CAFhB,iBAAkB,CAIlB,gBACF,CAEA,yBAEE,YAAa,CACb,kBAAoB,CAFpB,8BAGF,CAGE,0CACE,0CACF,CAEA,yCAEE,sCAAwC,CADxC,8BAEF,CAIA,6CACE,2BACF,CAGF,uBACE,QAAS,CACT,iBACF,CAEA,wBACE,WAAY,CACZ,kBACF,CAEA,2BACE,0BAKF,CAHE,gDACE,eACF","file":"toggle_switch.css","sourcesContent":["/* ToggleSwitch */\n\n/* Catalyst in dotcom applies a display: block to all web component elements. This\n** rule overrides it so the status label and toggle switch are laid out correctly. */\n.ToggleSwitch.ToggleSwitch {\n display: inline-flex;\n}\n\n.ToggleSwitch {\n align-items: center;\n display: inline-flex;\n gap: var(--controlStack-medium-gap-condensed, 8px);\n}\n\n.ToggleSwitch--checked {\n & .ToggleSwitch-statusOn {\n height: auto;\n visibility: visible;\n }\n\n & .ToggleSwitch-statusOff {\n height: 0;\n visibility: hidden;\n }\n}\n\n.ToggleSwitch-track {\n position: relative;\n display: block;\n width: var(--base-size-64, 64px);\n height: var(--control-medium-size, 32px);\n padding: 0;\n overflow: hidden;\n text-decoration: none;\n cursor: pointer;\n user-select: none;\n background-color: var(--color-switch-track-bg);\n border: var(--borderWidth-thin, 1px) solid var(--color-switch-track-border);\n border-radius: var(--borderRadius-medium, 6px);\n transition-timing-function: cubic-bezier(0.5, 1, 0.89, 1);\n transition-duration: 80ms;\n transition-property: background-color, border-color;\n appearance: none;\n\n &:focus,\n &:focus-visible {\n outline-offset: 1px;\n }\n\n &:hover {\n background-color: var(--color-switch-track-hover-bg);\n }\n\n &:active {\n background-color: var(--color-switch-track-active-bg);\n }\n\n @media (pointer: coarse) {\n &::before {\n @mixin minTouchTarget 44px;\n }\n }\n\n @media (prefers-reduced-motion) {\n transition: none;\n\n & * {\n transition: none;\n }\n }\n}\n\n.ToggleSwitch-track[aria-pressed='true'][disabled] {\n background-color: var(--color-switch-track-disabled-bg);\n color: var(--color-switch-track-checked-disabled-fg);\n border-color: transparent;\n}\n\n.ToggleSwitch-track[aria-pressed='true'] {\n background-color: var(--color-switch-track-checked-bg);\n border-color: var(--color-switch-track-checked-border);\n\n &:not([disabled]) {\n &:hover {\n background-color: var(--color-switch-track-checked-hover-bg);\n }\n\n &:active {\n background-color: var(--color-switch-track-checked-active-bg);\n }\n }\n\n & .ToggleSwitch-knob {\n background-color: var(--color-switch-knob-checked-bg);\n border-color: var(--color-switch-knob-checked-border);\n transform: translateX(100%);\n }\n\n & .ToggleSwitch-lineIcon {\n transform: translateX(0%);\n }\n\n & .ToggleSwitch-circleIcon {\n transform: translateX(100%);\n }\n}\n\n.ToggleSwitch-track[disabled] {\n cursor: not-allowed;\n background-color: var(--color-switch-track-disabled-bg);\n border-color: transparent;\n transition-property: none;\n\n & .ToggleSwitch-knob {\n border-color: var(--color-border-default);\n box-shadow: none;\n }\n\n & .ToggleSwitch-lineIcon {\n color: var(--color-switch-track-disabled-fg);\n }\n\n & .ToggleSwitch-circleIcon {\n color: var(--color-switch-track-disabled-fg);\n }\n}\n\n.ToggleSwitch-icons {\n display: flex;\n align-items: center;\n width: 100%;\n height: 100%;\n overflow: hidden;\n}\n\n.ToggleSwitch-lineIcon {\n line-height: 0;\n color: var(--color-switch-track-checked-fg);\n transition-duration: 80ms;\n transition-property: transform;\n transform: translateX(-100%);\n flex: 1 0 50%;\n}\n\n.ToggleSwitch-circleIcon {\n line-height: 0;\n color: var(--color-switch-track-fg);\n transition-duration: 80ms;\n transition-property: transform;\n transform: translateX(0);\n flex: 1 0 50%;\n}\n\n.ToggleSwitch-knob {\n position: absolute;\n top: 0;\n bottom: 0;\n z-index: 1;\n width: 50%;\n background-color: var(--color-switch-knob-bg);\n border: var(--borderWidth-thin, 1px) solid var(--color-switch-knob-border);\n border-radius: var(--borderRadius-medium, 6px);\n box-shadow: var(--color-shadow-medium), var(--color-btn-inset-shadow);\n transition-timing-function: cubic-bezier(0.5, 1, 0.89, 1);\n transition-duration: 80ms;\n transition-property: transform;\n\n @media (prefers-reduced-motion) {\n transition: none;\n }\n}\n\n.ToggleSwitch-status {\n position: relative;\n font-size: var(--text-body-size-medium, 14px);\n line-height: 1.5;\n color: var(--color-fg-default);\n text-align: right;\n}\n\n.ToggleSwitch-statusIcon {\n width: var(--base-size-16, 16px);\n display: flex;\n margin-top: 0.063rem;\n}\n\n.ToggleSwitch--small {\n & .ToggleSwitch-status {\n font-size: var(--text-body-size-small, 12px);\n }\n\n & .ToggleSwitch-track {\n width: var(--base-size-48, 48px);\n height: var(--control-xsmall-size, 24px);\n }\n}\n\n.ToggleSwitch--disabled {\n & .ToggleSwitch-status {\n color: var(--color-fg-muted);\n }\n}\n\n.ToggleSwitch-statusOn {\n height: 0;\n visibility: hidden;\n}\n\n.ToggleSwitch-statusOff {\n height: auto;\n visibility: visible;\n}\n\n.ToggleSwitch--statusAtEnd {\n flex-direction: row-reverse;\n\n & .ToggleSwitch-status {\n text-align: left;\n }\n}\n",null]}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<%= render(Primer::BaseComponent.new(tag: "toggle-switch", **@system_arguments)) do %>
|
2
2
|
<span class="ToggleSwitch-statusIcon">
|
3
|
-
<%= render(Primer::Beta::Octicon.new(size: :small, color: :danger, icon: :alert, hidden: "true", data: { target: "toggle-switch.errorIcon" })) %>
|
3
|
+
<%= render(Primer::Beta::Octicon.new(size: :small, color: :danger, icon: :"alert-fill", hidden: "true", data: { target: "toggle-switch.errorIcon" })) %>
|
4
4
|
<%= render(Primer::Beta::Spinner.new(size: :small, hidden: "true", data: { target: "toggle-switch.loadingSpinner" })) %>
|
5
5
|
</span>
|
6
6
|
<%= render(Primer::Beta::Text.new(aria: { hidden: true }, classes: "ToggleSwitch-status")) do %>
|
@@ -8,7 +8,7 @@
|
|
8
8
|
<%= render(Primer::Box.new(classes: "ToggleSwitch-statusOff").with_content("Off")) %>
|
9
9
|
<% end %>
|
10
10
|
|
11
|
-
<%= render(Primer::BaseComponent.new(tag: :button, classes: "ToggleSwitch-track",
|
11
|
+
<%= render(Primer::BaseComponent.new(tag: :button, classes: "ToggleSwitch-track", disabled: disabled?, data: { target: "toggle-switch.switch", action: "click:toggle-switch#toggle" }, **@aria_arguments)) do %>
|
12
12
|
<%= render(Primer::Box.new(classes: "ToggleSwitch-icons", aria: { hidden: true })) do %>
|
13
13
|
<%= render(Primer::Box.new(classes: "ToggleSwitch-lineIcon")) do %>
|
14
14
|
<%= render(Primer::BaseComponent.new(
|
@@ -26,46 +26,59 @@ let ToggleSwitchElement = class ToggleSwitchElement extends HTMLElement {
|
|
26
26
|
isRemote() {
|
27
27
|
return this.src != null;
|
28
28
|
}
|
29
|
-
toggle() {
|
29
|
+
async toggle() {
|
30
30
|
if (this.isDisabled()) {
|
31
31
|
return;
|
32
32
|
}
|
33
|
-
if (this.isRemote()) {
|
34
|
-
this.setLoadingState();
|
35
|
-
this.submitForm();
|
36
|
-
}
|
37
|
-
else {
|
33
|
+
if (!this.isRemote()) {
|
38
34
|
this.performToggle();
|
35
|
+
return;
|
36
|
+
}
|
37
|
+
// toggle immediately to tell screen readers the switch was clicked
|
38
|
+
this.performToggle();
|
39
|
+
this.setLoadingState();
|
40
|
+
try {
|
41
|
+
await this.submitForm();
|
42
|
+
}
|
43
|
+
catch (error) {
|
44
|
+
if (error instanceof Error) {
|
45
|
+
// because we toggle immediately when the switch is clicked, toggle back to the
|
46
|
+
// old state on failure
|
47
|
+
this.setErrorState(error.message || 'An error occurred, please try again.');
|
48
|
+
this.performToggle();
|
49
|
+
}
|
50
|
+
return;
|
39
51
|
}
|
52
|
+
this.setSuccessState();
|
40
53
|
}
|
41
54
|
turnOn() {
|
42
55
|
if (this.isDisabled()) {
|
43
56
|
return;
|
44
57
|
}
|
45
|
-
this.switch.setAttribute('aria-
|
58
|
+
this.switch.setAttribute('aria-pressed', 'true');
|
46
59
|
this.classList.add('ToggleSwitch--checked');
|
47
60
|
}
|
48
61
|
turnOff() {
|
49
62
|
if (this.isDisabled()) {
|
50
63
|
return;
|
51
64
|
}
|
52
|
-
this.switch.setAttribute('aria-
|
65
|
+
this.switch.setAttribute('aria-pressed', 'false');
|
53
66
|
this.classList.remove('ToggleSwitch--checked');
|
54
67
|
}
|
55
68
|
isOn() {
|
56
|
-
return this.switch.getAttribute('aria-
|
69
|
+
return this.switch.getAttribute('aria-pressed') === 'true';
|
57
70
|
}
|
58
71
|
isOff() {
|
59
72
|
return !this.isOn();
|
60
73
|
}
|
61
74
|
isDisabled() {
|
62
|
-
return this.switch.getAttribute('
|
75
|
+
return this.switch.getAttribute('disabled') != null;
|
63
76
|
}
|
64
77
|
disable() {
|
65
|
-
this.switch.setAttribute('
|
78
|
+
this.switch.setAttribute('disabled', 'disabled');
|
66
79
|
}
|
67
80
|
enable() {
|
68
|
-
this.switch.
|
81
|
+
this.switch.removeAttribute('disabled');
|
69
82
|
}
|
70
83
|
performToggle() {
|
71
84
|
if (this.isOn()) {
|
@@ -76,9 +89,10 @@ let ToggleSwitchElement = class ToggleSwitchElement extends HTMLElement {
|
|
76
89
|
}
|
77
90
|
}
|
78
91
|
setLoadingState() {
|
79
|
-
this.disable();
|
80
92
|
this.errorIcon.setAttribute('hidden', 'hidden');
|
81
93
|
this.loadingSpinner.removeAttribute('hidden');
|
94
|
+
const event = new CustomEvent('toggleSwitchLoading', { bubbles: true });
|
95
|
+
this.dispatchEvent(event);
|
82
96
|
}
|
83
97
|
setSuccessState() {
|
84
98
|
const event = new CustomEvent('toggleSwitchSuccess', { bubbles: true });
|
@@ -95,43 +109,31 @@ let ToggleSwitchElement = class ToggleSwitchElement extends HTMLElement {
|
|
95
109
|
this.errorIcon.removeAttribute('hidden');
|
96
110
|
}
|
97
111
|
this.loadingSpinner.setAttribute('hidden', 'hidden');
|
98
|
-
this.enable();
|
99
112
|
}
|
100
113
|
async submitForm() {
|
101
114
|
const body = new FormData();
|
102
115
|
if (this.csrf) {
|
103
116
|
body.append(this.csrfField, this.csrf);
|
104
117
|
}
|
105
|
-
body.append('value', this.isOn() ? '
|
118
|
+
body.append('value', this.isOn() ? '1' : '0');
|
119
|
+
if (!this.src)
|
120
|
+
throw new Error('invalid src');
|
121
|
+
let response;
|
106
122
|
try {
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
'Requested-With': 'XMLHttpRequest'
|
116
|
-
},
|
117
|
-
body
|
118
|
-
});
|
119
|
-
}
|
120
|
-
catch (error) {
|
121
|
-
throw new Error('A network error occurred, please try again.');
|
122
|
-
}
|
123
|
-
if (response.ok) {
|
124
|
-
this.setSuccessState();
|
125
|
-
this.performToggle();
|
126
|
-
}
|
127
|
-
else {
|
128
|
-
throw new Error(await response.text());
|
129
|
-
}
|
123
|
+
response = await fetch(this.src, {
|
124
|
+
credentials: 'same-origin',
|
125
|
+
method: 'POST',
|
126
|
+
headers: {
|
127
|
+
'Requested-With': 'XMLHttpRequest'
|
128
|
+
},
|
129
|
+
body
|
130
|
+
});
|
130
131
|
}
|
131
132
|
catch (error) {
|
132
|
-
|
133
|
-
|
134
|
-
|
133
|
+
throw new Error('A network error occurred, please try again.');
|
134
|
+
}
|
135
|
+
if (!response.ok) {
|
136
|
+
throw new Error(await response.text());
|
135
137
|
}
|
136
138
|
}
|
137
139
|
};
|
@@ -146,7 +148,7 @@ __decorate([
|
|
146
148
|
], ToggleSwitchElement.prototype, "errorIcon", void 0);
|
147
149
|
__decorate([
|
148
150
|
debounce(300)
|
149
|
-
], ToggleSwitchElement.prototype, "
|
151
|
+
], ToggleSwitchElement.prototype, "toggle", null);
|
150
152
|
ToggleSwitchElement = __decorate([
|
151
153
|
controller
|
152
154
|
], ToggleSwitchElement);
|
@@ -70,17 +70,17 @@
|
|
70
70
|
}
|
71
71
|
}
|
72
72
|
|
73
|
-
.ToggleSwitch-track[aria-
|
73
|
+
.ToggleSwitch-track[aria-pressed='true'][disabled] {
|
74
74
|
background-color: var(--color-switch-track-disabled-bg);
|
75
75
|
color: var(--color-switch-track-checked-disabled-fg);
|
76
76
|
border-color: transparent;
|
77
77
|
}
|
78
78
|
|
79
|
-
.ToggleSwitch-track[aria-
|
79
|
+
.ToggleSwitch-track[aria-pressed='true'] {
|
80
80
|
background-color: var(--color-switch-track-checked-bg);
|
81
81
|
border-color: var(--color-switch-track-checked-border);
|
82
82
|
|
83
|
-
&:not([
|
83
|
+
&:not([disabled]) {
|
84
84
|
&:hover {
|
85
85
|
background-color: var(--color-switch-track-checked-hover-bg);
|
86
86
|
}
|
@@ -105,7 +105,7 @@
|
|
105
105
|
}
|
106
106
|
}
|
107
107
|
|
108
|
-
.ToggleSwitch-track[
|
108
|
+
.ToggleSwitch-track[disabled] {
|
109
109
|
cursor: not-allowed;
|
110
110
|
background-color: var(--color-switch-track-disabled-bg);
|
111
111
|
border-color: transparent;
|
@@ -31,17 +31,35 @@ class ToggleSwitchElement extends HTMLElement {
|
|
31
31
|
return this.src != null
|
32
32
|
}
|
33
33
|
|
34
|
-
|
34
|
+
@debounce(300)
|
35
|
+
async toggle() {
|
35
36
|
if (this.isDisabled()) {
|
36
37
|
return
|
37
38
|
}
|
38
39
|
|
39
|
-
if (this.isRemote()) {
|
40
|
-
this.setLoadingState()
|
41
|
-
this.submitForm()
|
42
|
-
} else {
|
40
|
+
if (!this.isRemote()) {
|
43
41
|
this.performToggle()
|
42
|
+
return
|
44
43
|
}
|
44
|
+
|
45
|
+
// toggle immediately to tell screen readers the switch was clicked
|
46
|
+
this.performToggle()
|
47
|
+
this.setLoadingState()
|
48
|
+
|
49
|
+
try {
|
50
|
+
await this.submitForm()
|
51
|
+
} catch (error) {
|
52
|
+
if (error instanceof Error) {
|
53
|
+
// because we toggle immediately when the switch is clicked, toggle back to the
|
54
|
+
// old state on failure
|
55
|
+
this.setErrorState(error.message || 'An error occurred, please try again.')
|
56
|
+
this.performToggle()
|
57
|
+
}
|
58
|
+
|
59
|
+
return
|
60
|
+
}
|
61
|
+
|
62
|
+
this.setSuccessState()
|
45
63
|
}
|
46
64
|
|
47
65
|
turnOn(): void {
|
@@ -49,7 +67,7 @@ class ToggleSwitchElement extends HTMLElement {
|
|
49
67
|
return
|
50
68
|
}
|
51
69
|
|
52
|
-
this.switch.setAttribute('aria-
|
70
|
+
this.switch.setAttribute('aria-pressed', 'true')
|
53
71
|
this.classList.add('ToggleSwitch--checked')
|
54
72
|
}
|
55
73
|
|
@@ -58,12 +76,12 @@ class ToggleSwitchElement extends HTMLElement {
|
|
58
76
|
return
|
59
77
|
}
|
60
78
|
|
61
|
-
this.switch.setAttribute('aria-
|
79
|
+
this.switch.setAttribute('aria-pressed', 'false')
|
62
80
|
this.classList.remove('ToggleSwitch--checked')
|
63
81
|
}
|
64
82
|
|
65
83
|
isOn(): boolean {
|
66
|
-
return this.switch.getAttribute('aria-
|
84
|
+
return this.switch.getAttribute('aria-pressed') === 'true'
|
67
85
|
}
|
68
86
|
|
69
87
|
isOff(): boolean {
|
@@ -71,15 +89,15 @@ class ToggleSwitchElement extends HTMLElement {
|
|
71
89
|
}
|
72
90
|
|
73
91
|
isDisabled(): boolean {
|
74
|
-
return this.switch.getAttribute('
|
92
|
+
return this.switch.getAttribute('disabled') != null
|
75
93
|
}
|
76
94
|
|
77
95
|
disable(): void {
|
78
|
-
this.switch.setAttribute('
|
96
|
+
this.switch.setAttribute('disabled', 'disabled')
|
79
97
|
}
|
80
98
|
|
81
99
|
enable(): void {
|
82
|
-
this.switch.
|
100
|
+
this.switch.removeAttribute('disabled')
|
83
101
|
}
|
84
102
|
|
85
103
|
private performToggle(): void {
|
@@ -91,9 +109,11 @@ class ToggleSwitchElement extends HTMLElement {
|
|
91
109
|
}
|
92
110
|
|
93
111
|
private setLoadingState(): void {
|
94
|
-
this.disable()
|
95
112
|
this.errorIcon.setAttribute('hidden', 'hidden')
|
96
113
|
this.loadingSpinner.removeAttribute('hidden')
|
114
|
+
|
115
|
+
const event = new CustomEvent('toggleSwitchLoading', {bubbles: true})
|
116
|
+
this.dispatchEvent(event)
|
97
117
|
}
|
98
118
|
|
99
119
|
private setSuccessState(): void {
|
@@ -116,10 +136,8 @@ class ToggleSwitchElement extends HTMLElement {
|
|
116
136
|
}
|
117
137
|
|
118
138
|
this.loadingSpinner.setAttribute('hidden', 'hidden')
|
119
|
-
this.enable()
|
120
139
|
}
|
121
140
|
|
122
|
-
@debounce(300)
|
123
141
|
private async submitForm() {
|
124
142
|
const body = new FormData()
|
125
143
|
|
@@ -127,36 +145,27 @@ class ToggleSwitchElement extends HTMLElement {
|
|
127
145
|
body.append(this.csrfField, this.csrf)
|
128
146
|
}
|
129
147
|
|
130
|
-
body.append('value', this.isOn() ? '
|
148
|
+
body.append('value', this.isOn() ? '1' : '0')
|
131
149
|
|
132
|
-
|
133
|
-
if (!this.src) throw new Error('invalid src')
|
134
|
-
|
135
|
-
let response
|
136
|
-
|
137
|
-
try {
|
138
|
-
response = await fetch(this.src, {
|
139
|
-
credentials: 'same-origin',
|
140
|
-
method: 'POST',
|
141
|
-
headers: {
|
142
|
-
'Requested-With': 'XMLHttpRequest'
|
143
|
-
},
|
144
|
-
body
|
145
|
-
})
|
146
|
-
} catch (error) {
|
147
|
-
throw new Error('A network error occurred, please try again.')
|
148
|
-
}
|
150
|
+
if (!this.src) throw new Error('invalid src')
|
149
151
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
152
|
+
let response
|
153
|
+
|
154
|
+
try {
|
155
|
+
response = await fetch(this.src, {
|
156
|
+
credentials: 'same-origin',
|
157
|
+
method: 'POST',
|
158
|
+
headers: {
|
159
|
+
'Requested-With': 'XMLHttpRequest'
|
160
|
+
},
|
161
|
+
body
|
162
|
+
})
|
156
163
|
} catch (error) {
|
157
|
-
|
158
|
-
|
159
|
-
|
164
|
+
throw new Error('A network error occurred, please try again.')
|
165
|
+
}
|
166
|
+
|
167
|
+
if (!response.ok) {
|
168
|
+
throw new Error(await response.text())
|
160
169
|
}
|
161
170
|
}
|
162
171
|
}
|