not-react-native-macos 0.87.1-rc.3 → 0.87.1-rc.4
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/Libraries/Components/View/ViewPropTypes.js +58 -0
- package/Libraries/NativeComponent/BaseViewConfig.macos.js +66 -11
- package/Libraries/NativeComponent/ViewConfigIgnore.js +5 -1
- package/Libraries/StyleSheet/PlatformColorValueTypes.macos.js +147 -10
- package/Libraries/StyleSheet/PlatformColorValueTypesMacOS.js +34 -0
- package/Libraries/StyleSheet/PlatformColorValueTypesMacOS.macos.js +55 -0
- package/React/Base/RCTConvert.mm +49 -0
- package/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +150 -0
- package/ReactCommon/React-Fabric.podspec +9 -0
- package/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformTouch.h +16 -0
- package/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEventEmitter.cpp +39 -0
- package/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEventEmitter.h +39 -0
- package/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEvents.h +59 -0
- package/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.cpp +113 -0
- package/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.h +66 -0
- package/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewTraitsInitializer.h +37 -0
- package/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/HostPlatformColor.h +6 -0
- package/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/HostPlatformColor.mm +31 -0
- package/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/PlatformColorParser.mm +34 -0
- package/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/RCTPlatformColorUtils.mm +23 -0
- package/index.js +10 -0
- package/macos/UIKitCompat/UIKit/UIColor.m +7 -1
- package/package.json +1 -1
|
@@ -128,6 +128,63 @@ type FocusEventProps = Readonly<{
|
|
|
128
128
|
onFocusCapture?: ?(event: FocusEvent) => void,
|
|
129
129
|
}>;
|
|
130
130
|
|
|
131
|
+
// [macOS] Props that only exist on macOS. They are declared here rather than in
|
|
132
|
+
// a .macos file because ViewPropTypes is shared, and a prop that is simply
|
|
133
|
+
// absent on other platforms costs them nothing. The native side is
|
|
134
|
+
// HostPlatformViewProps under components/view/platform/macos. macOS]
|
|
135
|
+
type MacOSViewProps = Readonly<{
|
|
136
|
+
/**
|
|
137
|
+
* The view's help tag, shown when the pointer rests over it.
|
|
138
|
+
*
|
|
139
|
+
* @platform macos
|
|
140
|
+
*/
|
|
141
|
+
tooltip?: ?string,
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Receive the click that activates a background window, rather than letting
|
|
145
|
+
* it be swallowed to bring the window forward.
|
|
146
|
+
*
|
|
147
|
+
* @platform macos
|
|
148
|
+
*/
|
|
149
|
+
acceptsFirstMouse?: ?boolean,
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Let the view blend with what is behind it when inside a vibrancy effect.
|
|
153
|
+
*
|
|
154
|
+
* @platform macos
|
|
155
|
+
*/
|
|
156
|
+
allowsVibrancy?: ?boolean,
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Draw the focus ring while the view is first responder. Defaults to true.
|
|
160
|
+
*
|
|
161
|
+
* @platform macos
|
|
162
|
+
*/
|
|
163
|
+
enableFocusRing?: ?boolean,
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Whether dragging the view moves the window. AppKit defaults this to true;
|
|
167
|
+
* set it false for a view that should handle its own drags.
|
|
168
|
+
*
|
|
169
|
+
* @platform macos
|
|
170
|
+
*/
|
|
171
|
+
mouseDownCanMoveWindow?: ?boolean,
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Called on a double click.
|
|
175
|
+
*
|
|
176
|
+
* @platform macos
|
|
177
|
+
*/
|
|
178
|
+
onDoubleClick?: ?(event: MouseEvent) => void,
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Called on a secondary (right) click.
|
|
182
|
+
*
|
|
183
|
+
* @platform macos
|
|
184
|
+
*/
|
|
185
|
+
onAuxClick?: ?(event: MouseEvent) => void,
|
|
186
|
+
}>;
|
|
187
|
+
|
|
131
188
|
type KeyEventProps = Readonly<{
|
|
132
189
|
onKeyDown?: ?(event: KeyDownEvent) => void,
|
|
133
190
|
onKeyDownCapture?: ?(event: KeyDownEvent) => void,
|
|
@@ -566,6 +623,7 @@ export type ViewProps = Readonly<{
|
|
|
566
623
|
...DirectEventProps,
|
|
567
624
|
...GestureResponderHandlers,
|
|
568
625
|
...MouseEventProps,
|
|
626
|
+
...MacOSViewProps, // [macOS]
|
|
569
627
|
...PointerEventProps,
|
|
570
628
|
...FocusEventProps,
|
|
571
629
|
...KeyEventProps,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
2
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
@@ -8,16 +8,71 @@
|
|
|
8
8
|
* @format
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
// [macOS]
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
11
|
+
// [macOS] The view config decides which props reach native at all: anything
|
|
12
|
+
// missing from `validAttributes` is dropped before it ever gets to C++. So the
|
|
13
|
+
// macOS-only props declared in HostPlatformViewProps have to be listed here as
|
|
14
|
+
// well, or setting them does nothing.
|
|
15
|
+
//
|
|
16
|
+
// Everything iOS declares still applies, so this extends that config rather
|
|
17
|
+
// than replacing it. Names match microsoft/react-native-macos. macOS]
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
// from 'react-native' with platform-specific extensions. It can be deleted
|
|
19
|
-
// once we remove the "./*" mapping from package.json "exports".
|
|
19
|
+
import type {PartialViewConfigWithoutName} from './PlatformBaseViewConfig';
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
// $FlowFixMe[cannot-resolve-module] macOS shares the iOS base config.
|
|
22
|
+
import PlatformBaseViewConfigIOS from './BaseViewConfig.ios';
|
|
23
|
+
import {ConditionallyIgnoredEventHandlers} from './ViewConfigIgnore';
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
const bubblingEventTypes = {
|
|
26
|
+
...PlatformBaseViewConfigIOS.bubblingEventTypes,
|
|
27
|
+
topKeyDown: {
|
|
28
|
+
phasedRegistrationNames: {
|
|
29
|
+
captured: 'onKeyDownCapture',
|
|
30
|
+
bubbled: 'onKeyDown',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
topKeyUp: {
|
|
34
|
+
phasedRegistrationNames: {
|
|
35
|
+
captured: 'onKeyUpCapture',
|
|
36
|
+
bubbled: 'onKeyUp',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const directEventTypes = {
|
|
42
|
+
...PlatformBaseViewConfigIOS.directEventTypes,
|
|
43
|
+
topDoubleClick: {registrationName: 'onDoubleClick'},
|
|
44
|
+
topAuxClick: {registrationName: 'onAuxClick'},
|
|
45
|
+
topMouseEnter: {registrationName: 'onMouseEnter'},
|
|
46
|
+
topMouseLeave: {registrationName: 'onMouseLeave'},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const validAttributesForNonEventProps = {
|
|
50
|
+
acceptsFirstMouse: true,
|
|
51
|
+
allowsVibrancy: true,
|
|
52
|
+
enableFocusRing: true,
|
|
53
|
+
focusable: true,
|
|
54
|
+
mouseDownCanMoveWindow: true,
|
|
55
|
+
tooltip: true,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const validAttributesForEventProps = ConditionallyIgnoredEventHandlers({
|
|
59
|
+
onAuxClick: true,
|
|
60
|
+
onDoubleClick: true,
|
|
61
|
+
onKeyDown: true,
|
|
62
|
+
onKeyUp: true,
|
|
63
|
+
onMouseEnter: true,
|
|
64
|
+
onMouseLeave: true,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const PlatformBaseViewConfigMacOS: PartialViewConfigWithoutName = {
|
|
68
|
+
bubblingEventTypes,
|
|
69
|
+
directEventTypes,
|
|
70
|
+
validAttributes: {
|
|
71
|
+
...PlatformBaseViewConfigIOS.validAttributes,
|
|
72
|
+
...validAttributesForNonEventProps,
|
|
73
|
+
// $FlowFixMe[exponential-spread]
|
|
74
|
+
...validAttributesForEventProps,
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export default PlatformBaseViewConfigMacOS;
|
|
@@ -39,7 +39,11 @@ export function DynamicallyInjectedByGestureHandler<T extends {...}>(
|
|
|
39
39
|
export function ConditionallyIgnoredEventHandlers<
|
|
40
40
|
const T extends {readonly [name: string]: true},
|
|
41
41
|
>(value: T): T | void {
|
|
42
|
-
|
|
42
|
+
// [macOS] macOS declares its view props the same way iOS does, so it keeps
|
|
43
|
+
// these too. Reporting Platform.OS as 'macos' without this drops every event
|
|
44
|
+
// handler in the base view config -- including iOS's own -- and nothing that
|
|
45
|
+
// depends on them ever fires. macOS]
|
|
46
|
+
if (Platform.OS === 'ios' || Platform.OS === 'macos') {
|
|
43
47
|
return value;
|
|
44
48
|
}
|
|
45
49
|
return undefined;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
2
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
@@ -8,14 +8,151 @@
|
|
|
8
8
|
* @format
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
// [macOS] macOS
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
11
|
+
// [macOS] The macOS colour types.
|
|
12
|
+
//
|
|
13
|
+
// `semantic` and `dynamic` carry over from iOS unchanged -- RCTConvert resolves
|
|
14
|
+
// both on this platform, and semantic names are looked up on NSColor, so
|
|
15
|
+
// AppKit's whole vocabulary (labelColor, windowBackgroundColor,
|
|
16
|
+
// controlAccentColor, ...) works. What iOS has no equivalent for is
|
|
17
|
+
// `colorWithSystemEffect`, AppKit's pressed / disabled / rollover variants of a
|
|
18
|
+
// colour, so that is added here. macOS]
|
|
16
19
|
|
|
17
|
-
// NOTE: This file supports backwards compatibility of subpath (deep) imports
|
|
18
|
-
// from 'react-native' with platform-specific extensions. It can be deleted
|
|
19
|
-
// once we remove the "./*" mapping from package.json "exports".
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
import type {ProcessedColorValue} from './processColor';
|
|
22
|
+
import type {ColorValue, NativeColorValue} from './StyleSheet';
|
|
23
|
+
|
|
24
|
+
/** The actual type of the opaque NativeColorValue on macOS platform */
|
|
25
|
+
type LocalNativeColorValue = {
|
|
26
|
+
semantic?: Array<string>,
|
|
27
|
+
colorWithSystemEffect?: {
|
|
28
|
+
baseColor: ?(ColorValue | ProcessedColorValue),
|
|
29
|
+
systemEffect: string,
|
|
30
|
+
},
|
|
31
|
+
dynamic?: {
|
|
32
|
+
light: ?(ColorValue | ProcessedColorValue),
|
|
33
|
+
dark: ?(ColorValue | ProcessedColorValue),
|
|
34
|
+
highContrastLight?: ?(ColorValue | ProcessedColorValue),
|
|
35
|
+
highContrastDark?: ?(ColorValue | ProcessedColorValue),
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const PlatformColor = (...names: Array<string>): NativeColorValue => {
|
|
40
|
+
// $FlowExpectedError[incompatible-type] LocalNativeColorValue is the iOS LocalNativeColorValue type
|
|
41
|
+
return {semantic: names} as LocalNativeColorValue;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type DynamicColorMacOSTuplePrivate = {
|
|
45
|
+
light: ColorValue,
|
|
46
|
+
dark: ColorValue,
|
|
47
|
+
highContrastLight?: ColorValue,
|
|
48
|
+
highContrastDark?: ColorValue,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const DynamicColorMacOSPrivate = (
|
|
52
|
+
tuple: DynamicColorMacOSTuplePrivate,
|
|
53
|
+
): ColorValue => {
|
|
54
|
+
return {
|
|
55
|
+
dynamic: {
|
|
56
|
+
light: tuple.light,
|
|
57
|
+
dark: tuple.dark,
|
|
58
|
+
highContrastLight: tuple.highContrastLight,
|
|
59
|
+
highContrastDark: tuple.highContrastDark,
|
|
60
|
+
},
|
|
61
|
+
/* $FlowExpectedError[incompatible-type]
|
|
62
|
+
* LocalNativeColorValue is the actual type of the opaque NativeColorValue on macOS platform */
|
|
63
|
+
} as LocalNativeColorValue;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export type SystemEffectMacOSPrivate =
|
|
67
|
+
| 'none'
|
|
68
|
+
| 'pressed'
|
|
69
|
+
| 'deepPressed'
|
|
70
|
+
| 'disabled'
|
|
71
|
+
| 'rollover';
|
|
72
|
+
|
|
73
|
+
export const ColorWithSystemEffectMacOSPrivate = (
|
|
74
|
+
color: ColorValue,
|
|
75
|
+
effect: SystemEffectMacOSPrivate,
|
|
76
|
+
): ColorValue => {
|
|
77
|
+
return {
|
|
78
|
+
colorWithSystemEffect: {
|
|
79
|
+
baseColor: color,
|
|
80
|
+
systemEffect: effect,
|
|
81
|
+
},
|
|
82
|
+
/* $FlowExpectedError[incompatible-type]
|
|
83
|
+
* LocalNativeColorValue is the actual type of the opaque NativeColorValue */
|
|
84
|
+
} as LocalNativeColorValue;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const _normalizeColorObject = (
|
|
88
|
+
color: LocalNativeColorValue,
|
|
89
|
+
): ?LocalNativeColorValue => {
|
|
90
|
+
if ('colorWithSystemEffect' in color && color.colorWithSystemEffect !== undefined) {
|
|
91
|
+
const normalizeColor = require('./normalizeColor').default;
|
|
92
|
+
const spec = color.colorWithSystemEffect;
|
|
93
|
+
return {
|
|
94
|
+
colorWithSystemEffect: {
|
|
95
|
+
// $FlowFixMe[incompatible-call]
|
|
96
|
+
baseColor: normalizeColor(spec.baseColor),
|
|
97
|
+
systemEffect: spec.systemEffect,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
} else if ('semantic' in color) {
|
|
101
|
+
// an AppKit or iOS semantic colour
|
|
102
|
+
return color;
|
|
103
|
+
} else if ('dynamic' in color && color.dynamic !== undefined) {
|
|
104
|
+
const normalizeColor = require('./normalizeColor').default;
|
|
105
|
+
|
|
106
|
+
// a dynamic, appearance aware color
|
|
107
|
+
const dynamic = color.dynamic;
|
|
108
|
+
const dynamicColor: LocalNativeColorValue = {
|
|
109
|
+
dynamic: {
|
|
110
|
+
// $FlowFixMe[incompatible-use]
|
|
111
|
+
light: normalizeColor(dynamic.light),
|
|
112
|
+
// $FlowFixMe[incompatible-use]
|
|
113
|
+
dark: normalizeColor(dynamic.dark),
|
|
114
|
+
// $FlowFixMe[incompatible-use]
|
|
115
|
+
highContrastLight: normalizeColor(dynamic.highContrastLight),
|
|
116
|
+
// $FlowFixMe[incompatible-use]
|
|
117
|
+
highContrastDark: normalizeColor(dynamic.highContrastDark),
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
return dynamicColor;
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export const normalizeColorObject: (
|
|
126
|
+
color: NativeColorValue,
|
|
127
|
+
/* $FlowExpectedError[incompatible-type]
|
|
128
|
+
* LocalNativeColorValue is the actual type of the opaque NativeColorValue on macOS platform */
|
|
129
|
+
) => ?ProcessedColorValue = _normalizeColorObject;
|
|
130
|
+
|
|
131
|
+
const _processColorObject = (
|
|
132
|
+
color: LocalNativeColorValue,
|
|
133
|
+
): ?LocalNativeColorValue => {
|
|
134
|
+
if ('dynamic' in color && color.dynamic != null) {
|
|
135
|
+
const processColor = require('./processColor').default;
|
|
136
|
+
const dynamic = color.dynamic;
|
|
137
|
+
const dynamicColor: LocalNativeColorValue = {
|
|
138
|
+
dynamic: {
|
|
139
|
+
// $FlowFixMe[incompatible-use]
|
|
140
|
+
light: processColor(dynamic.light),
|
|
141
|
+
// $FlowFixMe[incompatible-use]
|
|
142
|
+
dark: processColor(dynamic.dark),
|
|
143
|
+
// $FlowFixMe[incompatible-use]
|
|
144
|
+
highContrastLight: processColor(dynamic.highContrastLight),
|
|
145
|
+
// $FlowFixMe[incompatible-use]
|
|
146
|
+
highContrastDark: processColor(dynamic.highContrastDark),
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
return dynamicColor;
|
|
150
|
+
}
|
|
151
|
+
return color;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export const processColorObject: (
|
|
155
|
+
color: NativeColorValue,
|
|
156
|
+
/* $FlowExpectedError[incompatible-type]
|
|
157
|
+
* LocalNativeColorValue is the actual type of the opaque NativeColorValue on macOS platform */
|
|
158
|
+
) => ?NativeColorValue = _processColorObject;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict-local
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// [macOS] The off-macOS stand-in, matching how PlatformColorValueTypesIOS.js
|
|
12
|
+
// behaves elsewhere: importing is fine, calling is not.
|
|
13
|
+
|
|
14
|
+
import type {ColorValue} from './StyleSheet';
|
|
15
|
+
|
|
16
|
+
export type DynamicColorMacOSTuple = {
|
|
17
|
+
light: ColorValue,
|
|
18
|
+
dark: ColorValue,
|
|
19
|
+
highContrastLight?: ColorValue,
|
|
20
|
+
highContrastDark?: ColorValue,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const DynamicColorMacOS = (_tuple: DynamicColorMacOSTuple): ColorValue => {
|
|
24
|
+
throw new Error('DynamicColorMacOS is not available on this platform.');
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type SystemEffectMacOS = 'none' | 'pressed' | 'deepPressed' | 'disabled' | 'rollover';
|
|
28
|
+
|
|
29
|
+
export const ColorWithSystemEffectMacOS = (
|
|
30
|
+
_color: ColorValue,
|
|
31
|
+
_effect: SystemEffectMacOS,
|
|
32
|
+
): ColorValue => {
|
|
33
|
+
throw new Error('ColorWithSystemEffectMacOS is not available on this platform.');
|
|
34
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict-local
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// [macOS] The public macOS colour API, mirroring PlatformColorValueTypesIOS.
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
import type {ColorValue} from './StyleSheet';
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
ColorWithSystemEffectMacOSPrivate,
|
|
19
|
+
DynamicColorMacOSPrivate,
|
|
20
|
+
// $FlowFixMe[cannot-resolve-module] resolved by the macOS platform extension
|
|
21
|
+
} from './PlatformColorValueTypes.macos';
|
|
22
|
+
|
|
23
|
+
export type DynamicColorMacOSTuple = {
|
|
24
|
+
light: ColorValue,
|
|
25
|
+
dark: ColorValue,
|
|
26
|
+
highContrastLight?: ColorValue,
|
|
27
|
+
highContrastDark?: ColorValue,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* A colour that follows the system appearance, the macOS counterpart of
|
|
32
|
+
* `DynamicColorIOS`.
|
|
33
|
+
*/
|
|
34
|
+
export const DynamicColorMacOS = (tuple: DynamicColorMacOSTuple): ColorValue => {
|
|
35
|
+
return DynamicColorMacOSPrivate({
|
|
36
|
+
light: tuple.light,
|
|
37
|
+
dark: tuple.dark,
|
|
38
|
+
highContrastLight: tuple.highContrastLight,
|
|
39
|
+
highContrastDark: tuple.highContrastDark,
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export type SystemEffectMacOS = 'none' | 'pressed' | 'deepPressed' | 'disabled' | 'rollover';
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* A colour with one of AppKit's system effects applied. There is no iOS
|
|
47
|
+
* equivalent: UIKit expects the caller to supply the pressed or disabled
|
|
48
|
+
* colour, where AppKit derives it.
|
|
49
|
+
*/
|
|
50
|
+
export const ColorWithSystemEffectMacOS = (
|
|
51
|
+
color: ColorValue,
|
|
52
|
+
effect: SystemEffectMacOS,
|
|
53
|
+
): ColorValue => {
|
|
54
|
+
return ColorWithSystemEffectMacOSPrivate(color, effect);
|
|
55
|
+
};
|
package/React/Base/RCTConvert.mm
CHANGED
|
@@ -850,6 +850,26 @@ static UIColor *RCTColorFromSemanticColorName(NSString *semanticColorName)
|
|
|
850
850
|
NSDictionary<NSString *, NSDictionary *> *colorMap = RCTSemanticColorsMap();
|
|
851
851
|
UIColor *color = nil;
|
|
852
852
|
NSDictionary<NSString *, id> *colorInfo = colorMap[semanticColorName];
|
|
853
|
+
|
|
854
|
+
#if TARGET_OS_OSX // [macOS
|
|
855
|
+
// The map above is iOS's vocabulary. AppKit has its own -- labelColor,
|
|
856
|
+
// windowBackgroundColor, controlAccentColor and the rest -- and they are all
|
|
857
|
+
// class properties on NSColor, so asking NSColor directly covers every one of
|
|
858
|
+
// them without a second table to keep in sync. Only reached for names iOS
|
|
859
|
+
// does not define, so iOS names keep their mapping and their fallbacks.
|
|
860
|
+
if (colorInfo == nil) {
|
|
861
|
+
SEL appKitSelector = NSSelectorFromString(semanticColorName);
|
|
862
|
+
if (appKitSelector != nil && [UIColor respondsToSelector:appKitSelector]) {
|
|
863
|
+
IMP imp = [[UIColor class] methodForSelector:appKitSelector];
|
|
864
|
+
id (*getColor)(id, SEL) = (id (*)(id, SEL))imp;
|
|
865
|
+
id candidate = getColor([UIColor class], appKitSelector);
|
|
866
|
+
if ([candidate isKindOfClass:[UIColor class]]) {
|
|
867
|
+
return candidate;
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
#endif // macOS]
|
|
872
|
+
|
|
853
873
|
if (colorInfo) {
|
|
854
874
|
NSString *semanticColorSelector = colorInfo[RCTSelector];
|
|
855
875
|
if (semanticColorSelector == nil) {
|
|
@@ -1040,6 +1060,35 @@ void RCTSetDefaultColorSpace(RCTColorSpace colorSpace)
|
|
|
1040
1060
|
RCTLogConvertError(json, @"a UIColor. Expected an iOS dynamic appearance aware color.");
|
|
1041
1061
|
return nil;
|
|
1042
1062
|
}
|
|
1063
|
+
#if TARGET_OS_OSX // [macOS
|
|
1064
|
+
} else if ((value = [dictionary objectForKey:@"colorWithSystemEffect"])) {
|
|
1065
|
+
// AppKit's pressed / disabled / rollover variants of a colour. There is
|
|
1066
|
+
// no UIKit equivalent, so this arm exists only on macOS.
|
|
1067
|
+
NSDictionary *spec = value;
|
|
1068
|
+
UIColor *baseColor = [RCTConvert UIColor:[spec objectForKey:@"baseColor"]];
|
|
1069
|
+
NSString *effect = [RCTConvert NSString:[spec objectForKey:@"systemEffect"]];
|
|
1070
|
+
if (baseColor == nil) {
|
|
1071
|
+
RCTLogConvertError(json, @"a UIColor. colorWithSystemEffect needs a baseColor.");
|
|
1072
|
+
return nil;
|
|
1073
|
+
}
|
|
1074
|
+
static NSDictionary<NSString *, NSNumber *> *effects;
|
|
1075
|
+
static dispatch_once_t onceToken;
|
|
1076
|
+
dispatch_once(&onceToken, ^{
|
|
1077
|
+
effects = @{
|
|
1078
|
+
@"none" : @(NSColorSystemEffectNone),
|
|
1079
|
+
@"pressed" : @(NSColorSystemEffectPressed),
|
|
1080
|
+
@"deepPressed" : @(NSColorSystemEffectDeepPressed),
|
|
1081
|
+
@"disabled" : @(NSColorSystemEffectDisabled),
|
|
1082
|
+
@"rollover" : @(NSColorSystemEffectRollover),
|
|
1083
|
+
};
|
|
1084
|
+
});
|
|
1085
|
+
NSNumber *resolved = effects[effect ?: @"none"];
|
|
1086
|
+
if (resolved == nil) {
|
|
1087
|
+
RCTLogConvertError(json, @"a UIColor. Unknown system effect.");
|
|
1088
|
+
return nil;
|
|
1089
|
+
}
|
|
1090
|
+
return [baseColor colorWithSystemEffect:(NSColorSystemEffect)resolved.integerValue];
|
|
1091
|
+
#endif // macOS]
|
|
1043
1092
|
} else {
|
|
1044
1093
|
RCTLogConvertError(json, @"a UIColor. Expected an iOS semantic color or dynamic appearance aware color.");
|
|
1045
1094
|
return nil;
|
|
@@ -55,6 +55,13 @@ const CGFloat BACKGROUND_COLOR_ZPOSITION = -1024.0f;
|
|
|
55
55
|
NSMutableSet<NSString *> *_accessibilityOrderNativeIDs;
|
|
56
56
|
RCTSwiftUIContainerViewWrapper *_swiftUIWrapper;
|
|
57
57
|
BOOL _focusable;
|
|
58
|
+
#if TARGET_OS_OSX // [macOS
|
|
59
|
+
// AppKit reads these rather than being told them, so they are answered from
|
|
60
|
+
// stored values by the overrides further down.
|
|
61
|
+
BOOL _allowsVibrancy;
|
|
62
|
+
BOOL _mouseDownCanMoveWindow;
|
|
63
|
+
NSTrackingArea *_mouseTrackingArea;
|
|
64
|
+
#endif // macOS]
|
|
58
65
|
}
|
|
59
66
|
|
|
60
67
|
#ifdef RCT_DYNAMIC_FRAMEWORKS
|
|
@@ -69,6 +76,10 @@ const CGFloat BACKGROUND_COLOR_ZPOSITION = -1024.0f;
|
|
|
69
76
|
if (self = [super initWithFrame:frame]) {
|
|
70
77
|
_props = ViewShadowNode::defaultSharedProps();
|
|
71
78
|
_reactSubviews = [NSMutableArray new];
|
|
79
|
+
#if TARGET_OS_OSX // [macOS] mirror HostPlatformViewProps' defaults
|
|
80
|
+
_mouseDownCanMoveWindow = YES;
|
|
81
|
+
_allowsVibrancy = NO;
|
|
82
|
+
#endif // macOS]
|
|
72
83
|
#if !TARGET_OS_TV
|
|
73
84
|
self.multipleTouchEnabled = YES;
|
|
74
85
|
#endif
|
|
@@ -608,9 +619,148 @@ static BOOL RCTLayerTransformCollapsesAxis(CALayer *layer)
|
|
|
608
619
|
|
|
609
620
|
_needsInvalidateLayer = _needsInvalidateLayer || needsInvalidateLayer;
|
|
610
621
|
|
|
622
|
+
#if TARGET_OS_OSX // [macOS
|
|
623
|
+
[self _updateMacOSProps:oldViewProps newProps:newViewProps];
|
|
624
|
+
#endif // macOS]
|
|
625
|
+
|
|
611
626
|
_props = std::static_pointer_cast<const ViewProps>(props);
|
|
612
627
|
}
|
|
613
628
|
|
|
629
|
+
#if TARGET_OS_OSX // [macOS
|
|
630
|
+
/**
|
|
631
|
+
* The props AppKit has and UIKit does not. They are declared in
|
|
632
|
+
* HostPlatformViewProps, so `ViewProps` already carries them on this platform.
|
|
633
|
+
*/
|
|
634
|
+
- (void)_updateMacOSProps:(const ViewProps &)oldViewProps newProps:(const ViewProps &)newViewProps
|
|
635
|
+
{
|
|
636
|
+
if (oldViewProps.tooltip != newViewProps.tooltip) {
|
|
637
|
+
self.toolTip = newViewProps.tooltip.has_value() ? RCTNSStringFromString(*newViewProps.tooltip) : nil;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
if (oldViewProps.acceptsFirstMouse != newViewProps.acceptsFirstMouse) {
|
|
641
|
+
self.acceptsFirstMouse = newViewProps.acceptsFirstMouse;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
if (oldViewProps.mouseDownCanMoveWindow != newViewProps.mouseDownCanMoveWindow) {
|
|
645
|
+
_mouseDownCanMoveWindow = newViewProps.mouseDownCanMoveWindow;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
if (oldViewProps.enableFocusRing != newViewProps.enableFocusRing) {
|
|
649
|
+
self.enableFocusRing = newViewProps.enableFocusRing;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// -allowsVibrancy and -canBecomeKeyView are read by AppKit rather than set,
|
|
653
|
+
// so the values are stored and the overrides below answer from them.
|
|
654
|
+
if (oldViewProps.allowsVibrancy != newViewProps.allowsVibrancy) {
|
|
655
|
+
_allowsVibrancy = newViewProps.allowsVibrancy;
|
|
656
|
+
self.needsDisplay = YES;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
if (oldViewProps.focusable != newViewProps.focusable) {
|
|
660
|
+
_focusable = newViewProps.focusable;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
if (oldViewProps.hostPlatformEvents != newViewProps.hostPlatformEvents) {
|
|
664
|
+
[self _updateMouseTracking:newViewProps.hostPlatformEvents.wantsMouseTracking()];
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* A view only tracks the mouse while something is listening. Tracking every
|
|
670
|
+
* view would cost a dispatch per view per mouse move.
|
|
671
|
+
*/
|
|
672
|
+
- (void)_updateMouseTracking:(BOOL)wanted
|
|
673
|
+
{
|
|
674
|
+
if (wanted == (_mouseTrackingArea != nil)) {
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
if (!wanted) {
|
|
679
|
+
[self removeTrackingArea:_mouseTrackingArea];
|
|
680
|
+
_mouseTrackingArea = nil;
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
_mouseTrackingArea = [[NSTrackingArea alloc]
|
|
685
|
+
initWithRect:NSZeroRect
|
|
686
|
+
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | NSTrackingInVisibleRect
|
|
687
|
+
owner:self
|
|
688
|
+
userInfo:nil];
|
|
689
|
+
[self addTrackingArea:_mouseTrackingArea];
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
- (HostPlatformViewEventEmitter::MouseEvent)_mouseEventFromNSEvent:(NSEvent *)event
|
|
693
|
+
{
|
|
694
|
+
NSPoint inWindow = event.locationInWindow;
|
|
695
|
+
NSPoint inView = [self convertPoint:inWindow fromView:nil];
|
|
696
|
+
NSPoint onScreen = self.window != nil ? [self.window convertPointToScreen:inWindow] : inWindow;
|
|
697
|
+
|
|
698
|
+
HostPlatformViewEventEmitter::MouseEvent mouseEvent = {};
|
|
699
|
+
mouseEvent.clientX = inView.x;
|
|
700
|
+
mouseEvent.clientY = inView.y;
|
|
701
|
+
mouseEvent.pageX = inWindow.x;
|
|
702
|
+
mouseEvent.pageY = inWindow.y;
|
|
703
|
+
mouseEvent.screenX = onScreen.x;
|
|
704
|
+
mouseEvent.screenY = onScreen.y;
|
|
705
|
+
return mouseEvent;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
- (void)mouseEntered:(NSEvent *)event
|
|
709
|
+
{
|
|
710
|
+
[super mouseEntered:event];
|
|
711
|
+
if (_eventEmitter != nullptr) {
|
|
712
|
+
_eventEmitter->onMouseEnter([self _mouseEventFromNSEvent:event]);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
- (void)mouseExited:(NSEvent *)event
|
|
717
|
+
{
|
|
718
|
+
[super mouseExited:event];
|
|
719
|
+
if (_eventEmitter != nullptr) {
|
|
720
|
+
_eventEmitter->onMouseLeave([self _mouseEventFromNSEvent:event]);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
- (void)mouseUp:(NSEvent *)event
|
|
725
|
+
{
|
|
726
|
+
[super mouseUp:event];
|
|
727
|
+
const auto &viewProps = static_cast<const ViewProps &>(*_props);
|
|
728
|
+
if (_eventEmitter != nullptr && event.clickCount == 2 &&
|
|
729
|
+
viewProps.hostPlatformEvents[HostPlatformViewEvents::Offset::DoubleClick]) {
|
|
730
|
+
_eventEmitter->onDoubleClick([self _mouseEventFromNSEvent:event]);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
- (void)rightMouseUp:(NSEvent *)event
|
|
735
|
+
{
|
|
736
|
+
[super rightMouseUp:event];
|
|
737
|
+
const auto &viewProps = static_cast<const ViewProps &>(*_props);
|
|
738
|
+
if (_eventEmitter != nullptr && viewProps.hostPlatformEvents[HostPlatformViewEvents::Offset::AuxClick]) {
|
|
739
|
+
_eventEmitter->onAuxClick([self _mouseEventFromNSEvent:event]);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
- (BOOL)allowsVibrancy
|
|
744
|
+
{
|
|
745
|
+
return _allowsVibrancy;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
- (BOOL)mouseDownCanMoveWindow
|
|
749
|
+
{
|
|
750
|
+
return _mouseDownCanMoveWindow;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
- (BOOL)canBecomeKeyView
|
|
754
|
+
{
|
|
755
|
+
return _focusable;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
- (BOOL)acceptsFirstResponder
|
|
759
|
+
{
|
|
760
|
+
return _focusable || [super acceptsFirstResponder];
|
|
761
|
+
}
|
|
762
|
+
#endif // macOS]
|
|
763
|
+
|
|
614
764
|
- (void)updateEventEmitter:(const EventEmitter::Shared &)eventEmitter
|
|
615
765
|
{
|
|
616
766
|
assert(std::dynamic_pointer_cast<const ViewEventEmitter>(eventEmitter));
|
|
@@ -102,6 +102,10 @@ Pod::Spec.new do |s|
|
|
|
102
102
|
"\"$(PODS_TARGET_SRCROOT)/react/renderer/components/legacyviewmanagerinterop/platform/ios\"",
|
|
103
103
|
"\"$(PODS_TARGET_SRCROOT)/react/renderer/components/text/platform/cxx\"",
|
|
104
104
|
"\"$(PODS_TARGET_SRCROOT)/react/renderer/components/textinput/platform/ios\"",
|
|
105
|
+
# [macOS] macOS has its own HostPlatformViewProps -- tooltip, focus ring,
|
|
106
|
+
# first mouse and the rest. Its directory has to come first so it wins
|
|
107
|
+
# over the shared C++ one. macOS]
|
|
108
|
+
"\"$(PODS_TARGET_SRCROOT)/react/renderer/components/view/platform/macos\"",
|
|
105
109
|
"\"$(PODS_TARGET_SRCROOT)/react/renderer/components/view/platform/cxx\"",
|
|
106
110
|
]
|
|
107
111
|
end
|
|
@@ -135,6 +139,11 @@ Pod::Spec.new do |s|
|
|
|
135
139
|
sss.dependency "React-renderercss"
|
|
136
140
|
sss.dependency "Yoga"
|
|
137
141
|
sss.source_files = podspec_sources(["react/renderer/components/view/*.{m,mm,cpp,h}", "react/renderer/components/view/platform/cxx/**/*.{m,mm,cpp,h}"], ["react/renderer/components/view/*.{h}", "react/renderer/components/view/platform/cxx/**/*.{h}"])
|
|
142
|
+
# [macOS] Swap the shared C++ host-platform view files for the macOS ones.
|
|
143
|
+
# Both define the same symbols, so this is a replacement, not an addition.
|
|
144
|
+
sss.osx.source_files = podspec_sources(["react/renderer/components/view/*.{m,mm,cpp,h}", "react/renderer/components/view/platform/macos/**/*.{m,mm,cpp,h}"], ["react/renderer/components/view/*.{h}", "react/renderer/components/view/platform/macos/**/*.{h}"])
|
|
145
|
+
sss.osx.exclude_files = "react/renderer/components/view/platform/cxx/**/*"
|
|
146
|
+
# macOS]
|
|
138
147
|
sss.header_dir = "react/renderer/components/view"
|
|
139
148
|
end
|
|
140
149
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// [macOS] Touch is the shared one; a mouse is reported through the same path.
|
|
9
|
+
|
|
10
|
+
#pragma once
|
|
11
|
+
|
|
12
|
+
#include <react/renderer/components/view/BaseTouch.h>
|
|
13
|
+
|
|
14
|
+
namespace facebook::react {
|
|
15
|
+
using HostPlatformTouch = BaseTouch;
|
|
16
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// [macOS] See HostPlatformViewEventEmitter.h.
|
|
9
|
+
|
|
10
|
+
#include "HostPlatformViewEventEmitter.h"
|
|
11
|
+
|
|
12
|
+
namespace facebook::react {
|
|
13
|
+
|
|
14
|
+
static jsi::Value mouseEventPayload(jsi::Runtime &runtime, const HostPlatformViewEventEmitter::MouseEvent &event)
|
|
15
|
+
{
|
|
16
|
+
auto payload = jsi::Object(runtime);
|
|
17
|
+
payload.setProperty(runtime, "clientX", event.clientX);
|
|
18
|
+
payload.setProperty(runtime, "clientY", event.clientY);
|
|
19
|
+
payload.setProperty(runtime, "screenX", event.screenX);
|
|
20
|
+
payload.setProperty(runtime, "screenY", event.screenY);
|
|
21
|
+
payload.setProperty(runtime, "pageX", event.pageX);
|
|
22
|
+
payload.setProperty(runtime, "pageY", event.pageY);
|
|
23
|
+
return payload;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
#define RCT_MACOS_MOUSE_EVENT(name) \
|
|
27
|
+
void HostPlatformViewEventEmitter::name(const MouseEvent &event) const \
|
|
28
|
+
{ \
|
|
29
|
+
dispatchEvent(#name, [event](jsi::Runtime &runtime) { \
|
|
30
|
+
return mouseEventPayload(runtime, event); \
|
|
31
|
+
}); \
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
RCT_MACOS_MOUSE_EVENT(onMouseEnter)
|
|
35
|
+
RCT_MACOS_MOUSE_EVENT(onMouseLeave)
|
|
36
|
+
RCT_MACOS_MOUSE_EVENT(onDoubleClick)
|
|
37
|
+
RCT_MACOS_MOUSE_EVENT(onAuxClick)
|
|
38
|
+
|
|
39
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// [macOS] Adds the pointer events AppKit can report and UIKit cannot.
|
|
9
|
+
|
|
10
|
+
#pragma once
|
|
11
|
+
|
|
12
|
+
#include <react/renderer/components/view/BaseViewEventEmitter.h>
|
|
13
|
+
|
|
14
|
+
namespace facebook::react {
|
|
15
|
+
|
|
16
|
+
class HostPlatformViewEventEmitter : public BaseViewEventEmitter {
|
|
17
|
+
public:
|
|
18
|
+
using BaseViewEventEmitter::BaseViewEventEmitter;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A mouse crossing into or out of the view. There is no touch equivalent, so
|
|
22
|
+
* these have no counterpart in BaseViewEventEmitter.
|
|
23
|
+
*/
|
|
24
|
+
struct MouseEvent {
|
|
25
|
+
Float clientX{};
|
|
26
|
+
Float clientY{};
|
|
27
|
+
Float screenX{};
|
|
28
|
+
Float screenY{};
|
|
29
|
+
Float pageX{};
|
|
30
|
+
Float pageY{};
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
void onMouseEnter(const MouseEvent &event) const;
|
|
34
|
+
void onMouseLeave(const MouseEvent &event) const;
|
|
35
|
+
void onDoubleClick(const MouseEvent &event) const;
|
|
36
|
+
void onAuxClick(const MouseEvent &event) const;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// [macOS] Which macOS-only handlers a view actually has.
|
|
9
|
+
//
|
|
10
|
+
// Installing an NSTrackingArea on every view to find out later would cost a
|
|
11
|
+
// mouse-moved dispatch per view per move. The props carry a bitset instead, so
|
|
12
|
+
// the view only tracks the mouse when something is listening -- the same
|
|
13
|
+
// arrangement BaseViewProps uses for pointer and responder events.
|
|
14
|
+
|
|
15
|
+
#pragma once
|
|
16
|
+
|
|
17
|
+
#include <bitset>
|
|
18
|
+
#include <cstddef>
|
|
19
|
+
|
|
20
|
+
namespace facebook::react {
|
|
21
|
+
|
|
22
|
+
struct HostPlatformViewEvents {
|
|
23
|
+
std::bitset<8> bits{};
|
|
24
|
+
|
|
25
|
+
enum class Offset : std::size_t {
|
|
26
|
+
MouseEnter = 0,
|
|
27
|
+
MouseLeave = 1,
|
|
28
|
+
DoubleClick = 2,
|
|
29
|
+
AuxClick = 3,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
constexpr bool operator[](Offset offset) const
|
|
33
|
+
{
|
|
34
|
+
return bits[static_cast<std::size_t>(offset)];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
std::bitset<8>::reference operator[](Offset offset)
|
|
38
|
+
{
|
|
39
|
+
return bits[static_cast<std::size_t>(offset)];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** True when any macOS mouse handler is present. */
|
|
43
|
+
bool wantsMouseTracking() const
|
|
44
|
+
{
|
|
45
|
+
return (*this)[Offset::MouseEnter] || (*this)[Offset::MouseLeave];
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
inline bool operator==(const HostPlatformViewEvents &lhs, const HostPlatformViewEvents &rhs)
|
|
50
|
+
{
|
|
51
|
+
return lhs.bits == rhs.bits;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
inline bool operator!=(const HostPlatformViewEvents &lhs, const HostPlatformViewEvents &rhs)
|
|
55
|
+
{
|
|
56
|
+
return lhs.bits != rhs.bits;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// [macOS] See HostPlatformViewProps.h.
|
|
9
|
+
|
|
10
|
+
#include "HostPlatformViewProps.h"
|
|
11
|
+
|
|
12
|
+
#include <react/featureflags/ReactNativeFeatureFlags.h>
|
|
13
|
+
#include <react/renderer/core/propsConversions.h>
|
|
14
|
+
|
|
15
|
+
namespace facebook::react {
|
|
16
|
+
|
|
17
|
+
// The whole-map parsing path (feature flag off) needs a converter for the
|
|
18
|
+
// bitset, mirroring the one propsConversions.h provides for ViewEvents.
|
|
19
|
+
static inline HostPlatformViewEvents convertRawProp(
|
|
20
|
+
const PropsParserContext &context,
|
|
21
|
+
const RawProps &rawProps,
|
|
22
|
+
const HostPlatformViewEvents &sourceValue,
|
|
23
|
+
const HostPlatformViewEvents &defaultValue)
|
|
24
|
+
{
|
|
25
|
+
HostPlatformViewEvents result{};
|
|
26
|
+
using Offset = HostPlatformViewEvents::Offset;
|
|
27
|
+
|
|
28
|
+
#define RCT_MACOS_CONVERT_EVENT(name, offset) \
|
|
29
|
+
result[Offset::offset] = convertRawProp( \
|
|
30
|
+
context, rawProps, name, sourceValue[Offset::offset], defaultValue[Offset::offset])
|
|
31
|
+
|
|
32
|
+
RCT_MACOS_CONVERT_EVENT("onMouseEnter", MouseEnter);
|
|
33
|
+
RCT_MACOS_CONVERT_EVENT("onMouseLeave", MouseLeave);
|
|
34
|
+
RCT_MACOS_CONVERT_EVENT("onDoubleClick", DoubleClick);
|
|
35
|
+
RCT_MACOS_CONVERT_EVENT("onAuxClick", AuxClick);
|
|
36
|
+
|
|
37
|
+
#undef RCT_MACOS_CONVERT_EVENT
|
|
38
|
+
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Two parsing paths exist and both have to be fed. With the iterator setter
|
|
43
|
+
// feature flag on, props arrive one at a time through setProp and the
|
|
44
|
+
// constructor just carries the previous value forward; with it off, the
|
|
45
|
+
// constructor parses the whole RawProps map itself.
|
|
46
|
+
#define RCT_MACOS_PROP(name) \
|
|
47
|
+
name(ReactNativeFeatureFlags::enableCppPropsIteratorSetter() \
|
|
48
|
+
? sourceProps.name \
|
|
49
|
+
: convertRawProp(context, rawProps, #name, sourceProps.name, {}))
|
|
50
|
+
|
|
51
|
+
HostPlatformViewProps::HostPlatformViewProps(
|
|
52
|
+
const PropsParserContext &context,
|
|
53
|
+
const HostPlatformViewProps &sourceProps,
|
|
54
|
+
const RawProps &rawProps)
|
|
55
|
+
: BaseViewProps(context, sourceProps, rawProps),
|
|
56
|
+
hostPlatformEvents(
|
|
57
|
+
ReactNativeFeatureFlags::enableCppPropsIteratorSetter()
|
|
58
|
+
? sourceProps.hostPlatformEvents
|
|
59
|
+
: convertRawProp(context, rawProps, sourceProps.hostPlatformEvents, {})),
|
|
60
|
+
RCT_MACOS_PROP(focusable),
|
|
61
|
+
RCT_MACOS_PROP(enableFocusRing),
|
|
62
|
+
RCT_MACOS_PROP(tooltip),
|
|
63
|
+
RCT_MACOS_PROP(acceptsFirstMouse),
|
|
64
|
+
RCT_MACOS_PROP(allowsVibrancy),
|
|
65
|
+
RCT_MACOS_PROP(mouseDownCanMoveWindow)
|
|
66
|
+
{
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
#undef RCT_MACOS_PROP
|
|
70
|
+
|
|
71
|
+
void HostPlatformViewProps::setProp(
|
|
72
|
+
const PropsParserContext &context,
|
|
73
|
+
RawPropsPropNameHash hash,
|
|
74
|
+
const char *propName,
|
|
75
|
+
const RawValue &value)
|
|
76
|
+
{
|
|
77
|
+
// Every Props struct must call super unconditionally: several structs can
|
|
78
|
+
// share the same raw value, and skipping the call drops it for all of them.
|
|
79
|
+
BaseViewProps::setProp(context, hash, propName, value);
|
|
80
|
+
|
|
81
|
+
static auto defaults = HostPlatformViewProps{};
|
|
82
|
+
|
|
83
|
+
// An `onX` prop is stored as a bit rather than a value: all the view needs to
|
|
84
|
+
// know is whether anything is listening.
|
|
85
|
+
#define RCT_MACOS_EVENT_CASE(eventType) \
|
|
86
|
+
case CONSTEXPR_RAW_PROPS_KEY_HASH("on" #eventType): { \
|
|
87
|
+
const auto offset = HostPlatformViewEvents::Offset::eventType; \
|
|
88
|
+
HostPlatformViewEvents defaultEvents{}; \
|
|
89
|
+
bool listening = defaultEvents[offset]; \
|
|
90
|
+
if (value.hasValue()) { \
|
|
91
|
+
fromRawValue(context, value, listening); \
|
|
92
|
+
} \
|
|
93
|
+
hostPlatformEvents[offset] = listening; \
|
|
94
|
+
return; \
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
switch (hash) {
|
|
98
|
+
RCT_MACOS_EVENT_CASE(MouseEnter);
|
|
99
|
+
RCT_MACOS_EVENT_CASE(MouseLeave);
|
|
100
|
+
RCT_MACOS_EVENT_CASE(DoubleClick);
|
|
101
|
+
RCT_MACOS_EVENT_CASE(AuxClick);
|
|
102
|
+
RAW_SET_PROP_SWITCH_CASE_BASIC(focusable);
|
|
103
|
+
RAW_SET_PROP_SWITCH_CASE_BASIC(enableFocusRing);
|
|
104
|
+
RAW_SET_PROP_SWITCH_CASE_BASIC(tooltip);
|
|
105
|
+
RAW_SET_PROP_SWITCH_CASE_BASIC(acceptsFirstMouse);
|
|
106
|
+
RAW_SET_PROP_SWITCH_CASE_BASIC(allowsVibrancy);
|
|
107
|
+
RAW_SET_PROP_SWITCH_CASE_BASIC(mouseDownCanMoveWindow);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
#undef RCT_MACOS_EVENT_CASE
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// [macOS] The props a Mac view has and an iOS one does not.
|
|
9
|
+
//
|
|
10
|
+
// React Native reaches platform-specific view props through this class -- see
|
|
11
|
+
// the sibling directories under components/view/platform. Adding them here
|
|
12
|
+
// means no shared C++ changes at all, and the names match
|
|
13
|
+
// microsoft/react-native-macos so code written against that fork type-checks
|
|
14
|
+
// and behaves the same.
|
|
15
|
+
|
|
16
|
+
#pragma once
|
|
17
|
+
|
|
18
|
+
#include <react/renderer/components/view/BaseViewProps.h>
|
|
19
|
+
#include <react/renderer/core/PropsParserContext.h>
|
|
20
|
+
|
|
21
|
+
#include <optional>
|
|
22
|
+
#include <string>
|
|
23
|
+
|
|
24
|
+
#include "HostPlatformViewEvents.h"
|
|
25
|
+
|
|
26
|
+
namespace facebook::react {
|
|
27
|
+
|
|
28
|
+
class HostPlatformViewProps : public BaseViewProps {
|
|
29
|
+
public:
|
|
30
|
+
HostPlatformViewProps() = default;
|
|
31
|
+
HostPlatformViewProps(
|
|
32
|
+
const PropsParserContext &context,
|
|
33
|
+
const HostPlatformViewProps &sourceProps,
|
|
34
|
+
const RawProps &rawProps);
|
|
35
|
+
|
|
36
|
+
void
|
|
37
|
+
setProp(const PropsParserContext &context, RawPropsPropNameHash hash, const char *propName, const RawValue &value);
|
|
38
|
+
|
|
39
|
+
/** Which macOS-only handlers are attached; see HostPlatformViewEvents. */
|
|
40
|
+
HostPlatformViewEvents hostPlatformEvents{};
|
|
41
|
+
|
|
42
|
+
#pragma mark - Props
|
|
43
|
+
|
|
44
|
+
/** Participates in the key view loop, i.e. reachable by Tab. */
|
|
45
|
+
bool focusable{false};
|
|
46
|
+
|
|
47
|
+
/** Draws the focus ring while first responder. On by default, as in AppKit. */
|
|
48
|
+
bool enableFocusRing{true};
|
|
49
|
+
|
|
50
|
+
/** The view's help tag. std::nullopt leaves any inherited tooltip alone. */
|
|
51
|
+
std::optional<std::string> tooltip{};
|
|
52
|
+
|
|
53
|
+
/** Take the click that activates a background window, rather than swallowing it. */
|
|
54
|
+
bool acceptsFirstMouse{false};
|
|
55
|
+
|
|
56
|
+
/** Let the view sit in an NSVisualEffectView and blend with what is behind it. */
|
|
57
|
+
bool allowsVibrancy{false};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Whether dragging the view moves the window. AppKit's default is true, and
|
|
61
|
+
* that is kept here: a view that opts out is the interesting case.
|
|
62
|
+
*/
|
|
63
|
+
bool mouseDownCanMoveWindow{true};
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// [macOS] Keyboard focus is a real thing on macOS, so unlike the shared C++
|
|
9
|
+
// initializer this reports `focusable` views as keyboard-focusable.
|
|
10
|
+
|
|
11
|
+
#pragma once
|
|
12
|
+
|
|
13
|
+
#include <react/renderer/components/view/ViewProps.h>
|
|
14
|
+
#include <react/renderer/core/ShadowNodeTraits.h>
|
|
15
|
+
|
|
16
|
+
namespace facebook::react::HostPlatformViewTraitsInitializer {
|
|
17
|
+
|
|
18
|
+
inline bool formsStackingContext(const ViewProps & /*props*/)
|
|
19
|
+
{
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
inline bool formsView(const ViewProps &props)
|
|
24
|
+
{
|
|
25
|
+
// These all need a backing NSView, so a view carrying any of them must not be
|
|
26
|
+
// flattened away: a focusable view has to join the key view loop, a tooltip
|
|
27
|
+
// has to attach to something, and mouse tracking needs an NSTrackingArea
|
|
28
|
+
// owner. Flattening is otherwise invisible -- the handler simply never fires.
|
|
29
|
+
return props.focusable || props.tooltip.has_value() || props.hostPlatformEvents.bits.any();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
inline bool isKeyboardFocusable(const ViewProps &props)
|
|
33
|
+
{
|
|
34
|
+
return props.focusable;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
} // namespace facebook::react::HostPlatformViewTraitsInitializer
|
package/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/HostPlatformColor.h
CHANGED
|
@@ -30,6 +30,12 @@ struct Color {
|
|
|
30
30
|
|
|
31
31
|
static Color createSemanticColor(std::vector<std::string> &semanticItems);
|
|
32
32
|
|
|
33
|
+
#if TARGET_OS_OSX // [macOS] Wrap an already-resolved NSColor. AppKit derives some
|
|
34
|
+
// colours from others -- colorWithSystemEffect: -- so the parser needs a way
|
|
35
|
+
// to hand back a colour it built itself. macOS]
|
|
36
|
+
static Color createFromHostPlatformColor(std::shared_ptr<void> hostPlatformColor);
|
|
37
|
+
#endif
|
|
38
|
+
|
|
33
39
|
std::shared_ptr<void> getUIColor() const
|
|
34
40
|
{
|
|
35
41
|
return uiColor_;
|
|
@@ -95,6 +95,13 @@ int32_t ColorFromColorComponents(const facebook::react::ColorComponents &compone
|
|
|
95
95
|
int32_t ColorFromUIColor(UIColor *color)
|
|
96
96
|
{
|
|
97
97
|
CGFloat rgba[4];
|
|
98
|
+
#if TARGET_OS_OSX // [macOS] catalog colours need converting first; see Color::getChannel
|
|
99
|
+
NSColor *rgbColor = [color colorUsingColorSpace:NSColorSpace.sRGBColorSpace];
|
|
100
|
+
if (rgbColor == nil) {
|
|
101
|
+
return 0;
|
|
102
|
+
}
|
|
103
|
+
color = rgbColor;
|
|
104
|
+
#endif // macOS]
|
|
98
105
|
[color getRed:&rgba[0] green:&rgba[1] blue:&rgba[2] alpha:&rgba[3]];
|
|
99
106
|
return ColorFromColorComponents(
|
|
100
107
|
{.red = (float)rgba[0], .green = (float)rgba[1], .blue = (float)rgba[2], .alpha = (float)rgba[3]});
|
|
@@ -226,6 +233,23 @@ float Color::getChannel(int channelId) const
|
|
|
226
233
|
{
|
|
227
234
|
CGFloat rgba[4];
|
|
228
235
|
UIColor *color = (__bridge UIColor *)getUIColor().get();
|
|
236
|
+
#if TARGET_OS_OSX // [macOS
|
|
237
|
+
// AppKit's named colours -- everything PlatformColor() resolves to, plus the
|
|
238
|
+
// system palette -- live in the Catalog colour space, and asking one for its
|
|
239
|
+
// RGBA components without converting first raises:
|
|
240
|
+
//
|
|
241
|
+
// -getRed:green:blue:alpha: not valid for the NSColor Catalog color
|
|
242
|
+
//
|
|
243
|
+
// sRGB is the right target: it is what the components are interpreted as
|
|
244
|
+
// everywhere else in the renderer.
|
|
245
|
+
NSColor *rgbColor = [color colorUsingColorSpace:NSColorSpace.sRGBColorSpace];
|
|
246
|
+
if (rgbColor == nil) {
|
|
247
|
+
// A pattern or otherwise unconvertible colour. Treat it as transparent
|
|
248
|
+
// rather than raising, which would take the whole app down.
|
|
249
|
+
return 0;
|
|
250
|
+
}
|
|
251
|
+
color = rgbColor;
|
|
252
|
+
#endif // macOS]
|
|
229
253
|
[color getRed:&rgba[0] green:&rgba[1] blue:&rgba[2] alpha:&rgba[3]];
|
|
230
254
|
return static_cast<float>(rgba[channelId]);
|
|
231
255
|
}
|
|
@@ -235,6 +259,13 @@ std::size_t Color::getUIColorHash() const
|
|
|
235
259
|
return uiColorHashValue_;
|
|
236
260
|
}
|
|
237
261
|
|
|
262
|
+
#if TARGET_OS_OSX // [macOS
|
|
263
|
+
Color Color::createFromHostPlatformColor(std::shared_ptr<void> hostPlatformColor)
|
|
264
|
+
{
|
|
265
|
+
return Color(std::move(hostPlatformColor));
|
|
266
|
+
}
|
|
267
|
+
#endif // macOS]
|
|
268
|
+
|
|
238
269
|
Color Color::createSemanticColor(std::vector<std::string> &semanticItems)
|
|
239
270
|
{
|
|
240
271
|
auto semanticColor = RCTPlatformColorFromSemanticItems(semanticItems);
|
|
@@ -63,6 +63,40 @@ SharedColor parsePlatformColor(const ContextContainer &contextContainer, int32_t
|
|
|
63
63
|
items.at("dynamic").hasType<std::unordered_map<std::string, RawValue>>()) {
|
|
64
64
|
auto dynamicItems = (std::unordered_map<std::string, RawValue>)items.at("dynamic");
|
|
65
65
|
return RCTPlatformColorComponentsFromDynamicItems(contextContainer, surfaceId, dynamicItems);
|
|
66
|
+
#if TARGET_OS_OSX // [macOS
|
|
67
|
+
} else if (
|
|
68
|
+
items.find("colorWithSystemEffect") != items.end() &&
|
|
69
|
+
items.at("colorWithSystemEffect").hasType<std::unordered_map<std::string, RawValue>>()) {
|
|
70
|
+
// AppKit derives the pressed / disabled / rollover variant of a colour
|
|
71
|
+
// rather than making the caller supply it. UIKit has no equivalent, so
|
|
72
|
+
// this arm only exists here.
|
|
73
|
+
auto effectItems = (std::unordered_map<std::string, RawValue>)items.at("colorWithSystemEffect");
|
|
74
|
+
if (effectItems.count("baseColor") == 0u || effectItems.count("systemEffect") == 0u) {
|
|
75
|
+
return clearColor();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
SharedColor baseSharedColor;
|
|
79
|
+
fromRawValue(contextContainer, surfaceId, effectItems.at("baseColor"), baseSharedColor);
|
|
80
|
+
auto effectName = (std::string)effectItems.at("systemEffect");
|
|
81
|
+
|
|
82
|
+
static const std::unordered_map<std::string, NSColorSystemEffect> effects = {
|
|
83
|
+
{"none", NSColorSystemEffectNone},
|
|
84
|
+
{"pressed", NSColorSystemEffectPressed},
|
|
85
|
+
{"deepPressed", NSColorSystemEffectDeepPressed},
|
|
86
|
+
{"disabled", NSColorSystemEffectDisabled},
|
|
87
|
+
{"rollover", NSColorSystemEffectRollover}};
|
|
88
|
+
|
|
89
|
+
auto effect = effects.find(effectName);
|
|
90
|
+
if (effect == effects.end()) {
|
|
91
|
+
return clearColor();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
NSColor *baseColor = RCTPlatformColorFromColor(*baseSharedColor);
|
|
95
|
+
if (baseColor == nil) {
|
|
96
|
+
return clearColor();
|
|
97
|
+
}
|
|
98
|
+
return SharedColor(Color::createFromHostPlatformColor(wrapManagedObject([baseColor colorWithSystemEffect:effect->second])));
|
|
99
|
+
#endif // macOS]
|
|
66
100
|
}
|
|
67
101
|
}
|
|
68
102
|
|
|
@@ -183,6 +183,13 @@ static inline NSString *_NSStringFromCString(
|
|
|
183
183
|
static inline facebook::react::ColorComponents _ColorComponentsFromUIColor(UIColor *color)
|
|
184
184
|
{
|
|
185
185
|
CGFloat rgba[4];
|
|
186
|
+
#if TARGET_OS_OSX // [macOS] catalog colours need converting first
|
|
187
|
+
NSColor *rgbColor = [color colorUsingColorSpace:NSColorSpace.sRGBColorSpace];
|
|
188
|
+
if (rgbColor == nil) {
|
|
189
|
+
return {.red = 0, .green = 0, .blue = 0, .alpha = 0};
|
|
190
|
+
}
|
|
191
|
+
color = rgbColor;
|
|
192
|
+
#endif // macOS]
|
|
186
193
|
[color getRed:&rgba[0] green:&rgba[1] blue:&rgba[2] alpha:&rgba[3]];
|
|
187
194
|
return {.red = (float)rgba[0], .green = (float)rgba[1], .blue = (float)rgba[2], .alpha = (float)rgba[3]};
|
|
188
195
|
}
|
|
@@ -204,6 +211,22 @@ UIColor *RCTPlatformColorFromSemanticItems(std::vector<std::string> &semanticIte
|
|
|
204
211
|
if (uiColor != nil) {
|
|
205
212
|
return uiColor;
|
|
206
213
|
}
|
|
214
|
+
#if TARGET_OS_OSX // [macOS
|
|
215
|
+
// _UIColorFromSemanticString only knows UIKit's vocabulary. AppKit's own --
|
|
216
|
+
// labelColor, controlAccentColor, windowBackgroundColor and the rest -- are
|
|
217
|
+
// class properties on NSColor, so asking NSColor directly covers all of
|
|
218
|
+
// them without a second table. Without this a macOS-only name silently
|
|
219
|
+
// resolves to clearColor and the view just renders transparent.
|
|
220
|
+
SEL appKitSelector = NSSelectorFromString(semanticNSString);
|
|
221
|
+
if (appKitSelector != nil && [UIColor respondsToSelector:appKitSelector]) {
|
|
222
|
+
IMP imp = [[UIColor class] methodForSelector:appKitSelector];
|
|
223
|
+
id (*getColor)(id, SEL) = (id (*)(id, SEL))imp;
|
|
224
|
+
id candidate = getColor([UIColor class], appKitSelector);
|
|
225
|
+
if ([candidate isKindOfClass:[UIColor class]]) {
|
|
226
|
+
return candidate;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
#endif // macOS]
|
|
207
230
|
}
|
|
208
231
|
|
|
209
232
|
return UIColor.clearColor;
|
package/index.js
CHANGED
|
@@ -270,6 +270,16 @@ module.exports = {
|
|
|
270
270
|
return require('./Libraries/StyleSheet/PlatformColorValueTypesIOS')
|
|
271
271
|
.DynamicColorIOS;
|
|
272
272
|
},
|
|
273
|
+
// [macOS] AppKit's appearance-aware and system-effect colours.
|
|
274
|
+
get DynamicColorMacOS() {
|
|
275
|
+
return require('./Libraries/StyleSheet/PlatformColorValueTypesMacOS')
|
|
276
|
+
.DynamicColorMacOS;
|
|
277
|
+
},
|
|
278
|
+
get ColorWithSystemEffectMacOS() {
|
|
279
|
+
return require('./Libraries/StyleSheet/PlatformColorValueTypesMacOS')
|
|
280
|
+
.ColorWithSystemEffectMacOS;
|
|
281
|
+
},
|
|
282
|
+
// macOS]
|
|
273
283
|
get Easing() {
|
|
274
284
|
return require('./Libraries/Animated/Easing').default;
|
|
275
285
|
},
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
#import "UIColor.h"
|
|
10
|
+
#import "UITraitCollection.h"
|
|
10
11
|
|
|
11
12
|
@implementation NSColor (UIKitCompat)
|
|
12
13
|
|
|
@@ -14,7 +15,12 @@
|
|
|
14
15
|
{
|
|
15
16
|
return [NSColor colorWithName:nil
|
|
16
17
|
dynamicProvider:^NSColor *(NSAppearance *appearance) {
|
|
17
|
-
|
|
18
|
+
// UIKit hands the provider a UITraitCollection and callers
|
|
19
|
+
// read -userInterfaceStyle and -accessibilityContrast off it.
|
|
20
|
+
// AppKit hands out an NSAppearance, which answers neither, so
|
|
21
|
+
// passing it straight through raises "unrecognized selector"
|
|
22
|
+
// the first time a dynamic colour is resolved.
|
|
23
|
+
return provider([UITraitCollection traitCollectionWithAppearance:appearance]);
|
|
18
24
|
}];
|
|
19
25
|
}
|
|
20
26
|
|