@octane-xplat/ui 0.7.1 → 0.7.3
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/dist/native/CommandPalette.tsrx.js +7 -1
- package/dist/native/Grid.tsrx.js +31 -2
- package/dist/native/Hoverable.mobile.tsrx.js +39 -0
- package/dist/native/Pagination.tsrx.js +15 -12
- package/dist/native/Popover.tsrx.js +18 -7
- package/dist/native/Screen.tsrx.js +1 -1
- package/dist/native/Sheet.tsrx.js +1 -1
- package/dist/native/Slider.tsrx.js +23 -14
- package/dist/native/Text.tsrx.js +16 -0
- package/dist/native/Tooltip.mobile.tsrx.js +39 -0
- package/dist/native/WebView.tsrx.js +17 -2
- package/dist/native/_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js +9 -0
- package/dist/native/escape-props.js +2 -0
- package/dist/native/grid-auto-placement.js +83 -0
- package/dist/native/grid-placement.js +20 -0
- package/dist/native/index.shared.js +2 -2
- package/dist/native/octane-client-build.json +1 -1
- package/dist/native/shared.js +2 -2
- package/dist/native/sheet-service.js +1 -1
- package/dist/native/{tap-to-blur.mobile.js → tap-to-blur.ios.js} +20 -32
- package/dist/native/ui.js +2 -2
- package/dist/native/useMeasure.tsrx.js +17 -18
- package/dist/web/index.shared.js +92 -0
- package/dist/web/octane-client-build.json +1 -1
- package/dist/web/ui.js +1 -0
- package/package.json +1 -1
- package/src/CommandPalette.tsrx +7 -1
- package/src/Grid.tsrx +30 -1
- package/src/Pagination.tsrx +6 -4
- package/src/Popover.tsrx +20 -6
- package/src/Screen.tsrx +1 -1
- package/src/Sheet.tsrx +1 -1
- package/src/Slider.tsrx +13 -11
- package/src/Text.tsrx +34 -0
- package/src/WebView.tsrx +19 -10
- package/src/escape-props.ts +11 -1
- package/src/grid-auto-placement.ts +121 -0
- package/src/grid-placement.ts +29 -0
- package/src/index.shared.ts +84 -84
- package/src/index.web.ts +1 -261
- package/src/sheet-service.ts +1 -1
- package/src/tap-to-blur.ios.ts +90 -0
- package/src/tap-to-blur.mobile.ts +12 -94
- package/src/theme/tokens.css +24 -8
- package/src/useMeasure.tsrx +20 -21
- package/types/generated/.tsrx-typegen-manifest.json +10 -1
- package/types/generated/Grid.d.ts +0 -1
- package/types/generated/Hoverable.mobile.d.ts +8 -0
- package/types/generated/Tooltip.mobile.d.ts +7 -0
- package/types/generated/camera-permission.web.d.ts +2 -0
- package/types/generated/escape-props.d.ts +4 -0
- package/types/generated/escape-props.web.d.ts +5 -0
- package/types/generated/grid-auto-placement.d.ts +13 -0
- package/types/generated/grid-placement.d.ts +5 -0
- package/types/generated/index.web.d.ts +1 -111
- package/types/generated/tap-to-blur.ios.d.ts +13 -0
- package/types/generated/tap-to-blur.mobile.d.ts +1 -15
- package/types/generated/text-write.web.d.ts +4 -0
- package/types/generated/toast.d.ts +3 -0
- package/types/generated/toast.web.d.ts +3 -0
- package/dist/native/Hoverable.tsrx.js +0 -139
- package/dist/native/Tooltip.tsrx.js +0 -131
- package/types/generated/theme/colorScheme.web.d.ts +0 -5
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
//#region src/tap-to-blur.
|
|
1
|
+
import __decorate from "./_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
2
|
+
//#region src/tap-to-blur.ios.ts
|
|
3
3
|
/** Tap-outside-to-blur: iOS keeps a focused UITextField/UITextView as first
|
|
4
4
|
* responder until something else takes it, so a tap on blank chrome never
|
|
5
5
|
* dismisses the keyboard on its own.
|
|
@@ -11,36 +11,15 @@ import { Application } from "@nativescript/core";
|
|
|
11
11
|
* editable text view (otherwise the field would focus-then-blur in the same
|
|
12
12
|
* tap — recognizers fire on touch-up, after the field's touch-down focus).
|
|
13
13
|
* Keyboard taps live in a separate UIWindow, so they never reach it.
|
|
14
|
-
* `cancelsTouchesInView` stays false so taps still reach buttons.
|
|
15
|
-
*
|
|
16
|
-
* Android: hides the soft keyboard from the currently focused view when a
|
|
17
|
-
* tap lands on the attached container. */
|
|
14
|
+
* `cancelsTouchesInView` stays false so taps still reach buttons. */
|
|
18
15
|
function attachTapToBlur(view) {
|
|
19
16
|
const marker = "__xplatTapToBlur";
|
|
20
17
|
if (!view || view[marker]) return () => {};
|
|
21
18
|
view[marker] = true;
|
|
22
|
-
|
|
23
|
-
iosAttach();
|
|
24
|
-
return () => {
|
|
25
|
-
view[marker] = false;
|
|
26
|
-
iosDetach();
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
if (Application.android) {
|
|
30
|
-
const handler = (_args) => {
|
|
31
|
-
const activity = Application.android.foregroundActivity;
|
|
32
|
-
const focused = activity?.currentFocus;
|
|
33
|
-
if (!focused) return;
|
|
34
|
-
activity.getSystemService(android.content.Context.INPUT_METHOD_SERVICE)?.hideSoftInputFromWindow(focused.getWindowToken(), 0);
|
|
35
|
-
};
|
|
36
|
-
view.on("tap", handler);
|
|
37
|
-
return () => {
|
|
38
|
-
view[marker] = false;
|
|
39
|
-
view.off("tap", handler);
|
|
40
|
-
};
|
|
41
|
-
}
|
|
19
|
+
iosAttach();
|
|
42
20
|
return () => {
|
|
43
21
|
view[marker] = false;
|
|
22
|
+
iosDetach();
|
|
44
23
|
};
|
|
45
24
|
}
|
|
46
25
|
var iosCount = 0;
|
|
@@ -53,25 +32,34 @@ function iosAttach() {
|
|
|
53
32
|
const appWin = appWindow();
|
|
54
33
|
if (!appWin) return;
|
|
55
34
|
iosWindow = appWin;
|
|
56
|
-
|
|
35
|
+
let TapToBlurRecognizerTarget = class TapToBlurRecognizerTarget extends NSObject {
|
|
36
|
+
static {
|
|
37
|
+
this.ObjCProtocols = [UIGestureRecognizerDelegate];
|
|
38
|
+
}
|
|
57
39
|
static {
|
|
58
40
|
this.ObjCExposedMethods = { tap: {
|
|
59
41
|
returns: interop.types.void,
|
|
60
42
|
params: [UITapGestureRecognizer]
|
|
61
43
|
} };
|
|
62
44
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
let hit = iosWindow.hitTest(point, null);
|
|
45
|
+
gestureRecognizerShouldReceiveTouch(_recognizer, touch) {
|
|
46
|
+
let hit = touch.view;
|
|
66
47
|
while (hit) {
|
|
67
|
-
|
|
48
|
+
const textField = hit.isKindOfClass(UITextField.class());
|
|
49
|
+
const textView = hit.isKindOfClass(UITextView.class());
|
|
50
|
+
if (textField || textView) return false;
|
|
68
51
|
hit = hit.superview;
|
|
69
52
|
}
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
tap(_recognizer) {
|
|
70
56
|
iosWindow.endEditing(true);
|
|
71
57
|
}
|
|
72
58
|
};
|
|
73
|
-
|
|
59
|
+
TapToBlurRecognizerTarget = __decorate([NativeClass], TapToBlurRecognizerTarget);
|
|
60
|
+
iosTarget = TapToBlurRecognizerTarget.new();
|
|
74
61
|
iosRecognizer = UITapGestureRecognizer.alloc().initWithTargetAction(iosTarget, "tap");
|
|
62
|
+
iosRecognizer.delegate = iosTarget;
|
|
75
63
|
iosRecognizer.cancelsTouchesInView = false;
|
|
76
64
|
appWin.addGestureRecognizer(iosRecognizer);
|
|
77
65
|
}
|
package/dist/native/ui.js
CHANGED
|
@@ -68,8 +68,8 @@ import { ScrollBox } from "./ScrollBox.tsrx.js";
|
|
|
68
68
|
import { ScrollView } from "./ScrollView.tsrx.js";
|
|
69
69
|
import { VirtualList } from "./VirtualList.tsrx.js";
|
|
70
70
|
import { WebView } from "./WebView.tsrx.js";
|
|
71
|
-
import { Hoverable } from "./Hoverable.tsrx.js";
|
|
72
|
-
import { Tooltip } from "./Tooltip.tsrx.js";
|
|
71
|
+
import { Hoverable } from "./Hoverable.mobile.tsrx.js";
|
|
72
|
+
import { Tooltip } from "./Tooltip.mobile.tsrx.js";
|
|
73
73
|
import { showToast } from "./toast-anchor.tsrx.js";
|
|
74
74
|
import { useAnimation } from "./anim.tsrx.js";
|
|
75
75
|
import { styled } from "./styled.tsrx.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { hookSlots, useCallback, useEffect, useState } from "@nativescript-community/octane";
|
|
1
|
+
import { hookSlots, useCallback, useEffect, useRef, useState } from "@nativescript-community/octane";
|
|
2
2
|
//#region src/useMeasure.tsrx
|
|
3
3
|
var _hs$ = /* @__PURE__ */ hookSlots(4);
|
|
4
4
|
var _h$0 = /* @__PURE__ */ Symbol(_hs$);
|
|
@@ -17,44 +17,43 @@ function readBounds(view) {
|
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
19
|
function useMeasure(options = {}) {
|
|
20
|
-
const [
|
|
21
|
-
const
|
|
20
|
+
const [bounds, setBounds] = useState(null, _h$0);
|
|
21
|
+
const detach = useRef(null, _h$1);
|
|
22
22
|
const observe = options.observe ?? true;
|
|
23
|
-
const bind = useCallback((
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
useEffect(() => {
|
|
23
|
+
const bind = useCallback((view) => {
|
|
24
|
+
detach.current?.();
|
|
25
|
+
detach.current = null;
|
|
27
26
|
if (!view) {
|
|
28
27
|
setBounds(null);
|
|
29
28
|
return;
|
|
30
29
|
}
|
|
31
30
|
const update = () => {
|
|
32
31
|
const next = readBounds(view);
|
|
33
|
-
setBounds((prev) =>
|
|
32
|
+
setBounds((prev) => {
|
|
33
|
+
return prev && next && prev.x === next.x && prev.y === next.y && prev.width === next.width && prev.height === next.height ? prev : next;
|
|
34
|
+
});
|
|
34
35
|
};
|
|
35
|
-
|
|
36
|
-
view.on?.("loaded", onLoaded);
|
|
36
|
+
view.on?.("loaded", update);
|
|
37
37
|
update();
|
|
38
|
+
const scrollParents = [];
|
|
38
39
|
if (observe) {
|
|
39
40
|
view.on?.("layoutChanged", update);
|
|
40
41
|
let parent = view.parent;
|
|
41
42
|
while (parent) {
|
|
42
43
|
parent.on?.("scroll", update);
|
|
44
|
+
scrollParents.push(parent);
|
|
43
45
|
parent = parent.parent;
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
|
-
|
|
47
|
-
view.off?.("loaded",
|
|
48
|
+
detach.current = () => {
|
|
49
|
+
view.off?.("loaded", update);
|
|
48
50
|
if (observe) {
|
|
49
51
|
view.off?.("layoutChanged", update);
|
|
50
|
-
|
|
51
|
-
while (parent) {
|
|
52
|
-
parent.off?.("scroll", update);
|
|
53
|
-
parent = parent.parent;
|
|
54
|
-
}
|
|
52
|
+
for (const parent of scrollParents) parent.off?.("scroll", update);
|
|
55
53
|
}
|
|
56
54
|
};
|
|
57
|
-
}, [
|
|
55
|
+
}, [observe], _h$2);
|
|
56
|
+
useEffect(() => () => detach.current?.(), [], _h$3);
|
|
58
57
|
return {
|
|
59
58
|
bind,
|
|
60
59
|
bounds
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { View } from "./View.web.tsrx.js";
|
|
2
|
+
import { Row } from "./Row.web.tsrx.js";
|
|
3
|
+
import { Grid } from "./Grid.web.tsrx.js";
|
|
4
|
+
import { Stack } from "./Stack.web.tsrx.js";
|
|
5
|
+
import { Absolute } from "./Absolute.web.tsrx.js";
|
|
6
|
+
import { setTranslate } from "./translate.web.js";
|
|
7
|
+
import { Spacer } from "./Spacer.web.tsrx.js";
|
|
8
|
+
import { Text } from "./Text.web.tsrx.js";
|
|
9
|
+
import { RichText, RichTextSpan } from "./RichText.web.tsrx.js";
|
|
10
|
+
import { Pressable } from "./Pressable.web.tsrx.js";
|
|
11
|
+
import { ActivityIndicator } from "./ActivityIndicator.web.tsrx.js";
|
|
12
|
+
import { Button } from "./Button.web.tsrx.js";
|
|
13
|
+
import { Collapsible } from "./Collapsible.web.tsrx.js";
|
|
14
|
+
import { Accordion } from "./Accordion.web.tsrx.js";
|
|
15
|
+
import { Checkbox } from "./Checkbox.web.tsrx.js";
|
|
16
|
+
import { RadioGroup } from "./RadioGroup.web.tsrx.js";
|
|
17
|
+
import { getColorScheme, useColorScheme } from "./theme/colorScheme.web.js";
|
|
18
|
+
import { applyThemeClasses, getThemePreference, getThemeScheme, onThemeSchemeChange, setThemePreference, themeSchemeClasses, useThemeScheme } from "./theme/theme-scheme.js";
|
|
19
|
+
import { Popover } from "./Popover.web.tsrx.js";
|
|
20
|
+
import { registerIcon, registerIcons } from "./icons.js";
|
|
21
|
+
import { Icon } from "./Icon.web.tsrx.js";
|
|
22
|
+
import { DropdownMenu } from "./DropdownMenu.web.tsrx.js";
|
|
23
|
+
import { ContextMenu } from "./ContextMenu.web.tsrx.js";
|
|
24
|
+
import { Badge } from "./Badge.web.tsrx.js";
|
|
25
|
+
import { Separator } from "./Separator.web.tsrx.js";
|
|
26
|
+
import { Skeleton } from "./Skeleton.web.tsrx.js";
|
|
27
|
+
import { Avatar } from "./Avatar.web.tsrx.js";
|
|
28
|
+
import { AvatarGroup } from "./AvatarGroup.web.tsrx.js";
|
|
29
|
+
import { FormField } from "./FormField.web.tsrx.js";
|
|
30
|
+
import { FieldGroup } from "./FieldGroup.web.tsrx.js";
|
|
31
|
+
import { ListItem } from "./ListItem.web.tsrx.js";
|
|
32
|
+
import { TextInput } from "./TextInput.web.tsrx.js";
|
|
33
|
+
import { InputNumber } from "./InputNumber.web.tsrx.js";
|
|
34
|
+
import { PinInput } from "./PinInput.web.tsrx.js";
|
|
35
|
+
import { Select } from "./Select.web.tsrx.js";
|
|
36
|
+
import { Combobox, InputMenu, SelectMenu } from "./aliases.web.tsrx.js";
|
|
37
|
+
import { InputTags } from "./InputTags.web.tsrx.js";
|
|
38
|
+
import { InputRating } from "./InputRating.web.tsrx.js";
|
|
39
|
+
import { CheckboxGroup } from "./CheckboxGroup.web.tsrx.js";
|
|
40
|
+
import { Breadcrumb } from "./Breadcrumb.web.tsrx.js";
|
|
41
|
+
import { Pagination } from "./Pagination.web.tsrx.js";
|
|
42
|
+
import { Stepper } from "./Stepper.web.tsrx.js";
|
|
43
|
+
import { NavigationMenu } from "./NavigationMenu.web.tsrx.js";
|
|
44
|
+
import { Overlay } from "./Overlay.web.tsrx.js";
|
|
45
|
+
import { CommandPalette } from "./CommandPalette.web.tsrx.js";
|
|
46
|
+
import { Table } from "./Table.web.tsrx.js";
|
|
47
|
+
import { Timeline } from "./Timeline.web.tsrx.js";
|
|
48
|
+
import { Tree } from "./Tree.web.tsrx.js";
|
|
49
|
+
import { Alert } from "./Alert.web.tsrx.js";
|
|
50
|
+
import { Card } from "./Card.web.tsrx.js";
|
|
51
|
+
import { Chip } from "./Chip.web.tsrx.js";
|
|
52
|
+
import { Kbd } from "./Kbd.web.tsrx.js";
|
|
53
|
+
import { Empty } from "./Empty.web.tsrx.js";
|
|
54
|
+
import { Banner } from "./Banner.web.tsrx.js";
|
|
55
|
+
import { User } from "./User.web.tsrx.js";
|
|
56
|
+
import { Meter } from "./Meter.web.tsrx.js";
|
|
57
|
+
import { ProgressGroup } from "./ProgressGroup.web.tsrx.js";
|
|
58
|
+
import { Link } from "./Link.web.tsrx.js";
|
|
59
|
+
import { defineRoutes, deriveRouteManifest, mergeRouteManifests } from "./route-table.js";
|
|
60
|
+
import { addBackInterceptor, addRoutes, canGoBack, currentModalRoute, currentRoute, hrefFor, layoutsFor, popRoute, pushDeepLink, pushRoute, redirect, registerRoutes, registerScreens, routeFor, routeStacks, screenFor, useCanGoBack, useModalRoute, useRoute } from "./route.web.js";
|
|
61
|
+
import { NavLink } from "./NavLink.web.tsrx.js";
|
|
62
|
+
import { TextArea } from "./TextArea.web.tsrx.js";
|
|
63
|
+
import { SearchInput } from "./SearchInput.web.tsrx.js";
|
|
64
|
+
import { SegmentedControl } from "./SegmentedControl.web.tsrx.js";
|
|
65
|
+
import { ScrollView } from "./ScrollView.web.tsrx.js";
|
|
66
|
+
import { ScrollBox } from "./ScrollBox.web.tsrx.js";
|
|
67
|
+
import { VirtualList } from "./VirtualList.web.tsrx.js";
|
|
68
|
+
import { Image } from "./Image.web.tsrx.js";
|
|
69
|
+
import { WebView } from "./WebView.web.tsrx.js";
|
|
70
|
+
import { Hoverable } from "./Hoverable.web.tsrx.js";
|
|
71
|
+
import { Tooltip } from "./Tooltip.web.tsrx.js";
|
|
72
|
+
import { showToast } from "./toast-anchor.web.tsrx.js";
|
|
73
|
+
import { useAnimation } from "./anim.web.tsrx.js";
|
|
74
|
+
import { styled } from "./styled.web.tsrx.js";
|
|
75
|
+
import { openWindow } from "./windows.web.js";
|
|
76
|
+
import { Screen } from "./Screen.web.tsrx.js";
|
|
77
|
+
import { Tabs } from "./Tabs.web.tsrx.js";
|
|
78
|
+
import { Switch } from "./Switch.web.tsrx.js";
|
|
79
|
+
import { useSafeAreaInsets } from "./safeAreaInsets.web.tsrx.js";
|
|
80
|
+
import { SafeArea } from "./SafeArea.web.tsrx.js";
|
|
81
|
+
import { Drawer } from "./Drawer.web.tsrx.js";
|
|
82
|
+
import { useMeasure } from "./useMeasure.web.tsrx.js";
|
|
83
|
+
import { Slider } from "./Slider.web.tsrx.js";
|
|
84
|
+
import { Heading } from "./Heading.web.tsrx.js";
|
|
85
|
+
import { isNative } from "./platform.web.js";
|
|
86
|
+
import { getStack, registerStack, stackEntries } from "./stacks.web.js";
|
|
87
|
+
import { useBackInterceptor } from "./use-back.web.tsrx.js";
|
|
88
|
+
import { createStore } from "./store.js";
|
|
89
|
+
import { useStore } from "./use-store.web.tsrx.js";
|
|
90
|
+
import { Sheet } from "./Sheet.web.tsrx.js";
|
|
91
|
+
import { closeSheet, openSheet } from "./sheet-service.web.js";
|
|
92
|
+
export { Absolute, Accordion, ActivityIndicator, Alert, Avatar, AvatarGroup, Badge, Banner, Breadcrumb, Button, Card, Checkbox, CheckboxGroup, Chip, Collapsible, View as Column, Combobox, CommandPalette, ContextMenu, Drawer, DropdownMenu, Empty, FieldGroup, FormField, Grid, Heading, Hoverable, Icon, Image, InputMenu, InputNumber, InputRating, InputTags, Kbd, Link, ListItem, Meter, NavLink, NavigationMenu, Overlay, Pagination, PinInput, Popover, Pressable, ProgressGroup, RadioGroup, RichText, RichTextSpan, Row, SafeArea, Screen, ScrollBox, ScrollView, SearchInput, SegmentedControl, Select, SelectMenu, Separator, Sheet, Skeleton, Slider, Spacer, Stack, Stepper, Switch, Table, Tabs, Text, TextArea, TextInput, Timeline, Tooltip, Tree, User, View, VirtualList, WebView, addBackInterceptor, addRoutes, applyThemeClasses, canGoBack, closeSheet, createStore, currentModalRoute, currentRoute, defineRoutes, deriveRouteManifest, getColorScheme, getStack, getThemePreference, getThemeScheme, hrefFor, isNative, layoutsFor as layoutsForRoute, mergeRouteManifests, onThemeSchemeChange, openSheet, openWindow, popRoute, pushDeepLink, pushRoute, redirect, registerIcon, registerIcons, registerRoutes, registerScreens, registerStack, routeFor, routeStacks, screenFor, setThemePreference, setTranslate, showToast, stackEntries, styled, themeSchemeClasses, useAnimation, useBackInterceptor, useCanGoBack, useColorScheme, useMeasure, useModalRoute, useRoute, useSafeAreaInsets, useStore, useThemeScheme };
|
package/dist/web/ui.js
CHANGED
|
@@ -89,4 +89,5 @@ import { createStore } from "./store.js";
|
|
|
89
89
|
import { useStore } from "./use-store.web.tsrx.js";
|
|
90
90
|
import { Sheet } from "./Sheet.web.tsrx.js";
|
|
91
91
|
import { closeSheet, openSheet } from "./sheet-service.web.js";
|
|
92
|
+
import "./index.shared.js";
|
|
92
93
|
export { Absolute, Accordion, ActivityIndicator, Alert, Avatar, AvatarGroup, Badge, Banner, Breadcrumb, Button, Card, Checkbox, CheckboxGroup, Chip, Collapsible, View as Column, Combobox, CommandPalette, ContextMenu, Drawer, DropdownMenu, Empty, FieldGroup, FormField, Grid, Heading, Hoverable, Icon, Image, InputMenu, InputNumber, InputRating, InputTags, Kbd, Link, ListItem, Meter, NavLink, NavigationMenu, Overlay, Pagination, PinInput, Popover, Pressable, ProgressGroup, RadioGroup, RichText, RichTextSpan, Row, SafeArea, Screen, ScrollBox, ScrollView, SearchInput, SegmentedControl, Select, SelectMenu, Separator, Sheet, Skeleton, Slider, Spacer, Stack, Stepper, Switch, Table, Tabs, Text, TextArea, TextInput, Timeline, Tooltip, Tree, User, View, VirtualList, WebView, addBackInterceptor, addRoutes, applyThemeClasses, canGoBack, closeSheet, createStore, currentModalRoute, currentRoute, defineRoutes, deriveRouteManifest, getColorScheme, getStack, getThemePreference, getThemeScheme, hrefFor, isNative, layoutsFor as layoutsForRoute, mergeRouteManifests, onThemeSchemeChange, openSheet, openWindow, popRoute, pushDeepLink, pushRoute, redirect, registerIcon, registerIcons, registerRoutes, registerScreens, registerStack, routeFor, routeStacks, screenFor, setThemePreference, setTranslate, showToast, stackEntries, styled, themeSchemeClasses, useAnimation, useBackInterceptor, useCanGoBack, useColorScheme, useMeasure, useModalRoute, useRoute, useSafeAreaInsets, useStore, useThemeScheme };
|
package/package.json
CHANGED
package/src/CommandPalette.tsrx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** @jsxImportSource @nativescript-community/octane */
|
|
2
2
|
import { useState } from 'octane';
|
|
3
|
+
import { Screen } from '@nativescript/core';
|
|
3
4
|
import type { CommandPaletteProps, MenuItem } from "./props";
|
|
4
5
|
import { cx } from "./cx";
|
|
5
6
|
import { Overlay } from './Overlay.tsrx';
|
|
@@ -19,6 +20,10 @@ export function CommandPalette(props: CommandPaletteProps) @{
|
|
|
19
20
|
const shown = query
|
|
20
21
|
? props.items.filter((i) => (i.label ?? i.key).toLowerCase().includes(query.toLowerCase()))
|
|
21
22
|
: props.items;
|
|
23
|
+
const panelStyle = {
|
|
24
|
+
...props.style,
|
|
25
|
+
maxWidth: props.style?.maxWidth ?? Screen.mainScreen.widthDIPs * 0.9,
|
|
26
|
+
};
|
|
22
27
|
|
|
23
28
|
const select = (item: MenuItem) => {
|
|
24
29
|
if (item.disabled) return;
|
|
@@ -29,8 +34,9 @@ export function CommandPalette(props: CommandPaletteProps) @{
|
|
|
29
34
|
<Overlay open={props.open} shadeCover={true} onDismiss={() => setOpen(false)} className="vx-cmdk-layer">
|
|
30
35
|
<flexboxlayout
|
|
31
36
|
className={cx('vx-commandpalette', props.className)}
|
|
32
|
-
style={
|
|
37
|
+
style={panelStyle}
|
|
33
38
|
id={props.id}
|
|
39
|
+
flexDirection="column"
|
|
34
40
|
horizontalAlignment="center"
|
|
35
41
|
verticalAlignment="top"
|
|
36
42
|
marginTop={80}
|
package/src/Grid.tsrx
CHANGED
|
@@ -1,20 +1,49 @@
|
|
|
1
1
|
/** @jsxImportSource @nativescript-community/octane */
|
|
2
|
+
import { useEffect, useRef } from 'octane';
|
|
2
3
|
import type { GridProps } from './props';
|
|
3
4
|
import { cx } from './cx';
|
|
4
5
|
import { applyEscapeProps, nativeAccessibilityRole, nativeAccessibilityState } from './escape-props';
|
|
6
|
+
import { autoPlaceGridChildren, ensureGridTracks } from './grid-auto-placement';
|
|
7
|
+
import { gridChildPlacement } from './grid-placement';
|
|
5
8
|
|
|
6
9
|
let warnedAboutGap = false;
|
|
7
10
|
|
|
8
11
|
export function Grid(props: GridProps) @{
|
|
12
|
+
const grid = useRef<any>(null);
|
|
9
13
|
const deprecatedGap = (props as GridProps & { gap?: number | string }).gap;
|
|
10
14
|
if (deprecatedGap != null && !warnedAboutGap) {
|
|
11
15
|
warnedAboutGap = true;
|
|
12
16
|
console.warn('[Grid] gap was removed; use child margins');
|
|
13
17
|
}
|
|
14
18
|
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const host = grid.current;
|
|
21
|
+
if (!host) return;
|
|
22
|
+
|
|
23
|
+
const views: any[] = [];
|
|
24
|
+
host.eachChildView((child: any) => {
|
|
25
|
+
views.push(child);
|
|
26
|
+
return true;
|
|
27
|
+
});
|
|
28
|
+
const placement = autoPlaceGridChildren(
|
|
29
|
+
views.map(gridChildPlacement),
|
|
30
|
+
props.rows,
|
|
31
|
+
props.columns,
|
|
32
|
+
);
|
|
33
|
+
host.rows = ensureGridTracks(props.rows, placement.rowCount);
|
|
34
|
+
host.columns = ensureGridTracks(props.columns, placement.columnCount);
|
|
35
|
+
for (let index = 0; index < views.length; index++) {
|
|
36
|
+
views[index].row = placement.cells[index].row;
|
|
37
|
+
views[index].col = placement.cells[index].col;
|
|
38
|
+
}
|
|
39
|
+
}, [props.children, props.rows, props.columns]);
|
|
40
|
+
|
|
15
41
|
<gridlayout
|
|
16
42
|
id={props.id}
|
|
17
|
-
ref={(view: any) =>
|
|
43
|
+
ref={(view: any) => {
|
|
44
|
+
grid.current = view;
|
|
45
|
+
applyEscapeProps(view, props);
|
|
46
|
+
}}
|
|
18
47
|
rows={props.rows}
|
|
19
48
|
columns={props.columns}
|
|
20
49
|
className={cx('vx-grid', props.className)}
|
package/src/Pagination.tsrx
CHANGED
|
@@ -36,11 +36,13 @@ export function Pagination(props: PaginationProps) @{
|
|
|
36
36
|
>
|
|
37
37
|
<flexboxlayout className="vx-page-btn" onTap={() => go(current - 1)}><label text="‹" /></flexboxlayout>
|
|
38
38
|
@for (const e of pages; key e.key) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
@if (e.page == null) {
|
|
40
|
+
<label className="vx-page-ellipsis" text="…" />
|
|
41
|
+
} @else {
|
|
42
|
+
<flexboxlayout className={cx('vx-page-btn', e.page === current && 'vx-page-btn--on')} onTap={() => go(e.page!)}>
|
|
42
43
|
<label text={String(e.page)} />
|
|
43
|
-
</flexboxlayout>
|
|
44
|
+
</flexboxlayout>
|
|
45
|
+
}
|
|
44
46
|
}
|
|
45
47
|
<flexboxlayout className="vx-page-btn" onTap={() => go(current + 1)}><label text="›" /></flexboxlayout>
|
|
46
48
|
</flexboxlayout>
|
package/src/Popover.tsrx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @jsxImportSource @nativescript-community/octane */
|
|
2
2
|
import { useEffect, useRef, useState } from 'octane';
|
|
3
|
-
import { GridLayout } from '@nativescript/core';
|
|
3
|
+
import { GridLayout, isIOS, Screen } from '@nativescript/core';
|
|
4
4
|
import { createNativeScriptRoot } from '@nativescript-community/octane';
|
|
5
5
|
import type { UniversalComponent } from 'octane/universal';
|
|
6
6
|
import type { PopoverProps } from './props';
|
|
@@ -38,13 +38,19 @@ function PopoverLayer(props: PopoverProps & { anchorView: any }) @{
|
|
|
38
38
|
},
|
|
39
39
|
props.placement ?? 'bottom',
|
|
40
40
|
);
|
|
41
|
-
|
|
41
|
+
const insets = isIOS ? panelRef.current?.parent?.getSafeAreaInsets?.() : undefined;
|
|
42
|
+
const scale = isIOS ? Number(Screen.mainScreen.scale) || 1 : 1;
|
|
43
|
+
const panelPosition = {
|
|
44
|
+
...next,
|
|
45
|
+
left: next.left - Number(insets?.left ?? 0) / scale,
|
|
46
|
+
top: next.top - Number(insets?.top ?? 0) / scale,
|
|
47
|
+
};
|
|
42
48
|
setPosition((current) =>
|
|
43
|
-
current?.left ===
|
|
44
|
-
current?.top ===
|
|
45
|
-
current?.placement ===
|
|
49
|
+
current?.left === panelPosition.left &&
|
|
50
|
+
current?.top === panelPosition.top &&
|
|
51
|
+
current?.placement === panelPosition.placement
|
|
46
52
|
? current
|
|
47
|
-
:
|
|
53
|
+
: panelPosition,
|
|
48
54
|
);
|
|
49
55
|
|
|
50
56
|
if (panelSize?.width > 0 && panelSize?.height > 0) setSettled(true);
|
|
@@ -73,6 +79,14 @@ function PopoverLayer(props: PopoverProps & { anchorView: any }) @{
|
|
|
73
79
|
};
|
|
74
80
|
}, [props.open, props.anchorView, props.placement, props.children, props.style]);
|
|
75
81
|
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
if (position) {
|
|
84
|
+
const panel = panelRef.current;
|
|
85
|
+
const parent = panel?.parent;
|
|
86
|
+
parent?.requestLayout?.();
|
|
87
|
+
}
|
|
88
|
+
}, [position]);
|
|
89
|
+
|
|
76
90
|
useEffect(() => {
|
|
77
91
|
applyNativeProps(panelRef.current, props);
|
|
78
92
|
}, [props.ios, props.android, settled]);
|
package/src/Screen.tsrx
CHANGED
|
@@ -3,7 +3,7 @@ import type { ScreenProps } from "./props";
|
|
|
3
3
|
import { cx } from "./cx";
|
|
4
4
|
import { applyEscapeProps } from "./escape-props";
|
|
5
5
|
import { registerRootLayout, unregisterRootLayout } from "./root-layout.mobile";
|
|
6
|
-
import { attachTapToBlur } from "./tap-to-blur
|
|
6
|
+
import { attachTapToBlur } from "./tap-to-blur";
|
|
7
7
|
// The screen shell is a RootLayout so RootLayout.open() can layer overlays
|
|
8
8
|
// over it (decision #22). Self-registers on loaded/unloaded — overlay and
|
|
9
9
|
// sheet services mount on the most recently mounted shell (topRootLayout).
|
package/src/Sheet.tsrx
CHANGED
|
@@ -9,7 +9,7 @@ import { applyThemeClasses } from './theme/theme-scheme';
|
|
|
9
9
|
import { rootLayoutFor } from './root-layout.mobile';
|
|
10
10
|
import { attachSheetDetents } from './sheet-detents';
|
|
11
11
|
import { bindBottomInsetToKeyboard } from './keyboard-inset.mobile';
|
|
12
|
-
import { attachTapToBlur } from './tap-to-blur
|
|
12
|
+
import { attachTapToBlur } from './tap-to-blur';
|
|
13
13
|
|
|
14
14
|
function SheetBody(props: { children?: any }) @{
|
|
15
15
|
<>{props.children}</>
|
package/src/Slider.tsrx
CHANGED
|
@@ -22,14 +22,20 @@ export function Slider(props: SliderProps) @{
|
|
|
22
22
|
const ratio = Math.min(1, Math.max(0, (value - min) / (max - min)));
|
|
23
23
|
const width = measure.bounds?.width ?? 0;
|
|
24
24
|
|
|
25
|
-
//
|
|
26
|
-
//
|
|
25
|
+
// Keep one ref identity so native measurement listeners stay attached to
|
|
26
|
+
// the same host across rerenders.
|
|
27
27
|
const host = useRef<any>(null);
|
|
28
28
|
const bindHost = useCallback((el: any) => {
|
|
29
29
|
host.current = el;
|
|
30
30
|
measure.bind(el);
|
|
31
31
|
}, []);
|
|
32
32
|
|
|
33
|
+
const trackHeight = 4;
|
|
34
|
+
const thumbSize = 20;
|
|
35
|
+
const trackTop = (28 - trackHeight) / 2;
|
|
36
|
+
const thumbTop = (28 - thumbSize) / 2;
|
|
37
|
+
const thumbLeft = Math.min(Math.max(ratio * width - thumbSize / 2, 0), Math.max(width - thumbSize, 0));
|
|
38
|
+
|
|
33
39
|
useEffect(() => {
|
|
34
40
|
applyNativeProps(host.current, props);
|
|
35
41
|
});
|
|
@@ -52,7 +58,7 @@ export function Slider(props: SliderProps) @{
|
|
|
52
58
|
}
|
|
53
59
|
});
|
|
54
60
|
|
|
55
|
-
<
|
|
61
|
+
<absolutelayout
|
|
56
62
|
id={props.id}
|
|
57
63
|
className={cx('vx-slider', props.className)}
|
|
58
64
|
style={props.style}
|
|
@@ -60,12 +66,8 @@ export function Slider(props: SliderProps) @{
|
|
|
60
66
|
onPan={onPan}
|
|
61
67
|
ref={bindHost}
|
|
62
68
|
>
|
|
63
|
-
<flexboxlayout className="vx-slider-track" />
|
|
64
|
-
<flexboxlayout className="vx-slider-fill"
|
|
65
|
-
<flexboxlayout
|
|
66
|
-
|
|
67
|
-
horizontalAlignment="left"
|
|
68
|
-
style={{ marginLeft: Math.min(Math.max(ratio * width - 10, 0), Math.max(width - 20, 0)) }}
|
|
69
|
-
/>
|
|
70
|
-
</gridlayout>
|
|
69
|
+
<flexboxlayout className="vx-slider-track" style={{ width, translateY: trackTop }} />
|
|
70
|
+
<flexboxlayout className="vx-slider-fill" style={{ width: ratio * width, translateY: trackTop }} />
|
|
71
|
+
<flexboxlayout className="vx-slider-thumb" style={{ translateX: thumbLeft, translateY: thumbTop }} />
|
|
72
|
+
</absolutelayout>
|
|
71
73
|
}
|
package/src/Text.tsrx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** @jsxImportSource @nativescript-community/octane */
|
|
2
2
|
import { createContext, useContext } from 'octane';
|
|
3
|
+
import { Application } from '@nativescript/core';
|
|
3
4
|
import type { TextProps } from "./props";
|
|
4
5
|
import { cx } from "./cx";
|
|
5
6
|
import { applyEscapeProps, nativeAccessibilityRole, nativeAccessibilityState } from "./escape-props";
|
|
@@ -24,8 +25,41 @@ function TextScope(props: { children?: any }) {
|
|
|
24
25
|
|
|
25
26
|
export function Text(props: TextProps) @{
|
|
26
27
|
const inText = useContext(InText);
|
|
28
|
+
const fontWeightValue = String(props.style?.fontWeight ?? '').toLowerCase();
|
|
29
|
+
const namedWeights: Record<string, number> = {
|
|
30
|
+
normal: 400,
|
|
31
|
+
bold: 700,
|
|
32
|
+
thin: 100,
|
|
33
|
+
'extra-light': 200,
|
|
34
|
+
light: 300,
|
|
35
|
+
medium: 500,
|
|
36
|
+
'semi-bold': 600,
|
|
37
|
+
'extra-bold': 800,
|
|
38
|
+
black: 900,
|
|
39
|
+
};
|
|
40
|
+
const fontWeight = /^\d+$/.test(fontWeightValue)
|
|
41
|
+
? Number(fontWeightValue)
|
|
42
|
+
: namedWeights[fontWeightValue];
|
|
43
|
+
const lineHeight = props.style?.lineHeight;
|
|
44
|
+
// UIFontDescriptor resolves variable fonts to the regular axis default on
|
|
45
|
+
// iOS. Set wght explicitly so CSS fontWeight selects the matching instance.
|
|
27
46
|
const textStyle = {
|
|
28
47
|
...props.style,
|
|
48
|
+
...((Application.ios || Application.android) &&
|
|
49
|
+
typeof lineHeight === 'number' &&
|
|
50
|
+
Number.isFinite(lineHeight) &&
|
|
51
|
+
lineHeight > 0 &&
|
|
52
|
+
props.style?.height == null &&
|
|
53
|
+
props.style?.minHeight == null
|
|
54
|
+
? { minHeight: lineHeight }
|
|
55
|
+
: {}),
|
|
56
|
+
...(Application.ios &&
|
|
57
|
+
props.style?.fontVariationSettings == null &&
|
|
58
|
+
fontWeight !== undefined &&
|
|
59
|
+
fontWeight >= 100 &&
|
|
60
|
+
fontWeight <= 900
|
|
61
|
+
? { fontVariationSettings: `'wght' ${fontWeight}` }
|
|
62
|
+
: {}),
|
|
29
63
|
// Clamped text must be allowed to shrink — the shared shrink:0 default
|
|
30
64
|
// would let the label overflow its row instead of truncating.
|
|
31
65
|
...(props.ellipsize || props.numberOfLines ? { flexShrink: 1 } : {}),
|
package/src/WebView.tsrx
CHANGED
|
@@ -24,6 +24,22 @@ function reportContentLayout(view: any, props: WebViewProps) {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
function applyNativeScrollEnabled(view: any, enabled: boolean | undefined) {
|
|
28
|
+
if (isIOS) {
|
|
29
|
+
const scrollView = view?.ios?.scrollView
|
|
30
|
+
if (scrollView) scrollView.scrollEnabled = enabled !== false
|
|
31
|
+
} else if (isAndroid) {
|
|
32
|
+
const nativeView = view?.android
|
|
33
|
+
if (!nativeView?.setOnTouchListener) return
|
|
34
|
+
nativeView.setOnTouchListener(enabled === false
|
|
35
|
+
? new android.view.View.OnTouchListener({
|
|
36
|
+
onTouch: (_view: any, event: any) =>
|
|
37
|
+
event.getActionMasked() === android.view.MotionEvent.ACTION_MOVE,
|
|
38
|
+
})
|
|
39
|
+
: null)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
27
43
|
/** Embedded web document — NS <webview> (WKWebView / android.webkit.WebView).
|
|
28
44
|
* `html` flows through the `src` property: values that aren't http/file
|
|
29
45
|
* URLs take its `_loadData` path. NS reports failures as `loadFinished`
|
|
@@ -39,16 +55,7 @@ export function WebView(props: WebViewProps) @{
|
|
|
39
55
|
useEffect(() => {
|
|
40
56
|
const v = el.current;
|
|
41
57
|
if (!v) return;
|
|
42
|
-
|
|
43
|
-
v.ios.scrollView.scrollEnabled = props.scrollEnabled !== false;
|
|
44
|
-
} else if (isAndroid) {
|
|
45
|
-
v.android.setOnTouchListener(props.scrollEnabled === false
|
|
46
|
-
? new android.view.View.OnTouchListener({
|
|
47
|
-
onTouch: (_view: any, event: any) =>
|
|
48
|
-
event.getActionMasked() === android.view.MotionEvent.ACTION_MOVE,
|
|
49
|
-
})
|
|
50
|
-
: null);
|
|
51
|
-
}
|
|
58
|
+
applyNativeScrollEnabled(v, props.scrollEnabled)
|
|
52
59
|
if (props.matchContents && loaded.current) reportContentLayout(v, props);
|
|
53
60
|
}, [props.scrollEnabled, props.matchContents]);
|
|
54
61
|
|
|
@@ -70,7 +77,9 @@ export function WebView(props: WebViewProps) @{
|
|
|
70
77
|
className={cx('vx-webview', props.className)}
|
|
71
78
|
style={props.style}
|
|
72
79
|
src={props.html !== undefined ? props.html : props.src}
|
|
80
|
+
onLoaded={() => applyNativeScrollEnabled(el.current, props.scrollEnabled)}
|
|
73
81
|
onLoadFinished={(e: any) => {
|
|
82
|
+
applyNativeScrollEnabled(e.object ?? el.current, props.scrollEnabled)
|
|
74
83
|
if (e.error) props.onError?.({ url: e.url, error: e.error });
|
|
75
84
|
else {
|
|
76
85
|
loaded.current = true;
|
package/src/escape-props.ts
CHANGED
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
import { isAndroid, isIOS } from '@nativescript/core'
|
|
2
2
|
import type { NativeModifier, Role } from './props'
|
|
3
3
|
import { applyNativeModifiers } from './apply-native-modifiers.native'
|
|
4
|
+
import { rememberGridChildPlacement } from './grid-placement'
|
|
4
5
|
|
|
5
6
|
/** Apply only the active device's escape bag after the primitive's own props. */
|
|
6
7
|
export function applyEscapeProps(
|
|
7
8
|
view: any,
|
|
8
|
-
props: {
|
|
9
|
+
props: {
|
|
10
|
+
ios?: any
|
|
11
|
+
android?: any
|
|
12
|
+
modifiers?: readonly NativeModifier[]
|
|
13
|
+
row?: number
|
|
14
|
+
col?: number
|
|
15
|
+
rowSpan?: number
|
|
16
|
+
colSpan?: number
|
|
17
|
+
},
|
|
9
18
|
): void {
|
|
10
19
|
if (!view) {
|
|
11
20
|
return
|
|
12
21
|
}
|
|
22
|
+
rememberGridChildPlacement(view, props)
|
|
13
23
|
|
|
14
24
|
const bag = isIOS ? props.ios : isAndroid ? props.android : undefined
|
|
15
25
|
if (bag) {
|