primer_view_components 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,7 +7,7 @@ module Primer
7
7
  class ActionBar
8
8
  # ActionBar::Item is an internal component that wraps the items in a div with the `ActionBar-item` class.
9
9
  class Item < Primer::Component
10
- def initialize
10
+ def initialize(item_content)
11
11
  @system_arguments = {
12
12
  tag: :div,
13
13
  data: {
@@ -15,10 +15,11 @@ module Primer
15
15
  },
16
16
  classes: "ActionBar-item"
17
17
  }
18
+ @item_content = item_content
18
19
  end
19
20
 
20
21
  def call
21
- render(Primer::BaseComponent.new(**@system_arguments)) { content }
22
+ render(Primer::BaseComponent.new(**@system_arguments)) { render(@item_content) }
22
23
  end
23
24
  end
24
25
  end
@@ -23,9 +23,7 @@ module Primer
23
23
  c.with_leading_visual_icon(icon: icon)
24
24
  end
25
25
 
26
- render(Item.new) do
27
- render(Primer::Beta::IconButton.new(id: item_id, icon: icon, "aria-label": label, size: @size, scheme: :invisible, **system_arguments))
28
- end
26
+ Item.new(Primer::Beta::IconButton.new(id: item_id, icon: icon, "aria-label": label, size: @size, scheme: :invisible, **system_arguments))
29
27
  },
30
28
  divider: lambda {
31
29
  @action_menu.with_divider(hidden: true) if @overflow_menu
@@ -68,8 +66,6 @@ module Primer
68
66
  system_arguments = {
69
67
  **system_arguments,
70
68
  hidden: true,
71
- tag: :button,
72
- type: "button",
73
69
  "data-for": id,
74
70
  "data-action": "click:action-bar#menuItemClick"
75
71
  }
@@ -1 +1 @@
1
- anchored-position[popover]{border-width:0;inset:auto;min-width:192px;overflow:visible;padding:0;position:absolute}.Overlay{display:flex}anchored-position[popover]:not(.\:popover-open){display:none}@supports selector(:popover-open){anchored-position[popover]:not(.\:popover-open){display:revert}}@supports selector(:open){anchored-position[popover]:not(.\:popover-open){display:revert}}
1
+ anchored-position[popover]{border-width:0;inset:auto;min-width:192px;overflow:visible;padding:0;position:absolute}.Overlay{display:flex}anchored-position[popover]:not(.\:popover-open){display:none}anchored-position.not-anchored::-webkit-backdrop{background-color:var(--overlay-backdrop-bgColor,var(--color-neutral-muted))}anchored-position.not-anchored::backdrop{background-color:var(--overlay-backdrop-bgColor,var(--color-neutral-muted))}@supports selector(:popover-open){anchored-position[popover]:not(.\:popover-open){display:revert}}@supports selector(:open){anchored-position[popover]:not(.\:popover-open){display:revert}}
@@ -3,6 +3,8 @@
3
3
  "selectors": [
4
4
  "anchored-position[popover]",
5
5
  ".Overlay",
6
- "anchored-position[popover]:not(.\\:popover-open)"
6
+ "anchored-position[popover]:not(.\\:popover-open)",
7
+ "anchored-position.not-anchored::-webkit-backdrop",
8
+ "anchored-position.not-anchored::backdrop"
7
9
  ]
8
10
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["overlay.pcss"],"names":[],"mappings":"AAAA,2BACE,cAAe,CAIf,UAAW,CADX,eAAgB,CAEhB,gBAAiB,CAJjB,SAAU,CACV,iBAIF,CAEA,SACE,YACF,CAEA,gDACE,YACF,CAGA,kCACE,gDACE,cACF,CACF,CAGA,0BACE,gDACI,cACJ,CACF","file":"overlay.css","sourcesContent":["anchored-position[popover] {\n border-width: 0;\n padding: 0;\n position: absolute;\n min-width: 192px;\n inset: auto;\n overflow: visible;\n}\n\n.Overlay {\n display: flex;\n}\n\nanchored-position[popover]:not(.\\:popover-open) {\n display: none;\n}\n\n/* This reverts the declaration above for native popover, where `:popover-open` is supported */\n@supports selector(:popover-open) {\n anchored-position[popover]:not(.\\:popover-open) {\n display: revert;\n }\n}\n\n/* This reverts the declaration above for native popover, where `:open` is supported (Chrome 113, Safari TP) */\n@supports selector(:open) {\n anchored-position[popover]:not(.\\:popover-open) {\n display: revert;\n }\n}\n"]}
1
+ {"version":3,"sources":["overlay.pcss"],"names":[],"mappings":"AAAA,2BACE,cAAe,CAIf,UAAW,CADX,eAAgB,CAEhB,gBAAiB,CAJjB,SAAU,CACV,iBAIF,CAEA,SACE,YACF,CAEA,gDACE,YACF,CAEA,iDACE,2EACF,CAFA,yCACE,2EACF,CAGA,kCACE,gDACE,cACF,CACF,CAGA,0BACE,gDACI,cACJ,CACF","file":"overlay.css","sourcesContent":["anchored-position[popover] {\n border-width: 0;\n padding: 0;\n position: absolute;\n min-width: 192px;\n inset: auto;\n overflow: visible;\n}\n\n.Overlay {\n display: flex;\n}\n\nanchored-position[popover]:not(.\\:popover-open) {\n display: none;\n}\n\nanchored-position.not-anchored::backdrop {\n background-color: var(--overlay-backdrop-bgColor, var(--color-neutral-muted));\n}\n\n/* This reverts the declaration above for native popover, where `:popover-open` is supported */\n@supports selector(:popover-open) {\n anchored-position[popover]:not(.\\:popover-open) {\n display: revert;\n }\n}\n\n/* This reverts the declaration above for native popover, where `:open` is supported (Chrome 113, Safari TP) */\n@supports selector(:open) {\n anchored-position[popover]:not(.\\:popover-open) {\n display: revert;\n }\n}\n"]}
@@ -15,6 +15,10 @@ anchored-position[popover]:not(.\:popover-open) {
15
15
  display: none;
16
16
  }
