openproject-primer_view_components 0.22.0 → 0.22.1

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.
@@ -18,7 +18,6 @@ function dialogInvokerButtonHandler(event) {
18
18
  // If the user is clicking a valid dialog trigger
19
19
  let dialogId = button === null || button === void 0 ? void 0 : button.getAttribute('data-show-dialog-id');
20
20
  if (dialogId) {
21
- event.stopPropagation();
22
21
  const dialog = document.getElementById(dialogId);
23
22
  if (dialog instanceof HTMLDialogElement) {
24
23
  dialog.showModal();
@@ -26,7 +25,6 @@ function dialogInvokerButtonHandler(event) {
26
25
  // If the behaviour is allowed through the dialog will be shown but then
27
26
  // quickly hidden- as if it were never shown. This prevents that.
28
27
  event.preventDefault();
29
- event.stopPropagation();
30
28
  }
31
29
  }
32
30
  dialogId = button.getAttribute('data-close-dialog-id') || button.getAttribute('data-submit-dialog-id');
@@ -54,6 +52,21 @@ export class DialogHelperElement extends HTMLElement {
54
52
  for (const record of records) {
55
53
  if (record.target === this.dialog) {
56
54
  this.ownerDocument.body.classList.toggle('has-modal', this.dialog.hasAttribute('open'));
55
+ // In some older browsers, such as Chrome 122, when a top layer element (such as a dialog)
56
+ // opens from within a popover, the "hide all popovers" internal algorithm runs, hiding
57
+ // any popover that is currently open, regardless of whether or not another top layer element,
58
+ // such as a <dialog> is nested inside.
59
+ // See https://github.com/whatwg/html/issues/9998.
60
+ // This is fixed by https://github.com/whatwg/html/pull/10116, but while we still support browsers that present this bug,
61
+ // we must undo the work they did to hide ancestral popovers of the dialog:
62
+ if (this.dialog.hasAttribute('open')) {
63
+ let node = this.dialog;
64
+ while (node) {
65
+ node = node.closest('[popover]:not(:popover-open)');
66
+ if (node)
67
+ node.showPopover();
68
+ }
69
+ }
57
70
  }
58
71
  }
59
72
  }).observe(this, { subtree: true, attributeFilter: ['open'] });
@@ -65,11 +78,8 @@ export class DialogHelperElement extends HTMLElement {
65
78
  handleEvent(event) {
66
79
  const target = event.target;
67
80
  const dialog = this.dialog;
68
- if (!(dialog === null || dialog === void 0 ? void 0 : dialog.open))
69
- return;
70
- // if the target is inside the dialog, but is not the dialog itself, leave
71
- // the dialog open
72
- if ((target === null || target === void 0 ? void 0 : target.closest('dialog')) === dialog && target !== dialog)
81
+ // The click target _must_ be the dialog element itself, and not elements underneath or inside.
82
+ if (target !== dialog || !(dialog === null || dialog === void 0 ? void 0 : dialog.open))
73
83
  return;
74
84
  const rect = dialog.getBoundingClientRect();
75
85
  const clickWasInsideDialog = rect.top <= event.clientY &&
@@ -7,7 +7,6 @@ function dialogInvokerButtonHandler(event: Event) {
7
7
  // If the user is clicking a valid dialog trigger
8
8
  let dialogId = button?.getAttribute('data-show-dialog-id')
9
9
  if (dialogId) {
10
- event.stopPropagation()
11
10
  const dialog = document.getElementById(dialogId)
12
11
  if (dialog instanceof HTMLDialogElement) {
13
12
  dialog.showModal()
@@ -15,7 +14,6 @@ function dialogInvokerButtonHandler(event: Event) {
15
14
  // If the behaviour is allowed through the dialog will be shown but then
16
15
  // quickly hidden- as if it were never shown. This prevents that.
17
16
  event.preventDefault()
18
- event.stopPropagation()
19
17
  }
20
18
  }
21
19
 
@@ -46,6 +44,20 @@ export class DialogHelperElement extends HTMLElement {
46
44
  for (const record of records) {
47
45
  if (record.target === this.dialog) {
48
46
  this.ownerDocument.body.classList.toggle('has-modal', this.dialog.hasAttribute('open'))
47
+ // In some older browsers, such as Chrome 122, when a top layer element (such as a dialog)
48
+ // opens from within a popover, the "hide all popovers" internal algorithm runs, hiding
49
+ // any popover that is currently open, regardless of whether or not another top layer element,
50
+ // such as a <dialog> is nested inside.
51
+ // See https://github.com/whatwg/html/issues/9998.
52
+ // This is fixed by https://github.com/whatwg/html/pull/10116, but while we still support browsers that present this bug,
53
+ // we must undo the work they did to hide ancestral popovers of the dialog:
54
+ if (this.dialog.hasAttribute('open')) {
55
+ let node: HTMLElement | null = this.dialog
56
+ while (node) {
57
+ node = node.closest('[popover]:not(:popover-open)')
58
+ if (node) node.showPopover()
59
+ }
60
+ }
49
61
  }
50
62
  }
51
63
  }).observe(this, {subtree: true, attributeFilter: ['open']})
@@ -58,11 +70,8 @@ export class DialogHelperElement extends HTMLElement {
58
70
  handleEvent(event: MouseEvent) {
59
71
  const target = event.target as HTMLElement
60
72
  const dialog = this.dialog
61
- if (!dialog?.open) return
62
-
63
- // if the target is inside the dialog, but is not the dialog itself, leave
64
- // the dialog open
65
- if (target?.closest('dialog') === dialog && target !== dialog) return
73
+ // The click target _must_ be the dialog element itself, and not elements underneath or inside.
74
+ if (target !== dialog || !dialog?.open) return
66
75
 
67
76
  const rect = dialog.getBoundingClientRect()
68
77
  const clickWasInsideDialog =
@@ -6,7 +6,7 @@ module Primer
6
6
  module VERSION
7
7
  MAJOR = 0
8
8
  MINOR = 22
9
- PATCH = 0
9
+ PATCH = 1
10
10
 
11
11
  STRING = [MAJOR, MINOR, PATCH].join(".")
12
12
  end
@@ -0,0 +1,9 @@
1
+ <%= render(Primer::Alpha::Overlay.new(title: "An overlay")) do |o| %>
2
+ <% o.with_show_button() { "Show overlay" } %>
3
+ <% o.with_body() do %>
4
+ <%= render(Primer::Alpha::Dialog.new(id: "dialog-one", title: title, position: position, subtitle: subtitle, visually_hide_title: false)) do |d| %>
5
+ <% d.with_show_button { button_text } %>
6
+ <% d.with_body { body_text} %>
7
+ <% end %>
8
+ <% end %>
9
+ <% end %>
@@ -12,3 +12,10 @@
12
12
  <% end %>
13
13
  <% end %>
14
14
  <% end %>
15
+
16
+ <div style="margin-top:2rem">
17
+ <%= render(Primer::Beta::Flash.new(scheme: :warning)) do %>
18
+ <p>Please be careful nesting dialogs! Note that in this example, opening the second dialog does not close the first.</p>
19
+ <p>Closing a dialog while opening a dialog inside, will cause both to be invisible which will lead to undesired effects!</p>
20
+ <% end %>
21
+ </div>
@@ -248,6 +248,29 @@ module Primer
248
248
  visually_hide_title: visually_hide_title
249
249
  })
250
250
  end
251
+
252
+ # @label Dialog inside Overlay
253
+ #
254
+ # @param title [String] text
255
+ # @param subtitle [String] text
256
+ # @param size [Symbol] select [small, medium, medium_portrait, large, xlarge]
257
+ # @param position [Symbol] select [center, right, left]
258
+ # @param position_narrow [Symbol] select [inherit, bottom, fullscreen, left, right]
259
+ # @param visually_hide_title [Boolean] toggle
260
+ # @param button_text [String] text
261
+ # @param body_text [String] text
262
+ def dialog_inside_overlay(title: "Test Dialog", subtitle: nil, position: :center, size: :medium, button_text: "Show Dialog", body_text: "Content", position_narrow: :fullscreen, visually_hide_title: false)
263
+ render_with_template(locals: {
264
+ title: title,
265
+ subtitle: subtitle,
266
+ position: position,
267
+ size: size,
268
+ button_text: button_text,
269
+ body_text: body_text,
270
+ position_narrow: position_narrow,
271
+ visually_hide_title: visually_hide_title
272
+ })
273
+ end
251
274
  end
252
275
  end
253
276
  end
@@ -3375,6 +3375,19 @@
3375
3375
  "color-contrast"
3376
3376
  ]
3377
3377
  }
3378
+ },
3379
+ {
3380
+ "preview_path": "primer/alpha/dialog/dialog_inside_overlay",
3381
+ "name": "dialog_inside_overlay",
3382
+ "snapshot": "false",
3383
+ "skip_rules": {
3384
+ "wont_fix": [
3385
+ "region"
3386
+ ],
3387
+ "will_fix": [
3388
+ "color-contrast"
3389
+ ]
3390
+ }
3378
3391
  }
3379
3392
  ],
