primer_view_components 0.12.0 → 0.13.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +45 -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_bar_element.js +10 -3
  8. data/app/components/primer/alpha/action_bar_element.ts +10 -1
  9. data/app/components/primer/alpha/action_list/form_wrapper.html.erb +4 -2
  10. data/app/components/primer/alpha/action_list/form_wrapper.rb +20 -9
  11. data/app/components/primer/alpha/action_menu/action_menu_element.js +18 -12
  12. data/app/components/primer/alpha/action_menu/action_menu_element.ts +24 -12
  13. data/app/components/primer/alpha/action_menu.rb +120 -3
  14. data/app/components/primer/alpha/modal_dialog.js +10 -13
  15. data/app/components/primer/alpha/modal_dialog.ts +10 -13
  16. data/app/components/primer/alpha/segmented_control.css +1 -1
  17. data/app/components/primer/alpha/segmented_control.css.json +14 -13
  18. data/app/components/primer/alpha/segmented_control.css.map +1 -1
  19. data/app/components/primer/alpha/segmented_control.pcss +75 -68
  20. data/app/components/primer/alpha/segmented_control.rb +10 -0
  21. data/app/components/primer/alpha/text_field.css +1 -1
  22. data/app/components/primer/alpha/tool_tip.js +17 -26
  23. data/app/components/primer/alpha/tool_tip.ts +17 -26
  24. data/lib/primer/static/generate_info_arch.rb +86 -5
  25. data/lib/primer/view_components/version.rb +2 -2
  26. data/previews/primer/alpha/action_menu_preview/single_select_form_items.html.erb +31 -0
  27. data/previews/primer/alpha/action_menu_preview/with_actions.html.erb +1 -1
  28. data/previews/primer/alpha/action_menu_preview.rb +8 -2
  29. data/previews/primer/alpha/check_box_preview.rb +0 -2
  30. data/previews/primer/alpha/dialog_preview/autofocus_element.html.erb +8 -0
  31. data/previews/primer/alpha/dialog_preview/with_text_input.html.erb +2 -1
  32. data/previews/primer/alpha/dialog_preview.rb +5 -0
  33. data/previews/primer/alpha/radio_button_preview.rb +0 -2
  34. data/previews/primer/alpha/tooltip_preview.rb +2 -2
  35. data/previews/primer/beta/button_group_preview.rb +6 -6
  36. data/static/classes.json +12 -0
  37. data/static/constants.json +12 -1
  38. data/static/info_arch.json +28 -2
  39. data/static/previews.json +26 -0
  40. metadata +4 -310
@@ -15,7 +15,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
15
15
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
16
16
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
17
17
  };
18
- var _ActionBarElement_instances, _ActionBarElement_initialBarWidth, _ActionBarElement_previousBarWidth, _ActionBarElement_focusZoneAbortController, _ActionBarElement_itemGap, _ActionBarElement_availableSpace, _ActionBarElement_menuSpace, _ActionBarElement_shrink, _ActionBarElement_grow, _ActionBarElement_showItem, _ActionBarElement_hideItem, _ActionBarElement_menuItems_get;
18
+ var _ActionBarElement_instances, _ActionBarElement_initialBarWidth, _ActionBarElement_previousBarWidth, _ActionBarElement_focusZoneAbortController, _ActionBarElement_isVisible, _ActionBarElement_itemGap, _ActionBarElement_availableSpace, _ActionBarElement_menuSpace, _ActionBarElement_shrink, _ActionBarElement_grow, _ActionBarElement_showItem, _ActionBarElement_hideItem, _ActionBarElement_menuItems_get;
19
19
  import { controller, targets, target } from '@github/catalyst';
20
20
  import { focusZone, FocusKeys } from '@primer/behaviors';
21
21
  const instersectionObserver = new IntersectionObserver(entries => {
@@ -94,12 +94,19 @@ let ActionBarElement = class ActionBarElement extends HTMLElement {
94
94
  bindKeys: FocusKeys.ArrowHorizontal | FocusKeys.HomeAndEnd,
95
95
  focusOutBehavior: 'wrap',
96
96
  focusableElementFilter: element => {
97
- return !element.closest('.ActionBar-item[hidden]') && !element.closest('li.ActionListItem');
97
+ return __classPrivateFieldGet(this, _ActionBarElement_instances, "m", _ActionBarElement_isVisible).call(this, element);
98
98
  }
99
99
  }), "f");
100
100
  }
101
101
  };
102
- _ActionBarElement_initialBarWidth = new WeakMap(), _ActionBarElement_previousBarWidth = new WeakMap(), _ActionBarElement_focusZoneAbortController = new WeakMap(), _ActionBarElement_instances = new WeakSet(), _ActionBarElement_itemGap = function _ActionBarElement_itemGap() {
102
+ _ActionBarElement_initialBarWidth = new WeakMap(), _ActionBarElement_previousBarWidth = new WeakMap(), _ActionBarElement_focusZoneAbortController = new WeakMap(), _ActionBarElement_instances = new WeakSet(), _ActionBarElement_isVisible = function _ActionBarElement_isVisible(element) {
103
+ // Safari doesn't support `checkVisibility` yet.
104
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
105
+ // @ts-ignore
106
+ if (typeof element.checkVisibility === 'function')
107
+ return element.checkVisibility();
108
+ return Boolean(element.offsetParent || element.offsetWidth || element.offsetHeight);
109
+ }, _ActionBarElement_itemGap = function _ActionBarElement_itemGap() {
103
110
  var _a;
104
111
  return parseInt((_a = window.getComputedStyle(this.itemContainer)) === null || _a === void 0 ? void 0 : _a.columnGap, 10) || 0;
105
112
  }, _ActionBarElement_availableSpace = function _ActionBarElement_availableSpace() {
@@ -86,11 +86,20 @@ class ActionBarElement extends HTMLElement {
86
86
  bindKeys: FocusKeys.ArrowHorizontal | FocusKeys.HomeAndEnd,
87
87
  focusOutBehavior: 'wrap',
88
88
  focusableElementFilter: element => {
89
- return !element.closest('.ActionBar-item[hidden]') && !element.closest('li.ActionListItem')
89
+ return this.#isVisible(element)
90
90
  }
91
91
  })
92
92
  }
93
93
 
94
+ #isVisible(element: HTMLElement): boolean {
95
+ // Safari doesn't support `checkVisibility` yet.
96
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
97
+ // @ts-ignore
98
+ if (typeof element.checkVisibility === 'function') return element.checkVisibility()
99
+
100
+ return Boolean(element.offsetParent || element.offsetWidth || element.offsetHeight)
101
+ }
102
+
94
103
  #itemGap(): number {
95
104
  return parseInt(window.getComputedStyle(this.itemContainer)?.columnGap, 10) || 0
96
105
  }
@@ -1,7 +1,9 @@
1
1
  <% if form_required? %>
2
2
  <%= form_with(url: @action, method: @http_method, **@form_arguments) do %>
