@fluentui-react-native/callout 0.19.30 → 0.19.33

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.
package/CHANGELOG.json CHANGED
@@ -2,7 +2,64 @@
2
2
  "name": "@fluentui-react-native/callout",
3
3
  "entries": [
4
4
  {
5
- "date": "Fri, 04 Mar 2022 23:41:59 GMT",
5
+ "date": "Fri, 18 Mar 2022 07:18:53 GMT",
6
+ "tag": "@fluentui-react-native/callout_v0.19.33",
7
+ "version": "0.19.33",
8
+ "comments": {
9
+ "patch": [
10
+ {
11
+ "author": "sanajmi@microsoft.com",
12
+ "package": "@fluentui-react-native/callout",
13
+ "commit": "be918e28dc086179801a25f9e664ceedbb81e85c",
14
+ "comment": "ContextualMenu macOS: Improve lifecycle management"
15
+ }
16
+ ]
17
+ }
18
+ },
19
+ {
20
+ "date": "Fri, 11 Mar 2022 00:34:53 GMT",
21
+ "tag": "@fluentui-react-native/callout_v0.19.32",
22
+ "version": "0.19.32",
23
+ "comments": {
24
+ "patch": [
25
+ {
26
+ "author": "sanajmi@microsoft.com",
27
+ "package": "@fluentui-react-native/callout",
28
+ "commit": "489339a0f6ebd9a4687c1c84e9bf8d274d8806d5",
29
+ "comment": "ContextualMenu macOS: Focus on menu rather than first menu item"
30
+ }
31
+ ]
32
+ }
33
+ },
34
+ {
35
+ "date": "Mon, 07 Mar 2022 19:15:33 GMT",
36
+ "tag": "@fluentui-react-native/callout_v0.19.31",
37
+ "version": "0.19.31",
38
+ "comments": {
39
+ "patch": [
40
+ {
41
+ "author": "beachball",
42
+ "package": "@fluentui-react-native/callout",
43
+ "comment": "Bump @fluentui-react-native/adapters to v0.8.4",
44
+ "commit": "d437b204aa63de4c9d4dd2f58ccf541c388ddaee"
45
+ },
46
+ {
47
+ "author": "beachball",
48
+ "package": "@fluentui-react-native/callout",
49
+ "comment": "Bump @fluentui-react-native/interactive-hooks to v0.14.3",
50
+ "commit": "d437b204aa63de4c9d4dd2f58ccf541c388ddaee"
51
+ },
52
+ {
53
+ "author": "beachball",
54
+ "package": "@fluentui-react-native/callout",
55
+ "comment": "Bump @fluentui-react-native/tokens to v0.11.8",
56
+ "commit": "d437b204aa63de4c9d4dd2f58ccf541c388ddaee"
57
+ }
58
+ ]
59
+ }
60
+ },
61
+ {
62
+ "date": "Fri, 04 Mar 2022 23:43:10 GMT",
6
63
  "tag": "@fluentui-react-native/callout_v0.19.30",
7
64
  "version": "0.19.30",
8
65
  "comments": {
package/CHANGELOG.md CHANGED
@@ -1,12 +1,38 @@
1
1
  # Change Log - @fluentui-react-native/callout
2
2
 
3
- This log was last generated on Fri, 04 Mar 2022 23:41:59 GMT and should not be manually modified.
3
+ This log was last generated on Fri, 18 Mar 2022 07:18:53 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## 0.19.33
8
+
9
+ Fri, 18 Mar 2022 07:18:53 GMT
10
+
11
+ ### Patches
12
+
13
+ - ContextualMenu macOS: Improve lifecycle management (sanajmi@microsoft.com)
14
+
15
+ ## 0.19.32
16
+
17
+ Fri, 11 Mar 2022 00:34:53 GMT
18
+
19
+ ### Patches
20
+
21
+ - ContextualMenu macOS: Focus on menu rather than first menu item (sanajmi@microsoft.com)
22
+
23
+ ## 0.19.31
24
+
25
+ Mon, 07 Mar 2022 19:15:33 GMT
26
+
27
+ ### Patches
28
+
29
+ - Bump @fluentui-react-native/adapters to v0.8.4
30
+ - Bump @fluentui-react-native/interactive-hooks to v0.14.3
31
+ - Bump @fluentui-react-native/tokens to v0.11.8
32
+
7
33
  ## 0.19.30
8
34
 
9
- Fri, 04 Mar 2022 23:41:59 GMT
35
+ Fri, 04 Mar 2022 23:43:10 GMT
10
36
 
11
37
  ### Patches
12
38
 
@@ -26,9 +26,9 @@ class CalloutView: RCTView, CalloutWindowLifeCycleDelegate {
26
26
  }
27
27
  }
28
28
 
29
- @objc public var onShow: RCTBubblingEventBlock?
29
+ @objc public var onShow: RCTDirectEventBlock?
30
30
 
31
- @objc public var onDismiss: RCTBubblingEventBlock?
31
+ @objc public var onDismiss: RCTDirectEventBlock?
32
32
 
33
33
  public weak var bridge: RCTBridge?
34
34
 
@@ -79,14 +79,68 @@ class CalloutView: RCTView, CalloutWindowLifeCycleDelegate {
79
79
  // MARK: Private methods
80
80
 
81
81
  private func showCallout() {
82
+ guard !isCalloutWindowShown else {
83
+ return
84
+ }
85
+
82
86
  updateCalloutFrameToAnchor()
83
87
  calloutWindow.makeKeyAndOrderFront(self)
88
+
89
+ // Dismiss the Callout if the window is no longer active.
90
+ NotificationCenter.default.addObserver(self, selector: #selector(dismissCallout), name: NSApplication.didResignActiveNotification, object: nil)
91
+
92
+ mouseEventMonitor.addLocalMonitorForEvents(matching: .leftMouseUp, handler: { [weak self] (event) -> NSEvent? in
93
+ guard let clickedWindow = event.window else {
94
+ return event
95
+ }
96
+
97
+ var shouldDismissCallout = true
98
+
99
+ // Did the click happened in our own window?
100
+ if (clickedWindow.isEqual(to: self) ) {
101
+ shouldDismissCallout = false
102
+
103
+ // Are we a child window of a Callout (e.g: a ContextualMenu submenu), where the click happened in our parent?
104
+ } else if (clickedWindow.isEqual(to: self?.calloutWindow.parent as? CalloutWindow)) {
105
+ shouldDismissCallout = false
106
+
107
+ // Did the click happened in any of our child windows (e.g: our submenus)?
108
+ } else if (self?.calloutWindow.childWindows?.contains(clickedWindow) ?? false) {
109
+ shouldDismissCallout = false
110
+ }
111
+
112
+ if (shouldDismissCallout) {
113
+ self?.dismissCallout()
114
+ }
115
+
116
+ return event
117
+ })
118
+
119
+ isCalloutWindowShown = true
120
+
84
121
  onShowCallout()
85
122
  }
86
123
 
87
- private func dismissCallout() {
88
- calloutWindow.close()
89
- onDismissCallout()
124
+ @objc private func dismissCallout() {
125
+ guard isCalloutWindowShown else {
126
+ return
127
+ }
128
+
129
+ // Dismiss any children Callouts (I.E: Submenus) first
130
+ if let childWindows = calloutWindow.childWindows {
131
+ for childWindow in childWindows {
132
+ if let childCallout = childWindow as? CalloutWindow {
133
+ childCallout.dismissCallout()
134
+ }
135
+ }
136
+ }
137
+
138
+ calloutWindow.dismissCallout()
139
+
140
+ NotificationCenter.default.removeObserver(self)
141
+ mouseEventMonitor.removeMonitor()
142
+
143
+ isCalloutWindowShown = false
90
144
  }
91
145
 
92
146
  /// Sets the frame of the Callout Window (in screen coordinates to be off of the Anchor on the preferred edge
@@ -307,18 +361,14 @@ class CalloutView: RCTView, CalloutWindowLifeCycleDelegate {
307
361
  if let parentWindow = self.window {
308
362
  parentWindow.addChildWindow(window, ordered: .above)
309
363
  }
310
-
311
364
  return window
312
365
  }()
366
+
367
+ private var mouseEventMonitor = GuardedEventMonitor()
368
+
369
+ private var isCalloutWindowShown = false
313
370
  }
314
371
 
315
- /// React Native macOS uses a flipped coordinate space by default. Let's stay consistent and
316
- /// ensure any views hosting React Native views are also flipped. This helps RCTTouchHandler
317
- /// register clicks in the right location.
318
- private class FlippedVisualEffectView: NSVisualEffectView {
319
- override var isFlipped: Bool {
320
- return true
321
- }
322
- }
372
+
323
373
 
324
374
  private var calloutWindowCornerRadius: CGFloat = 5.0
@@ -7,48 +7,15 @@ protocol CalloutWindowLifeCycleDelegate: AnyObject {
7
7
  }
8
8
 
9
9
  class CalloutWindow: NSWindow {
10
-
11
10
  weak var lifeCycleDelegate: CalloutWindowLifeCycleDelegate?
12
11
 
13
12
  override init(contentRect: NSRect, styleMask style: NSWindow.StyleMask, backing backingStoreType: NSWindow.BackingStoreType, defer flag: Bool) {
14
13
  super.init(contentRect: contentRect, styleMask: style, backing: backingStoreType, defer: flag)
15
- isReleasedWhenClosed = false
16
14
 
17
15
  styleMask = .borderless
18
16
  level = .popUpMenu
19
17
  backgroundColor = .clear
20
18
  isMovable = false
21
-
22
- // Dismiss the Callout if the window is no longer active.
23
- NotificationCenter.default.addObserver(self, selector: #selector(dismissCallout), name: NSApplication.didResignActiveNotification, object: nil)
24
-
25
- // Dismiss the Callout if the user clicked outside the Callout Window or any of our child windows.
26
- mouseEventMonitor = NSEvent.addLocalMonitorForEvents(matching: .leftMouseUp, handler: { [weak self] (event) -> NSEvent? in
27
- guard let clickedWindow = event.window else {
28
- return event
29
- }
30
-
31
- var shouldDismissCallout = true
32
-
33
- // Did the click happened in our own window?
34
- if (clickedWindow.isEqual(to: self) ) {
35
- shouldDismissCallout = false
36
-
37
- // Are we a child window of a Callout (e.g: a ContextualMenu submenu), where the click happened in our parent?
38
- } else if (clickedWindow.isEqual(to: self?.parent as? CalloutWindow)) {
39
- shouldDismissCallout = false
40
-
41
- // Did the click happened in any of our child windows (e.g: our submenus)?
42
- } else if (self?.childWindows?.contains(clickedWindow) ?? false) {
43
- shouldDismissCallout = false
44
- }
45
-
46
- if (shouldDismissCallout) {
47
- self?.dismissCallout()
48
- }
49
-
50
- return event
51
- })
52
19
  }
53
20
 
54
21
  // Required to get a key view loop in the window
@@ -65,15 +32,9 @@ class CalloutWindow: NSWindow {
65
32
  dismissCallout()
66
33
  }
67
34
 
68
- @objc private func dismissCallout() {
35
+ @objc public func dismissCallout() {
69
36
  lifeCycleDelegate?.calloutWillDismiss(window: self)
70
-
71
- if let monitor = mouseEventMonitor {
72
- NSEvent.removeMonitor(monitor)
73
- }
74
-
75
37
  orderOut(self)
76
38
  }
77
-
78
- private var mouseEventMonitor: Any?
79
39
  }
40
+
@@ -42,8 +42,8 @@ RCT_EXPORT_VIEW_PROPERTY(anchorRect, screenRect)
42
42
 
43
43
  RCT_EXPORT_VIEW_PROPERTY(directionalHint, NSRectEdge)
44
44
 
45
- RCT_EXPORT_VIEW_PROPERTY(onShow, RCTBubblingEventBlock)
45
+ RCT_EXPORT_VIEW_PROPERTY(onShow, RCTDirectEventBlock)
46
46
 
47
- RCT_EXPORT_VIEW_PROPERTY(onDismiss, RCTBubblingEventBlock)
47
+ RCT_EXPORT_VIEW_PROPERTY(onDismiss, RCTDirectEventBlock)
48
48
 
49
49
  @end
@@ -0,0 +1,8 @@
1
+ /// React Native macOS uses a flipped coordinate space by default. Let's stay consistent and
2
+ /// ensure any views hosting React Native views are also flipped. This helps RCTTouchHandler
3
+ /// register clicks in the right location.
4
+ internal class FlippedVisualEffectView: NSVisualEffectView {
5
+ override var isFlipped: Bool {
6
+ return true
7
+ }
8
+ }
@@ -0,0 +1,30 @@
1
+
2
+
3
+ /// NSEvent localMonitors are an _old_ API that requires you to do some memory management yourself.
4
+ /// You _must_ call `removeMonitor`exactly once per monitor created from. This helper class enforces
5
+ /// that with the use of an extra boolean to track whether we have already allocated/released our monitor.
6
+ /// https://developer.apple.com/documentation/appkit/nsevent/1533709-removemonitor
7
+ internal class GuardedEventMonitor: Any {
8
+
9
+ private var isMonitorAllocated = false
10
+ private var allocatedMonitor: Any?
11
+
12
+
13
+ func addLocalMonitorForEvents(matching mask: NSEvent.EventTypeMask, handler block: @escaping (NSEvent) -> NSEvent?) {
14
+ if (!isMonitorAllocated) {
15
+ allocatedMonitor = NSEvent.addLocalMonitorForEvents(matching: mask, handler: block)
16
+ isMonitorAllocated = true
17
+ }
18
+ }
19
+
20
+ func removeMonitor() {
21
+ if (isMonitorAllocated) {
22
+ NSEvent.removeMonitor(allocatedMonitor as Any)
23
+ isMonitorAllocated = false
24
+ }
25
+ }
26
+
27
+ deinit {
28
+ removeMonitor()
29
+ }
30
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluentui-react-native/callout",
3
- "version": "0.19.30",
3
+ "version": "0.19.33",
4
4
  "description": "A cross-platform Callout component using the Fluent Design System",
5
5
  "license": "MIT",
6
6
  "author": "",
@@ -25,10 +25,10 @@
25
25
  "directory": "packages/components/Callout"
26
26
  },
27
27
  "dependencies": {
28
- "@fluentui-react-native/adapters": "^0.8.3",
28
+ "@fluentui-react-native/adapters": "^0.8.4",
29
29
  "@fluentui-react-native/component-cache": "^1.3.1",
30
- "@fluentui-react-native/interactive-hooks": ">=0.14.2 <1.0.0",
31
- "@fluentui-react-native/tokens": ">=0.11.7 <1.0.0",
30
+ "@fluentui-react-native/interactive-hooks": ">=0.14.3 <1.0.0",
31
+ "@fluentui-react-native/tokens": ">=0.11.8 <1.0.0",
32
32
  "@uifabricshared/foundation-composable": ">=0.10.2 <1.0.0",
33
33
  "@uifabricshared/foundation-compose": "^1.11.11",
34
34
  "@uifabricshared/foundation-settings": ">=0.11.2 <1.0.0"