openproject-primer_view_components 0.9.1 → 0.11.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -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/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/border_grid/cell.html.erb +3 -0
  19. data/app/components/primer/open_project/border_grid/cell.rb +25 -0
  20. data/app/components/primer/open_project/border_grid.css +1 -0
  21. data/app/components/primer/open_project/border_grid.css.json +11 -0
  22. data/app/components/primer/open_project/border_grid.css.map +1 -0
  23. data/app/components/primer/open_project/border_grid.html.erb +7 -0
  24. data/app/components/primer/open_project/border_grid.pcss +35 -0
  25. data/app/components/primer/open_project/border_grid.rb +36 -0
  26. data/app/components/primer/open_project/drag_handle.css +1 -0
  27. data/app/components/primer/open_project/drag_handle.css.json +6 -0
  28. data/app/components/primer/open_project/drag_handle.css.map +1 -0
  29. data/app/components/primer/open_project/drag_handle.html.erb +6 -0
  30. data/app/components/primer/open_project/drag_handle.pcss +6 -0
  31. data/app/components/primer/open_project/drag_handle.rb +28 -0
  32. data/app/components/primer/primer.pcss +2 -0
  33. data/lib/primer/view_components/linters/migrations/iconbutton_component.rb +36 -0
  34. data/lib/primer/view_components/version.rb +2 -2
  35. data/previews/primer/alpha/overlay_preview/in_an_action_menu.html.erb +13 -0
  36. data/previews/primer/alpha/overlay_preview.rb +5 -0
  37. data/previews/primer/open_project/border_grid_preview.rb +42 -0
  38. data/previews/primer/open_project/drag_handle_preview.rb +23 -0
  39. data/static/arguments.json +54 -0
  40. data/static/audited_at.json +3 -0
  41. data/static/classes.json +15 -0
  42. data/static/constants.json +13 -0
  43. data/static/info_arch.json +195 -0
  44. data/static/previews.json +94 -0
  45. data/static/statuses.json +3 -0
  46. metadata +20 -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 %>
