basalt-appkit 0.0.0-rc5
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/LICENSE +21 -0
- package/cli/runMacos.js +33 -0
- package/cli/shared.js +75 -0
- package/native/CMakeLists.txt +298 -0
- package/native/appkit/AppKitAnimationChoreographer.h +54 -0
- package/native/appkit/AppKitAnimationChoreographer.mm +125 -0
- package/native/appkit/AppKitDropTarget.h +34 -0
- package/native/appkit/AppKitDropTarget.mm +292 -0
- package/native/appkit/AppKitFocus.h +120 -0
- package/native/appkit/AppKitFocus.mm +293 -0
- package/native/appkit/AppKitImageLoader.h +80 -0
- package/native/appkit/AppKitImageLoader.mm +156 -0
- package/native/appkit/AppKitKeyEvents.h +26 -0
- package/native/appkit/AppKitKeyEvents.mm +97 -0
- package/native/appkit/AppKitMenuBar.mm +424 -0
- package/native/appkit/AppKitMountingManager.h +135 -0
- package/native/appkit/AppKitMountingManager.mm +946 -0
- package/native/appkit/AppKitRunLoopObserver.h +34 -0
- package/native/appkit/AppKitRunLoopObserver.mm +42 -0
- package/native/appkit/AppKitScrollView.h +168 -0
- package/native/appkit/AppKitScrollView.mm +550 -0
- package/native/appkit/AppKitSkiaContext.h +33 -0
- package/native/appkit/AppKitSkiaContext.mm +255 -0
- package/native/appkit/AppKitSkiaModule.h +53 -0
- package/native/appkit/AppKitSkiaModule.mm +81 -0
- package/native/appkit/AppKitSkiaPeer.h +37 -0
- package/native/appkit/AppKitSkiaPeer.mm +123 -0
- package/native/appkit/AppKitSkiaView.h +62 -0
- package/native/appkit/AppKitSnapshot.h +21 -0
- package/native/appkit/AppKitSnapshot.mm +91 -0
- package/native/appkit/AppKitTextInput.h +140 -0
- package/native/appkit/AppKitTextInput.mm +588 -0
- package/native/appkit/AppKitTextPeer.h +74 -0
- package/native/appkit/AppKitTextPeer.mm +353 -0
- package/native/appkit/AppKitTitleBar.h +90 -0
- package/native/appkit/AppKitTitleBar.mm +186 -0
- package/native/appkit/AppKitTouchDispatcher.h +138 -0
- package/native/appkit/AppKitTouchDispatcher.mm +514 -0
- package/native/appkit/AppKitWindowControl.mm +222 -0
- package/native/appkit/AppKitWindowModule.h +62 -0
- package/native/appkit/AppKitWindowModule.mm +194 -0
- package/native/appkit/ColorSchemeAppKit.mm +71 -0
- package/native/appkit/ComponentRegistryAppKit.mm +121 -0
- package/native/appkit/CoreTextLayout.h +43 -0
- package/native/appkit/CoreTextLayout.mm +252 -0
- package/native/appkit/CoreTextLayoutManager.mm +138 -0
- package/native/appkit/FontRegistryCoreText.mm +148 -0
- package/native/appkit/PlatformServicesAppKit.mm +540 -0
- package/native/appkit/RnAppKitView.h +417 -0
- package/native/appkit/RnAppKitView.mm +1605 -0
- package/native/appkit/RnTextLayout.h +38 -0
- package/native/appkit/RnTextLayout.mm +168 -0
- package/native/appkit/demo_layout_appkit.mm +93 -0
- package/native/appkit/main_appkit.mm +1860 -0
- package/native/appkit/mount_harness_appkit.mm +197 -0
- package/native/tests/test_appkit_accessibility.mm +170 -0
- package/native/tests/test_appkit_image.mm +237 -0
- package/native/tests/test_appkit_input.mm +852 -0
- package/native/tests/test_appkit_key_events.mm +150 -0
- package/native/tests/test_appkit_mounting.mm +430 -0
- package/native/tests/test_appkit_scrollbar.mm +132 -0
- package/native/tests/test_appkit_services.mm +57 -0
- package/native/tests/test_appkit_skia.mm +212 -0
- package/native/tests/test_appkit_text.mm +180 -0
- package/native/tests/test_appkit_textinput.mm +748 -0
- package/native/tests/test_appkit_titlebar.mm +107 -0
- package/native/tests/test_appkit_view.mm +237 -0
- package/package.json +26 -0
- package/react-native.config.js +22 -0
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
// The macOS view layer: an NSView that Fabric's mounting can drive.
|
|
2
|
+
//
|
|
3
|
+
// Deliberately the same shape as the GTK one in `gtk/RnView.h` -- a view owns a
|
|
4
|
+
// tag and an absolute frame, does no layout of its own, and places each child
|
|
5
|
+
// at the rect the shadow tree already resolved. Yoga has done the layout by the
|
|
6
|
+
// time a mutation arrives, and a second layout system underneath it is the
|
|
7
|
+
// thing to avoid, not to add.
|
|
8
|
+
//
|
|
9
|
+
// Two decisions are worth stating because they are easy to get wrong and hard
|
|
10
|
+
// to notice afterwards.
|
|
11
|
+
//
|
|
12
|
+
// The view is **flipped**. AppKit's default origin is bottom-left; React
|
|
13
|
+
// Native's is top-left, and every frame Fabric produces assumes top-left. An
|
|
14
|
+
// unflipped view renders a correct-looking layout upside down about its own
|
|
15
|
+
// centre, which reads as a mysterious ordering bug rather than a coordinate
|
|
16
|
+
// one.
|
|
17
|
+
//
|
|
18
|
+
// The view is **layer-backed**, and props are layer properties rather than
|
|
19
|
+
// drawing code. Background colour, opacity, corner radius, clipping and
|
|
20
|
+
// transform all exist on CALayer with the semantics React Native wants, so
|
|
21
|
+
// mapping onto them is both less code and closer to what the platform will do
|
|
22
|
+
// well. The GTK side has to compose these by hand in a snapshot; here it would
|
|
23
|
+
// be work to avoid using them.
|
|
24
|
+
|
|
25
|
+
#pragma once
|
|
26
|
+
|
|
27
|
+
#ifdef __OBJC__
|
|
28
|
+
#import <Cocoa/Cocoa.h>
|
|
29
|
+
|
|
30
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
31
|
+
|
|
32
|
+
@class RnAppKitView;
|
|
33
|
+
|
|
34
|
+
// Where a view sends the mouse.
|
|
35
|
+
//
|
|
36
|
+
// Set on the surface root only. A view that has no handler walks up to one that
|
|
37
|
+
// does, which is how every view in the tree feeds a single dispatcher without
|
|
38
|
+
// anything having to attach one per view -- the same arrangement the GTK side
|
|
39
|
+
// gets by putting its controllers on the root.
|
|
40
|
+
//
|
|
41
|
+
// Points arrive in the handler's own coordinates, which is the surface root's,
|
|
42
|
+
// which is what React Native calls the page.
|
|
43
|
+
//
|
|
44
|
+
// `button` is W3C's numbering rather than AppKit's selector-per-button, because
|
|
45
|
+
// that is what a pointer event carries and what decides whether the click
|
|
46
|
+
// presses anything at all. See core/PointerButtons.h.
|
|
47
|
+
@protocol RnAppKitInputHandler <NSObject>
|
|
48
|
+
- (void)rnMouseDownAt:(NSPoint)point button:(int)button;
|
|
49
|
+
- (void)rnMouseDraggedTo:(NSPoint)point;
|
|
50
|
+
- (void)rnMouseUpAt:(NSPoint)point button:(int)button;
|
|
51
|
+
// The pointer moving with no button down, and the pointer leaving the surface.
|
|
52
|
+
// Not part of React Native's touch model -- a finger that is not touching does
|
|
53
|
+
// not exist -- but it is what W3C pointer events call hover, and what
|
|
54
|
+
// `onPointerEnter` and friends are fed from. See core/HoverTracker.h.
|
|
55
|
+
- (void)rnMouseMovedTo:(NSPoint)point;
|
|
56
|
+
- (void)rnMouseExited;
|
|
57
|
+
@end
|
|
58
|
+
|
|
59
|
+
// Where a view sends a change of keyboard focus.
|
|
60
|
+
//
|
|
61
|
+
// Set on the surface root, like RnAppKitInputHandler, and found by walking up
|
|
62
|
+
// from whichever view gained or lost it. AppKit has no reliable notification
|
|
63
|
+
// for "the window's first responder changed" -- NSWindow's firstResponder is
|
|
64
|
+
// not KVO-observable -- so the views that can hold focus report it themselves.
|
|
65
|
+
@protocol RnAppKitFocusHandler <NSObject>
|
|
66
|
+
- (void)rnView:(RnAppKitView *)view didChangeFocus:(BOOL)focused;
|
|
67
|
+
// Enter or space on a focused view. Returns YES if it was handled, so a view
|
|
68
|
+
// with nothing listening passes the key on rather than swallowing it.
|
|
69
|
+
- (BOOL)rnActivateView:(RnAppKitView *)view;
|
|
70
|
+
// Tab and Shift-Tab. AppKit's own key-view loop cannot do this for a window
|
|
71
|
+
// built without a nib; see AppKitFocus.h.
|
|
72
|
+
- (BOOL)rnMoveFocusForward:(BOOL)forward;
|
|
73
|
+
// A key a view declared through `<KeyHandler>`. Returns YES if some view in the
|
|
74
|
+
// focus path claimed it, in which case the key is consumed; NO passes it on, and
|
|
75
|
+
// passing it on is what keeps the menu, a focused text field and a scrolling
|
|
76
|
+
// ancestor working. Asked through this protocol and not answered here because the
|
|
77
|
+
// registry is in core, which the view library does not link. See
|
|
78
|
+
// core/KeyEvents.h.
|
|
79
|
+
- (BOOL)rnView:(RnAppKitView *)view handlesKey:(NSEvent *)event;
|
|
80
|
+
@end
|
|
81
|
+
|
|
82
|
+
// Where a scrolling view sends the wheel.
|
|
83
|
+
//
|
|
84
|
+
// Set only on views that are ScrollViews. A view with none calls super, which
|
|
85
|
+
// walks the responder chain to an ancestor that has one -- so a wheel over a
|
|
86
|
+
// plain view inside a list scrolls the list, and a list inside a list scrolls
|
|
87
|
+
// the inner one first, which is what AppKit's own nesting does.
|
|
88
|
+
@protocol RnAppKitScrollHandler <NSObject>
|
|
89
|
+
// Returns YES if the scroll was consumed.
|
|
90
|
+
//
|
|
91
|
+
// Two phases, because a touchpad has two gestures in one stream. `phase` is
|
|
92
|
+
// the fingers: it begins when they land and ends when they lift. `momentum` is
|
|
93
|
+
// what the system keeps sending after they have gone, and it is the only
|
|
94
|
+
// reason React Native's `onMomentumScrollBegin` and `onMomentumScrollEnd` can
|
|
95
|
+
// be answered honestly on this platform -- macOS does the deceleration itself,
|
|
96
|
+
// so there is nothing here to model, only something to report.
|
|
97
|
+
- (BOOL)rnScrollView:(RnAppKitView *)view
|
|
98
|
+
by:(NSPoint)delta
|
|
99
|
+
precise:(BOOL)precise
|
|
100
|
+
phase:(NSEventPhase)phase
|
|
101
|
+
momentum:(NSEventPhase)momentum;
|
|
102
|
+
@end
|
|
103
|
+
|
|
104
|
+
// The deepest view at a point, in `root`'s coordinates, or nil for a miss.
|
|
105
|
+
//
|
|
106
|
+
// A free function because it is a pure function of the view tree and nothing
|
|
107
|
+
// else, which is also what makes it testable: hit testing is the part of input
|
|
108
|
+
// most likely to be quietly wrong, and it needs no mouse to exercise. It lives
|
|
109
|
+
// here rather than with the dispatcher so that testing it needs no React Native.
|
|
110
|
+
RnAppKitView *_Nullable RnAppKitHitTest(RnAppKitView *_Nullable root, CGFloat x, CGFloat y);
|
|
111
|
+
|
|
112
|
+
@interface RnAppKitView : NSView
|
|
113
|
+
|
|
114
|
+
// Fabric's tag for this view. Set once, at creation.
|
|
115
|
+
@property(nonatomic, readonly) NSInteger rnTag;
|
|
116
|
+
|
|
117
|
+
+ (instancetype)viewWithTag:(NSInteger)tag;
|
|
118
|
+
|
|
119
|
+
// The frame the shadow tree resolved, in the parent's coordinates, top-left
|
|
120
|
+
// origin. Applied directly: nothing here recomputes it.
|
|
121
|
+
- (void)setRnFrameX:(CGFloat)x y:(CGFloat)y width:(CGFloat)width height:(CGFloat)height;
|
|
122
|
+
|
|
123
|
+
// Components are premultiplied-free 0..1, as React Native's colour components
|
|
124
|
+
// arrive. Passing hasColor:NO means "no background", which is not the same as
|
|
125
|
+
// transparent black: a view with no background does not paint at all.
|
|
126
|
+
- (void)setRnBackgroundColorRed:(CGFloat)red
|
|
127
|
+
green:(CGFloat)green
|
|
128
|
+
blue:(CGFloat)blue
|
|
129
|
+
alpha:(CGFloat)alpha
|
|
130
|
+
hasColor:(BOOL)hasColor;
|
|
131
|
+
|
|
132
|
+
- (void)setRnOpacity:(CGFloat)opacity;
|
|
133
|
+
|
|
134
|
+
// React Native's transform, as sixteen floats in CSS `matrix3d` order -- which
|
|
135
|
+
// is CATransform3D's field order too, so the two are the same sixteen numbers
|
|
136
|
+
// in the same places. Null clears it.
|
|
137
|
+
//
|
|
138
|
+
// The anchor is the view's centre, which is what React Native means by an
|
|
139
|
+
// untouched `transformOrigin` and what a layer-backed NSView already uses.
|
|
140
|
+
- (void)setRnTransform:(nullable const float *)matrix;
|
|
141
|
+
|
|
142
|
+
// `backfaceVisibility: 'hidden'`. A view whose transform has turned it away
|
|
143
|
+
// from the viewer is not drawn at all -- nor are its children, which is what
|
|
144
|
+
// CALayer's own `doubleSided` does and what a card's back should do.
|
|
145
|
+
//
|
|
146
|
+
// Whether it has turned away is `basalt::facesAway`; see core/Backface.h for
|
|
147
|
+
// why the rule is shared rather than left to each toolkit.
|
|
148
|
+
- (void)setRnHidesBackFace:(BOOL)hides;
|
|
149
|
+
|
|
150
|
+
// `display: 'none'`. Separate from the back face above because the two are
|
|
151
|
+
// independent reasons to hide the same view, and Fabric applies them through
|
|
152
|
+
// different calls -- props, then layout metrics. Setting `hidden` directly
|
|
153
|
+
// from either one made the later call answer for both, which is why a view
|
|
154
|
+
// turned away from the viewer came back the moment its layout was applied.
|
|
155
|
+
- (void)setRnHidden:(BOOL)hidden;
|
|
156
|
+
|
|
157
|
+
// How an image fills its frame. Mirrors React Native's ImageResizeMode, minus
|
|
158
|
+
// Repeat, which needs a tiled draw rather than one image draw.
|
|
159
|
+
// Accessible states. Each is a tri-state: unset leaves AppKit's default alone,
|
|
160
|
+
// which is not the same as setting it false.
|
|
161
|
+
typedef NS_ENUM(NSInteger, RnAppKitAccessibleFlag) {
|
|
162
|
+
RnAppKitAccessibleUnset,
|
|
163
|
+
RnAppKitAccessibleFalse,
|
|
164
|
+
RnAppKitAccessibleTrue,
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// `pointerEvents`, which decides what a press can land on rather than what is
|
|
168
|
+
// drawn. CSS's four values, and React Native's: a view is a target, or it is
|
|
169
|
+
// not, or its children are and it is not, or it is and they are not.
|
|
170
|
+
//
|
|
171
|
+
// Here rather than in the mounting manager because hit testing is a pure
|
|
172
|
+
// function of the view tree -- `RnAppKitHitTest` takes no React Native types
|
|
173
|
+
// and has nowhere to look a prop up.
|
|
174
|
+
typedef NS_ENUM(NSInteger, RnAppKitPointerEvents) {
|
|
175
|
+
RnAppKitPointerEventsAuto,
|
|
176
|
+
RnAppKitPointerEventsNone,
|
|
177
|
+
RnAppKitPointerEventsBoxNone,
|
|
178
|
+
RnAppKitPointerEventsBoxOnly,
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
typedef NS_ENUM(NSInteger, RnAppKitImageFit) {
|
|
182
|
+
RnAppKitImageFitCover,
|
|
183
|
+
RnAppKitImageFitContain,
|
|
184
|
+
RnAppKitImageFitStretch,
|
|
185
|
+
RnAppKitImageFitCenter,
|
|
186
|
+
// Tiled from the top left at the image's own size, which is what CSS
|
|
187
|
+
// `repeat` and React Native's `resizeMode: 'repeat'` mean.
|
|
188
|
+
RnAppKitImageFitRepeat,
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
// The decoded pixels of an <Image>. Pass nil to clear.
|
|
192
|
+
//
|
|
193
|
+
// A CGImage rather than a React Native type, so the view layer stays free of
|
|
194
|
+
// React Native headers -- the same arrangement the text layout has.
|
|
195
|
+
// AppKitImageLoader produces the image and AppKitMountingManager chooses the
|
|
196
|
+
// fit.
|
|
197
|
+
- (void)setRnImage:(nullable CGImageRef)image fit:(RnAppKitImageFit)fit;
|
|
198
|
+
|
|
199
|
+
// `tintColor`: recolours the image, keeping its alpha, so one silhouette asset
|
|
200
|
+
// can be drawn in any colour. Pass nil to clear.
|
|
201
|
+
//
|
|
202
|
+
// Separate from the image because the tint arrives from the props and the image
|
|
203
|
+
// from a loader, and either can land first.
|
|
204
|
+
- (void)setRnImageTint:(nullable NSColor *)tint;
|
|
205
|
+
|
|
206
|
+
// The paragraph this view draws, or nil for a view that draws none.
|
|
207
|
+
//
|
|
208
|
+
// A view either paints a layer or draws text; nothing here does both, because
|
|
209
|
+
// React Native's <Text> is a Paragraph node with no children of its own. Held
|
|
210
|
+
// as an opaque object so this header stays free of Core Text -- see
|
|
211
|
+
// RnTextLayout.h for the object, and CoreTextLayout.h for what builds one --
|
|
212
|
+
// both the mounting manager and the measurement seam go through that, so the
|
|
213
|
+
// size a view draws at is the size Yoga was told.
|
|
214
|
+
- (void)setRnTextLayout:(nullable id)layout;
|
|
215
|
+
- (void)setRnClipsChildren:(BOOL)clips;
|
|
216
|
+
|
|
217
|
+
// `zIndex`. Reorders painting and hit testing, and never the child list --
|
|
218
|
+
// Fabric's Insert and Remove carry an index into that list, so it has to stay
|
|
219
|
+
// in mutation order. Equal values keep document order, which is what CSS and
|
|
220
|
+
// React Native both promise.
|
|
221
|
+
- (void)setRnZIndex:(NSInteger)zIndex;
|
|
222
|
+
@property(nonatomic, readonly) NSInteger rnZIndex;
|
|
223
|
+
|
|
224
|
+
// `pointerEvents`. Read by RnAppKitHitTest and by nothing else -- it changes
|
|
225
|
+
// what a press finds and never what is drawn.
|
|
226
|
+
@property(nonatomic) RnAppKitPointerEvents rnPointerEvents;
|
|
227
|
+
|
|
228
|
+
// Whether this view takes keyboard focus, and therefore whether Tab stops on
|
|
229
|
+
// it.
|
|
230
|
+
//
|
|
231
|
+
// React Native has a `focusable` prop and it does not reach this platform:
|
|
232
|
+
// ReactCommon parses it only into Android's and tvOS's HostPlatformViewProps,
|
|
233
|
+
// and the C++ host's is a bare alias of BaseViewProps. What does reach here is
|
|
234
|
+
// `accessible`, which is what <Pressable> sets on everything it renders. See
|
|
235
|
+
// AppKitFocus.h.
|
|
236
|
+
//
|
|
237
|
+
// AppKit owns the chain: a view that accepts first responder status joins the
|
|
238
|
+
// window's key-view loop, so Tab and Shift+Tab work without this project
|
|
239
|
+
// deciding what "next" means.
|
|
240
|
+
@property(nonatomic) BOOL rnFocusable;
|
|
241
|
+
|
|
242
|
+
// This view's children in the order they paint: back to front, stably sorted
|
|
243
|
+
// by zIndex. The same list hit testing walks in reverse, so what is on top is
|
|
244
|
+
// what is hit -- the Win32 host pairs them the same way.
|
|
245
|
+
- (NSArray<RnAppKitView *> *)rnChildrenInPaintOrder;
|
|
246
|
+
|
|
247
|
+
// This view's placement in its parent: the frame's translation with the
|
|
248
|
+
// transform composed in, anchored at the centre.
|
|
249
|
+
//
|
|
250
|
+
// Public for one reason, which is the same reason Win32's `localToParent` is:
|
|
251
|
+
// hit testing inverts this, so deriving it anywhere else would let the two end
|
|
252
|
+
// up with different ideas of where a view is. A transform that is not affine --
|
|
253
|
+
// perspective -- has no 2D inverse, and this answers with the translation
|
|
254
|
+
// alone, which is what hit testing did for every transform before this existed.
|
|
255
|
+
- (CGAffineTransform)rnLocalToParent;
|
|
256
|
+
|
|
257
|
+
// A point in `root`'s coordinates, expressed in this view's own.
|
|
258
|
+
//
|
|
259
|
+
// Walks up composing `rnLocalToParent` and inverts the chain, which is the
|
|
260
|
+
// same matrix the hit test inverts one level at a time on the way down -- so a
|
|
261
|
+
// press and the coordinates it reports cannot disagree about where a view is.
|
|
262
|
+
//
|
|
263
|
+
// Not `-[NSView convertPoint:fromView:]`, which ignores the layer transform
|
|
264
|
+
// and so answers for a rotated view as though it were not rotated.
|
|
265
|
+
//
|
|
266
|
+
// NO when the chain has no inverse, which `scale: 0` produces and which has no
|
|
267
|
+
// sensible point in it; `out` is untouched then.
|
|
268
|
+
- (BOOL)rnPageToLocal:(NSPoint)page
|
|
269
|
+
fromRoot:(nullable RnAppKitView *)root
|
|
270
|
+
into:(NSPoint *)out;
|
|
271
|
+
- (void)setRnCornerRadius:(CGFloat)radius;
|
|
272
|
+
|
|
273
|
+
// Per-corner radii, as four (horizontal, vertical) pairs -- eight floats -- in
|
|
274
|
+
// the order top-left, top-right, bottom-right, bottom-left. React Native's
|
|
275
|
+
// radii are elliptical and CALayer's single `cornerRadius` cannot express
|
|
276
|
+
// that, so anything a plain cornerRadius cannot say is applied as a mask layer
|
|
277
|
+
// instead. Null clears them. `setRnCornerRadius:` is the uniform-circular
|
|
278
|
+
// shorthand and goes through here.
|
|
279
|
+
- (void)setRnBorderRadii:(nullable const CGFloat *)radii;
|
|
280
|
+
|
|
281
|
+
// Per-edge border widths and colours, in the order top, right, bottom, left --
|
|
282
|
+
// the order CSS names them, and the order the GTK and Win32 sides store them
|
|
283
|
+
// in. `widths` is four floats; `colors` is sixteen, four RGBA quadruples in
|
|
284
|
+
// the same edge order. Either being null clears the border.
|
|
285
|
+
- (void)setRnBorderWidths:(nullable const CGFloat *)widths
|
|
286
|
+
colors:(nullable const CGFloat *)colors;
|
|
287
|
+
|
|
288
|
+
// Fabric's Insert and Remove carry an index into the parent's child list, so
|
|
289
|
+
// that list has to stay in mutation order.
|
|
290
|
+
- (void)insertRnChild:(RnAppKitView *)child atIndex:(NSInteger)index;
|
|
291
|
+
- (void)removeRnChild:(RnAppKitView *)child;
|
|
292
|
+
|
|
293
|
+
// The same one-line-per-view format the GTK side produces, so the two can be
|
|
294
|
+
// compared and eventually asserted on by the same tests.
|
|
295
|
+
// --- React DevTools' overlay --------------------------------------------------
|
|
296
|
+
//
|
|
297
|
+
// The rectangles a `DebuggingOverlay` draws: an inspected element's blue box,
|
|
298
|
+
// or an outline around everything that just re-rendered. Set from
|
|
299
|
+
// AppKitMountingManager, which parses them; see core/DebuggingOverlay.h.
|
|
300
|
+
//
|
|
301
|
+
// Eight numbers per rectangle -- x, y, width, height, then r, g, b, a -- and a
|
|
302
|
+
// flag per rectangle for whether to fill. Plain arrays rather than the core
|
|
303
|
+
// struct because this file has no React Native in it.
|
|
304
|
+
- (void)setRnHighlights:(nullable const float *)rectangles
|
|
305
|
+
filled:(nullable const bool *)filled
|
|
306
|
+
count:(NSInteger)count;
|
|
307
|
+
|
|
308
|
+
// Accessibility, as a screen reader sees it.
|
|
309
|
+
//
|
|
310
|
+
// The role arrives as React Native's own string -- "button", "image", "text" --
|
|
311
|
+
// rather than as an NSAccessibilityRole, and the view maps it. Two reasons.
|
|
312
|
+
// The mapping is a platform decision and belongs beside the platform; and the
|
|
313
|
+
// string is what `describeTree` reports, so the two hosts' trees can be
|
|
314
|
+
// compared without one of them speaking AppKit's vocabulary and the other
|
|
315
|
+
// speaking GTK's.
|
|
316
|
+
//
|
|
317
|
+
// Pass nil or an empty string for no role, which is what a plain <View> is.
|
|
318
|
+
- (void)setRnAccessibleRole:(nullable NSString *)role;
|
|
319
|
+
|
|
320
|
+
// `label` is the accessible name and `hint` the description; either may be nil
|
|
321
|
+
// or empty to leave it unset.
|
|
322
|
+
- (void)setRnAccessibleLabel:(nullable NSString *)label hint:(nullable NSString *)hint;
|
|
323
|
+
|
|
324
|
+
// Accessible states. Each is a tri-state: unset leaves AppKit's default alone,
|
|
325
|
+
// which is not the same as setting it false.
|
|
326
|
+
|
|
327
|
+
- (void)setRnAccessibleStateDisabled:(RnAppKitAccessibleFlag)disabled
|
|
328
|
+
checked:(RnAppKitAccessibleFlag)checked
|
|
329
|
+
selected:(RnAppKitAccessibleFlag)selected
|
|
330
|
+
expanded:(RnAppKitAccessibleFlag)expanded
|
|
331
|
+
busy:(RnAppKitAccessibleFlag)busy;
|
|
332
|
+
|
|
333
|
+
// Hidden from assistive technology, for accessible={false} and
|
|
334
|
+
// accessibilityElementsHidden.
|
|
335
|
+
- (void)setRnAccessibleHidden:(BOOL)hidden;
|
|
336
|
+
|
|
337
|
+
// The app's `nativeID`, which this platform uses to mark a view for a native
|
|
338
|
+
// behaviour it has no React Native prop for -- today, a drop target. See
|
|
339
|
+
// core/DragAndDrop.h, and core/TitleBarRegions.h for the older use of the
|
|
340
|
+
// same idea. Stored and never drawn.
|
|
341
|
+
@property(nonatomic, copy, nullable) NSString *rnNativeId;
|
|
342
|
+
|
|
343
|
+
// Set on the surface root. See RnAppKitInputHandler.
|
|
344
|
+
@property(nonatomic, weak, nullable) id<RnAppKitInputHandler> rnInputHandler;
|
|
345
|
+
|
|
346
|
+
// Set on the surface root. See RnAppKitFocusHandler.
|
|
347
|
+
@property(nonatomic, weak, nullable) id<RnAppKitFocusHandler> rnFocusHandler;
|
|
348
|
+
|
|
349
|
+
// The text field this view hosts, for <TextInput>.
|
|
350
|
+
//
|
|
351
|
+
// Set by AppKitTextInputManager, which owns it and positions it; the view only
|
|
352
|
+
// reads it, to report the field's contents in `describeTree`. Held weakly so a
|
|
353
|
+
// deleted field is not kept alive by the view that was showing it.
|
|
354
|
+
//
|
|
355
|
+
// A real NSTextField rather than a caret drawn on a paragraph: that brings
|
|
356
|
+
// input methods, selection, the clipboard and every key binding a Mac user
|
|
357
|
+
// expects, none of which is worth reimplementing and all of which is easy to
|
|
358
|
+
// get subtly wrong. The GTK side embeds a real GtkText for the same reason.
|
|
359
|
+
// The <TextInput> peer: an NSTextField for a single-line field and an
|
|
360
|
+
// NSTextView for a multiline one. See AppKitTextPeer.h.
|
|
361
|
+
@property(nonatomic, weak, nullable) NSView *rnEditable;
|
|
362
|
+
|
|
363
|
+
// --- Controls ----------------------------------------------------------------
|
|
364
|
+
//
|
|
365
|
+
// The three components that are a toolkit control rather than a box:
|
|
366
|
+
// <ActivityIndicator> and <RefreshControl> are an NSProgressIndicator,
|
|
367
|
+
// <Switch> is an NSSwitch. Held the same way the text peer above is -- weakly,
|
|
368
|
+
// because the subview relationship is what owns it -- and for the same reason:
|
|
369
|
+
// AppKit's own control brings the theme, the animation and the accessibility
|
|
370
|
+
// with it.
|
|
371
|
+
typedef NS_ENUM(NSInteger, RnAppKitControlKind) {
|
|
372
|
+
RnAppKitControlNone = 0,
|
|
373
|
+
RnAppKitControlSpinner,
|
|
374
|
+
RnAppKitControlSwitch,
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
@property(nonatomic, weak, nullable) NSView *rnControl;
|
|
378
|
+
@property(nonatomic) RnAppKitControlKind rnControlKind;
|
|
379
|
+
|
|
380
|
+
// What `describeTree` prints for this control, written by
|
|
381
|
+
// core/DesktopControls.h so that three hosts cannot describe the same switch
|
|
382
|
+
// differently.
|
|
383
|
+
@property(nonatomic, copy, nullable) NSString *rnControlDescription;
|
|
384
|
+
|
|
385
|
+
// Set on ScrollViews only. See RnAppKitScrollHandler.
|
|
386
|
+
@property(nonatomic, weak, nullable) id<RnAppKitScrollHandler> rnScrollHandler;
|
|
387
|
+
|
|
388
|
+
// Shifts this view's children by (-x, -y), which is how a ScrollView scrolls.
|
|
389
|
+
//
|
|
390
|
+
// Through `bounds.origin` rather than by moving every child: AppKit then shifts
|
|
391
|
+
// drawing, hit testing and the clip together, and the frames the mounting
|
|
392
|
+
// manager wrote stay exactly the ones Yoga produced. The GTK side does the same
|
|
393
|
+
// thing by shifting children in its layout manager, for the same reason --
|
|
394
|
+
// React Native decides sizes, and the platform only places.
|
|
395
|
+
- (void)setRnScrollOffsetX:(CGFloat)x y:(CGFloat)y;
|
|
396
|
+
- (NSPoint)rnScrollOffset;
|
|
397
|
+
|
|
398
|
+
// The overlay scrollbars, as core/ScrollIndicator.h decides them: an offset
|
|
399
|
+
// along the track and a length, per axis, with a length of zero meaning "do not
|
|
400
|
+
// draw one".
|
|
401
|
+
//
|
|
402
|
+
// Drawn by a subview kept above every React child rather than in `drawRect:`,
|
|
403
|
+
// because AppKit paints subviews over their superview and a ScrollView's whole
|
|
404
|
+
// job is to have one covering it. That view is not an RnAppKitView, so it stays
|
|
405
|
+
// out of the paint order, out of hit testing and out of `describeTree`'s
|
|
406
|
+
// children -- the numbers are reported on the ScrollView's own line instead.
|
|
407
|
+
- (void)setRnScrollIndicatorVerticalOffset:(CGFloat)verticalOffset
|
|
408
|
+
verticalLength:(CGFloat)verticalLength
|
|
409
|
+
horizontalOffset:(CGFloat)horizontalOffset
|
|
410
|
+
horizontalLength:(CGFloat)horizontalLength;
|
|
411
|
+
|
|
412
|
+
- (NSString *)describeTree;
|
|
413
|
+
|
|
414
|
+
@end
|
|
415
|
+
|
|
416
|
+
NS_ASSUME_NONNULL_END
|
|
417
|
+
#endif
|