openproject-primer_view_components 0.9.0 → 0.10.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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -1
  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/item.rb +3 -2
  8. data/app/components/primer/alpha/action_bar.rb +1 -5
  9. data/app/components/primer/alpha/overlay.css +1 -1
  10. data/app/components/primer/alpha/overlay.css.json +3 -1
  11. data/app/components/primer/alpha/overlay.css.map +1 -1
  12. data/app/components/primer/alpha/overlay.pcss +4 -0
  13. data/app/components/primer/alpha/tool_tip.js +28 -8
  14. data/app/components/primer/alpha/tool_tip.ts +27 -8
  15. data/app/components/primer/anchored_position.js +14 -5
  16. data/app/components/primer/anchored_position.ts +13 -4
  17. data/app/components/primer/beta/spinner.html.erb +1 -1
  18. data/app/components/primer/open_project/page_header.css +1 -1
  19. data/app/components/primer/open_project/page_header.css.json +1 -0
  20. data/app/components/primer/open_project/page_header.css.map +1 -1
  21. data/app/components/primer/open_project/page_header.pcss +6 -1
  22. data/app/components/primer/open_project/page_header.rb +13 -3
  23. data/lib/primer/view_components/linters/migrations/iconbutton_component.rb +36 -0
  24. data/lib/primer/view_components/version.rb +1 -1
  25. data/previews/primer/alpha/overlay_preview/in_an_action_menu.html.erb +13 -0
  26. data/previews/primer/alpha/overlay_preview.rb +5 -0
  27. data/previews/primer/open_project/page_header_preview.rb +13 -4
  28. data/static/arguments.json +11 -0
  29. data/static/audited_at.json +1 -0
  30. data/static/classes.json +3 -0
  31. data/static/constants.json +16 -0
  32. data/static/info_arch.json +129 -0
  33. data/static/previews.json +33 -7
  34. data/static/statuses.json +1 -0
  35. metadata +4 -2