@@ -0,0 +1,3 @@
1
+ <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
+ <%= content %>
3
+ <% end %>
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module OpenProject
5
+ class BorderGrid
6
+ # A single cell inside the BorderGrid
7
+ # A cell can contain for example an action list or a status badge
8
+ class Cell < Primer::Component
9
+ status :open_project
10
+
11
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
12
+ def initialize(**system_arguments)
13
+ @system_arguments = system_arguments
14
+ @system_arguments[:tag] = "div"
15
+
16
+ @system_arguments[:classes] =
17
+ class_names(
18
+ @system_arguments[:classes],
19
+ "BorderGrid-cell"
20
+ )
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1 @@
1
+ .BorderGrid{border-collapse:collapse;border-style:hidden;display:table;margin-bottom:-16px;margin-top:-16px;table-layout:fixed;width:100%}.BorderGrid .BorderGrid-cell{padding-bottom:16px;padding-top:16px}.BorderGrid--spacious{margin-bottom:-24px;margin-top:-24px}.BorderGrid--spacious .BorderGrid-cell{padding-bottom:24px;padding-top:24px}.BorderGrid-row{display:table-row}.BorderGrid-cell{border:1px solid var(--borderColor-muted,var(--color-border-muted));display:table-cell}
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "open_project/border_grid",
3
+ "selectors": [
4
+ ".BorderGrid",
5
+ ".BorderGrid .BorderGrid-cell",
6
+ ".BorderGrid--spacious",
7
+ ".BorderGrid--spacious .BorderGrid-cell",
8
+ ".BorderGrid-row",
9
+ ".BorderGrid-cell"
10
+ ]
11
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["border_grid.pcss"],"names":[],"mappings":"AAEA,YAMI,wBAAyB,CACzB,mBAAmB,CANnB,aAAc,CAGd,mBAAoB,CADpB,gBAAiB,CAEjB,kBAAmB,CAHnB,UAMJ,CAEA,6BAEI,mBAAmB,CADnB,gBAEJ,CAEA,sBAEI,mBAAmB,CADnB,gBAEJ,CAEA,uCAEI,mBAAmB,CADnB,gBAEJ,CAEA,gBACI,iBACJ,CAEA,iBAEI,mEAAyC,CADzC,kBAEJ","file":"border_grid.css","sourcesContent":["/* CSS for BorderGrid */\n\n.BorderGrid {\n display: table;\n width: 100%;\n margin-top: -16px;\n margin-bottom: -16px;\n table-layout: fixed;\n border-collapse: collapse;\n border-style: hidden\n}\n\n.BorderGrid .BorderGrid-cell {\n padding-top: 16px;\n padding-bottom: 16px\n}\n\n.BorderGrid--spacious {\n margin-top: -24px;\n margin-bottom: -24px\n}\n\n.BorderGrid--spacious .BorderGrid-cell {\n padding-top: 24px;\n padding-bottom: 24px\n}\n\n.BorderGrid-row {\n display: table-row\n}\n\n.BorderGrid-cell {\n display: table-cell;\n border: 1px solid var(--borderColor-muted)\n}\n"]}
@@ -0,0 +1,7 @@
1
+ <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
+ <% rows.each do |row| %>
3
+ <%= render Primer::BaseComponent.new(tag: :div, classes: "BorderGrid-row") do %>
4
+ <%= row %>
5
+ <% end %>
6
+ <% end %>
7
+ <% end %>
@@ -0,0 +1,35 @@
1
+ /* CSS for BorderGrid */
2
+
3
+ .BorderGrid {
4
+ display: table;
5
+ width: 100%;
6
+ margin-top: -16px;
7
+ margin-bottom: -16px;
8
+ table-layout: fixed;
9
+ border-collapse: collapse;
10
+ border-style: hidden
11
+ }
12
+
13
+ .BorderGrid .BorderGrid-cell {
14
+ padding-top: 16px;
15
+ padding-bottom: 16px
16
+ }
17
+
18
+ .BorderGrid--spacious {
19
+ margin-top: -24px;
20
+ margin-bottom: -24px
21
+ }
22
+
23
+ .BorderGrid--spacious .BorderGrid-cell {
24
+ padding-top: 24px;
25
+ padding-bottom: 24px
26
+ }
27
+
28
+ .BorderGrid-row {
29
+ display: table-row
30
+ }
31
+
32
+ .BorderGrid-cell {
33
+ display: table-cell;
34
+ border: 1px solid var(--borderColor-muted)
35
+ }
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module OpenProject
5
+ # A set of blocks that are shown below each other with separator lines in between
6
+ class BorderGrid < Primer::Component
7
+ status :open_project
8
+
9
+ # Use to render a block inside the grid
10
+ #
11
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
12
+ renders_many :rows, lambda { |**system_arguments|
13
+ Primer::OpenProject::BorderGrid::Cell.new(**system_arguments)
14
+ }
15
+
16
+ # @param spacious [Boolean] Whether to add margin to the bottom of the component.
17
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
18
+ def initialize(spacious: false, **system_arguments)
19
+ @system_arguments = system_arguments
20
+ @system_arguments[:tag] = "div"
21
+ @spacious = spacious
22
+
23
+ @system_arguments[:classes] =
24
+ class_names(
25
+ @system_arguments[:classes],
26
+ "BorderGrid",
27
+ "BorderGrid--spacious" => @spacious
28
+ )
29
+ end
30
+
31
+ def render?
32
+ rows.any?
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1 @@
1
+ .DragHandle{color:var(--fgColor-muted,var(--color-fg-muted));cursor:move}
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "open_project/drag_handle",
3
+ "selectors": [
4
+ ".DragHandle"
5
+ ]
6
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["drag_handle.pcss"],"names":[],"mappings":"AAEA,YAEI,gDAA2B,CAD3B,WAEJ","file":"drag_handle.css","sourcesContent":["/* CSS for DragHandle */\n\n.DragHandle {\n cursor: move;\n color: var(--fgColor-muted);\n}\n"]}
@@ -0,0 +1,6 @@
1
+ <%= render Primer::BaseComponent.new(**@system_arguments) do %>
2
+ <%= render(Primer::Beta::Octicon.new(
3
+ icon: :grabber,
4
+ size: @size
5
+ )) %>
6
+ <% end %>
@@ -0,0 +1,6 @@
1
+ /* CSS for DragHandle */
2
+
3
+ .DragHandle {
4
+ cursor: move;
5
+ color: var(--fgColor-muted);
6
+ }
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Primer
4
+ module OpenProject
5
+ # Add a general description of component here
6
+ # Add additional usage considerations or best practices that may aid the user to use the component correctly.
7
+ # @accessibility Add any accessibility considerations
8
+ class DragHandle < Primer::Component
9
+ status :open_project
10
+
11
+ DEFAULT_SIZE = Primer::Beta::Octicon::SIZE_DEFAULT
12
+ SIZE_OPTIONS = Primer::Beta::Octicon::SIZE_OPTIONS
13
+
14
+ # @param system_arguments [Hash] <%= link_to_system_arguments_docs %>
15
+ def initialize(size: Primer::OpenProject::DragHandle::DEFAULT_SIZE, **system_arguments)
16
+ @system_arguments = system_arguments
17
+ @system_arguments[:tag] = "div"
18
+ @system_arguments[:classes] =
19
+ class_names(
20
+ @system_arguments[:classes],
21
+ "DragHandle"
22
+ )
23
+
24
+ @size = fetch_or_fallback(Primer::OpenProject::DragHandle::SIZE_OPTIONS, size, Primer::OpenProject::DragHandle::DEFAULT_SIZE)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -43,3 +43,5 @@
43
43
 