3
- <% if render_input? %>
4
- <%= render(Primer::BaseComponent.new(tag: :input, **@input_arguments)) %>
3
+ <% if render_inputs? %>
4
+ <% @inputs.each do |input_arguments| %>
5
+ <%= render(Primer::BaseComponent.new(tag: :input, **input_arguments)) %>
6
+ <% end %>
5
7
  <% end %>
6
8
  <%= content %>
7
9
  <% end %>
@@ -24,14 +24,25 @@ module Primer
24
24
 
25
25
  name = @form_arguments.delete(:name)
26
26
  value = @form_arguments.delete(:value) || name
27
+ inputs = @form_arguments.delete(:inputs) || []
27
28
 
28
- @input_arguments = {
29
- type: :hidden,
30
- name: name,
31
- value: value,
32
- data: { list_item_input: true },
33
- **(@form_arguments.delete(:input_arguments) || {})
34
- }
29
+ # For the older version of this component that only allowed you to
30
+ # specify a single input
31
+ if inputs.empty?
32
+ inputs << {
33
+ name: name,
34
+ value: value,
35
+ **(@form_arguments.delete(:input_arguments) || {})
36
+ }
37
+ end
38
+
39
+ @inputs = inputs.map do |input_data|
40
+ input_data = input_data.dup
41
+ input_data[:type] ||= :hidden
42
+ input_data[:data] ||= {}
43
+ input_data[:data][:list_item_input] = true
44
+ input_data
45
+ end
35
46
  end
36
47
 
37
48
  def get?
@@ -42,8 +53,8 @@ module Primer
42
53
  @action && !get?
43
54
  end
44
55
 
45
- def render_input?
46
- @input_arguments[:name].present?
56
+ def render_inputs?
57
+ @inputs.present?
47
58
  end
48
59
 
49
60
  private
@@ -15,7 +15,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
15
15
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
16
16
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
17
17
  };
18
- var _ActionMenuElement_instances, _ActionMenuElement_abortController, _ActionMenuElement_originalLabel, _ActionMenuElement_inputName, _ActionMenuElement_invokerBeingClicked, _ActionMenuElement_softDisableItems, _ActionMenuElement_potentiallyDisallowActivation, _ActionMenuElement_isKeyboardActivation, _ActionMenuElement_isMouseActivation, _ActionMenuElement_isActivation, _ActionMenuElement_handleInvokerActivated, _ActionMenuElement_handleDialogItemActivated, _ActionMenuElement_handleItemActivated, _ActionMenuElement_activateItem, _ActionMenuElement_handleIncludeFragmentReplaced, _ActionMenuElement_handleFocusOut, _ActionMenuElement_show, _ActionMenuElement_hide, _ActionMenuElement_isOpen, _ActionMenuElement_setDynamicLabel, _ActionMenuElement_updateInput, _ActionMenuElement_firstItem_get, _ActionMenuElement_items_get;
18
+ var _ActionMenuElement_instances, _ActionMenuElement_abortController, _ActionMenuElement_originalLabel, _ActionMenuElement_inputName, _ActionMenuElement_invokerBeingClicked, _ActionMenuElement_softDisableItems, _ActionMenuElement_potentiallyDisallowActivation, _ActionMenuElement_isKeyboardActivation, _ActionMenuElement_isKeyboardActivationViaEnter, _ActionMenuElement_isKeyboardActivationViaSpace, _ActionMenuElement_isMouseActivation, _ActionMenuElement_isActivation, _ActionMenuElement_handleInvokerActivated, _ActionMenuElement_handleDialogItemActivated, _ActionMenuElement_handleItemActivated, _ActionMenuElement_activateItem, _ActionMenuElement_handleIncludeFragmentReplaced, _ActionMenuElement_handleFocusOut, _ActionMenuElement_show, _ActionMenuElement_hide, _ActionMenuElement_isOpen, _ActionMenuElement_setDynamicLabel, _ActionMenuElement_updateInput, _ActionMenuElement_firstItem_get, _ActionMenuElement_items_get;
19
19
  import { controller, target } from '@github/catalyst';
20
20
  import '@oddbird/popover-polyfill';
21
21
  const validSelectors = ['[role="menuitem"]', '[role="menuitemcheckbox"]', '[role="menuitemradio"]'];
@@ -109,7 +109,7 @@ let ActionMenuElement = class ActionMenuElement extends HTMLElement {
109
109
  __classPrivateFieldGet(this, _ActionMenuElement_abortController, "f").abort();
110
110
  }
111
111
  handleEvent(event) {
112
- var _a, _b, _c;
112
+ var _a, _b;
113
113
  const targetIsInvoker = (_a = this.invokerElement) === null || _a === void 0 ? void 0 : _a.contains(event.target);
114
114
  const eventIsActivation = __classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_isActivation).call(this, event);
115
115
  if (targetIsInvoker && event.type === 'mousedown') {
@@ -127,10 +127,6 @@ let ActionMenuElement = class ActionMenuElement extends HTMLElement {
127
127
  __classPrivateFieldSet(this, _ActionMenuElement_invokerBeingClicked, false, "f");
128
128
  return;
129
129
  }
130
- // Ignore events within dialogs within menus
131
- if (((_b = event.target) === null || _b === void 0 ? void 0 : _b.closest('dialog')) || ((_c = event.target) === null || _c === void 0 ? void 0 : _c.closest('modal-dialog'))) {
132
- return;
133
- }
134
130
  if (event.type === 'focusout') {
135
131
  if (__classPrivateFieldGet(this, _ActionMenuElement_invokerBeingClicked, "f"))
136
132
  return;
@@ -155,6 +151,14 @@ let ActionMenuElement = class ActionMenuElement extends HTMLElement {
155
151
  }
156
152
  __classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_activateItem).call(this, event, item);
157
153
  __classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_handleItemActivated).call(this, event, item);
154
+ // Pressing the space key on a button will cause the page to scroll unless preventDefault()
155
+ // is called. Unfortunately, calling preventDefault() will also skip form submission. The
156
+ // code below therefore only calls preventDefault() if the button submits a form and the
157
+ // button is being activated by the space key.
158
+ if (item.getAttribute('type') === 'submit' && __classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_isKeyboardActivationViaSpace).call(this, event)) {
159
+ event.preventDefault();
160
+ (_b = item.closest('form')) === null || _b === void 0 ? void 0 : _b.submit();
161
+ }
158
162
  return;
159
163
  }
160
164
  if (event.type === 'include-fragment-replaced') {
@@ -180,10 +184,17 @@ _ActionMenuElement_abortController = new WeakMap(), _ActionMenuElement_originalL
180
184
  event.stopImmediatePropagation();
181
185
  }