@@ -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 %>
@@ -1 +1 @@
1
- .PageHeader{border-bottom:var(--borderWidth-thin,max(1px,.0625rem)) solid var(--borderColor-muted,var(--color-border-muted));display:flex;flex-flow:row wrap;justify-content:flex-end;margin-bottom:var(--stack-gap-normal,1rem);padding-bottom:var(--stack-padding-condensed,.5rem)}.PageHeader-title{flex:1 1 auto;order:0}.PageHeader-description{color:var(--fgColor-muted,var(--color-fg-muted));flex:1 100%;font-size:var(--text-body-size-medium,.875rem);order:2}.PageHeader-actions{align-self:center;justify-content:flex-end;margin:var(--base-size-4,.25rem) 0 var(--base-size-4,.25rem) var(--base-size-4,.25rem);order:1}.PageHeader-actions+.PageHeader-description{margin-top:var(--base-size-4,.25rem)}
1
+ .PageHeader{border-bottom:var(--borderWidth-thin,max(1px,.0625rem)) solid var(--borderColor-muted,var(--color-border-muted));display:flex;flex-flow:row wrap;justify-content:flex-end;margin-bottom:var(--stack-gap-normal,1rem);padding-bottom:var(--stack-padding-condensed,.5rem)}.PageHeader-title{flex:1 1 auto;font-size:24px;font-weight:var(--base-text-weight-normal,400);order:0}.PageHeader-title--large{font-size:var(--text-title-size-large,2rem)}.PageHeader-description{color:var(--fgColor-muted,var(--color-fg-muted));flex:1 100%;font-size:var(--text-body-size-medium,.875rem);order:2}.PageHeader-actions{align-self:center;justify-content:flex-end;margin:var(--base-size-4,.25rem) 0 var(--base-size-4,.25rem) var(--base-size-4,.25rem);order:1}.PageHeader-actions+.PageHeader-description{margin-top:var(--base-size-4,.25rem)}
@@ -3,6 +3,7 @@
3
3
  "selectors": [
4
4
  ".PageHeader",
5
5
  ".PageHeader-title",
6
+ ".PageHeader-title--large",
6
7
  ".PageHeader-description",
7
8
  ".PageHeader-actions",
8
9
  ".PageHeader-actions+.PageHeader-description"
@@ -1 +1 @@
1
- {"version":3,"sources":["page_header.pcss"],"names":[],"mappings":"AAEA,YAIE,gHAAqE,CAHrE,YAAa,CAIb,kBAAmB,CACnB,wBAAyB,CAHzB,0CAAsC,CADtC,mDAKF,CAGA,kBACE,aAAc,CACd,OACF,CAGA,wBAEE,gDAA2B,CAC3B,WAAY,CAFZ,8CAAuC,CAGvC,OACF,CAGA,oBAEE,iBAAkB,CAClB,wBAAyB,CAFzB,sFAAkE,CAGlE,OAKF,CAHE,4CACE,oCACF","file":"page_header.css","sourcesContent":["/* OP PageHeader */\n\n.PageHeader {\n display: flex;\n padding-bottom: var(--stack-padding-condensed);\n margin-bottom: var(--stack-gap-normal);\n border-bottom: var(--borderWidth-thin) solid var(--borderColor-muted);\n flex-flow: row wrap;\n justify-content: flex-end; /* Keep actions right aligned. */\n}\n\n/* <h2> sized heading with normal font weight */\n.PageHeader-title {\n flex: 1 1 auto;\n order: 0;\n}\n\n/* One-liner of supporting text */\n.PageHeader-description {\n font-size: var(--text-body-size-medium);\n color: var(--fgColor-muted);\n flex: 1 100%;\n order: 2;\n}\n\n/* Add 1 or 2 buttons to the right of the heading */\n.PageHeader-actions {\n margin: var(--base-size-4) 0 var(--base-size-4) var(--base-size-4);\n align-self: center;\n justify-content: flex-end;\n order: 1;\n\n & + .PageHeader-description {\n margin-top: var(--base-size-4);\n }\n}\n"]}
1
+ {"version":3,"sources":["page_header.pcss"],"names":[],"mappings":"AAEA,YAIE,gHAAqE,CAHrE,YAAa,CAIb,kBAAmB,CACnB,wBAAyB,CAHzB,0CAAsC,CADtC,mDAKF,CAEA,kBAGE,aAAc,CAFd,cAAe,CACf,8CAA2C,CAE3C,OACF,CAEA,yBACE,2CACF,CAGA,wBAEE,gDAA2B,CAC3B,WAAY,CAFZ,8CAAuC,CAGvC,OACF,CAGA,oBAEE,iBAAkB,CAClB,wBAAyB,CAFzB,sFAAkE,CAGlE,OAKF,CAHE,4CACE,oCACF","file":"page_header.css","sourcesContent":["/* OP PageHeader */\n\n.PageHeader {\n display: flex;\n padding-bottom: var(--stack-padding-condensed);\n margin-bottom: var(--stack-gap-normal);\n border-bottom: var(--borderWidth-thin) solid var(--borderColor-muted);\n flex-flow: row wrap;\n justify-content: flex-end; /* Keep actions right aligned. */\n}\n\n.PageHeader-title {\n font-size: 24px;\n font-weight: var(--base-text-weight-normal);\n flex: 1 1 auto;\n order: 0;\n}\n\n.PageHeader-title--large {\n font-size: var(--text-title-size-large);\n}\n\n/* One-liner of supporting text */\n.PageHeader-description {\n font-size: var(--text-body-size-medium);\n color: var(--fgColor-muted);\n flex: 1 100%;\n order: 2;\n}\n\n/* Add 1 or 2 buttons to the right of the heading */\n.PageHeader-actions {\n margin: var(--base-size-4) 0 var(--base-size-4) var(--base-size-4);\n align-self: center;\n justify-content: flex-end;\n order: 1;\n\n & + .PageHeader-description {\n margin-top: var(--base-size-4);\n }\n}\n"]}
@@ -9,12 +9,17 @@
9
9
  justify-content: flex-end; /* Keep actions right aligned. */
10
10
  }
11
11
 
12
- /* <h2> sized heading with normal font weight */
13
12
  .PageHeader-title {
13
+ font-size: 24px;
14
+ font-weight: var(--base-text-weight-normal);
14
15
  flex: 1 1 auto;
15
16
  order: 0;
16
17
  }
17
18
 
19
+ .PageHeader-title--large {
20
+ font-size: var(--text-title-size-large);
21
+ }
22
+
18
23
  /* One-liner of supporting text */
