not-react-native-macos 0.87.1-rc.3 → 0.87.1-rc.5

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.
Files changed (25) hide show
  1. package/Libraries/Components/View/ViewPropTypes.js +91 -0
  2. package/Libraries/NativeComponent/BaseViewConfig.macos.js +68 -11
  3. package/Libraries/NativeComponent/ViewConfigIgnore.js +5 -1
  4. package/Libraries/StyleSheet/PlatformColorValueTypes.macos.js +147 -10
  5. package/Libraries/StyleSheet/PlatformColorValueTypesMacOS.js +34 -0
  6. package/Libraries/StyleSheet/PlatformColorValueTypesMacOS.macos.js +55 -0
  7. package/Libraries/Types/CoreEventTypes.js +11 -0
  8. package/React/Base/RCTConvert.mm +49 -0
  9. package/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm +294 -0
  10. package/ReactCommon/React-Fabric.podspec +9 -0
  11. package/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformTouch.h +16 -0
  12. package/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEventEmitter.cpp +74 -0
  13. package/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEventEmitter.h +52 -0
  14. package/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEvents.h +61 -0
  15. package/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.cpp +121 -0
  16. package/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.h +76 -0
  17. package/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewTraitsInitializer.h +38 -0
  18. package/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/KeyEvent.h +100 -0
  19. package/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/HostPlatformColor.h +6 -0
  20. package/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/HostPlatformColor.mm +31 -0
  21. package/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/PlatformColorParser.mm +34 -0
  22. package/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/RCTPlatformColorUtils.mm +23 -0
  23. package/index.js +10 -0
  24. package/macos/UIKitCompat/UIKit/UIColor.m +7 -1
  25. package/package.json +1 -1
