Skip to content
This repository was archived by the owner on Nov 11, 2024. It is now read-only.

Commit 3baecb6

Browse files
committed
feat: add "WindowDrag" component
1 parent da8b2e7 commit 3baecb6

File tree

6 files changed

+79
-0
lines changed

6 files changed

+79
-0
lines changed

@types/index.d.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8424,6 +8424,14 @@ declare class SwitchComponent extends React.Component<SwitchProps> {}
84248424
declare const SwitchBase: Constructor<NativeMethodsMixin> & typeof SwitchComponent;
84258425
export class Switch extends SwitchBase {}
84268426

8427+
/**
8428+
* The `WindowDrag` component provides an area where the mouse can left-click
8429+
* and then drag in order to move the native `RCTWindow` that contains this view.
8430+
*
8431+
* @platform macos
8432+
*/
8433+
export class WindowDrag extends React.Component<ViewProps> {}
8434+
84278435
/**
84288436
* NOTE: `VibrationIOS` is being deprecated. Use `Vibration` instead.
84298437
*
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
* @providesModule WindowDrag
10+
* @noflow
11+
*/
12+
'use strict';
13+
14+
const React = require('react');
15+
const ReactNative = require('ReactNative');
16+
const TouchableWithoutFeedback = require('TouchableWithoutFeedback');
17+
const UIManager = require('UIManager');
18+
const View = require('View');
19+
20+
const DRAG_REF = 'drag';
21+
22+
class WindowDrag extends React.Component {
23+
render() {
24+
return (
25+
<TouchableWithoutFeedback
26+
onPressIn={() => (
27+
UIManager.dispatchViewManagerCommand(
28+
ReactNative.findNodeHandle(this.refs[DRAG_REF]),
29+
UIManager.RCTView.Commands.performWindowDrag,
30+
null
31+
)
32+
)}>
33+
<View ref={DRAG_REF} {...this.props} />
34+
</TouchableWithoutFeedback>
35+
);
36+
}
37+
}
38+
39+
module.exports = WindowDrag;

Libraries/react-native/react-native-implementation.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ const ReactNative = {
6060
get ViewPagerAndroid() { return require('ViewPagerAndroid'); },
6161
get VirtualizedList() { return require('VirtualizedList'); },
6262
get WebView() { return require('WebView'); },
63+
get WindowDrag() { return require('WindowDrag'); },
6364

6465
// APIs
6566
get ActionSheetIOS() { return require('ActionSheetIOS'); },

React/Views/RCTViewManager.m

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#import "RCTUIManagerUtils.h"
2323
#import "RCTUtils.h"
2424
#import "RCTView.h"
25+
#import "RCTWindow.h"
2526
#import "NSView+React.h"
2627
#import "RCTConvert+Transform.h"
2728

@@ -364,4 +365,28 @@ - (RCTShadowView *)shadowView
364365

365366
RCT_EXPORT_SHADOW_PROPERTY(direction, YGDirection)
366367

368+
RCT_EXPORT_METHOD(performWindowDrag:(nonnull NSNumber *)reactTag)
369+
{
370+
[self.bridge.uiManager addUIBlock:
371+
^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTView *> *viewRegistry) {
372+
373+
RCTView *view = viewRegistry[reactTag];
374+
if (!view || ![view isKindOfClass:[RCTView class]]) {
375+
RCTLogError(@"Cannot find RCTView with tag #%@", reactTag);
376+
return;
377+
}
378+
379+
RCTWindow *window = (RCTWindow *)view.window;
380+
if (!window || ![window isKindOfClass:[RCTWindow class]]) {
381+
RCTLogError(@"Expected RCTView.window to be a RCTWindow, but got a %@", window.className);
382+
return;
383+
}
384+
385+
NSEvent *event = window.lastLeftMouseEvent;
386+
if (event && event.type != NSLeftMouseUp) {
387+
[window performWindowDragWithEvent:window.lastLeftMouseEvent];
388+
}
389+
}];
390+
}
391+
367392
@end

React/Views/RCTWindow.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,6 @@
2424
// Only exists between mouseDown and mouseUp events (may not be a React view)
2525
@property (nullable, strong) NSView *clickOrigin;
2626

27+
@property (nonatomic, readonly) NSEvent *lastLeftMouseEvent;
28+
2729
@end

React/Views/RCTWindow.m

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ - (void)sendEvent:(NSEvent *)event
126126

127127
if (_clickTarget) {
128128
if (type == NSEventTypeLeftMouseDragged) {
129+
_lastLeftMouseEvent = event;
129130
if (_clickType == NSEventTypeLeftMouseDown) {
130131
[self _sendTouchEvent:@"touchMove"];
131132
}
@@ -162,6 +163,7 @@ - (void)sendEvent:(NSEvent *)event
162163
}
163164

164165
if (type == NSEventTypeLeftMouseDown) {
166+
_lastLeftMouseEvent = event;
165167
[self _sendTouchEvent:@"touchStart"];
166168
}
167169

@@ -172,6 +174,8 @@ - (void)sendEvent:(NSEvent *)event
172174
}
173175

174176
if (type == NSEventTypeLeftMouseUp) {
177+
_lastLeftMouseEvent = event;
178+
175179
if (_clickType == NSEventTypeLeftMouseDown) {
176180
[self _sendTouchEvent:@"touchEnd"];
177181
_clickTarget = nil;

0 commit comments

Comments
 (0)