19
24
  .PageHeader-description {
20
25
  font-size: var(--text-body-size-medium);
@@ -5,7 +5,13 @@ module Primer
5
5
  # A ViewComponent PageHeader inspired by the primer react variant
6
6
  class PageHeader < Primer::Component
7
7
  HEADING_TAG_OPTIONS = [:h1, :h2, :h3, :h4, :h5, :h6].freeze
8
- HEADING_TAG_FALLBACK = :h1
8
+ HEADING_TAG_FALLBACK = :h2
9
+
10
+ DEFAULT_HEADER_VARIANT = :medium
11
+ HEADER_VARIANT_OPTIONS = [
12
+ :large,
13
+ DEFAULT_HEADER_VARIANT
14
+ ].freeze
9
15
 
10
16
  status :open_project
11
17
 
@@ -13,9 +19,13 @@ module Primer
13
19
  #
14
20
  # @param tag [Symbol] <%= one_of(Primer::Beta::Heading::TAG_OPTIONS) %>
15
21
  # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
16
- renders_one :title, lambda { |tag: :h1, **system_arguments|
22
+ renders_one :title, lambda { |tag: HEADING_TAG_FALLBACK, variant: DEFAULT_HEADER_VARIANT, **system_arguments|
17
23
  system_arguments[:tag] = fetch_or_fallback(HEADING_TAG_OPTIONS, tag, HEADING_TAG_FALLBACK)
18
- system_arguments[:classes] = class_names(system_arguments[:classes], "PageHeader-title")
24
+ system_arguments[:classes] = class_names(
25
+ system_arguments[:classes],
26
+ "PageHeader-title",
27
+ "PageHeader-title--#{variant}"
28
+ )
19
29
 
20
30
  Primer::BaseComponent.new(**system_arguments)
21
31
  }
@@ -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 = 9
8
+ MINOR = 10
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
@@ -14,12 +14,21 @@ module Primer
14
14
  end
15
15
  end
16
16
 
17
-
18
17
  # @label Playground
19
- #
20
- def playground
18
+ # @param variant [Symbol] select [medium, large]
19
+ # @param title [String] text
20
+ # @param description [String] text
21
+ def playground(variant: :medium, title: "Hello", description: "Last updated 5 minutes ago by XYZ.")
21
22
  render(Primer::OpenProject::PageHeader.new) do |header|
22
- header.with_title { "Hello" }
23
+ header.with_title(variant: variant) { title }
24
+ header.with_description { description }
25
+ end
26
+ end
27
+
28
+ # @label Large
29
+ def large_title
30
+ render(Primer::OpenProject::PageHeader.new) do |header|
31
+ header.with_title(variant: :large) { "Hello" }
23
32
  header.with_description { "Last updated 5 minutes ago by XYZ." }
24
33
  end
25
34
  end
@@ -4423,6 +4423,17 @@
4423
4423
  }
4424
4424
  ]
4425
4425
  },
4426
+ {
4427
+ "component": "OpenProject::PageHeader",
4428
+ "status": "open_project",
4429
+ "a11y_reviewed": false,
4430
+ "short_name": "OpenProjectPageHeader",
4431
+ "source": "https://github.com/primer/view_components/tree/main/app/components/primer/open_project/page_header.rb",
4432
+ "lookbook": "https://primer.style/view-components/lookbook/inspect/primer/open_project/page_header/default/",
4433
+ "parameters": [
4434
+
4435
+ ]
4436
+ },
4426
4437
  {
4427
4438
  "component": "Tooltip",
4428
4439
  "status": "deprecated",
@@ -102,6 +102,7 @@
102
102
  "Primer::IconButton": "",
103
103
  "Primer::LayoutComponent": "",
104
104
  "Primer::Navigation::TabComponent": "",
105
+ "Primer::OpenProject::PageHeader": "",
105
106
  "Primer::Tooltip": "",
106
107
  "Primer::Truncate": ""
107
108
  }
data/static/classes.json CHANGED
@@ -423,6 +423,9 @@
423
423
  "PageHeader-title": [
424
424
  "Primer::OpenProject::PageHeader"
425
425
  ],
426
+ "PageHeader-title--large": [
427
+ "Primer::OpenProject::PageHeader"
428
+ ],
426
429
  "Popover": [
427
430
  "Primer::Beta::Popover"
428
431
  ],
@@ -1300,6 +1300,22 @@
1300
1300
  },
1301
1301
  "Primer::Navigation::TabComponent": {
1302
1302
  },
1303
+ "Primer::OpenProject::PageHeader": {
1304
+ "DEFAULT_HEADER_VARIANT": "medium",
1305
+ "HEADER_VARIANT_OPTIONS": [
1306
+ "large",
1307
+ "medium"
1308
+ ],
1309
+ "HEADING_TAG_FALLBACK": "h2",
1310
+ "HEADING_TAG_OPTIONS": [
1311
+ "h1",
1312
+ "h2",
1313
+ "h3",
1314
+ "h4",
1315
+ "h5",
1316
+ "h6"
1317
+ ]
1318
+ },
1303
1319
  "Primer::Tooltip": {
1304
1320
  "ALIGN_DEFAULT": "default",
1305
1321
  "ALIGN_MAPPING": {