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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -0
  3. data/app/assets/javascripts/primer_view_components.js +1 -1
  4. data/app/assets/javascripts/primer_view_components.js.map +1 -1
  5. data/app/assets/styles/primer_view_components.css +1 -1
  6. data/app/assets/styles/primer_view_components.css.map +1 -1
  7. data/app/components/primer/alpha/action_list/item.rb +1 -3
  8. data/app/components/primer/alpha/action_menu.rb +1 -1
  9. data/app/components/primer/alpha/modal_dialog.js +6 -0
  10. data/app/components/primer/alpha/modal_dialog.ts +6 -0
  11. data/app/components/primer/alpha/overlay/header.html.erb +5 -3
  12. data/app/components/primer/alpha/overlay/header.rb +4 -1
  13. data/app/components/primer/alpha/overlay.css +1 -1
  14. data/app/components/primer/alpha/overlay.css.json +1 -1
  15. data/app/components/primer/alpha/overlay.css.map +1 -1
  16. data/app/components/primer/alpha/overlay.pcss +1 -1
  17. data/app/components/primer/alpha/overlay.rb +1 -0
  18. data/app/components/primer/alpha/toggle_switch.css +1 -1
  19. data/app/components/primer/alpha/toggle_switch.css.json +11 -11
  20. data/app/components/primer/alpha/toggle_switch.css.map +1 -1
  21. data/app/components/primer/alpha/toggle_switch.d.ts +1 -1
  22. data/app/components/primer/alpha/toggle_switch.html.erb +2 -2
  23. data/app/components/primer/alpha/toggle_switch.js +44 -42
  24. data/app/components/primer/alpha/toggle_switch.pcss +4 -4
  25. data/app/components/primer/alpha/toggle_switch.rb +7 -0
  26. data/app/components/primer/alpha/toggle_switch.ts +50 -41
  27. data/app/components/primer/beta/auto_complete.rb +1 -1
  28. data/app/components/primer/focus_group.js +10 -6
  29. data/app/components/primer/focus_group.ts +10 -5
  30. data/lib/primer/forms/dsl/input.rb +4 -8
  31. data/lib/primer/forms/dsl/text_field_input.rb +0 -4
  32. data/lib/primer/forms/dsl/toggle_switch_input.rb +4 -0
  33. data/lib/primer/forms/form_control.html.erb +3 -5
  34. data/lib/primer/forms/primer_base_component_wrapper.html.erb +3 -0
  35. data/lib/primer/forms/primer_base_component_wrapper.rb +24 -0
  36. data/lib/primer/forms/toggle_switch.html.erb +3 -3
  37. data/lib/primer/forms/toggle_switch.rb +6 -2
  38. data/lib/primer/forms/toggle_switch_input.js +7 -2
  39. data/lib/primer/forms/toggle_switch_input.ts +9 -2
  40. data/lib/primer/static/generate_info_arch.rb +3 -0
  41. data/lib/primer/view_components/version.rb +1 -1
  42. data/lib/primer/yard/component_manifest.rb +1 -1
  43. data/lib/primer/yard/lookbook_pages_backend.rb +7 -1
  44. data/lib/primer/yard/registry.rb +4 -0
  45. data/previews/primer/alpha/overlay_preview/middle_of_page_with_relative_container.html.erb +19 -0
  46. data/previews/primer/alpha/overlay_preview.rb +31 -0
  47. data/static/arguments.json +7 -1
  48. data/static/info_arch.json +312 -1
  49. data/static/previews.json +5 -0
  50. metadata +5 -9
  51. data/lib/tasks/docs.rake +0 -185
  52. data/lib/tasks/helpers/ast_processor.rb +0 -44
  53. data/lib/tasks/helpers/ast_traverser.rb +0 -77
  54. data/lib/tasks/primer_view_components.rake +0 -47
  55. data/lib/tasks/static.rake +0 -29
  56. data/lib/tasks/test.rake +0 -83
  57. 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: lambda { |**system_arguments|
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", is_dangerous: true) do %>
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
- <div class="Overlay-actionWrap">
12
- <%= render Primer::Beta::CloseButton.new(classes: "Overlay-closeButton", "popoverhidetarget": @id) %>
13
- </div>
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 dditional context for the Overlay, also setting the `aria-describedby` attribute.
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}
@@ -2,7 +2,7 @@
2
2
  "name": "alpha/overlay",