182
186
  }, _ActionMenuElement_isKeyboardActivation = function _ActionMenuElement_isKeyboardActivation(event) {
187
+ return __classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_isKeyboardActivationViaEnter).call(this, event) || __classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_isKeyboardActivationViaSpace).call(this, event);
188
+ }, _ActionMenuElement_isKeyboardActivationViaEnter = function _ActionMenuElement_isKeyboardActivationViaEnter(event) {
183
189
  return (event instanceof KeyboardEvent &&
184
190
  event.type === 'keydown' &&
185
191
  !(event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) &&
186
- (event.key === 'Enter' || event.key === ' '));
192
+ event.key === 'Enter');
193
+ }, _ActionMenuElement_isKeyboardActivationViaSpace = function _ActionMenuElement_isKeyboardActivationViaSpace(event) {
194
+ return (event instanceof KeyboardEvent &&
195
+ event.type === 'keydown' &&
196
+ !(event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) &&
197
+ event.key === ' ');
187
198
  }, _ActionMenuElement_isMouseActivation = function _ActionMenuElement_isMouseActivation(event) {
188
199
  return event instanceof MouseEvent && event.type === 'click';
189
200
  }, _ActionMenuElement_isActivation = function _ActionMenuElement_isActivation(event) {
@@ -249,11 +260,6 @@ _ActionMenuElement_abortController = new WeakMap(), _ActionMenuElement_originalL
249
260
  item.setAttribute('aria-checked', `${checked}`);
250
261
  }
251
262
  __classPrivateFieldGet(this, _ActionMenuElement_instances, "m", _ActionMenuElement_updateInput).call(this);
252
- if (event instanceof KeyboardEvent && event.target instanceof HTMLButtonElement) {
253
- // prevent buttons from being clicked twice
254
- event.preventDefault();
255
- return;
256
- }
257
263
  }, _ActionMenuElement_activateItem = function _ActionMenuElement_activateItem(event, item) {
258
264
  const eventWillActivateByDefault = (event instanceof MouseEvent && event.type === 'click') ||
259
265
  (event instanceof KeyboardEvent &&
@@ -134,11 +134,24 @@ export class ActionMenuElement extends HTMLElement {
134
134
  }
135
135
 
136
136
  #isKeyboardActivation(event: Event): boolean {
137
+ return this.#isKeyboardActivationViaEnter(event) || this.#isKeyboardActivationViaSpace(event)
138
+ }
139
+
140
+ #isKeyboardActivationViaEnter(event: Event): boolean {
141
+ return (
142
+ event instanceof KeyboardEvent &&
143
+ event.type === 'keydown' &&
144
+ !(event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) &&
145
+ event.key === 'Enter'
146
+ )
147
+ }
148
+
149
+ #isKeyboardActivationViaSpace(event: Event): boolean {
137
150
  return (
138
151
  event instanceof KeyboardEvent &&
139
152
  event.type === 'keydown' &&
140
153
  !(event.ctrlKey || event.altKey || event.metaKey || event.shiftKey) &&
141
- (event.key === 'Enter' || event.key === ' ')
154
+ event.key === ' '
142
155
  )
143
156
  }
144
157
 
@@ -172,11 +185,6 @@ export class ActionMenuElement extends HTMLElement {
172
185
  return
173
186
  }
174
187
 