17
17
 
18
+ anchored-position.not-anchored::backdrop {
19
+ background-color: var(--overlay-backdrop-bgColor, var(--color-neutral-muted));
20
+ }
21
+
18
22
  /* This reverts the declaration above for native popover, where `:popover-open` is supported */
19
23
  @supports selector(:popover-open) {
20
24
  anchored-position[popover]:not(.\:popover-open) {
@@ -12,6 +12,26 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
12
12
  var _ToolTipElement_instances, _ToolTipElement_abortController, _ToolTipElement_align, _ToolTipElement_side, _ToolTipElement_allowUpdatePosition, _ToolTipElement_update, _ToolTipElement_updateControlReference, _ToolTipElement_updateDirection, _ToolTipElement_updatePosition;
13
13
  import '@oddbird/popover-polyfill';
14
14
  import { getAnchoredPosition } from '@primer/behaviors';
15
+ const isPopoverOpen = (() => {
16
+ let selector;
17
+ function setSelector(el) {
18
+ try {
19
+ selector = ':popover-open';
20
+ return el.matches(selector);
21
+ }
22
+ catch (_a) {
23
+ try {
24
+ selector = ':open';
25
+ return el.matches(':open');
26
+ }
27
+ catch (_b) {
28
+ selector = '.\\:popover-open';
29
+ return el.matches('.\\:popover-open');
30
+ }
31
+ }
32
+ }
33
+ return (el) => (selector ? el.matches(selector) : setSelector(el));
34
+ })();
15
35
  const TOOLTIP_ARROW_EDGE_OFFSET = 6;
16
36
  const TOOLTIP_SR_ONLY_CLASS = 'sr-only';
17
37
  const TOOLTIP_OFFSET = 10;
@@ -29,7 +49,7 @@ function closeOpenTooltips(except) {
29
49
  for (const tooltip of openTooltips) {
30
50
  if (tooltip === except)
31
51
  continue;
32
- if (tooltip.matches(':popover-open')) {
52
+ if (isPopoverOpen(tooltip)) {
33
53
  tooltip.hidePopover();
34
54
  }
35
55
  else {
@@ -207,16 +227,16 @@ class ToolTipElement extends HTMLElement {
207
227
  }
208
228
  /* @deprecated */
209
229
  set hiddenFromView(value) {
210
- if (value && this.matches(':popover-open')) {
230
+ if (value && isPopoverOpen(this)) {
211
231
  this.hidePopover();
212
232
  }
213
- else if (!value && this.matches(':not(:popover-open)')) {
233
+ else if (!value && !isPopoverOpen(this)) {
214
234
  this.showPopover();
215
235
  }
216
236
  }
217
237
  /* @deprecated */
218
238
  get hiddenFromView() {
219
- return !this.matches(':popover-open');
239
+ return !isPopoverOpen(this);
220
240
  }
221
241
  connectedCallback() {
222
242
  var _a, _b;
@@ -260,7 +280,7 @@ class ToolTipElement extends HTMLElement {
260
280
  async handleEvent(event) {
261
281
  if (!this.control)
262
282
  return;
263
- const showing = this.matches(':popover-open');
283
+ const showing = isPopoverOpen(this);
264
284
  // Ensures that tooltip stays open when hovering between tooltip and element
265
285
  // WCAG Success Criterion 1.4.13 Hoverable
266
286
  const shouldShow = event.type === 'mouseenter' || event.type === 'focus';
@@ -272,10 +292,10 @@ class ToolTipElement extends HTMLElement {
272
292
  const isOpeningOtherPopover = event.type === 'beforetoggle' && event.currentTarget !== this;
273
293
  const shouldHide = isMouseLeaveFromButton || isEscapeKeydown || isMouseDownOnButton || isOpeningOtherPopover;
274
294
  await Promise.resolve();
275
- if (!showing && shouldShow && this.matches(':not(:popover-open)')) {
295
+ if (!showing && shouldShow && !isPopoverOpen(this)) {
276
296
  this.showPopover();
277
297
  }
278
- else if (showing && shouldHide && this.matches(':popover-open')) {
298
+ else if (showing && shouldHide && isPopoverOpen(this)) {
279
299
  this.hidePopover();
280
300
  }
281
301
  if (event.type === 'toggle') {
@@ -378,7 +398,7 @@ _ToolTipElement_abortController = new WeakMap(), _ToolTipElement_align = new Wea
378
398
  }, _ToolTipElement_updatePosition = function _ToolTipElement_updatePosition() {
379
399
  if (!this.control)
380
400
  return;
381
- if (!__classPrivateFieldGet(this, _ToolTipElement_allowUpdatePosition, "f") || !this.matches(':popover-open'))
401
+ if (!__classPrivateFieldGet(this, _ToolTipElement_allowUpdatePosition, "f") || !isPopoverOpen(this))
382
402
  return;
383
403
  const position = getAnchoredPosition(this, this.control, {
384
404
  side: __classPrivateFieldGet(this, _ToolTipElement_side, "f"),
@@ -2,6 +2,25 @@ import type {AnchorAlignment, AnchorSide} from '@primer/behaviors'
2
2
  import '@oddbird/popover-polyfill'
3
3
  import {getAnchoredPosition} from '@primer/behaviors'
4
4
 
5
+ const isPopoverOpen = (() => {
6
+ let selector: string
7
+ function setSelector(el: Element) {
8
+ try {
9
+ selector = ':popover-open'
10
+ return el.matches(selector)
11
+ } catch {
12
+ try {
13
+ selector = ':open'
14
+ return el.matches(':open')
15
+ } catch {
16
+ selector = '.\\:popover-open'
17
+ return el.matches('.\\:popover-open')
18
+ }
19
+ }
20
+ }
21
+ return (el: Element) => (selector ? el.matches(selector) : setSelector(el))
22
+ })()
23
+
5
24
  const TOOLTIP_ARROW_EDGE_OFFSET = 6
6
25
  const TOOLTIP_SR_ONLY_CLASS = 'sr-only'
7
26
  const TOOLTIP_OFFSET = 10
@@ -22,7 +41,7 @@ const DIRECTION_CLASSES = [
22
41
  function closeOpenTooltips(except?: Element) {
23
42
  for (const tooltip of openTooltips) {
24
43
  if (tooltip === except) continue
25
- if (tooltip.matches(':popover-open')) {
44
+ if (isPopoverOpen(tooltip)) {
26
45
  tooltip.hidePopover()
27
46
  } else {
28
47
  openTooltips.delete(tooltip)
@@ -206,16 +225,16 @@ class ToolTipElement extends HTMLElement {
206
225
 
207
226
  /* @deprecated */
208
227
  set hiddenFromView(value: true | false) {
209
- if (value && this.matches(':popover-open')) {
228
+ if (value && isPopoverOpen(this)) {
210
229
  this.hidePopover()
211
- } else if (!value && this.matches(':not(:popover-open)')) {
230
+ } else if (!value && !isPopoverOpen(this)) {
212
231
  this.showPopover()
213
232
  }
214
233
  }
215
234
 
216
235
  /* @deprecated */
217
236
  get hiddenFromView() {
218
- return !this.matches(':popover-open')
237
+ return !isPopoverOpen(this)
219
238
  }
220
239
 
221
240
  connectedCallback() {
@@ -262,7 +281,7 @@ class ToolTipElement extends HTMLElement {
262
281
 
263
282
  async handleEvent(event: Event) {
264
283
  if (!this.control) return
265
- const showing = this.matches(':popover-open')
284
+ const showing = isPopoverOpen(this)
266
285
 
267
286
  // Ensures that tooltip stays open when hovering between tooltip and element
268
287
  // WCAG Success Criterion 1.4.13 Hoverable
@@ -277,9 +296,9 @@ class ToolTipElement extends HTMLElement {
277
296
  const shouldHide = isMouseLeaveFromButton || isEscapeKeydown || isMouseDownOnButton || isOpeningOtherPopover
278
297
 
279
298
  await Promise.resolve()
280
- if (!showing && shouldShow && this.matches(':not(:popover-open)')) {
299
+ if (!showing && shouldShow && !isPopoverOpen(this)) {
281
300
  this.showPopover()
282
- } else if (showing && shouldHide && this.matches(':popover-open')) {
301
+ } else if (showing && shouldHide && isPopoverOpen(this)) {
283
302
  this.hidePopover()
284
303
  }
285
304
 
@@ -377,7 +396,7 @@ class ToolTipElement extends HTMLElement {
377
396
 
378
397
  #updatePosition() {
379
398
  if (!this.control) return
380
- if (!this.#allowUpdatePosition || !this.matches(':popover-open')) return
399
+ if (!this.#allowUpdatePosition || !isPopoverOpen(this)) return
381
400
 
382
401
  const position = getAnchoredPosition(this, this.control, {
383
402
  side: this.#side,
@@ -131,11 +131,20 @@ export default class AnchoredPositionElement extends HTMLElement {
131
131
  cancelAnimationFrame(__classPrivateFieldGet(this, _AnchoredPositionElement_animationFrame, "f"));
132
132
  __classPrivateFieldSet(this, _AnchoredPositionElement_animationFrame, requestAnimationFrame(() => {
133
133
  const anchor = this.anchorElement;
134
- if (!anchor)
135
- return;
136
- const { left, top } = getAnchoredPosition(this, anchor, this);
137
- this.style.top = `${top}px`;
138
- this.style.left = `${left}px`;
134
+ this.classList.toggle('not-anchored', !anchor);
135
+ if (anchor) {
136
+ const { left, top } = getAnchoredPosition(this, anchor, this);
137
+ this.style.top = `${top}px`;
138
+ this.style.left = `${left}px`;
139
+ this.style.bottom = 'auto';
140
+ this.style.right = 'auto';
141
+ }
142
+ else {
143
+ this.style.top = '0';
144
+ this.style.left = '0';
145
+ this.style.bottom = '0';
146
+ this.style.right = '0';
147
+ }
139
148
  }), "f");
140
149
  }
141
150
  }
@@ -133,10 +133,19 @@ export default class AnchoredPositionElement extends HTMLElement implements Posi
133
133
 
134
134
  this.#animationFrame = requestAnimationFrame(() => {
135
135
  const anchor = this.anchorElement
136
- if (!anchor) return
137
- const {left, top} = getAnchoredPosition(this, anchor, this)
138
- this.style.top = `${top}px`
139
- this.style.left = `${left}px`
136
+ this.classList.toggle('not-anchored', !anchor)
137
+ if (anchor) {
138
+ const {left, top} = getAnchoredPosition(this, anchor, this)
139
+ this.style.top = `${top}px`
140
+ this.style.left = `${left}px`
141
+ this.style.bottom = 'auto'
142
+ this.style.right = 'auto'
143
+ } else {
144
+ this.style.top = '0'
145
+ this.style.left = '0'
146
+ this.style.bottom = '0'
147
+ this.style.right = '0'
148
+ }
140
149
  })
141
150
  }
142
151
  }
@@ -1,4 +1,4 @@
1
1
  <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
- <circle cx="8" cy="8" r="7" stroke="currentColor" stroke-opacity="0.25" stroke-width="2" vector-effect="non-scaling-stroke" />
2
+ <circle cx="8" cy="8" r="7" stroke="currentColor" stroke-opacity="0.25" stroke-width="2" vector-effect="non-scaling-stroke" fill="none" />
3
3
  <path d="M15 8a7.002 7.002 0 00-7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" vector-effect="non-scaling-stroke" />
4
4
  <% end %>
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Migrations
6
+ # Lint and autocorrect deprecated IconButton
7
+ class IconButtonComponent < RuboCop::Cop::Cop
8
+ INVALID_MESSAGE = <<~STR
9
+ `Primer::IconButton` is deprecated. Please use `Primer::Beta::IconButton` instead.
10
+ STR
11
+
12
+ def_node_matcher :icon_button, <<~PATTERN
13
+ (send $(const (const nil? :Primer) :IconButton) :new ...)
14
+ PATTERN
15
+
16
+ def_node_matcher :hash_with_box_value?, <<~PATTERN
17
+ (hash ... (pair (sym :box) (...)) ... )
18
+ PATTERN
19
+
20
+ def on_send(node)
21
+ return unless icon_button(node)
22
+
23
+ add_offense(node, message: INVALID_MESSAGE)
24
+ end
25
+
26
+ def autocorrect(node)
27
+ return if hash_with_box_value?(node.arguments.first)
28
+
29
+ lambda do |corrector|
30
+ corrector.replace(icon_button(node), "Primer::Beta::IconButton")
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -5,7 +5,7 @@ module Primer
5
5
  module ViewComponents
6
6
  module VERSION
7
7
  MAJOR = 0
8
- MINOR = 8
8
+ MINOR = 9
9
9
  PATCH = 0
10
10
 
11
11
  STRING = [MAJOR, MINOR, PATCH].join(".")
@@ -0,0 +1,13 @@
1
+ <%= render(Primer::Alpha::ActionMenu.new()) do |menu| %>
2
+ <% menu.with_show_button { "Menu" } %>
3
+ <% menu.with_item(label: "Open Overlay", content_arguments: { id: "overlay-show-my-overlay", popovertarget: "my-overlay" }) %>
4
+ <% end %>
5
+ <%= render(Primer::Alpha::Overlay.new(
6
+ id: "my-overlay",
7
+ title: "An overlay",
8
+ role: :dialog,
9
+ popover: "manual",
10
+ )) do |d| %>
11
+ <% d.with_header(title: "An overlay") %>
12
+ <% d.with_body { "This is an overlay" } %>
13
+ <% end %>
@@ -164,6 +164,11 @@ module Primer
164
164
  })
165
165
  end
166
166
 
167
+ # @label In an ActionMenu
168
+ def in_an_action_menu()
169
+ render_with_template(locals: {})
170
+ end
171
+
167
172
  # @label Dialog with header and footer
168
173
  #
169
174
  def dialog_with_header_footer
@@ -5910,6 +5910,19 @@
5910
5910
  ]
5911
5911
  }
5912
5912
  },
5913
+ {
5914
+ "preview_path": "primer/alpha/overlay/in_an_action_menu",
5915
+ "name": "in_an_action_menu",
5916
+ "snapshot": "false",
5917
+ "skip_rules": {
5918
+ "wont_fix": [
5919
+ "region"
5920
+ ],
5921
+ "will_fix": [
5922
+ "color-contrast"
5923
+ ]
5924
+ }
5925
+ },
5913
5926
  {
5914
5927
  "preview_path": "primer/alpha/overlay/dialog_with_header_footer",
5915
5928
  "name": "dialog_with_header_footer",
data/static/previews.json CHANGED
@@ -4417,6 +4417,19 @@
4417
4417
  ]
4418
4418
  }
4419
4419
  },
4420
+ {
4421
+ "preview_path": "primer/alpha/overlay/in_an_action_menu",
4422
+ "name": "in_an_action_menu",
4423
+ "snapshot": "false",
4424
+ "skip_rules": {
4425
+ "wont_fix": [
4426
+ "region"
4427
+ ],
4428
+ "will_fix": [
4429
+ "color-contrast"
4430
+ ]
4431
+ }
4432
+ },
4420
4433
  {
4421
4434
  "preview_path": "primer/alpha/overlay/dialog_with_header_footer",
4422
4435
  "name": "dialog_with_header_footer",
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: primer_view_components
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub Open Source
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-28 00:00:00.000000000 Z
11
+ date: 2023-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionview
@@ -935,6 +935,7 @@ files:
935
935
  - lib/primer/view_components/linters/helpers/rule_helpers.rb
936
936
  - lib/primer/view_components/linters/label_component_migration_counter.rb
937
937
  - lib/primer/view_components/linters/migrate_deprecated_flash_arguments.rb
938
+ - lib/primer/view_components/linters/migrations/iconbutton_component.rb
938
939
  - lib/primer/view_components/linters/migrations/truncate_component.rb
939
940
  - lib/primer/view_components/linters/severity_schema.rb
940
941
  - lib/primer/view_components/linters/subhead_component_migration_counter.rb
@@ -1021,6 +1022,7 @@ files:
1021
1022
  - previews/primer/alpha/nav_list_preview.rb
1022
1023
  - previews/primer/alpha/nav_list_preview/trailing_action.html.erb
1023
1024
  - previews/primer/alpha/overlay_preview.rb
1025
+ - previews/primer/alpha/overlay_preview/in_an_action_menu.html.erb
1024
1026
  - previews/primer/alpha/overlay_preview/middle_of_page.html.erb
1025
1027
  - previews/primer/alpha/overlay_preview/middle_of_page_with_relative_container.html.erb
1026
1028
  - previews/primer/alpha/radio_button_group_preview.rb