@fluentui-react-native/callout 0.19.32 → 0.19.35

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,58 @@
2
2
  "name": "@fluentui-react-native/callout",
3
3
  "entries": [
4
4
  {
5
- "date": "Fri, 11 Mar 2022 00:34:24 GMT",
5
+ "date": "Wed, 23 Mar 2022 17:22:10 GMT",
6
+ "tag": "@fluentui-react-native/callout_v0.19.35",
7
+ "version": "0.19.35",
8
+ "comments": {
9
+ "patch": [
10
+ {
11
+ "author": "beachball",
12
+ "package": "@fluentui-react-native/callout",
13
+ "comment": "Bump @fluentui-react-native/interactive-hooks to v0.14.4",
14
+ "commit": "f9260dc63f46f9b1fe54f6b2ab4babbfccc0c8b0"
15
+ },
16
+ {
17
+ "author": "beachball",
18
+ "package": "@fluentui-react-native/callout",
19
+ "comment": "Bump @uifabricshared/foundation-compose to v1.11.12",
20
+ "commit": "f9260dc63f46f9b1fe54f6b2ab4babbfccc0c8b0"
21
+ }
22
+ ]
23
+ }
24
+ },
25
+ {
26
+ "date": "Mon, 21 Mar 2022 01:47:54 GMT",
27
+ "tag": "@fluentui-react-native/callout_v0.19.34",
28
+ "version": "0.19.34",
29
+ "comments": {
30
+ "patch": [
31
+ {
32
+ "author": "sanajmi@microsoft.com",
33
+ "package": "@fluentui-react-native/callout",
34
+ "commit": "b772dfe4542b7032f216bf5c2faa807c695fa2a7",
35
+ "comment": "width -> maxWidth"
36
+ }
37
+ ]
38
+ }
39
+ },
40
+ {
41
+ "date": "Fri, 18 Mar 2022 07:19:17 GMT",
42
+ "tag": "@fluentui-react-native/callout_v0.19.33",
43
+ "version": "0.19.33",
44
+ "comments": {
45
+ "patch": [
46
+ {
47
+ "author": "sanajmi@microsoft.com",
48
+ "package": "@fluentui-react-native/callout",
49
+ "commit": "be918e28dc086179801a25f9e664ceedbb81e85c",
50
+ "comment": "ContextualMenu macOS: Improve lifecycle management"
51
+ }
52
+ ]
53
+ }
54
+ },
55
+ {
56
+ "date": "Fri, 11 Mar 2022 00:34:53 GMT",
6
57
  "tag": "@fluentui-react-native/callout_v0.19.32",
7
58
  "version": "0.19.32",
8
59
  "comments": {
package/CHANGELOG.md CHANGED
@@ -1,12 +1,37 @@
1
1
  # Change Log - @fluentui-react-native/callout
2
2
 
3
- This log was last generated on Fri, 11 Mar 2022 00:34:24 GMT and should not be manually modified.
3
+ This log was last generated on Wed, 23 Mar 2022 17:22:10 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## 0.19.35
8
+
9
+ Wed, 23 Mar 2022 17:22:10 GMT
10
+
11
+ ### Patches
12
+
13
+ - Bump @fluentui-react-native/interactive-hooks to v0.14.4
14
+ - Bump @uifabricshared/foundation-compose to v1.11.12
15
+
16
+ ## 0.19.34
17
+
18
+ Mon, 21 Mar 2022 01:47:54 GMT
19
+
20
+ ### Patches
21
+
22
+ - width -> maxWidth (sanajmi@microsoft.com)
23
+
24
+ ## 0.19.33
25
+
26
+ Fri, 18 Mar 2022 07:19:17 GMT
27
+
28
+ ### Patches
29
+
30
+ - ContextualMenu macOS: Improve lifecycle management (sanajmi@microsoft.com)
31
+
7
32
  ## 0.19.32
8
33
 
9
- Fri, 11 Mar 2022 00:34:24 GMT
34
+ Fri, 11 Mar 2022 00:34:53 GMT
10
35
 
11
36
  ### Patches
12
37
 
@@ -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,76 @@ 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: .leftMouseDown, handler: { [weak self] (event) -> NSEvent? in
93
+ func isClickInsideWindowHierarchy(window: NSWindow?, event: NSEvent) -> Bool {
94
+ guard let window = window else {
95
+ return false
96
+ }
97
+ guard let clickedWindow = event.window else {
98
+ return false
99
+ }
100
+
101
+ var isClickInHierarchy = false
102
+
103
+ if (window.isEqual(to: clickedWindow)) {
104
+ isClickInHierarchy = true
105
+ } else {
106
+ if let childWindows = window.childWindows {
107
+ for childWindow in childWindows {
108
+ isClickInHierarchy = isClickInsideWindowHierarchy(window: childWindow, event: event)
109
+ }
110
+ }
111
+ }
112
+
113
+ return isClickInHierarchy
114
+ }
115
+
116
+ var window: NSWindow? = self?.calloutWindow
117
+ while (window?.parent as? CalloutWindow != nil) {
118
+ window = window?.parent
119
+ }
120
+
121
+ if (!isClickInsideWindowHierarchy(window: window, event: event)) {
122
+ self?.dismissCallout()
123
+ }
124
+
125
+ return event
126
+ })
127
+
128
+ isCalloutWindowShown = true
84
129
  onShowCallout()
85
130
  }
86
131
 
87
- private func dismissCallout() {
88
- calloutWindow.close()
89
- onDismissCallout()
132
+ @objc private func dismissCallout() {
133
+ guard isCalloutWindowShown else {
134
+ return
135
+ }
136
+
137
+ // Dismiss any children Callouts (I.E: Submenus) first
138
+ if let childWindows = calloutWindow.childWindows {
139
+ for childWindow in childWindows {
140
+ if let childCallout = childWindow as? CalloutWindow {
141
+ childCallout.dismissCallout()
142
+ }
143
+ }
144
+ }
145
+
146
+ calloutWindow.dismissCallout()
147
+
148
+ NotificationCenter.default.removeObserver(self)
149
+ mouseEventMonitor.removeMonitor()
150
+
151
+ isCalloutWindowShown = false
90
152
  }
91
153
 
92
154
  /// Sets the frame of the Callout Window (in screen coordinates to be off of the Anchor on the preferred edge
@@ -274,7 +336,7 @@ class CalloutView: RCTView, CalloutWindowLifeCycleDelegate {
274
336
  private var anchorView: NSView?
275
337
 
276
338
  /// The view we forward Callout's Children to. It's hosted within the CalloutWindow's
277
- /// view heirarchy, ensuring our React Views are not placed in the main window.
339
+ /// view hierarchy, ensuring our React Views are not placed in the main window.
278
340
  private lazy var proxyView: NSView = {
279
341
  let visualEffectView = FlippedVisualEffectView()
280
342
  visualEffectView.translatesAutoresizingMaskIntoConstraints = false
@@ -307,18 +369,14 @@ class CalloutView: RCTView, CalloutWindowLifeCycleDelegate {
307
369
  if let parentWindow = self.window {
308
370
  parentWindow.addChildWindow(window, ordered: .above)
309
371
  }
310
-
311
372
  return window
312
373
  }()
313
- }
314
374
 
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
- }
375
+ private var mouseEventMonitor = GuardedEventMonitor()
376
+
377
+ private var isCalloutWindowShown = false
322
378
  }
323
379
 
380
+
381
+
324
382
  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,16 +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
37
  orderOut(self)
71
38
  }