3
3
  "selectors": [
4
4
  ".Overlay[popover]",
5
- ".Overlay[popover]:not(:open)",
5
+ ".Overlay[popover]:not(:popover-open)",
6
6
  "anchored-position"
7
7
  ]
8
8
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["overlay.pcss"],"names":[],"mappings":"AAAA,kBACE,cAAe,CAGf,eAAgB,CAFhB,SAAU,CACV,iBAEF,CAGA,6BACE,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(:open) {\n display: none;\n}\n\nanchored-position {\n display: block;\n}\n"]}
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"]}
@@ -6,7 +6,7 @@
6
6
  }
7
7
 
8
8
  /* stylelint-disable-next-line selector-pseudo-class-no-unknown */
9
- .Overlay[popover]:not(:open) {
9
+ .Overlay[popover]:not(:popover-open) {
10
10
  display: none;
11
11
  }
12
12
 
@@ -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-checked=true][aria-disabled=true]{background-color:var(--color-switch-track-disabled-bg);border-color:#0000;color:var(--color-switch-track-checked-disabled-fg)}.ToggleSwitch-track[aria-checked=true]{background-color:var(--color-switch-track-checked-bg);border-color:var(--color-switch-track-checked-border)}.ToggleSwitch-track[aria-checked=true]:not([aria-disabled=true]):hover{background-color:var(--color-switch-track-checked-hover-bg)}.ToggleSwitch-track[aria-checked=true]:not([aria-disabled=true]):active{background-color:var(--color-switch-track-checked-active-bg)}.ToggleSwitch-track[aria-checked=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-checked=true] .ToggleSwitch-lineIcon{transform:translateX(0)}.ToggleSwitch-track[aria-checked=true] .ToggleSwitch-circleIcon{transform:translateX(100%)}.ToggleSwitch-track[aria-disabled=true]{background-color:var(--color-switch-track-disabled-bg);border-color:#0000;cursor:not-allowed;transition-property:none}.ToggleSwitch-track[aria-disabled=true] .ToggleSwitch-knob{border-color:var(--color-border-default);box-shadow:none}.ToggleSwitch-track[aria-disabled=true] .ToggleSwitch-circleIcon,.ToggleSwitch-track[aria-disabled=true] .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}
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-checked=true][aria-disabled=true]",
16
- ".ToggleSwitch-track[aria-checked=true]",
17
- ".ToggleSwitch-track[aria-checked=true]:not([aria-disabled=true]):hover",
18
- ".ToggleSwitch-track[aria-checked=true]:not([aria-disabled=true]):active",
19
- ".ToggleSwitch-track[aria-checked=true] .ToggleSwitch-knob",
20
- ".ToggleSwitch-track[aria-checked=true] .ToggleSwitch-lineIcon",
21
- ".ToggleSwitch-track[aria-checked=true] .ToggleSwitch-circleIcon",
22
- ".ToggleSwitch-track[aria-disabled=true]",
23
- ".ToggleSwitch-track[aria-disabled=true] .ToggleSwitch-knob",
24
- ".ToggleSwitch-track[aria-disabled=true] .ToggleSwitch-circleIcon",
25
- ".ToggleSwitch-track[aria-disabled=true] .ToggleSwitch-lineIcon",
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,2DACE,sDAAuD,CAEvD,kBAAyB,CADzB,mDAEF,CAEA,uCACE,qDAAsD,CACtD,qDAyBF,CAtBI,uEACE,2DACF,CAEA,wEACE,4DACF,CAGF,0DACE,oDAAqD,CACrD,oDAAqD,CACrD,0BACF,CAEA,8DACE,uBACF,CAEA,gEACE,0BACF,CAGF,wCAEE,sDAAuD,CACvD,kBAAyB,CAFzB,kBAAmB,CAGnB,wBAcF,CAZE,2DACE,wCAAyC,CACzC,eACF,CAMA,gIACE,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-checked='true'][aria-disabled='true'] {\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-checked='true'] {\n background-color: var(--color-switch-track-checked-bg);\n border-color: var(--color-switch-track-checked-border);\n\n &:not([aria-disabled='true']) {\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[aria-disabled='true'] {\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
+ {"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]}
@@ -6,7 +6,7 @@ declare class ToggleSwitchElement extends HTMLElement {
6
6
  get csrf(): string | null;
7
7
  get csrfField(): string;
8
8
  isRemote(): boolean;
9
- toggle(): void;
9
+ toggle(): Promise<void>;
10
10
  turnOn(): void;
11
11
  turnOff(): void;
12
12
  isOn(): boolean;
@@ -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", role: "switch", data: { target: "toggle-switch.switch", action: "click:toggle-switch#toggle" }, aria: { checked: on?, disabled: disabled?, label: "Switch" })) do %>
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-checked', 'true');
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-checked', 'false');
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-checked') === 'true';
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('aria-disabled') === 'true';
75
+ return this.switch.getAttribute('disabled') != null;
63
76
  }
64
77
  disable() {
65
- this.switch.setAttribute('aria-disabled', 'true');
78
+ this.switch.setAttribute('disabled', 'disabled');
66
79
  }
67
80
  enable() {
68
- this.switch.setAttribute('aria-disabled', 'false');
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() ? '0' : '1');
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
- if (!this.src)
108
- throw new Error('invalid src');
109
- let response;
110
- try {
111
- response = await fetch(this.src, {
112
- credentials: 'same-origin',
113
- method: 'POST',
114
- headers: {
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
- if (error instanceof Error) {
133
- this.setErrorState(error.message || 'An error occurred, please try again.');
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, "submitForm", null);
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-checked='true'][aria-disabled='true'] {
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-checked='true'] {
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([aria-disabled='true']) {
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[aria-disabled='true'] {
108
+ .ToggleSwitch-track[disabled] {
109
109
  cursor: not-allowed;
110
110
  background-color: var(--color-switch-track-disabled-bg);
111
111
  border-color: transparent;
@@ -66,6 +66,13 @@ module Primer
66
66
  SIZE_MAPPINGS[@size]
67
67
  )
68
68
 
69
+ @aria_arguments = {
70
+ aria: merge_aria(
71
+ @system_arguments,
72
+ aria: { pressed: on? }
73
+ )
74
+ }
75
+
69
76
  @system_arguments[:src] = @src if @src
70
77
 
71
78
  return unless @src && @csrf_token
@@ -31,17 +31,35 @@ class ToggleSwitchElement extends HTMLElement {
31
31
  return this.src != null
32
32
  }
33
33
 
34
- toggle() {
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-checked', 'true')
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-checked', 'false')
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-checked') === 'true'
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('aria-disabled') === 'true'
92
+ return this.switch.getAttribute('disabled') != null
75
93
  }
76
94
 
77
95
  disable(): void {
78
- this.switch.setAttribute('aria-disabled', 'true')
96
+ this.switch.setAttribute('disabled', 'disabled')
79
97
  }
80
98
 
81
99
  enable(): void {
82
- this.switch.setAttribute('aria-disabled', 'false')
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() ? '0' : '1')
148
+ body.append('value', this.isOn() ? '1' : '0')
131
149
 
132
- try {
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
- if (response.ok) {
151
- this.setSuccessState()
152
- this.performToggle()
153
- } else {
154
- throw new Error(await response.text())
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
- if (error instanceof Error) {
158
- this.setErrorState(error.message || 'An error occurred, please try again.')
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
  }
@@ -41,7 +41,7 @@ module Primer
41
41
  system_arguments[:tag] = :ul
42
42
  system_arguments[:id] = @list_id
43
43
  system_arguments[:classes] = class_names(
44
- "ActionListWrap",
44
+ "ActionListWrap ActionListWrap--inset",
45
45
  system_arguments[:classes]
46
46
  )
47
47