primer_view_components 0.1.8 → 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
}
|