44
44
  /* OP specifics */
45
45
  @import "./open_project/page_header.pcss";
46
+ @import "./open_project/drag_handle.pcss";
47
+ @import "./open_project/border_grid.pcss";
@@ -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,8 +5,8 @@ module Primer
5
5
  module ViewComponents
6
6
  module VERSION
7
7
  MAJOR = 0
8
- MINOR = 9
9
- PATCH = 1
8
+ MINOR = 11
9
+ PATCH = 0
10
10
 
11
11
  STRING = [MAJOR, MINOR, PATCH].join(".")
12
12
  end
@@ -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
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Setup Playground to use all available component props
4
+ # Setup Features to use individual component props and combinations
5
+
6
+ module Primer
7
+ module OpenProject
8
+ # @label BorderGrid
9
+ class BorderGridPreview < ViewComponent::Preview
10
+
11
+ # @label Playground
12
+ # @param spacious [Boolean] toggle
13
+ def playground(spacious: false)
14
+ render(Primer::OpenProject::BorderGrid.new(spacious: spacious)) do |grid|
15
+ grid.with_row { "Block 1" }
16
+ grid.with_row { "Block 2" }
17
+ grid.with_row { "Block 3" }
18
+ end
19
+ end
20
+
21
+ # @label Default Options
22
+ #
23
+ # @snapshot
24
+ def default()
25
+ render(Primer::OpenProject::BorderGrid.new) do |grid|
26
+ grid.with_row { "Block 1" }
27
+ grid.with_row { "Block 2" }
28
+ grid.with_row { "Block 3" }
29
+ end
30
+ end
31
+
32
+ # @label Spacious
33
+ def spacious()
34
+ render(Primer::OpenProject::BorderGrid.new(spacious: true)) do |grid|
35
+ grid.with_row { "Block 1" }
36
+ grid.with_row { "Block 2" }
37
+ grid.with_row { "Block 3" }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Setup Playground to use all available component props
4
+ # Setup Features to use individual component props and combinations
5
+
6
+ module Primer
7
+ module OpenProject
8
+ # @label DragHandle
9
+ class DragHandlePreview < ViewComponent::Preview
10
+ # @label Default
11
+ # @snapshot
12
+ def default(size: :small)
13
+ render(Primer::OpenProject::DragHandle.new(size: size))
14
+ end
15
+
16
+ # @label Playground
17
+ # @param size [Symbol] select [xsmall, small, medium]
18
+ def playground(size: :small)
19
+ render(Primer::OpenProject::DragHandle.new(size: size))
20
+ end
21
+ end
22
+ end
23
+ end