72
-
73
- deinit {
74
- if let monitor = mouseEventMonitor {
75
- NSEvent.removeMonitor(monitor)
76
- }
77
- }
78
-
79
- private var mouseEventMonitor: Any?
80
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,28 @@
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
+ /// we set the reference to nil after `removeMonitor` so that subsequent calls don't cause an over release.
6
+ /// One instance should only be used to allocate and manage one NSEvent monitor.
7
+ /// https://developer.apple.com/documentation/appkit/nsevent/1533709-removemonitor
8
+ internal class GuardedEventMonitor: Any {
9
+
10
+ private var allocatedMonitor: Any?
11
+
12
+ func addLocalMonitorForEvents(matching mask: NSEvent.EventTypeMask, handler block: @escaping (NSEvent) -> NSEvent?) {
13
+ if (allocatedMonitor == nil) {
14
+ allocatedMonitor = NSEvent.addLocalMonitorForEvents(matching: mask, handler: block)
15
+ }
16
+ }
17
+
18
+ func removeMonitor() {
19
+ if let monitor = allocatedMonitor {
20
+ NSEvent.removeMonitor(monitor)
21
+ allocatedMonitor = nil
22
+ }
23
+ }
24
+
25
+ deinit {
26
+ removeMonitor()
27
+ }
28
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluentui-react-native/callout",
3
- "version": "0.19.32",
3
+ "version": "0.19.35",
4
4
  "description": "A cross-platform Callout component using the Fluent Design System",
5
5
  "license": "MIT",
6
6
  "author": "",
@@ -27,10 +27,10 @@
27
27
  "dependencies": {
28
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.3 <1.0.0",
30
+ "@fluentui-react-native/interactive-hooks": ">=0.14.4 <1.0.0",
31
31
  "@fluentui-react-native/tokens": ">=0.11.8 <1.0.0",
32
32
  "@uifabricshared/foundation-composable": ">=0.10.2 <1.0.0",
33
- "@uifabricshared/foundation-compose": "^1.11.11",
33
+ "@uifabricshared/foundation-compose": "^1.11.12",
34
34
  "@uifabricshared/foundation-settings": ">=0.11.2 <1.0.0"
35
35
  },
36
36
  "devDependencies": {