@@ -128,6 +128,96 @@ 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
+ /**
136
+ * A key the view means to act on itself. A modifier left out is a wildcard:
137
+ * `{key: 'c'}` matches Cmd-C and a bare c alike.
138
+ *
139
+ * @platform macos
140
+ */
141
+ export type HandledKeyEvent = Readonly<{
142
+ key: string,
143
+ altKey?: ?boolean,
144
+ ctrlKey?: ?boolean,
145
+ metaKey?: ?boolean,
146
+ shiftKey?: ?boolean,
147
+ }>;
148
+
149
+ type MacOSViewProps = Readonly<{
150
+ /**
151
+ * Keys this view handles itself, suppressing AppKit's own interpretation of
152
+ * them -- Tab moving focus, Escape cancelling, an unclaimed key beeping.
153
+ *
154
+ * Separate from `onKeyDown`, deliberately: listening to a key does not change
155
+ * what it does, so a view that observes Tab still lets Tab move focus. Only
156
+ * listing a key here claims it.
157
+ *
158
+ * @platform macos
159
+ */
160
+ keyDownEvents?: ?$ReadOnlyArray<HandledKeyEvent>,
161
+
162
+ /**
163
+ * As `keyDownEvents`, for key release.
164
+ *
165
+ * @platform macos
166
+ */
167
+ keyUpEvents?: ?$ReadOnlyArray<HandledKeyEvent>,
168
+
169
+ /**
170
+ * The view's help tag, shown when the pointer rests over it.
171
+ *
172
+ * @platform macos
173
+ */
174
+ tooltip?: ?string,
175
+
176
+ /**
177
+ * Receive the click that activates a background window, rather than letting
178
+ * it be swallowed to bring the window forward.
179
+ *
180
+ * @platform macos
181
+ */
182
+ acceptsFirstMouse?: ?boolean,
183
+
184
+ /**
185
+ * Let the view blend with what is behind it when inside a vibrancy effect.
186
+ *
187
+ * @platform macos
188
+ */
189
+ allowsVibrancy?: ?boolean,
190
+
191
+ /**
192
+ * Draw the focus ring while the view is first responder. Defaults to true.
193
+ *
194
+ * @platform macos
195
+ */
196
+ enableFocusRing?: ?boolean,
197
+
198
+ /**
199
+ * Whether dragging the view moves the window. AppKit defaults this to true;
200
+ * set it false for a view that should handle its own drags.
201
+ *
202
+ * @platform macos
203
+ */
204
+ mouseDownCanMoveWindow?: ?boolean,
205
+
206
+ /**
207
+ * Called on a double click.
208
+ *
209
+ * @platform macos
210
+ */
211
+ onDoubleClick?: ?(event: MouseEvent) => void,
212
+
213
+ /**
214
+ * Called on a secondary (right) click.
215
+ *
216
+ * @platform macos
217
+ */
218
+ onAuxClick?: ?(event: MouseEvent) => void,
219
+ }>;
220
+
131
221
  type KeyEventProps = Readonly<{
132
222
  onKeyDown?: ?(event: KeyDownEvent) => void,
133
223
  onKeyDownCapture?: ?(event: KeyDownEvent) => void,
@@ -566,6 +656,7 @@ export type ViewProps = Readonly<{
566
656
  ...DirectEventProps,
567
657
  ...GestureResponderHandlers,
568
658
  ...MouseEventProps,
659
+ ...MacOSViewProps, // [macOS]
569
660
  ...PointerEventProps,
570
661
  ...FocusEventProps,
571
662
  ...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,73 @@
8
8
  * @format
9
9
  */
10
10
 
11
- // [macOS] macOS resolves as `.macos` -> `.native` -> shared, so without this
12
- // file `BaseViewConfig` re-exports itself: the shared file is a
13
- // stub that expects a platform-suffixed sibling to answer. Point it at the iOS
14
- // implementation, which is what this fork uses on macOS wherever upstream has
15
- // no platform-neutral one. macOS]
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
- // 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".
19
+ import type {PartialViewConfigWithoutName} from './PlatformBaseViewConfig';
20
20
 
21
- import BaseViewConfig from './BaseViewConfig.ios';
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
- export default BaseViewConfig;
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
+ keyDownEvents: true,
55
+ keyUpEvents: true,
56
+ mouseDownCanMoveWindow: true,
57
+ tooltip: true,
58
+ };
59
+
60
+ const validAttributesForEventProps = ConditionallyIgnoredEventHandlers({
61
+ onAuxClick: true,
62
+ onDoubleClick: true,
63
+ onKeyDown: true,
64
+ onKeyUp: true,
65
+ onMouseEnter: true,
66
+ onMouseLeave: true,
67
+ });
68
+
69
+ const PlatformBaseViewConfigMacOS: PartialViewConfigWithoutName = {
70
+ bubblingEventTypes,
71
+ directEventTypes,
72
+ validAttributes: {
73
+ ...PlatformBaseViewConfigIOS.validAttributes,
74
+ ...validAttributesForNonEventProps,
75
+ // $FlowFixMe[exponential-spread]
76
+ ...validAttributesForEventProps,
77
+ },
78
+ };
79
+
80
+ 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
- if (Platform.OS === 'ios') {
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 resolves as `.macos` -> `.native` -> shared, so without this
12
- // file `PlatformColorValueTypes` re-exports itself: the shared file is a
13
- // stub that expects a platform-suffixed sibling to answer. Point it at the iOS
14
- // implementation, which is what this fork uses on macOS wherever upstream has
15
- // no platform-neutral one. macOS]
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
- export * from './PlatformColorValueTypes.ios';
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
+ };
@@ -351,6 +351,17 @@ export type KeyEvent = Readonly<{
351
351
  * @see https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent/isComposing
352
352
  */
353
353
  isComposing?: boolean,
354
+ // [macOS] Modifiers AppKit reports and no other platform has. Optional, so
355
+ // shared code that never reads them is unaffected.
356
+ /** @platform macos */
357
+ capsLockKey?: boolean,
358
+ /** @platform macos */
359
+ numericPadKey?: boolean,
360
+ /** @platform macos */
361
+ helpKey?: boolean,
362
+ /** @platform macos */
363
+ functionKey?: boolean,
364
+ // macOS]
354
365
  }>;
355
366
 
356
367
  export type KeyUpEvent = NativeSyntheticEvent<KeyEvent>;
@@ -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;