175
- // Ignore events within dialogs within menus
176
- if ((event.target as Element)?.closest('dialog') || (event.target as Element)?.closest('modal-dialog')) {
177
- return
178
- }
179
-
180
188
  if (event.type === 'focusout') {
181
189
  if (this.#invokerBeingClicked) return
182
190
 
@@ -207,6 +215,16 @@ export class ActionMenuElement extends HTMLElement {
207
215
 
208
216
  this.#activateItem(event, item)
209
217
  this.#handleItemActivated(event, item)
218
+
219
+ // Pressing the space key on a button will cause the page to scroll unless preventDefault()
220
+ // is called. Unfortunately, calling preventDefault() will also skip form submission. The
221
+ // code below therefore only calls preventDefault() if the button submits a form and the
222
+ // button is being activated by the space key.
223
+ if (item.getAttribute('type') === 'submit' && this.#isKeyboardActivationViaSpace(event)) {
224
+ event.preventDefault()
225
+ item.closest('form')?.submit()
226
+ }
227
+
210
228
  return
211
229
  }
212
230
 
@@ -283,12 +301,6 @@ export class ActionMenuElement extends HTMLElement {
283
301
  }
284
302
 
285
303
  this.#updateInput()
286
-
287
- if (event instanceof KeyboardEvent && event.target instanceof HTMLButtonElement) {
288
- // prevent buttons from being clicked twice
289
- event.preventDefault()
290
- return
291
- }
292
304
  }
293
305
 
294
306
  #activateItem(event: Event, item: Element) {
@@ -3,14 +3,131 @@
3
3
 
4
4
  module Primer
5
5
  module Alpha
6
- # ActionMenu is used for actions, navigation, to display secondary options, or single/multi select lists. They appear when users interact with buttons, actions, or other controls.
6
+ # ActionMenu is used for actions, navigation, to display secondary options, or single/multi select lists. They appear when
7
+ # users interact with buttons, actions, or other controls.
7
8
  #
8
9
  # The only allowed elements for the `Item` components are: `:a`, `:button`, and `:clipboard-copy`. The default is `:button`.
9
10
  #
11
+ # ### Select variants
12
+ #
13
+ # While `ActionMenu`s default to a list of buttons that can link to other pages, copy text to the clipboard, etc, they also support
14
+ # `single` and `multiple` select variants. The single select variant allows a single item to be "selected" (i.e. marked "active")
15
+ # when clicked, which will cause a check mark to appear to the left of the item text. When the `multiple` select variant is chosen,
16
+ # multiple items may be selected and check marks will appear next to each selected item.
17
+ #
18
+ # Use the `select_variant:` option to control which variant the `ActionMenu` uses. For more information, see the documentation on
19
+ # supported arguments below.
20
+ #
21
+ # ### Dynamic labels
22
+ #
23
+ # When using the `single` select variant, an optional label indicating the selected item can be displayed inside the menu button.
24
+ # Dynamic labels can also be prefixed with custom text.
25
+ #
26
+ # Pass `dynamic_label: true` to enable dynamic label behavior, and pass `dynamic_label_prefix: "<string>"` to set a custom prefix.
27
+ # For more information, see the documentation on supported arguments below.
28
+ #
29
+ # ### `ActionMenu`s as form inputs
30
+ #
31
+ # When using either the `single` or `multiple` select variants, `ActionMenu`s can be used as form inputs. They behave very
32
+ # similarly to how HTML `<select>` boxes behave, and play nicely with Rails' built-in form mechanisms. Pass arguments via the
33
+ # `form_arguments:` argument, including the Rails form builder object and the name of the field:
34
+ #
35
+ # ```erb
36
+ # <% form_with(url: update_merge_strategy_path) do |f| %>
37
+ # <%= render(Primer::Alpha::ActionMenu.new(form_arguments: { builder: f, name: "merge_strategy" })) do |menu| %>
38
+ # <% menu.with_item(label: "Fast forward", data: { value: "fast_forward" }) %>
39
+ # <% menu.with_item(label: "Recursive", data: { value: "recursive" }) %>
40
+ # <% menu.with_item(label: "Ours", data: { value: "ours" }) %>
41
+ # <% menu.with_item(label: "Theirs", data: { value: "theirs" }) %>
42
+ # <% end %>
43
+ # <% end %>
44
+ # ```
45
+ #
46
+ # The value of the `data: { value: ... }` argument is sent to the server on submit, keyed using the name provided above
47
+ # (eg. `"merge_strategy"`). If no value is provided for an item, the value of that item is the item's label. Here's the
48
+ # corresponding `MergeStrategyController` that might be written to handle the form above:
49
+ #
50
+ # ```ruby
51
+ # class MergeStrategyController < ApplicationController
52
+ # def update
53
+ # puts "You chose #{merge_strategy_params[:merge_strategy]}"
54
+ # end
55
+ #
56
+ # private
57
+ #
58
+ # def merge_strategy_params
59
+ # params.permit(:merge_strategy)
60
+ # end
61
+ # end
62
+ # ```
63
+ #
64
+ # ### `ActionMenu` items that submit forms
65
+ #
66
+ # Whereas `ActionMenu` items normally permit navigation via `<a>` tags which make HTTP `get` requests, `ActionMenu` items
67
+ # also permit navigation via `POST` requests. To enable this behavior, include the `href:` argument as normal, but also pass
68
+ # the `form_arguments:` argument to the appropriate item:
69
+ #
70
+ # ```erb
71
+ # <%= render(Primer::Alpha::ActionMenu.new) do |menu| %>
72
+ # <% menu.with_item(
73
+ # label: "Repository",
74
+ # href: update_repo_grouping_path,
75
+ # form_arguments: {
76
+ # method: :post,
77
+ # name: "group_by",
78
+ # value: "repository"
79
+ # }
80
+ # ) %>
81
+ # <% end %>
82
+ # ```
83
+ #
84
+ # Make sure to specify `method: :post`, as the default is `:get`. When clicked, the list item will submit a POST request to
85
+ # the URL passed in the `href:` argument, including a parameter named `"group_by"` with a value of `"repository"`. If no value
86
+ # is given, the name, eg. `"group_by"`, will be used as the value.
87
+ #
88
+ # It is possible to include multiple fields on submit. Instead of passing the `name:` and `value:` arguments, pass an array via
89
+ # the `inputs:` argument:
90
+ #
91
+ # ```erb
92
+ # <%= render(Primer::Alpha::ActionMenu.new) do |menu| %>
93
+ # <% menu.with_show_button { "Group By" } %>
94
+ # <% menu.with_item(
95
+ # label: "Repository",
96
+ # href: update_repo_grouping_path,
97
+ # form_arguments: {
98
+ # method: :post,
99
+ # inputs: [{
100
+ # name: "group_by",
101
+ # value: "repository"
102
+ # }, {
103
+ # name: "some_other_field",
104
+ # value: "some value",
105
+ # }],
106
+ # }
107
+ # ) %>
108
+ # <% end %>
109
+ # ```
110
+ #
111
+ # ### Form arguments
112
+ #
113
+ # The following table summarizes the arguments allowed in the `form_arguments:` hash mentioned above.
114
+ #
115
+ # |Name |Type |Default|Description|
116
+ # |:----------------|:-------------|:------|:----------|
117
+ # |`method` |`Symbol` |`:get` |The HTTP request method to use to submit the form. One of `:get`, `:post`, `:patch`, `:put`, `:delete`, or `:head`|
118
+ # |`name` |`String` |`nil` |The name of the field that will be sent to the server on submit.|
119
+ # |`value` |`String` |`nil` |The value of the field that will be sent to the server on submit.|
120
+ # |`input_arguments`|`Hash` |`{}` |Additional key/value pairs to emit as HTML attributes on the `<input type="hidden">` element.|
121
+ # |`inputs` |`Array<Hash>` |`[]` |An array of hashes representing HTML `<input type="hidden">` elements. Must contain at least `name:` and `value:` keys. If additional key/value pairs are provided, they are emitted as HTML attributes on the `<input>` element. This argument supercedes the `name:`, `value:`, and `:input_arguments` arguments listed above.|
122
+ #
123
+ # The elements of the `inputs:` array will be emitted as HTML `<input type="hidden">` elements.
124
+ #
10
125
  # @accessibility
11
- # The action for the menu item needs to be on the element with `role="menuitem"`. Semantics are removed for everything nested inside of it. When a menu item is selected, the menu will close immediately.
126
+ # The action for the menu item needs to be on the element with `role="menuitem"`. Semantics are removed for everything
127
+ # nested inside of it. When a menu item is selected, the menu will close immediately.
12
128
  #
13
- # Additional information around the keyboard functionality and implementation can be found on the [WAI-ARIA Authoring Practices](https://www.w3.org/TR/wai-aria-practices-1.2/#menu).
129
+ # Additional information around the keyboard functionality and implementation can be found on the
130
+ # [WAI-ARIA Authoring Practices](https://www.w3.org/TR/wai-aria-practices-1.2/#menu).
14
131
  class ActionMenu < Primer::Component
15
132
  status :alpha
16
133
 
@@ -38,19 +38,16 @@ function clickHandler(event) {
38
38
  return;
39
39
  }
40
40
  }
41
- // Find the top level dialog that is open.
42
- const topLevelDialog = overlayStack[overlayStack.length - 1];
43
- if (!topLevelDialog)
41
+ if (!overlayStack.length)
44
42
  return;
45
- dialogId = button.getAttribute('data-close-dialog-id');
46
- if (dialogId === topLevelDialog.id) {
47
- overlayStack.pop();
48
- topLevelDialog.close();
49
- }
50
- dialogId = button.getAttribute('data-submit-dialog-id');
51
- if (dialogId === topLevelDialog.id) {
52
- overlayStack.pop();
53
- topLevelDialog.close(true);
43
+ dialogId = button.getAttribute('data-close-dialog-id') || button.getAttribute('data-submit-dialog-id');
44
+ if (dialogId) {
45
+ const dialog = document.getElementById(dialogId);
46
+ if (dialog instanceof ModalDialogElement) {
47
+ const dialogIndex = overlayStack.findIndex(ele => ele.id === dialogId);
48
+ overlayStack.splice(dialogIndex, 1);
49
+ dialog.close(button.hasAttribute('data-submit-dialog-id'));
50
+ }
54
51
  }
55
52
  }