3380
3393
  "subcomponents": [
data/static/previews.json CHANGED
@@ -3186,6 +3186,19 @@
3186
3186
  "color-contrast"
3187
3187
  ]
3188
3188
  }
3189
+ },
3190
+ {
3191
+ "preview_path": "primer/alpha/dialog/dialog_inside_overlay",
3192
+ "name": "dialog_inside_overlay",
3193
+ "snapshot": "false",
3194
+ "skip_rules": {
3195
+ "wont_fix": [
3196
+ "region"
3197
+ ],
3198
+ "will_fix": [
3199
+ "color-contrast"
3200
+ ]
3201
+ }
3189
3202
  }
3190
3203
  ]
3191
3204
  },
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openproject-primer_view_components
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.22.0
4
+ version: 0.22.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub Open Source
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-02-01 00:00:00.000000000 Z
12
+ date: 2024-02-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionview
@@ -760,6 +760,7 @@ files:
760
760
  - previews/primer/alpha/dialog_preview/autofocus_element.html.erb
761
761
  - previews/primer/alpha/dialog_preview/body_has_scrollbar_overflow.html.erb
762
762
  - previews/primer/alpha/dialog_preview/custom_header.html.erb
763
+ - previews/primer/alpha/dialog_preview/dialog_inside_overlay.html.erb
763
764
  - previews/primer/alpha/dialog_preview/nested_dialog.html.erb
764
765
  - previews/primer/alpha/dialog_preview/scroll_container.html.erb
765
766
  - previews/primer/alpha/dialog_preview/test.html.erb