basalt-appkit 0.0.0-rc5 → 0.2.0
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/native/CMakeLists.txt +16 -2
- package/native/appkit/AppKitAppWindow.h +24 -0
- package/native/appkit/AppKitImageLoader.h +48 -1
- package/native/appkit/AppKitImageLoader.mm +228 -10
- package/native/appkit/AppKitMenuBar.mm +58 -0
- package/native/appkit/AppKitMountingManager.h +34 -0
- package/native/appkit/AppKitMountingManager.mm +582 -12
- package/native/appkit/AppKitScrollView.h +48 -0
- package/native/appkit/AppKitScrollView.mm +210 -0
- package/native/appkit/AppKitSkiaPeer.h +15 -0
- package/native/appkit/AppKitTextInput.h +38 -1
- package/native/appkit/AppKitTextInput.mm +235 -8
- package/native/appkit/AppKitTextPeer.h +60 -0
- package/native/appkit/AppKitTextPeer.mm +307 -0
- package/native/appkit/AppKitTouchDispatcher.h +56 -0
- package/native/appkit/AppKitTouchDispatcher.mm +140 -0
- package/native/appkit/AppKitWindowControl.mm +38 -3
- package/native/appkit/ComponentRegistryAppKit.mm +28 -3
- package/native/appkit/CoreTextLayout.h +64 -2
- package/native/appkit/CoreTextLayout.mm +431 -71
- package/native/appkit/CoreTextLayoutManager.mm +57 -6
- package/native/appkit/FontRegistryCoreText.mm +6 -5
- package/native/appkit/PlatformServicesAppKit.mm +101 -20
- package/native/appkit/RnAppKitView.h +492 -0
- package/native/appkit/RnAppKitView.mm +2266 -23
- package/native/appkit/RnTextLayout.h +106 -0
- package/native/appkit/RnTextLayout.mm +321 -2
- package/native/appkit/main_appkit.mm +174 -3
- package/native/tests/test_appkit_accessibility.mm +289 -0
- package/native/tests/test_appkit_borders.mm +975 -0
- package/native/tests/test_appkit_fonts.mm +203 -0
- package/native/tests/test_appkit_image.mm +392 -17
- package/native/tests/test_appkit_input.mm +209 -0
- package/native/tests/test_appkit_mounting.mm +360 -0
- package/native/tests/test_appkit_scrollbar.mm +125 -0
- package/native/tests/test_appkit_scrollview.mm +371 -0
- package/native/tests/test_appkit_selection.mm +349 -0
- package/native/tests/test_appkit_services.mm +51 -1
- package/native/tests/test_appkit_text.mm +1628 -0
- package/native/tests/test_appkit_textinput.mm +819 -0
- package/native/tests/test_appkit_titlebar.mm +43 -0
- package/native/tests/test_appkit_view.mm +609 -0
- package/package.json +4 -3
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
#include <vector>
|
|
15
15
|
#include "WindowControl.h"
|
|
16
16
|
|
|
17
|
+
#import "AppKitAppWindow.h"
|
|
18
|
+
|
|
17
19
|
#import <Cocoa/Cocoa.h>
|
|
18
20
|
|
|
19
21
|
namespace basalt {
|
|
@@ -21,9 +23,27 @@ namespace basalt {
|
|
|
21
23
|
namespace {
|
|
22
24
|
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
// The window this process owns, which is a different question from which window
|
|
27
|
+
// has the keyboard.
|
|
28
|
+
//
|
|
29
|
+
// `NSApp.keyWindow` and `NSApp.mainWindow` are both nil whenever the app is not
|
|
30
|
+
// the active one: a background app has no key window and no main window. Asking
|
|
31
|
+
// only those two meant an app that was not frontmost read a *zero* size out of
|
|
32
|
+
// `getBounds()` and had `setSize` silently do nothing.
|
|
33
|
+
//
|
|
34
|
+
// That is worse than it sounds, because the bounds cache is primed once at
|
|
35
|
+
// startup, immediately after `activateIgnoringOtherApps:`, and activation is
|
|
36
|
+
// asynchronous. If the window server had not granted it by then the cache was
|
|
37
|
+
// zeroed, and nothing corrected it: the only thing that writes the cache again
|
|
38
|
+
// is a move or a resize, and a window nobody is using gets neither. An app
|
|
39
|
+
// launched while another window had focus therefore believed it was 0x0 for its
|
|
40
|
+
// whole life, which is how `e2e/window.tsx` found this.
|
|
41
|
+
//
|
|
42
|
+
// GTK had the rule right already -- GtkWindowControl.cpp prefers the active
|
|
43
|
+
// toplevel and falls back to the first visible one -- so this is the same rule
|
|
44
|
+
// rather than a new idea. A panel is skipped: LogBox and the dev menu are
|
|
45
|
+
// windows too, and neither is what an app means by "my window".
|
|
46
|
+
NSWindow *window() { return appWindow(); }
|
|
27
47
|
|
|
28
48
|
// The height AppKit measures y from. `NSScreen.screens.firstObject` is the
|
|
29
49
|
// primary display, which is the one AppKit's global coordinates are anchored
|
|
@@ -35,6 +55,21 @@ CGFloat primaryHeight() {
|
|
|
35
55
|
|
|
36
56
|
} // namespace
|
|
37
57
|
|
|
58
|
+
NSWindow *appWindow() {
|
|
59
|
+
if (NSApp.keyWindow != nil) {
|
|
60
|
+
return NSApp.keyWindow;
|
|
61
|
+
}
|
|
62
|
+
if (NSApp.mainWindow != nil) {
|
|
63
|
+
return NSApp.mainWindow;
|
|
64
|
+
}
|
|
65
|
+
for (NSWindow *candidate in NSApp.windows) {
|
|
66
|
+
if (candidate.isVisible && ![candidate isKindOfClass:NSPanel.class]) {
|
|
67
|
+
return candidate;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return nil;
|
|
71
|
+
}
|
|
72
|
+
|
|
38
73
|
std::vector<DisplayInfo> displays() {
|
|
39
74
|
std::vector<DisplayInfo> found;
|
|
40
75
|
@autoreleasepool {
|
|
@@ -18,10 +18,13 @@
|
|
|
18
18
|
|
|
19
19
|
#include "ComponentRegistry.h"
|
|
20
20
|
#include "ExpoImageComponent.h"
|
|
21
|
+
#include "SafeAreaComponent.h"
|
|
22
|
+
#include "ScreensComponent.h"
|
|
21
23
|
|
|
22
24
|
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
|
|
23
25
|
|
|
24
26
|
#include "SkiaPictureViewComponent.h"
|
|
27
|
+
#include "SkiaViewComponent.h"
|
|
25
28
|
#include <react/renderer/components/FBReactNativeSpec/ComponentDescriptors.h>
|
|
26
29
|
#include <react/renderer/components/image/ImageComponentDescriptor.h>
|
|
27
30
|
#include <react/renderer/components/iostextinput/TextInputComponentDescriptor.h>
|
|
@@ -41,6 +44,24 @@ ComponentRegistryFactory getDefaultComponentRegistryFactory() {
|
|
|
41
44
|
static auto providerRegistry = []() {
|
|
42
45
|
auto registry = std::make_shared<ComponentDescriptorProviderRegistry>();
|
|
43
46
|
registry->add(concreteComponentDescriptorProvider<ViewComponentDescriptor>());
|
|
47
|
+
// react-native-safe-area-context's provider. Registered on every
|
|
48
|
+
// platform, like expo-image's above: the descriptor is ordinary Fabric
|
|
49
|
+
// C++ and an app that never mounts one pays a registry entry. Without
|
|
50
|
+
// it the provider renders its children never, not badly. See
|
|
51
|
+
// core/SafeAreaComponent.h.
|
|
52
|
+
registry->add(concreteComponentDescriptorProvider<SafeAreaProviderComponentDescriptor>());
|
|
53
|
+
// react-native-screens. RNSScreen carries activityState, which is what
|
|
54
|
+
// hides the screen behind the one in front; the rest are containers that
|
|
55
|
+
// only need their names known, since an unregistered name becomes
|
|
56
|
+
// UnimplementedNativeView and carries none of the layout props. See
|
|
57
|
+
// core/ScreensComponent.h.
|
|
58
|
+
registry->add(concreteComponentDescriptorProvider<RNSScreenComponentDescriptor>());
|
|
59
|
+
registry->add(concreteComponentDescriptorProvider<RNSScreenStackComponentDescriptor>());
|
|
60
|
+
registry->add(concreteComponentDescriptorProvider<RNSScreenContainerComponentDescriptor>());
|
|
61
|
+
registry->add(concreteComponentDescriptorProvider<RNSScreenNavigationContainerComponentDescriptor>());
|
|
62
|
+
registry->add(concreteComponentDescriptorProvider<RNSScreenContentWrapperComponentDescriptor>());
|
|
63
|
+
registry->add(concreteComponentDescriptorProvider<RNSScreenStackHeaderConfigComponentDescriptor>());
|
|
64
|
+
registry->add(concreteComponentDescriptorProvider<RNSScreenStackHeaderSubviewComponentDescriptor>());
|
|
44
65
|
// Text is three descriptors and only one of them mounts. <Text> becomes a
|
|
45
66
|
// Text node, its string a RawText node, and the outermost <Text> a
|
|
46
67
|
// Paragraph that folds the whole subtree into a single AttributedString.
|
|
@@ -61,11 +82,15 @@ ComponentRegistryFactory getDefaultComponentRegistryFactory() {
|
|
|
61
82
|
// through a TextLayoutManager, which here is the Core Text one.
|
|
62
83
|
// Android's needs fbjni. Its component name is "TextInput".
|
|
63
84
|
registry->add(concreteComponentDescriptorProvider<TextInputComponentDescriptor>());
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
85
|
+
// React Native Skia's <Canvas>, under both of its names: 2.x mounts a
|
|
86
|
+
// "SkiaPictureView" and 3.x a "SkiaView", and which one an app mounts is
|
|
87
|
+
// decided by the Skia it installed, which a host binary cannot know
|
|
88
|
+
// until the app's JavaScript runs. Registered whether or not the build
|
|
89
|
+
// has Skia in it, for the reason the Expo one below gives: it costs a
|
|
90
|
+
// name in a registry. Without Skia the view mounts and stays empty, and
|
|
67
91
|
// an app that draws has already failed at getEnforcing('RNSkiaModule').
|
|
68
92
|
registry->add(concreteComponentDescriptorProvider<SkiaPictureViewComponentDescriptor>());
|
|
93
|
+
registry->add(concreteComponentDescriptorProvider<SkiaViewComponentDescriptor>());
|
|
69
94
|
// expo-image's view. Registered whether or not the build has Expo in it:
|
|
70
95
|
// the descriptor is ordinary Fabric C++, and an app that never renders
|
|
71
96
|
// one pays a registry entry. See core/ExpoImageComponent.h.
|
|
@@ -24,6 +24,9 @@
|
|
|
24
24
|
|
|
25
25
|
#import "RnTextLayout.h"
|
|
26
26
|
|
|
27
|
+
#include "FontFitting.h"
|
|
28
|
+
#include "TextAlignments.h"
|
|
29
|
+
|
|
27
30
|
#include <react/renderer/attributedstring/AttributedString.h>
|
|
28
31
|
#include <react/renderer/attributedstring/ParagraphAttributes.h>
|
|
29
32
|
#include <react/renderer/attributedstring/TextAttributes.h>
|
|
@@ -31,13 +34,72 @@
|
|
|
31
34
|
namespace basalt {
|
|
32
35
|
|
|
33
36
|
// Builds a layout for `attributedString`.
|
|
37
|
+
//
|
|
38
|
+
// `fit` is `adjustsFontSizeToFit`'s answer: the ratio every font size is
|
|
39
|
+
// multiplied by and the two bounds it is clamped against. The default is what a
|
|
40
|
+
// paragraph that never asked gets, which changes nothing -- see
|
|
41
|
+
// core/FontFitting.h.
|
|
34
42
|
RnTextLayout *buildTextLayout(const facebook::react::AttributedString &attributedString,
|
|
35
|
-
const facebook::react::ParagraphAttributes ¶graphAttributes
|
|
43
|
+
const facebook::react::ParagraphAttributes ¶graphAttributes,
|
|
44
|
+
basalt::FontFit fit = {});
|
|
45
|
+
|
|
46
|
+
// How far this paragraph's fonts have to shrink to fit a box, for
|
|
47
|
+
// `adjustsFontSizeToFit`.
|
|
48
|
+
//
|
|
49
|
+
// The search is core's; this is the half that measures, which means building a
|
|
50
|
+
// layout per probe -- about eight of them -- and is why it runs only for a
|
|
51
|
+
// paragraph that asked. Both the measurement seam and the mounting manager call
|
|
52
|
+
// it, with the constraints and the frame respectively, so the text is painted
|
|
53
|
+
// at the size it was measured at.
|
|
54
|
+
basalt::FontFit textFitScale(const facebook::react::AttributedString &attributedString,
|
|
55
|
+
const facebook::react::ParagraphAttributes ¶graphAttributes,
|
|
56
|
+
float maxWidth,
|
|
57
|
+
float maxHeight);
|
|
58
|
+
|
|
59
|
+
// One fragment's text with its `textTransform` applied, which has to happen
|
|
60
|
+
// before anything measures the string *and* before anything indexes into it: a
|
|
61
|
+
// transform can change the length -- ß uppercases to SS -- so an attachment
|
|
62
|
+
// after one would otherwise be looked up at the wrong offset. Shared with
|
|
63
|
+
// CoreTextLayoutManager.mm for exactly that reason.
|
|
64
|
+
NSString *transformedFragmentText(const facebook::react::AttributedString::Fragment &fragment,
|
|
65
|
+
NSString *text);
|
|
36
66
|
|
|
37
67
|
// The attributes for a whole string, for anything that holds its own text
|
|
38
68
|
// rather than a layout built here -- the equivalent of Pango's
|
|
39
69
|
// buildTextAttributes, and what a <TextInput> will need.
|
|
70
|
+
// `directions` is which way the text runs and what `start` and `end` mean,
|
|
71
|
+
// which the relative alignments need; see core/TextAlignments.h. A caller that
|
|
72
|
+
// holds its own text and resolves its own direction -- an NSTextField --
|
|
73
|
+
// passes neither and leaves `natural` to AppKit.
|
|
40
74
|
NSDictionary<NSAttributedStringKey, id> *buildTextAttributes(
|
|
41
|
-
const facebook::react::TextAttributes &textAttributes
|
|
75
|
+
const facebook::react::TextAttributes &textAttributes,
|
|
76
|
+
basalt::FontFit fit = {},
|
|
77
|
+
basalt::TextDirections directions = {});
|
|
78
|
+
|
|
79
|
+
// `fontVariant` in Core Text's vocabulary, which is not OpenType's: Apple's
|
|
80
|
+
// older AAT pairs, a feature type and a selector inside it, as upstream's
|
|
81
|
+
// `RCTFontFeatures` uses.
|
|
82
|
+
//
|
|
83
|
+
// Exposed for the suite rather than for callers. The mapping is the part this
|
|
84
|
+
// platform owns and a wrong selector would be invisible: `[NSFont
|
|
85
|
+
// fontWithDescriptor:]` resolves against a real font and **drops features that
|
|
86
|
+
// font does not have**, so asking the resolved font what it kept measures the
|
|
87
|
+
// machine's fonts rather than this code. The system font has small caps and
|
|
88
|
+
// tabular figures and has neither oldstyle figures nor a twentieth stylistic
|
|
89
|
+
// set, which is how that was found.
|
|
90
|
+
NSArray *fontFeaturesFor(const facebook::react::TextAttributes &textAttributes);
|
|
91
|
+
|
|
92
|
+
// The desktop's text scale, which on macOS is 1 and is a function anyway.
|
|
93
|
+
//
|
|
94
|
+
// macOS publishes no scalar for this. Accessibility's "Text size" works through
|
|
95
|
+
// the text-style ramp instead: an app opts in by asking
|
|
96
|
+
// `[NSFont preferredFontForTextStyle:options:]` for its fonts, and the system
|
|
97
|
+
// answers a larger font for the style. That is `dynamicTypeRamp`'s shape rather
|
|
98
|
+
// than `fontSizeMultiplier`'s, and it is a different feature; backlog/text.md
|
|
99
|
+
// records it with that call named.
|
|
100
|
+
//
|
|
101
|
+
// So this exists to say so in one place, and to keep the host's wiring the same
|
|
102
|
+
// shape as GTK's, which does have a scale to read.
|
|
103
|
+
float appKitTextScale();
|
|
42
104
|
|
|
43
105
|
} // namespace basalt
|