56
53
  function keydownHandler(event) {
@@ -107,7 +104,7 @@ export class ModalDialogElement extends HTMLElement {
107
104
  if (__classPrivateFieldGet(this, _ModalDialogElement_focusAbortController, "f").signal.aborted) {
108
105
  __classPrivateFieldSet(this, _ModalDialogElement_focusAbortController, new AbortController(), "f");
109
106
  }
110
- focusTrap(this, undefined, __classPrivateFieldGet(this, _ModalDialogElement_focusAbortController, "f").signal);
107
+ focusTrap(this, this.querySelector('[autofocus]'), __classPrivateFieldGet(this, _ModalDialogElement_focusAbortController, "f").signal);
111
108
  overlayStack.push(this);
112
109
  }
113
110
  else {
@@ -30,20 +30,17 @@ function clickHandler(event: Event) {
30
30
  return
31
31
  }
32
32
  }
33
- // Find the top level dialog that is open.
34
- const topLevelDialog = overlayStack[overlayStack.length - 1]
35
- if (!topLevelDialog) return
36
33
 
37
- dialogId = button.getAttribute('data-close-dialog-id')
38
- if (dialogId === topLevelDialog.id) {
39
- overlayStack.pop()
40
- topLevelDialog.close()
41
- }
34
+ if (!overlayStack.length) return
42
35
 
43
- dialogId = button.getAttribute('data-submit-dialog-id')
44
- if (dialogId === topLevelDialog.id) {
45
- overlayStack.pop()
46
- topLevelDialog.close(true)
36
+ dialogId = button.getAttribute('data-close-dialog-id') || button.getAttribute('data-submit-dialog-id')
37
+ if (dialogId) {
38
+ const dialog = document.getElementById(dialogId)
39
+ if (dialog instanceof ModalDialogElement) {
40
+ const dialogIndex = overlayStack.findIndex(ele => ele.id === dialogId)
41
+ overlayStack.splice(dialogIndex, 1)
42
+ dialog.close(button.hasAttribute('data-submit-dialog-id'))
43
+ }
47
44
  }
48
45
  }
49
46
 
@@ -107,7 +104,7 @@ export class ModalDialogElement extends HTMLElement {
107
104
  if (this.#focusAbortController.signal.aborted) {
108
105
  this.#focusAbortController = new AbortController()
109
106
  }
110
- focusTrap(this, undefined, this.#focusAbortController.signal)
107
+ focusTrap(this, this.querySelector('[autofocus]') as HTMLElement, this.#focusAbortController.signal)
111
108
  overlayStack.push(this)
112
109
  } else {
113
110
  if (!this.open) return
@@ -1 +1 @@
1
- .SegmentedControl{background-color:var(--controlTrack-bgColor-rest,var(--color-segmented-control-bg));border-radius:var(--borderRadius-medium,.375rem);display:inline-flex;list-style:none}.SegmentedControl-item{border:var(--borderWidth-thin,max(1px,.0625rem)) solid #0000;border-radius:var(--borderRadius-medium,.375rem);display:inline-flex;padding:var(--control-xsmall-paddingInline-condensed,.25rem);position:relative}.SegmentedControl-item .Button--invisible:hover:not(:disabled){background-color:var(--controlTrack-bgColor-hover,var(--color-action-list-item-default-hover-bg))}.SegmentedControl-item .Button--invisible:active:not(:disabled){background-color:var(--controlTrack-bgColor-active,var(--color-action-list-item-default-active-bg))}.SegmentedControl-item.SegmentedControl-item--selected{background-color:var(--controlKnob-bgColor-rest,var(--color-segmented-control-button-bg));border-color:var(--controlKnob-borderColor-rest,var(--color-segmented-control-button-selected-border))}.SegmentedControl-item.SegmentedControl-item--selected .Button{font-weight:var(--base-text-weight-semibold,600)}.SegmentedControl-item.SegmentedControl-item--selected .Button:hover{background-color:initial}.SegmentedControl-item.SegmentedControl-item--selected:before{border-color:#0000!important}.SegmentedControl-item.SegmentedControl-item--selected+.SegmentedControl-item:before{border-color:#0000}.SegmentedControl-item .Button-label[data-content]:before{content:attr(data-content);display:block;font-weight:var(--base-text-weight-semibold,600);height:0;visibility:hidden}.SegmentedControl-item:not(:first-child):before{border-left:var(--borderWidth-thin,max(1px,.0625rem)) solid var(--borderColor-default,var(--color-border-default));content:"";inset:0 0 0 -1px;margin-bottom:var(--control-medium-paddingBlock,.375rem);margin-top:var(--control-medium-paddingBlock,.375rem);position:absolute}.SegmentedControl-item .Button{border:0;color:var(--button-default-fgColor-rest,var(--color-btn-text));font-weight:var(--base-text-weight-normal,400);transition:none}.SegmentedControl-item .Button:focus-visible{border-radius:calc(var(--borderRadius-medium,.375rem) - 5px);outline-offset:calc(var(--control-xsmall-paddingInline-condensed,.25rem) - var(--borderWidth-thin,max(1px, .0625rem)))}.SegmentedControl-item .Button--small{height:calc(var(--control-small-size,1.75rem) - var(--control-xsmall-paddingInline-condensed,.25rem)*2 - var(--borderWidth-thin,max(1px, .0625rem))*2);padding:0 calc(var(--control-small-paddingInline-condensed,.5rem) - var(--control-xsmall-paddingInline-condensed,.25rem))}.SegmentedControl-item .Button--small.Button--iconOnly{width:calc(var(--control-medium-size,2rem) - var(--control-xsmall-paddingInline-condensed,.25rem)*2 - var(--borderWidth-thin,max(1px, .0625rem))*2)}.SegmentedControl-item .Button--small.Button--iconOnly:before{content:"";height:100%;left:50%;min-height:var(--control-medium-size,2rem);min-width:var(--control-medium-size,2rem);position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:100%}.SegmentedControl-item .Button--medium{height:calc(var(--control-medium-size,2rem) - var(--control-xsmall-paddingInline-condensed,.25rem)*2 - var(--borderWidth-thin,max(1px, .0625rem))*2);padding:0 calc(var(--control-medium-paddingInline-normal,.75rem) - var(--control-xsmall-paddingInline-condensed,.25rem))}.SegmentedControl-item .Button--medium.Button--iconOnly{width:calc(var(--control-medium-size,2rem) - var(--control-xsmall-paddingInline-condensed,.25rem)*2 - var(--borderWidth-thin,max(1px, .0625rem))*2)}.SegmentedControl-item .Button--medium.Button--iconOnly:before{content:"";height:100%;left:50%;min-height:var(--control-medium-size,2rem);min-width:var(--control-medium-size,2rem);position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:100%}.SegmentedControl-item .Button--large{height:calc(var(--control-large-size,2.5rem) - var(--control-xsmall-paddingInline-condensed,.25rem)*2 - var(--borderWidth-thin,max(1px, .0625rem))*2);padding:0 calc(var(--control-large-paddingInline-spacious,1rem) - var(--control-xsmall-paddingInline-condensed,.25rem))}.SegmentedControl-item .Button--large.Button--iconOnly{width:calc(var(--control-large-size,2.5rem) - var(--control-xsmall-paddingInline-condensed,.25rem)*2 - var(--borderWidth-thin,max(1px, .0625rem))*2)}.SegmentedControl-item .Button--large.Button--iconOnly:before{content:"";height:100%;left:50%;min-height:var(--control-large-size,2.5rem);min-width:var(--control-large-size,2.5rem);position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:100%}.SegmentedControl-item .Button--iconOnly{padding:initial}.SegmentedControl-item .Button--invisible.Button--invisible-noVisuals .Button-label{color:var(--button-default-fgColor-rest,var(--color-btn-text))}.SegmentedControl--fullWidth{display:flex}.SegmentedControl--fullWidth .SegmentedControl-item{flex:1;justify-content:center}.SegmentedControl--fullWidth .Button--iconOnly,.SegmentedControl--fullWidth .Button-withTooltip{display:flex;justify-content:center;width:100%!important}
1
+ .SegmentedControl{--segmentedControl-item-padding:var(--control-small-paddingBlock,0.25rem);background-color:var(--controlTrack-bgColor-rest,var(--color-segmented-control-bg));border-radius:var(--borderRadius-medium,.375rem);display:inline-flex;list-style:none}.SegmentedControl--iconOnly .Button--iconOnly.Button--large,.SegmentedControl--iconOnly .Button--iconOnly.Button--medium,.SegmentedControl--iconOnly .Button--iconOnly.Button--small{padding-inline:0!important;width:100%}.SegmentedControl--small{--segmentedControl-item-padding:var(--control-xsmall-paddingBlock,0.125rem)}.SegmentedControl--small .SegmentedControl-item{height:var(--control-small-size,1.75rem)}.SegmentedControl--small .SegmentedControl-item .Button{padding-inline:calc(var(--control-xsmall-paddingInline-normal,.5rem) - var(--segmentedControl-item-padding))}.SegmentedControl--small.SegmentedControl--iconOnly .SegmentedControl-item{width:var(--control-small-size,1.75rem)}.SegmentedControl--medium .SegmentedControl-item{height:var(--control-medium-size,2rem)}.SegmentedControl--medium.SegmentedControl--iconOnly .SegmentedControl-item{width:var(--control-medium-size,2rem)}.SegmentedControl--large .SegmentedControl-item{height:var(--control-large-size,2.5rem)}.SegmentedControl--large .SegmentedControl-item .Button{padding-inline:calc(var(--control-large-paddingInline-normal,.75rem) - var(--segmentedControl-item-padding))}.SegmentedControl--large.SegmentedControl--iconOnly .SegmentedControl-item{width:var(--control-large-size,2.5rem)}.SegmentedControl-item{border:var(--borderWidth-thin,max(1px,.0625rem)) solid #0000;border-radius:var(--borderRadius-medium,.375rem);display:inline-flex;height:var(--control-medium-size,2rem);justify-content:center;padding:var(--segmentedControl-item-padding);position:relative}.SegmentedControl-item .Button-withTooltip{width:100%}.SegmentedControl-item .Button--invisible:hover:not(:disabled){background-color:var(--controlTrack-bgColor-hover,var(--color-action-list-item-default-hover-bg))}.SegmentedControl-item .Button--invisible:active:not(:disabled){background-color:var(--controlTrack-bgColor-active,var(--color-action-list-item-default-active-bg))}.SegmentedControl-item.SegmentedControl-item--selected{background-color:var(--controlKnob-bgColor-rest,var(--color-segmented-control-button-bg));border-color:var(--controlKnob-borderColor-rest,var(--color-segmented-control-button-selected-border))}.SegmentedControl-item.SegmentedControl-item--selected .Button{font-weight:var(--base-text-weight-semibold,600)}.SegmentedControl-item.SegmentedControl-item--selected .Button:hover{background-color:initial}.SegmentedControl-item.SegmentedControl-item--selected:before{border-color:#0000!important}.SegmentedControl-item.SegmentedControl-item--selected+.SegmentedControl-item:before{border-color:#0000}.SegmentedControl-item .Button-label[data-content]:before{content:attr(data-content);display:block;font-weight:var(--base-text-weight-semibold,600);height:0;visibility:hidden}.SegmentedControl-item:not(:first-child):before{border-left:var(--borderWidth-thin,max(1px,.0625rem)) solid var(--borderColor-default,var(--color-border-default));content:"";inset:0 0 0 -1px;margin-bottom:var(--control-medium-paddingBlock,.375rem);margin-top:var(--control-medium-paddingBlock,.375rem);position:absolute}.SegmentedControl-item .Button{border:0;border-radius:calc(var(--borderRadius-medium,.375rem) - var(--segmentedControl-item-padding)/2);font-weight:var(--base-text-weight-normal,400);height:100%;padding-inline:calc(var(--control-medium-paddingInline-normal,.75rem) - var(--segmentedControl-item-padding));width:100%}.SegmentedControl-item .Button:focus-visible{border-radius:calc(var(--borderRadius-medium,.375rem) - var(--segmentedControl-item-padding)/1);outline-offset:calc(var(--segmentedControl-item-padding) - var(--borderWidth-thin,max(1px, .0625rem)))}.SegmentedControl-item .Button--invisible.Button--invisible-noVisuals .Button-label{color:var(--button-default-fgColor-rest,var(--color-btn-text))}.SegmentedControl--fullWidth{display:flex}.SegmentedControl--fullWidth .SegmentedControl-item{flex:1;justify-content:center}
@@ -2,7 +2,20 @@
2
2
  "name": "alpha/segmented_control",
3
3
  "selectors": [
4
4
  ".SegmentedControl",
5
+ ".SegmentedControl--iconOnly .Button--iconOnly.Button--large",
6
+ ".SegmentedControl--iconOnly .Button--iconOnly.Button--medium",
7
+ ".SegmentedControl--iconOnly .Button--iconOnly.Button--small",
8
+ ".SegmentedControl--small",
9
+ ".SegmentedControl--small .SegmentedControl-item",
10
+ ".SegmentedControl--small .SegmentedControl-item .Button",
11
+ ".SegmentedControl--small.SegmentedControl--iconOnly .SegmentedControl-item",
12
+ ".SegmentedControl--medium .SegmentedControl-item",
13
+ ".SegmentedControl--medium.SegmentedControl--iconOnly .SegmentedControl-item",
14
+ ".SegmentedControl--large .SegmentedControl-item",
15
+ ".SegmentedControl--large .SegmentedControl-item .Button",
16
+ ".SegmentedControl--large.SegmentedControl--iconOnly .SegmentedControl-item",
5
17
  ".SegmentedControl-item",
18
+ ".SegmentedControl-item .Button-withTooltip",
6
19
  ".SegmentedControl-item .Button--invisible:hover:not(:disabled)",
7
20
  ".SegmentedControl-item .Button--invisible:active:not(:disabled)",
8
21
  ".SegmentedControl-item.SegmentedControl-item--selected",
@@ -14,20 +27,8 @@
14
27
  ".SegmentedControl-item:not(:first-child):before",
15
28
  ".SegmentedControl-item .Button",
16
29
  ".SegmentedControl-item .Button:focus-visible",
17
- ".SegmentedControl-item .Button--small",
18
- ".SegmentedControl-item .Button--small.Button--iconOnly",
19
- ".SegmentedControl-item .Button--small.Button--iconOnly:before",
20
- ".SegmentedControl-item .Button--medium",
21
- ".SegmentedControl-item .Button--medium.Button--iconOnly",
22
- ".SegmentedControl-item .Button--medium.Button--iconOnly:before",
23
- ".SegmentedControl-item .Button--large",
24
- ".SegmentedControl-item .Button--large.Button--iconOnly",
25
- ".SegmentedControl-item .Button--large.Button--iconOnly:before",
26
- ".SegmentedControl-item .Button--iconOnly",
27
30
  ".SegmentedControl-item .Button--invisible.Button--invisible-noVisuals .Button-label",
28
31
  ".SegmentedControl--fullWidth",
29
- ".SegmentedControl--fullWidth .SegmentedControl-item",
30
- ".SegmentedControl--fullWidth .Button--iconOnly",
31
- ".SegmentedControl--fullWidth .Button-withTooltip"
32
+ ".SegmentedControl--fullWidth .SegmentedControl-item"
32
33
  ]
33
34
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["segmented_control.pcss","<no source>"],"names":[],"mappings":"AAEA,kBAGE,mFAAqF,CACrF,gDAAyC,CAHzC,mBAAoB,CACpB,eAGF,CAEA,uBAGE,4DAAiD,CACjD,gDAAyC,CAFzC,mBAAoB,CAGpB,4DAAsD,CAJtD,iBAkIF,CA3HI,+DACE,iGACF,CAEA,gEACE,mGACF,CAIF,uDACE,yFAA2F,CAC3F,sGAiBF,CAfE,+DACE,gDAKF,CAHE,qEACE,wBACF,CAGF,8DACE,4BACF,CAEA,qFACE,kBACF,CAIF,0DAKE,0BAA2B,CAJ3B,aAAc,CAEd,gDAA6C,CAD7C,QAAS,CAET,iBAEF,CAIE,gDAME,kHAAqE,CADrE,UAAW,CAHX,gBAAiB,CAEjB,wDAAiD,CADjD,qDAA8C,CAF9C,iBAMF,CAIF,+BACE,QAAS,CAGT,8DAAyC,CAFzC,8CAA2C,CAC3C,eAOF,CAJE,6CAEE,4DAAqD,CADrD,sHAEF,CAGF,sCACE,sJAEC,CACD,yHAWF,CATE,uDACE,mJAOF,CAFI,8DC9FR,WAAA,YAAA,SAAA,2CAAA,0CAAA,kBAAA,QAAA,4CAAA,UD8FoF,CAKlF,uCACE,oJAEC,CACD,wHAWF,CATE,wDACE,mJAOF,CAFI,+DC/GR,WAAA,YAAA,SAAA,2CAAA,0CAAA,kBAAA,QAAA,4CAAA,UD+GoF,CAKlF,sCACE,qJAEC,CACD,uHAWF,CATE,uDACE,oJAOF,CAFI,8DChIR,WAAA,YAAA,SAAA,4CAAA,2CAAA,kBAAA,QAAA,4CAAA,UDgIkF,CAKhF,yCACE,eACF,CAEA,oFACE,8DACF,CAIF,6BACE,YAcF,CAZE,oDACE,MAAO,CACP,sBACF,CAGA,gGAGE,YAAa,CACb,sBAAuB,CAFvB,oBAGF","file":"segmented_control.css","sourcesContent":["/* SegmentedControl */\n\n.SegmentedControl {\n display: inline-flex;\n list-style: none;\n background-color: var(--controlTrack-bgColor-rest, var(--color-segmented-control-bg));\n border-radius: var(--borderRadius-medium);\n}\n\n.SegmentedControl-item {\n position: relative;\n display: inline-flex;\n border: var(--borderWidth-thin) solid transparent;\n border-radius: var(--borderRadius-medium);\n padding: var(--control-xsmall-paddingInline-condensed);\n\n & .Button--invisible {\n &:hover:not(:disabled) {\n background-color: var(--controlTrack-bgColor-hover, var(--color-action-list-item-default-hover-bg));\n }\n\n &:active:not(:disabled) {\n background-color: var(--controlTrack-bgColor-active, var(--color-action-list-item-default-active-bg));\n }\n }\n\n /* Selected ---------------------------------------- */\n &.SegmentedControl-item--selected {\n background-color: var(--controlKnob-bgColor-rest, var(--color-segmented-control-button-bg));\n border-color: var(--controlKnob-borderColor-rest, var(--color-segmented-control-button-selected-border));\n\n & .Button {\n font-weight: var(--base-text-weight-semibold);\n\n &:hover {\n background-color: transparent;\n }\n }\n\n &::before {\n border-color: transparent !important;\n }\n\n & + .SegmentedControl-item::before {\n border-color: transparent;\n }\n }\n\n /* renders a visibly hidden \"copy\" of the text in bold, reserving box space for when text becomes bold on selected */\n & .Button-label[data-content]::before {\n display: block;\n height: 0;\n font-weight: var(--base-text-weight-semibold);\n visibility: hidden;\n content: attr(data-content);\n }\n\n /* Separator lines */\n &:not(:first-child) {\n &::before {\n position: absolute;\n inset: 0 0 0 -1px;\n margin-top: var(--control-medium-paddingBlock);\n margin-bottom: var(--control-medium-paddingBlock);\n content: '';\n border-left: var(--borderWidth-thin) solid var(--borderColor-default);\n }\n }\n\n /* Button ----------------------------------------- */\n & .Button {\n border: 0;\n font-weight: var(--base-text-weight-normal);\n transition: none;\n color: var(--button-default-fgColor-rest);\n\n &:focus-visible {\n outline-offset: calc(var(--control-xsmall-paddingInline-condensed) - var(--borderWidth-thin));\n border-radius: calc(var(--borderRadius-medium) - 5px);\n }\n }\n\n & .Button--small {\n height: calc(\n var(--control-small-size) - var(--control-xsmall-paddingInline-condensed) * 2 - var(--borderWidth-thin) * 2\n );\n padding: 0 calc(var(--control-small-paddingInline-condensed) - var(--control-xsmall-paddingInline-condensed));\n\n &.Button--iconOnly {\n width: calc(\n var(--control-medium-size) - var(--control-xsmall-paddingInline-condensed) * 2 - var(--borderWidth-thin) * 2\n );\n\n &::before {\n @mixin minTouchTarget var(--control-medium-size), var(--control-medium-size);\n }\n }\n }\n\n & .Button--medium {\n height: calc(\n var(--control-medium-size) - var(--control-xsmall-paddingInline-condensed) * 2 - var(--borderWidth-thin) * 2\n );\n padding: 0 calc(var(--control-medium-paddingInline-normal) - var(--control-xsmall-paddingInline-condensed));\n\n &.Button--iconOnly {\n width: calc(\n var(--control-medium-size) - var(--control-xsmall-paddingInline-condensed) * 2 - var(--borderWidth-thin) * 2\n );\n\n &::before {\n @mixin minTouchTarget var(--control-medium-size), var(--control-medium-size);\n }\n }\n }\n\n & .Button--large {\n height: calc(\n var(--control-large-size) - var(--control-xsmall-paddingInline-condensed) * 2 - var(--borderWidth-thin) * 2\n );\n padding: 0 calc(var(--control-large-paddingInline-spacious) - var(--control-xsmall-paddingInline-condensed));\n\n &.Button--iconOnly {\n width: calc(\n var(--control-large-size) - var(--control-xsmall-paddingInline-condensed) * 2 - var(--borderWidth-thin) * 2\n );\n\n &::before {\n @mixin minTouchTarget var(--control-large-size), var(--control-large-size);\n }\n }\n }\n\n & .Button--iconOnly {\n padding: initial;\n }\n\n & .Button--invisible.Button--invisible-noVisuals .Button-label {\n color: var(--button-default-fgColor-rest);\n }\n}\n\n/* fullWidth */\n.SegmentedControl--fullWidth {\n display: flex;\n\n & .SegmentedControl-item {\n flex: 1;\n justify-content: center;\n }\n\n /* is .Button-withTooltip used anywhere? can't find use of it */\n & .Button--iconOnly,\n & .Button-withTooltip {\n width: 100% !important;\n display: flex;\n justify-content: center;\n }\n}\n",null]}
1
+ {"version":3,"sources":["segmented_control.pcss"],"names":[],"mappings":"AAEA,kBACE,yEAAkE,CAIlE,mFAAqF,CACrF,gDAAyC,CAHzC,mBAAoB,CACpB,eAGF,CAGE,qLAIE,0BAA4B,CAD5B,UAEF,CAKF,yBACE,2EAeF,CAbE,gDACE,wCAKF,CAHE,wDACE,4GACF,CAIA,2EACE,uCACF,CAKF,iDACE,sCACF,CAGE,4EACE,qCACF,CAKF,gDACE,uCAKF,CAHE,wDACE,4GACF,CAIA,2EACE,sCACF,CAMJ,uBAIE,4DAAiD,CACjD,gDAAyC,CAHzC,mBAAoB,CAIpB,sCAAkC,CAHlC,sBAAuB,CAIvB,4CAA6C,CAN7C,iBAoFF,CA5EE,2CACE,UACF,CAIE,+DACE,iGACF,CAEA,gEACE,mGACF,CAIF,uDACE,yFAA2F,CAC3F,sGAiBF,CAfE,+DACE,gDAKF,CAHE,qEACE,wBACF,CAGF,8DACE,4BACF,CAEA,qFACE,kBACF,CAIF,0DAKE,0BAA2B,CAJ3B,aAAc,CAEd,gDAA6C,CAD7C,QAAS,CAET,iBAEF,CAIE,gDAME,kHAAqE,CADrE,UAAW,CAHX,gBAAiB,CAEjB,wDAAiD,CADjD,qDAA8C,CAF9C,iBAMF,CAIF,+BAGE,QAAS,CAET,+FAA0F,CAD1F,8CAA2C,CAH3C,WAAY,CAKZ,6GAAuG,CAJvG,UAUF,CAJE,6CAEE,+FAA0F,CAD1F,sGAEF,CAGF,oFACE,8DACF,CAIF,6BACE,YAMF,CAJE,oDACE,MAAO,CACP,sBACF","file":"segmented_control.css","sourcesContent":["/* SegmentedControl */\n\n.SegmentedControl {\n --segmentedControl-item-padding: var(--control-small-paddingBlock);\n\n display: inline-flex;\n list-style: none;\n background-color: var(--controlTrack-bgColor-rest, var(--color-segmented-control-bg));\n border-radius: var(--borderRadius-medium);\n}\n\n.SegmentedControl--iconOnly {\n & .Button--iconOnly.Button--small,\n & .Button--iconOnly.Button--medium,\n & .Button--iconOnly.Button--large {\n width: 100%;\n padding-inline: 0 !important;\n }\n}\n\n/* sizes */\n\n.SegmentedControl--small {\n --segmentedControl-item-padding: var(--control-xsmall-paddingBlock);\n\n & .SegmentedControl-item {\n height: var(--control-small-size);\n\n & .Button {\n padding-inline: calc(var(--control-xsmall-paddingInline-normal) - var(--segmentedControl-item-padding));\n }\n }\n\n &.SegmentedControl--iconOnly {\n & .SegmentedControl-item {\n width: var(--control-small-size);\n }\n }\n}\n\n.SegmentedControl--medium {\n & .SegmentedControl-item {\n height: var(--control-medium-size);\n }\n\n &.SegmentedControl--iconOnly {\n & .SegmentedControl-item {\n width: var(--control-medium-size);\n }\n }\n}\n\n.SegmentedControl--large {\n & .SegmentedControl-item {\n height: var(--control-large-size);\n\n & .Button {\n padding-inline: calc(var(--control-large-paddingInline-normal) - var(--segmentedControl-item-padding));\n }\n }\n\n &.SegmentedControl--iconOnly {\n & .SegmentedControl-item {\n width: var(--control-large-size);\n }\n }\n}\n\n/* item */\n\n.SegmentedControl-item {\n position: relative;\n display: inline-flex;\n justify-content: center;\n border: var(--borderWidth-thin) solid transparent;\n border-radius: var(--borderRadius-medium);\n height: var(--control-medium-size);\n padding: var(--segmentedControl-item-padding);\n\n & .Button-withTooltip {\n width: 100%;\n }\n\n /* button color overrides */\n & .Button--invisible {\n &:hover:not(:disabled) {\n background-color: var(--controlTrack-bgColor-hover, var(--color-action-list-item-default-hover-bg));\n }\n\n &:active:not(:disabled) {\n background-color: var(--controlTrack-bgColor-active, var(--color-action-list-item-default-active-bg));\n }\n }\n\n /* Selected ---------------------------------------- */\n &.SegmentedControl-item--selected {\n background-color: var(--controlKnob-bgColor-rest, var(--color-segmented-control-button-bg));\n border-color: var(--controlKnob-borderColor-rest, var(--color-segmented-control-button-selected-border));\n\n & .Button {\n font-weight: var(--base-text-weight-semibold);\n\n &:hover {\n background-color: transparent;\n }\n }\n\n &::before {\n border-color: transparent !important;\n }\n\n & + .SegmentedControl-item::before {\n border-color: transparent;\n }\n }\n\n /* renders a visibly hidden \"copy\" of the text in bold, reserving box space for when text becomes bold on selected */\n & .Button-label[data-content]::before {\n display: block;\n height: 0;\n font-weight: var(--base-text-weight-semibold);\n visibility: hidden;\n content: attr(data-content);\n }\n\n /* Separator lines */\n &:not(:first-child) {\n &::before {\n position: absolute;\n inset: 0 0 0 -1px;\n margin-top: var(--control-medium-paddingBlock);\n margin-bottom: var(--control-medium-paddingBlock);\n content: '';\n border-left: var(--borderWidth-thin) solid var(--borderColor-default);\n }\n }\n\n /* Button ----------------------------------------- */\n & .Button {\n height: 100%;\n width: 100%;\n border: 0;\n font-weight: var(--base-text-weight-normal);\n border-radius: calc(var(--borderRadius-medium) - var(--segmentedControl-item-padding) / 2);\n padding-inline: calc(var(--control-medium-paddingInline-normal) - var(--segmentedControl-item-padding));\n\n &:focus-visible {\n outline-offset: calc(var(--segmentedControl-item-padding) - var(--borderWidth-thin));\n border-radius: calc(var(--borderRadius-medium) - var(--segmentedControl-item-padding) / 1);\n }\n }\n\n & .Button--invisible.Button--invisible-noVisuals .Button-label {\n color: var(--button-default-fgColor-rest);\n }\n}\n\n/* fullWidth */\n.SegmentedControl--fullWidth {\n display: flex;\n\n & .SegmentedControl-item {\n flex: 1;\n justify-content: center;\n }\n}\n"]}