@octane-xplat/ui 0.7.2 → 0.9.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/README.md +4 -3
- package/dist/native/Button.tsrx.js +1 -1
- package/dist/native/CommandPalette.tsrx.js +7 -1
- package/dist/native/Grid.tsrx.js +31 -2
- package/dist/native/KeyboardAvoiding.mobile.tsrx.js +2 -2
- package/dist/native/Markdown.tsrx.js +233 -0
- package/dist/native/Overlay.tsrx.js +15 -26
- package/dist/native/Pagination.tsrx.js +15 -12
- package/dist/native/PinInput.tsrx.js +25 -7
- package/dist/native/Popover.tsrx.js +33 -23
- package/dist/native/Pressable.tsrx.js +4 -1
- package/dist/native/Screen.tsrx.js +1 -1
- package/dist/native/SearchInput.tsrx.js +6 -3
- package/dist/native/Sheet.tsrx.js +23 -38
- package/dist/native/Slider.tsrx.js +23 -14
- package/dist/native/Text.tsrx.js +16 -0
- package/dist/native/TextArea.tsrx.js +6 -3
- package/dist/native/TextInput.tsrx.js +6 -3
- package/dist/native/VirtualList.tsrx.js +305 -121
- 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 +7 -5
- package/dist/native/keyboard-inset.mobile.js +5 -5
- package/dist/native/navigation-request.js +26 -0
- package/dist/native/octane-client-build.json +1 -1
- package/dist/native/overlay-lifetime.mobile.js +65 -0
- package/dist/native/pan.tsrx.js +16 -2
- package/dist/native/route-table.js +90 -10
- package/dist/native/route.js +26 -16
- package/dist/native/shared.js +7 -5
- package/dist/native/sheet-service.js +2 -2
- package/dist/native/svg.mobile.js +1 -1
- package/dist/native/{tap-to-blur.mobile.js → tap-to-blur.ios.js} +20 -32
- package/dist/native/text-focus.js +10 -0
- package/dist/native/text-write.js +18 -11
- package/dist/native/toast-anchor.tsrx.js +1 -1
- package/dist/native/ui.js +7 -6
- package/dist/native/useMeasure.tsrx.js +17 -18
- package/dist/native/vendor/ui-svg/index.android.js +2 -2
- package/dist/native/vendor/ui-svg/index.ios.js +2 -2
- package/dist/native/vendor/ui-svg/{index.common.js → src/index.common.js} +1 -1
- package/dist/native/virtual-list-cell-pool.js +63 -0
- package/dist/web/Button.web.tsrx.js +1 -1
- package/dist/web/KeyboardAvoiding.web.tsrx.js +78 -0
- package/dist/web/Markdown.tsrx.js +98 -0
- package/dist/web/Overlay.web.tsrx.js +81 -32
- package/dist/web/PinInput.web.tsrx.js +24 -10
- package/dist/web/Pressable.web.tsrx.js +169 -53
- package/dist/web/SearchInput.web.tsrx.js +2 -2
- package/dist/web/Sheet.web.tsrx.js +20 -7
- package/dist/web/TextArea.web.tsrx.js +22 -17
- package/dist/web/TextInput.web.tsrx.js +2 -2
- package/dist/web/VirtualList.web.tsrx.js +220 -109
- package/dist/web/WebView.web.tsrx.js +3 -3
- package/dist/web/{index.shared.js → index.shared.web.js} +7 -5
- package/dist/web/modal-focus.web.js +95 -0
- package/dist/web/navigation-request.js +26 -0
- package/dist/web/octane-client-build.json +1 -1
- package/dist/web/pan.web.tsrx.js +27 -10
- package/dist/web/route-table.js +90 -10
- package/dist/web/route.web.js +88 -22
- package/dist/web/sheet-service.web.js +8 -0
- package/dist/web/theme/colorScheme.web.js +31 -4
- package/dist/web/ui.js +8 -6
- package/dist/web/virtual-list-cell-pool.js +63 -0
- package/package.json +21 -19
- package/platforms/android/native-api-usage.json +7 -7
- package/src/CommandPalette.tsrx +8 -1
- package/src/Grid.tsrx +32 -1
- package/src/Icon.macos.tsrx +1 -0
- package/src/KeyboardAvoiding.macos.tsrx +7 -1
- package/src/KeyboardAvoiding.mobile.tsrx +2 -2
- package/src/KeyboardAvoiding.tsrx +15 -0
- package/src/KeyboardAvoiding.web.tsrx +15 -0
- package/src/Markdown.tsrx +121 -0
- package/src/Meter.tsrx +1 -0
- package/src/Overlay.tsrx +15 -30
- package/src/Overlay.web.tsrx +12 -3
- package/src/Pagination.tsrx +6 -4
- package/src/PinInput.macos.tsrx +20 -6
- package/src/PinInput.mobile.test.ts +107 -0
- package/src/PinInput.tsrx +20 -6
- package/src/PinInput.web.test.tsrx +42 -0
- package/src/PinInput.web.tsrx +20 -6
- package/src/Popover.tsrx +36 -22
- package/src/Pressable.tsrx +1 -1
- package/src/Pressable.web.test.tsrx +36 -0
- package/src/Pressable.web.tsrx +37 -6
- package/src/RouteHost.macos.tsrx +1 -0
- package/src/Screen.tsrx +1 -1
- package/src/SearchInput.tsrx +4 -3
- package/src/SearchInput.web.tsrx +1 -1
- package/src/Sheet.tsrx +21 -42
- package/src/Sheet.web.tsrx +9 -1
- package/src/Slider.tsrx +13 -11
- package/src/Text.tsrx +36 -0
- package/src/TextArea.tsrx +6 -5
- package/src/TextArea.web.test.tsrx +39 -0
- package/src/TextArea.web.tsrx +7 -5
- package/src/TextInput.tsrx +6 -6
- package/src/TextInput.web.tsrx +1 -1
- package/src/VirtualList.macos.tsrx +93 -6
- package/src/VirtualList.mobile.test.tsrx +232 -0
- package/src/VirtualList.tsrx +285 -81
- package/src/VirtualList.web.tsrx +131 -25
- package/src/WebView.tsrx +20 -10
- package/src/WebView.web.tsrx +3 -0
- package/src/android/BottomNavigationView.android.tsrx +1 -0
- package/src/android/MaterialDialog.android.tsrx +1 -0
- package/src/anim.macos.tsrx +1 -0
- package/src/apply-native-modifiers.native.ts +4 -1
- package/src/child-array.ts +12 -7
- package/src/colorScheme.macos.ts +1 -0
- package/src/controls.macos.tsrx +4 -1
- package/src/data-driver.mobile.test.ts +120 -0
- package/src/data-lifecycle.mobile.test.ts +251 -0
- package/src/escape-props.ts +13 -1
- package/src/grid-auto-placement.ts +163 -0
- package/src/grid-placement.ts +29 -0
- package/src/hosted-unsupported.macos.tsrx +1 -0
- package/src/index.macos.ts +23 -3
- package/src/index.mobile.ts +0 -1
- package/src/index.shared.ts +22 -1
- package/src/index.shared.web.ts +291 -0
- package/src/index.web.ts +1 -1
- package/src/input-readiness.web.test.tsrx +82 -0
- package/src/ios/UITabBar.ios.tsrx +1 -0
- package/src/keyboard-inset.mobile.test.ts +62 -0
- package/src/keyboard-inset.mobile.ts +63 -43
- package/src/layout-shells.macos.tsrx +1 -5
- package/src/macos-extras.macos.tsrx +2 -0
- package/src/modal-focus.web.test.tsrx +63 -0
- package/src/modal-focus.web.ts +162 -0
- package/src/navigation-request.ts +37 -0
- package/src/overlay-lifecycle.mobile.test.ts +316 -0
- package/src/overlay-lifetime.mobile.ts +107 -0
- package/src/pan.mobile.test.tsrx +116 -0
- package/src/pan.tsrx +20 -2
- package/src/pan.web.tsrx +35 -7
- package/src/platformProps.ts +1 -0
- package/src/popover.mobile.test.ts +9 -1
- package/src/pressable-accessibility.mobile.test.ts +30 -0
- package/src/props.ts +163 -3
- package/src/refresh.ts +6 -1
- package/src/refresh.web.test.ts +77 -77
- package/src/route-android.test.ts +162 -0
- package/src/route-history.web.test.ts +80 -0
- package/src/route-navigation.web.test.ts +173 -0
- package/src/route-table.test.ts +188 -9
- package/src/route-table.ts +138 -10
- package/src/route.macos.ts +56 -13
- package/src/route.ts +54 -24
- package/src/route.web.ts +141 -24
- package/src/sheet-detents.ts +5 -3
- package/src/sheet-service.macos.ts +5 -1
- package/src/sheet-service.ts +1 -1
- package/src/sheet-service.web.ts +8 -0
- package/src/sheet-snap.test.ts +23 -23
- package/src/sheet-snap.ts +6 -1
- package/src/svg.mobile.ts +9 -3
- package/src/tap-to-blur.ios.ts +106 -0
- package/src/tap-to-blur.mobile.ts +21 -95
- package/src/text-focus.ts +12 -0
- package/src/text-input.mobile.test.ts +89 -0
- package/src/text-write.ts +21 -11
- package/src/theme/colorScheme.linux.ts +2 -4
- package/src/theme/colorScheme.web.ts +51 -4
- package/src/theme/theme-scheme.macos.ts +8 -2
- package/src/theme/tokens.css +1740 -1718
- package/src/translate.macos.ts +4 -1
- package/src/useMeasure.tsrx +20 -21
- package/src/virtual-list-cell-pool.test.ts +53 -0
- package/src/virtual-list-cell-pool.ts +81 -0
- package/src/virtual-list-layout.test.ts +11 -8
- package/src/virtual-list-layout.ts +4 -8
- package/src/windows.linux.ts +7 -2
- package/src/windows.macos.ts +1 -0
- package/types/generated/.tsrx-typegen-manifest.json +16 -3
- package/types/generated/Grid.d.ts +0 -1
- package/types/generated/KeyboardAvoiding.d.ts +3 -0
- package/types/generated/KeyboardAvoiding.web.d.ts +2 -0
- package/types/generated/Markdown.d.ts +59 -0
- package/types/generated/TextArea.d.ts +2 -2
- package/types/generated/TextArea.web.d.ts +1 -1
- package/types/generated/TextInput.d.ts +2 -3
- package/types/generated/VirtualList.d.ts +3 -3
- package/types/generated/escape-props.d.ts +4 -0
- package/types/generated/grid-auto-placement.d.ts +13 -0
- package/types/generated/grid-placement.d.ts +5 -0
- package/types/generated/index.mobile.d.ts +0 -1
- package/types/generated/index.shared.d.ts +6 -3
- package/types/generated/index.shared.web.d.ts +114 -0
- package/types/generated/index.web.d.ts +1 -1
- package/types/generated/modal-focus.web.d.ts +3 -0
- package/types/generated/navigation-request.d.ts +10 -0
- package/types/generated/overlay-lifetime.mobile.d.ts +10 -0
- package/types/generated/props.d.ts +111 -3
- package/types/generated/route-table.d.ts +14 -3
- package/types/generated/svg.mobile.d.ts +2 -2
- 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-focus.d.ts +3 -0
- package/types/generated/text-write.d.ts +3 -1
- package/types/generated/theme/colorScheme.web.d.ts +5 -0
- package/types/generated/virtual-list-cell-pool.d.ts +18 -0
- package/types/index.macos.d.ts +15 -3
- /package/src/vendor/ui-svg/{index.android.ts → src/index.android.ts} +0 -0
- /package/src/vendor/ui-svg/{index.common.ts → src/index.common.ts} +0 -0
- /package/src/vendor/ui-svg/{index.ios.ts → src/index.ios.ts} +0 -0
- /package/src/vendor/ui-svg/{index.ts → src/index.ts} +0 -0
- /package/src/vendor/ui-svg/{typings → src/typings}/SVGKit.d.ts +0 -0
- /package/src/vendor/ui-svg/{typings → src/typings}/android.d.ts +0 -0
- /package/src/vendor/ui-svg/{typings → src/typings}/ios.d.ts +0 -0
- /package/types/generated/vendor/ui-svg/{index.common.d.ts → src/index.common.d.ts} +0 -0
- /package/types/generated/vendor/ui-svg/{index.d.ts → src/index.d.ts} +0 -0
- /package/types/generated/vendor/ui-svg/{index.ios.d.ts → src/index.ios.d.ts} +0 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { applyNativeModifiers } from "./apply-native-modifiers.native.js";
|
|
2
|
+
import { rememberGridChildPlacement } from "./grid-placement.js";
|
|
2
3
|
import { isAndroid, isIOS } from "@nativescript/core";
|
|
3
4
|
//#region src/escape-props.ts
|
|
4
5
|
/** Apply only the active device's escape bag after the primitive's own props. */
|
|
5
6
|
function applyEscapeProps(view, props) {
|
|
6
7
|
if (!view) return;
|
|
8
|
+
rememberGridChildPlacement(view, props);
|
|
7
9
|
const bag = isIOS ? props.ios : isAndroid ? props.android : void 0;
|
|
8
10
|
if (bag) Object.assign(view, bag);
|
|
9
11
|
applyNativeModifiers(view, props.modifiers);
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
//#region src/grid-auto-placement.ts
|
|
2
|
+
function gridIndex(value) {
|
|
3
|
+
if (value == null || value === "") return null;
|
|
4
|
+
const index = Number(value);
|
|
5
|
+
return Number.isInteger(index) && index >= 0 ? index : null;
|
|
6
|
+
}
|
|
7
|
+
function gridSpan(value) {
|
|
8
|
+
const span = Number(value);
|
|
9
|
+
return Number.isInteger(span) && span > 0 ? span : 1;
|
|
10
|
+
}
|
|
11
|
+
function trackCount(spec) {
|
|
12
|
+
return spec?.split(",").filter((track) => track.trim().length > 0).length ?? 0;
|
|
13
|
+
}
|
|
14
|
+
/** Match CSS Grid's row-flow placement for NativeScript GridLayout children. */
|
|
15
|
+
function autoPlaceGridChildren(items, rowTracks, columnTracks) {
|
|
16
|
+
const placements = items.map((item) => ({
|
|
17
|
+
row: gridIndex(item.row),
|
|
18
|
+
col: gridIndex(item.col),
|
|
19
|
+
rowSpan: gridSpan(item.rowSpan),
|
|
20
|
+
colSpan: gridSpan(item.colSpan)
|
|
21
|
+
}));
|
|
22
|
+
const columnCount = Math.max(1, trackCount(columnTracks), ...placements.filter((placement) => placement.col != null).map((placement) => placement.col + placement.colSpan), ...placements.map((placement) => placement.colSpan));
|
|
23
|
+
const occupied = /* @__PURE__ */ new Set();
|
|
24
|
+
const isFree = (row, col, rowSpan, colSpan) => {
|
|
25
|
+
for (let y = row; y < row + rowSpan; y++) for (let x = col; x < col + colSpan; x++) if (occupied.has(`${y},${x}`)) return false;
|
|
26
|
+
return true;
|
|
27
|
+
};
|
|
28
|
+
const occupy = (row, col, rowSpan, colSpan) => {
|
|
29
|
+
for (let y = row; y < row + rowSpan; y++) for (let x = col; x < col + colSpan; x++) occupied.add(`${y},${x}`);
|
|
30
|
+
};
|
|
31
|
+
for (const placement of placements) if (placement.row != null && placement.col != null) occupy(placement.row, placement.col, placement.rowSpan, placement.colSpan);
|
|
32
|
+
for (const placement of placements) {
|
|
33
|
+
if (placement.row == null || placement.col != null) continue;
|
|
34
|
+
let col = 0;
|
|
35
|
+
while (!isFree(placement.row, col, placement.rowSpan, placement.colSpan)) col++;
|
|
36
|
+
placement.col = col;
|
|
37
|
+
occupy(placement.row, col, placement.rowSpan, placement.colSpan);
|
|
38
|
+
}
|
|
39
|
+
for (const placement of placements) {
|
|
40
|
+
if (placement.col == null || placement.row != null) continue;
|
|
41
|
+
let row = 0;
|
|
42
|
+
while (!isFree(row, placement.col, placement.rowSpan, placement.colSpan)) row++;
|
|
43
|
+
placement.row = row;
|
|
44
|
+
occupy(row, placement.col, placement.rowSpan, placement.colSpan);
|
|
45
|
+
}
|
|
46
|
+
let cursorRow = 0;
|
|
47
|
+
let cursorCol = 0;
|
|
48
|
+
for (const placement of placements) {
|
|
49
|
+
if (placement.row != null && placement.col != null) continue;
|
|
50
|
+
while (true) {
|
|
51
|
+
if (cursorCol + placement.colSpan > columnCount) {
|
|
52
|
+
cursorRow++;
|
|
53
|
+
cursorCol = 0;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (isFree(cursorRow, cursorCol, placement.rowSpan, placement.colSpan)) break;
|
|
57
|
+
cursorCol++;
|
|
58
|
+
}
|
|
59
|
+
placement.row = cursorRow;
|
|
60
|
+
placement.col = cursorCol;
|
|
61
|
+
occupy(cursorRow, cursorCol, placement.rowSpan, placement.colSpan);
|
|
62
|
+
cursorCol += placement.colSpan;
|
|
63
|
+
if (cursorCol >= columnCount) {
|
|
64
|
+
cursorRow++;
|
|
65
|
+
cursorCol = 0;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
cells: placements.map(({ row, col }) => ({
|
|
70
|
+
row,
|
|
71
|
+
col
|
|
72
|
+
})),
|
|
73
|
+
rowCount: Math.max(trackCount(rowTracks), ...placements.map((item) => item.row + item.rowSpan)),
|
|
74
|
+
columnCount: Math.max(columnCount, ...placements.map((item) => item.col + item.colSpan))
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function ensureGridTracks(spec, requiredCount) {
|
|
78
|
+
const tracks = spec?.split(",").map((track) => track.trim()).filter(Boolean) ?? [];
|
|
79
|
+
while (tracks.length < requiredCount) tracks.push("auto");
|
|
80
|
+
return tracks.join(",");
|
|
81
|
+
}
|
|
82
|
+
//#endregion
|
|
83
|
+
export { autoPlaceGridChildren, ensureGridTracks };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/grid-placement.ts
|
|
2
|
+
var placements = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
/** Keep the authored Grid placement next to its mounted NativeScript view. */
|
|
4
|
+
function rememberGridChildPlacement(view, props) {
|
|
5
|
+
if ((typeof view !== "object" || view === null) && typeof view !== "function") return;
|
|
6
|
+
const placement = {};
|
|
7
|
+
for (const key of [
|
|
8
|
+
"row",
|
|
9
|
+
"col",
|
|
10
|
+
"rowSpan",
|
|
11
|
+
"colSpan"
|
|
12
|
+
]) if (props[key] !== void 0) placement[key] = props[key];
|
|
13
|
+
if (Object.keys(placement).length) placements.set(view, placement);
|
|
14
|
+
else placements.delete(view);
|
|
15
|
+
}
|
|
16
|
+
function gridChildPlacement(view) {
|
|
17
|
+
return typeof view === "object" && view !== null ? placements.get(view) ?? {} : {};
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { gridChildPlacement, rememberGridChildPlacement };
|
|
@@ -6,9 +6,12 @@ import { Absolute } from "./Absolute.tsrx.js";
|
|
|
6
6
|
import { setTranslate } from "./translate.js";
|
|
7
7
|
import { Spacer } from "./Spacer.tsrx.js";
|
|
8
8
|
import { Text } from "./Text.tsrx.js";
|
|
9
|
+
import { Screen } from "./Screen.tsrx.js";
|
|
10
|
+
import { ActivityIndicator } from "./ActivityIndicator.tsrx.js";
|
|
11
|
+
import { ScrollView } from "./ScrollView.tsrx.js";
|
|
12
|
+
import { Markdown, MarkdownScreen } from "./Markdown.tsrx.js";
|
|
9
13
|
import { RichText, RichTextSpan } from "./RichText.tsrx.js";
|
|
10
14
|
import { Pressable } from "./Pressable.tsrx.js";
|
|
11
|
-
import { ActivityIndicator } from "./ActivityIndicator.tsrx.js";
|
|
12
15
|
import { Button } from "./Button.tsrx.js";
|
|
13
16
|
import { Collapsible } from "./Collapsible.tsrx.js";
|
|
14
17
|
import { Accordion } from "./Accordion.tsrx.js";
|
|
@@ -58,14 +61,13 @@ import { Meter } from "./Meter.tsrx.js";
|
|
|
58
61
|
import { ProgressGroup } from "./ProgressGroup.tsrx.js";
|
|
59
62
|
import { Link } from "./Link.tsrx.js";
|
|
60
63
|
import { getStack, registerStack, stackEntries } from "./stacks.js";
|
|
61
|
-
import { defineRoutes, deriveRouteManifest, mergeRouteManifests } from "./route-table.js";
|
|
64
|
+
import { defineRoutes, deriveRouteManifest, manifestToJson, mergeRouteManifests } from "./route-table.js";
|
|
62
65
|
import { addBackInterceptor, addRoutes, canGoBack, currentModalRoute, currentRoute, hrefFor, layoutsForRoute, popRoute, pushDeepLink, pushRoute, redirect, registerRoutes, registerScreens, routeFor, routeStacks, screenFor, useCanGoBack, useModalRoute, useRoute } from "./route.js";
|
|
63
66
|
import { NavLink } from "./NavLink.tsrx.js";
|
|
64
67
|
import { TextArea } from "./TextArea.tsrx.js";
|
|
65
68
|
import { SearchInput } from "./SearchInput.tsrx.js";
|
|
66
69
|
import { SegmentedControl } from "./SegmentedControl.tsrx.js";
|
|
67
70
|
import { ScrollBox } from "./ScrollBox.tsrx.js";
|
|
68
|
-
import { ScrollView } from "./ScrollView.tsrx.js";
|
|
69
71
|
import { VirtualList } from "./VirtualList.tsrx.js";
|
|
70
72
|
import { WebView } from "./WebView.tsrx.js";
|
|
71
73
|
import { Hoverable } from "./Hoverable.mobile.tsrx.js";
|
|
@@ -74,11 +76,11 @@ import { showToast } from "./toast-anchor.tsrx.js";
|
|
|
74
76
|
import { useAnimation } from "./anim.tsrx.js";
|
|
75
77
|
import { styled } from "./styled.tsrx.js";
|
|
76
78
|
import { openWindow } from "./windows.js";
|
|
77
|
-
import { Screen } from "./Screen.tsrx.js";
|
|
78
79
|
import { Tabs } from "./Tabs.tsrx.js";
|
|
79
80
|
import { Switch } from "./Switch.tsrx.js";
|
|
80
81
|
import { useSafeAreaInsets } from "./safeAreaInsets.tsrx.js";
|
|
81
82
|
import { SafeArea } from "./SafeArea.tsrx.js";
|
|
83
|
+
import { KeyboardAvoiding } from "./KeyboardAvoiding.mobile.tsrx.js";
|
|
82
84
|
import { Drawer } from "./Drawer.tsrx.js";
|
|
83
85
|
import { useMeasure } from "./useMeasure.tsrx.js";
|
|
84
86
|
import { Slider } from "./Slider.tsrx.js";
|
|
@@ -89,4 +91,4 @@ import { createStore } from "./store.js";
|
|
|
89
91
|
import { useStore } from "./use-store.tsrx.js";
|
|
90
92
|
import { Sheet } from "./Sheet.tsrx.js";
|
|
91
93
|
import { closeSheet, openSheet } from "./sheet-service.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, 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 };
|
|
94
|
+
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, KeyboardAvoiding, Link, ListItem, Markdown, MarkdownScreen, 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, layoutsForRoute, manifestToJson, 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 };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Application } from "@nativescript/core";
|
|
1
|
+
import { Application, Utils } from "@nativescript/core";
|
|
2
2
|
//#region src/keyboard-inset.mobile.ts
|
|
3
3
|
var bound = /* @__PURE__ */ new Set();
|
|
4
4
|
var inset = 0;
|
|
@@ -39,19 +39,19 @@ function bindBottomInsetToKeyboard(host) {
|
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
41
|
if (Application.android) {
|
|
42
|
-
const nativeWindow = Application.android.foregroundActivity?.
|
|
42
|
+
const nativeWindow = Application.android.foregroundActivity?.getWindow();
|
|
43
43
|
if (!nativeWindow) return () => {};
|
|
44
44
|
const params = globalThis.android?.view?.WindowManager?.LayoutParams;
|
|
45
45
|
if (!params) return () => {};
|
|
46
|
-
if ((nativeWindow.
|
|
46
|
+
if ((nativeWindow.getAttributes().softInputMode & params.SOFT_INPUT_MASK_ADJUST) === params.SOFT_INPUT_ADJUST_RESIZE) return () => {};
|
|
47
47
|
const ViewCompat = globalThis.androidx?.core?.view?.ViewCompat;
|
|
48
48
|
const WindowInsetsCompat = globalThis.androidx?.core?.view?.WindowInsetsCompat;
|
|
49
49
|
if (!ViewCompat || !WindowInsetsCompat) return () => {};
|
|
50
|
-
const decorView = nativeWindow.
|
|
50
|
+
const decorView = nativeWindow.getDecorView();
|
|
51
51
|
const listener = new ViewCompat.OnApplyWindowInsetsListener({ onApplyWindowInsets: (v, insets) => {
|
|
52
52
|
const ime = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom;
|
|
53
53
|
const nav = insets.getInsets(WindowInsetsCompat.Type.systemBars()).bottom;
|
|
54
|
-
host.translateY = -Math.max(0, ime - nav);
|
|
54
|
+
host.translateY = -Utils.layout.toDeviceIndependentPixels(Math.max(0, ime - nav));
|
|
55
55
|
return insets;
|
|
56
56
|
} });
|
|
57
57
|
ViewCompat.setOnApplyWindowInsetsListener(decorView, listener);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/navigation-request.ts
|
|
2
|
+
function createNavigationRequests() {
|
|
3
|
+
const versions = /* @__PURE__ */ new Map();
|
|
4
|
+
const invalidate = (stack) => {
|
|
5
|
+
const version = (versions.get(stack) ?? 0) + 1;
|
|
6
|
+
versions.set(stack, version);
|
|
7
|
+
return version;
|
|
8
|
+
};
|
|
9
|
+
return {
|
|
10
|
+
invalidate,
|
|
11
|
+
begin(stack) {
|
|
12
|
+
const owned = /* @__PURE__ */ new Map([[stack, invalidate(stack)]]);
|
|
13
|
+
const isCurrent = () => [...owned].every(([name, version]) => versions.get(name) === version);
|
|
14
|
+
return {
|
|
15
|
+
isCurrent,
|
|
16
|
+
claim(name) {
|
|
17
|
+
if (!isCurrent()) return false;
|
|
18
|
+
if (!owned.has(name)) owned.set(name, invalidate(name));
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { createNavigationRequests };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
//#region src/overlay-lifetime.mobile.ts
|
|
2
|
+
/** Own the resources of one independently mounted overlay. RootLayout emits
|
|
3
|
+
* closed before removing the host, so that notification must never reenter close. */
|
|
4
|
+
function createOverlayLifetime(owner, host, root, label, onFinish) {
|
|
5
|
+
const registry = owner;
|
|
6
|
+
let released = false;
|
|
7
|
+
let closing = false;
|
|
8
|
+
const cleanups = /* @__PURE__ */ new Set();
|
|
9
|
+
const report = (action, error) => console.error(`[${label}] ${action} failed`, error);
|
|
10
|
+
const release = (dismissed) => {
|
|
11
|
+
if (released) return;
|
|
12
|
+
released = true;
|
|
13
|
+
host.off("closed", onClosed);
|
|
14
|
+
for (const cleanup of cleanups) cleanup();
|
|
15
|
+
cleanups.clear();
|
|
16
|
+
root.unmount();
|
|
17
|
+
onFinish(dismissed);
|
|
18
|
+
};
|
|
19
|
+
const onClosed = () => {
|
|
20
|
+
closing = true;
|
|
21
|
+
release(true);
|
|
22
|
+
};
|
|
23
|
+
const detach = () => {
|
|
24
|
+
if (closing || !registry.hasChild(host)) return;
|
|
25
|
+
if (registry.getPopupIndex(host) === -1) return;
|
|
26
|
+
closing = true;
|
|
27
|
+
const failed = (error) => {
|
|
28
|
+
report("close", error);
|
|
29
|
+
if (registry.hasChild(host)) owner.removeChild(host);
|
|
30
|
+
};
|
|
31
|
+
try {
|
|
32
|
+
owner.close(host).catch(failed);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
failed(error);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
host.on("closed", onClosed);
|
|
38
|
+
return {
|
|
39
|
+
own(cleanup) {
|
|
40
|
+
if (released) cleanup();
|
|
41
|
+
else cleanups.add(cleanup);
|
|
42
|
+
},
|
|
43
|
+
close() {
|
|
44
|
+
release(false);
|
|
45
|
+
detach();
|
|
46
|
+
},
|
|
47
|
+
open(options, afterOpen) {
|
|
48
|
+
const failed = (error) => {
|
|
49
|
+
report("open", error);
|
|
50
|
+
release(false);
|
|
51
|
+
detach();
|
|
52
|
+
};
|
|
53
|
+
try {
|
|
54
|
+
owner.open(host, options).then(() => {
|
|
55
|
+
if (released) detach();
|
|
56
|
+
else return afterOpen?.();
|
|
57
|
+
}).catch(failed);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
failed(error);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
export { createOverlayLifetime };
|
package/dist/native/pan.tsrx.js
CHANGED
|
@@ -11,6 +11,14 @@ var PAN_STATE = [
|
|
|
11
11
|
"ended"
|
|
12
12
|
];
|
|
13
13
|
function panVelocity(e, state, trackerRef) {
|
|
14
|
+
if (state === 0) {
|
|
15
|
+
trackerRef.current?.recycle?.();
|
|
16
|
+
trackerRef.current = null;
|
|
17
|
+
return {
|
|
18
|
+
vx: 0,
|
|
19
|
+
vy: 0
|
|
20
|
+
};
|
|
21
|
+
}
|
|
14
22
|
const recognizer = e.ios;
|
|
15
23
|
const nativeView = e.view?.nativeViewProtected;
|
|
16
24
|
if (recognizer?.velocityInView && nativeView) {
|
|
@@ -44,11 +52,17 @@ function panVelocity(e, state, trackerRef) {
|
|
|
44
52
|
}
|
|
45
53
|
return velocity;
|
|
46
54
|
}
|
|
55
|
+
function nativePanState(e) {
|
|
56
|
+
const motionEvent = e.android?.current;
|
|
57
|
+
if (!motionEvent) return e.state;
|
|
58
|
+
return motionEvent.getActionMasked?.() === (globalThis.android?.view?.MotionEvent?.ACTION_CANCEL ?? 3) ? 0 : e.state;
|
|
59
|
+
}
|
|
47
60
|
function usePan(cb) {
|
|
48
61
|
const velocityTracker = useRef(null, _h$0);
|
|
49
62
|
const handler = useCallback((e) => {
|
|
50
|
-
const
|
|
51
|
-
const
|
|
63
|
+
const nativeState = nativePanState(e);
|
|
64
|
+
const state = PAN_STATE[nativeState] ?? "moved";
|
|
65
|
+
const velocity = panVelocity(e, nativeState, velocityTracker);
|
|
52
66
|
cb?.({
|
|
53
67
|
x: e.deltaX,
|
|
54
68
|
y: e.deltaY,
|
|
@@ -2,7 +2,22 @@
|
|
|
2
2
|
var EXT = /\.(tsrx|tsx|ts|mts|cts|js|mjs|cjs|jsx)$/;
|
|
3
3
|
var SUFFIX = /\.(web|mobile|ios|android|macos|windows|linux)$/;
|
|
4
4
|
var PARAM = /^\[(.+)\]$/;
|
|
5
|
+
/** Build-time loader modules — `docs.loader.ts` pairs with route `docs`
|
|
6
|
+
* for `dataMode: 'baked'`. Never a route itself, never in a runtime glob. */
|
|
7
|
+
var LOADER_FILE = /\.loader\.(ts|mts|cts|js|mjs|cjs|jsx)$/;
|
|
5
8
|
var PRESENT = /\+(modal|fade|push)$/;
|
|
9
|
+
/** Loader for a `dataMode: 'baked'` route — resolves the name out of its
|
|
10
|
+
* owning manifest's `baked` map at push time. The map is assigned after
|
|
11
|
+
* the manifest is built (generated glue) or passed in (RouteSpecSet), so
|
|
12
|
+
* the lookup reads it lazily. A missing entry throws, landing as the
|
|
13
|
+
* screen's `error` prop like a live loader rejection. */
|
|
14
|
+
function bakedLookup(manifest, name) {
|
|
15
|
+
return () => {
|
|
16
|
+
const baked = manifest()?.baked;
|
|
17
|
+
if (baked && Object.prototype.hasOwnProperty.call(baked, name)) return baked[name];
|
|
18
|
+
throw new Error(`[octane-xplat] baked route '${name}' has no baked data — run \`xplat routes\` to regenerate`);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
6
21
|
/** Internal error carrier used by the public `redirect()` helper. Keeping
|
|
7
22
|
* this in the shared route table gives both platform leaves the same guard
|
|
8
23
|
* behavior without importing a platform runtime. */
|
|
@@ -35,7 +50,9 @@ function deriveRouteManifest(files, prefer, dir = "app") {
|
|
|
35
50
|
const layouts = {};
|
|
36
51
|
const loaders = {};
|
|
37
52
|
const warned = /* @__PURE__ */ new Set();
|
|
53
|
+
const self = {};
|
|
38
54
|
for (const key of Object.keys(files).sort()) {
|
|
55
|
+
if (LOADER_FILE.test(key)) continue;
|
|
39
56
|
let rel = key.replace(/^\.?\//, "");
|
|
40
57
|
if (rel.startsWith(prefix)) rel = rel.slice(prefix.length);
|
|
41
58
|
rel = rel.replace(EXT, "");
|
|
@@ -74,8 +91,13 @@ function deriveRouteManifest(files, prefer, dir = "app") {
|
|
|
74
91
|
file: key,
|
|
75
92
|
presentation
|
|
76
93
|
};
|
|
94
|
+
const dataMode = files[key]?.dataMode;
|
|
95
|
+
if (dataMode === "baked" || dataMode === "live") meta.dataMode = dataMode;
|
|
77
96
|
const loader = files[key]?.loader;
|
|
78
|
-
if (
|
|
97
|
+
if (meta.dataMode === "baked") {
|
|
98
|
+
meta.loader = bakedLookup(() => self.m, name);
|
|
99
|
+
if (typeof loader === "function") console.warn(`[octane-xplat] baked route '${name}' also exports a loader — move it to a .loader.ts sibling so its imports stay out of the bundle`);
|
|
100
|
+
} else if (typeof loader === "function") meta.loader = loader;
|
|
79
101
|
const beforeLoad = files[key]?.beforeLoad;
|
|
80
102
|
if (typeof beforeLoad === "function") meta.beforeLoad = beforeLoad;
|
|
81
103
|
if (files[key]?.head && (typeof files[key].head === "object" || typeof files[key].head === "function")) meta.head = files[key].head;
|
|
@@ -102,12 +124,14 @@ function deriveRouteManifest(files, prefer, dir = "app") {
|
|
|
102
124
|
if (meta.loader) loaders[meta.name] = meta.loader;
|
|
103
125
|
}
|
|
104
126
|
routes.sort(bySpecificity);
|
|
105
|
-
|
|
127
|
+
const manifest = {
|
|
106
128
|
screens,
|
|
107
129
|
routes,
|
|
108
130
|
layouts,
|
|
109
131
|
loaders
|
|
110
132
|
};
|
|
133
|
+
self.m = manifest;
|
|
134
|
+
return manifest;
|
|
111
135
|
}
|
|
112
136
|
/** Match-order comparator: static segments (2) outrank params (1), ties
|
|
113
137
|
* break alphabetically so ordering is total and stable across merges. */
|
|
@@ -131,7 +155,12 @@ var mergeWarned = /* @__PURE__ */ new Set();
|
|
|
131
155
|
* from their own sources, e.g. `readdirSync` over a content dir). Each
|
|
132
156
|
* spec's `path` uses the route-dir vocabulary; `layouts` keys are path
|
|
133
157
|
* prefixes playing the `_layout` role. Same-name duplicates inside the
|
|
134
|
-
* set keep the later entry with a warn, matching merge precedence.
|
|
158
|
+
* set keep the later entry with a warn, matching merge precedence.
|
|
159
|
+
*
|
|
160
|
+
* The return is branded with the spec-derived route types — read them
|
|
161
|
+
* with `ManifestRouteParams`/`ManifestRouteNames`/
|
|
162
|
+
* `ManifestRoutePresentations` to merge programmatic names into the
|
|
163
|
+
* app's typed navigation surface (`RouteName | …`, `RouteParams & …`). */
|
|
135
164
|
function defineRoutes(input) {
|
|
136
165
|
const set = Array.isArray(input) ? { routes: input } : input;
|
|
137
166
|
const specs = set.routes;
|
|
@@ -140,6 +169,7 @@ function defineRoutes(input) {
|
|
|
140
169
|
const layouts = {};
|
|
141
170
|
const metas = /* @__PURE__ */ new Map();
|
|
142
171
|
const warned = /* @__PURE__ */ new Set();
|
|
172
|
+
const self = {};
|
|
143
173
|
for (const [key, layout] of Object.entries(extra ?? {})) {
|
|
144
174
|
const dir = key.replace(/^\/+|\/+$/g, "");
|
|
145
175
|
if (dir !== key) console.warn(`[octane-xplat] layout key '${key}' normalized to '${dir}'`);
|
|
@@ -155,7 +185,11 @@ function defineRoutes(input) {
|
|
|
155
185
|
file: spec.source ?? `programmatic:${spec.path}`,
|
|
156
186
|
presentation: spec.presentation
|
|
157
187
|
};
|
|
158
|
-
if (spec.
|
|
188
|
+
if (spec.dataMode) meta.dataMode = spec.dataMode;
|
|
189
|
+
if (spec.dataMode === "baked") {
|
|
190
|
+
meta.loader = bakedLookup(() => self.m, name);
|
|
191
|
+
if (spec.loader) console.warn(`[octane-xplat] baked route '${name}' also carries a loader — bake it in the host and pass the result via 'baked' so its code stays out of the bundle`);
|
|
192
|
+
} else if (spec.loader) meta.loader = spec.loader;
|
|
159
193
|
if (spec.beforeLoad) meta.beforeLoad = spec.beforeLoad;
|
|
160
194
|
if (spec.head) meta.head = spec.head;
|
|
161
195
|
if (metas.has(name) && !warned.has(name)) {
|
|
@@ -172,12 +206,15 @@ function defineRoutes(input) {
|
|
|
172
206
|
const routes = [...metas.values()].sort(bySpecificity);
|
|
173
207
|
const loaders = {};
|
|
174
208
|
for (const meta of routes) if (meta.loader) loaders[meta.name] = meta.loader;
|
|
175
|
-
|
|
209
|
+
const manifest = {
|
|
176
210
|
screens,
|
|
177
211
|
routes,
|
|
178
212
|
layouts,
|
|
179
|
-
loaders
|
|
213
|
+
loaders,
|
|
214
|
+
baked: set.baked
|
|
180
215
|
};
|
|
216
|
+
self.m = manifest;
|
|
217
|
+
return manifest;
|
|
181
218
|
}
|
|
182
219
|
/** Compose manifests into one — file-derived base plus any number of
|
|
183
220
|
* programmatic sets (`registerRoutes(mergeRouteManifests(fromDir, dynamic))`).
|
|
@@ -188,9 +225,11 @@ function defineRoutes(input) {
|
|
|
188
225
|
function mergeRouteManifests(...manifests) {
|
|
189
226
|
const screens = {};
|
|
190
227
|
const layouts = {};
|
|
228
|
+
const baked = {};
|
|
191
229
|
const winners = /* @__PURE__ */ new Map();
|
|
192
230
|
for (const m of manifests) {
|
|
193
231
|
Object.assign(layouts, m.layouts);
|
|
232
|
+
Object.assign(baked, m.baked);
|
|
194
233
|
Object.assign(screens, m.screens);
|
|
195
234
|
for (const meta of m.routes) {
|
|
196
235
|
const prev = winners.get(meta.name);
|
|
@@ -208,7 +247,38 @@ function mergeRouteManifests(...manifests) {
|
|
|
208
247
|
screens,
|
|
209
248
|
routes,
|
|
210
249
|
layouts,
|
|
211
|
-
loaders
|
|
250
|
+
loaders,
|
|
251
|
+
baked
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
/** Serialize a manifest to the normalized `RouteManifestJson` shape — the
|
|
255
|
+
* same list `xplat routes` emits for file routes, produced here for
|
|
256
|
+
* programmatic/merged manifests so hosts consume one schema. */
|
|
257
|
+
function manifestToJson(manifest) {
|
|
258
|
+
return {
|
|
259
|
+
version: 1,
|
|
260
|
+
layouts: Object.keys(manifest.layouts).sort(),
|
|
261
|
+
screens: Object.keys(manifest.screens).sort(),
|
|
262
|
+
routes: manifest.routes.map((meta) => {
|
|
263
|
+
const segs = meta.name.split("/");
|
|
264
|
+
const layoutDirs = manifest.layouts[""] ? [""] : [];
|
|
265
|
+
for (let i = 1; i < segs.length; i++) {
|
|
266
|
+
const d = segs.slice(0, i).join("/");
|
|
267
|
+
if (manifest.layouts[d]) layoutDirs.push(d);
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
name: meta.name,
|
|
271
|
+
path: meta.name === "index" ? "" : meta.segments.join("/"),
|
|
272
|
+
params: [...meta.params],
|
|
273
|
+
...meta.presentation ? { presentation: meta.presentation } : {},
|
|
274
|
+
...meta.dataMode ? { dataMode: meta.dataMode } : {},
|
|
275
|
+
layouts: layoutDirs,
|
|
276
|
+
source: meta.file,
|
|
277
|
+
loader: !!meta.loader,
|
|
278
|
+
guard: !!meta.beforeLoad,
|
|
279
|
+
head: !!meta.head
|
|
280
|
+
};
|
|
281
|
+
})
|
|
212
282
|
};
|
|
213
283
|
}
|
|
214
284
|
/** Match URL path segments against a manifest — returns the winning meta
|
|
@@ -309,9 +379,19 @@ function linkPath(url) {
|
|
|
309
379
|
* is the stack prefix ('/demos/demo/x' → stack 'demos'). Unmatched names
|
|
310
380
|
* fall through as literal routes for pre-manifest callers. */
|
|
311
381
|
function matchUrl(routes, url) {
|
|
312
|
-
|
|
382
|
+
url = url.split("#", 1)[0];
|
|
383
|
+
const at = url.indexOf("?");
|
|
384
|
+
const p = at === -1 ? url : url.slice(0, at);
|
|
385
|
+
const qs = at === -1 ? void 0 : url.slice(at + 1);
|
|
313
386
|
const segs = p.split("/").filter(Boolean);
|
|
314
|
-
|
|
387
|
+
let query;
|
|
388
|
+
try {
|
|
389
|
+
if (!decodeURIComponent(p)) return null;
|
|
390
|
+
query = parseQueryString(qs);
|
|
391
|
+
} catch (error) {
|
|
392
|
+
if (error instanceof URIError) return null;
|
|
393
|
+
throw error;
|
|
394
|
+
}
|
|
315
395
|
if (!segs.length) return null;
|
|
316
396
|
const finish = (stack, m, fallbackName) => ({
|
|
317
397
|
stack,
|
|
@@ -347,4 +427,4 @@ function layoutChain(layouts, name) {
|
|
|
347
427
|
return chain;
|
|
348
428
|
}
|
|
349
429
|
//#endregion
|
|
350
|
-
export { RouteRedirect, buildRoutePath, defineRoutes, deriveRouteManifest, layoutChain, linkPath, matchRoute, matchUrl, mergeRouteManifests, parseQueryString };
|
|
430
|
+
export { RouteRedirect, buildRoutePath, defineRoutes, deriveRouteManifest, layoutChain, linkPath, manifestToJson, matchRoute, matchUrl, mergeRouteManifests, parseQueryString };
|
package/dist/native/route.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createNavigationRequests } from "./navigation-request.js";
|
|
1
2
|
import { getStack, onStackRegistered, stackEntries } from "./stacks.js";
|
|
2
3
|
import { RouteRedirect, buildRoutePath, layoutChain, linkPath, matchUrl, mergeRouteManifests } from "./route-table.js";
|
|
3
4
|
import { RouteHost } from "./RouteHost.mobile.tsrx.js";
|
|
@@ -23,6 +24,7 @@ import { hookSlots as hookSlots$1, useSyncExternalStore as useSyncExternalStore$
|
|
|
23
24
|
* - named stacks register via `TabSpec.stack` or `registerStack`.
|
|
24
25
|
* Every drop path warns loudly — silent no-ops are how apps ship a
|
|
25
26
|
* default route on native while working fine on web. */
|
|
27
|
+
var navigationRequests = createNavigationRequests();
|
|
26
28
|
var baseManifest = {
|
|
27
29
|
screens: {},
|
|
28
30
|
routes: [],
|
|
@@ -95,10 +97,11 @@ function warnOnce(key, msg) {
|
|
|
95
97
|
/** Attach the route-store emission hook once per frame. `navigatedTo`
|
|
96
98
|
* fires on push AND on pop (the revealed page re-fires it), so one
|
|
97
99
|
* listener keeps every useRoute snapshot honest. */
|
|
98
|
-
function trackFrame(frame) {
|
|
100
|
+
function trackFrame(frame, stack) {
|
|
99
101
|
if (tracked.has(frame)) return;
|
|
100
102
|
tracked.add(frame);
|
|
101
|
-
frame.on("navigatedTo", () => {
|
|
103
|
+
frame.on("navigatedTo", (event) => {
|
|
104
|
+
if (event?.isBackNavigation) navigationRequests.invalidate(stack);
|
|
102
105
|
const page = frame.currentPage;
|
|
103
106
|
if (page && page.isLoaded === false) page.callLoaded?.();
|
|
104
107
|
emit();
|
|
@@ -106,7 +109,7 @@ function trackFrame(frame) {
|
|
|
106
109
|
}
|
|
107
110
|
function resolveStack(stack) {
|
|
108
111
|
const frame = getStack(stack);
|
|
109
|
-
if (frame) trackFrame(frame);
|
|
112
|
+
if (frame) trackFrame(frame, stack);
|
|
110
113
|
return frame;
|
|
111
114
|
}
|
|
112
115
|
/** TabViewItem-hosted frames report isLoaded=false after tab-selection
|
|
@@ -117,8 +120,8 @@ function resolveStack(stack) {
|
|
|
117
120
|
function rearmFrameLoaded(frame) {
|
|
118
121
|
if (!frame.isLoaded) frame.callLoaded?.();
|
|
119
122
|
}
|
|
120
|
-
onStackRegistered((
|
|
121
|
-
trackFrame(frame);
|
|
123
|
+
onStackRegistered((name, frame) => {
|
|
124
|
+
trackFrame(frame, name);
|
|
122
125
|
ensureBackWired();
|
|
123
126
|
emit();
|
|
124
127
|
});
|
|
@@ -209,10 +212,12 @@ function headFor(r) {
|
|
|
209
212
|
function contextFor(r) {
|
|
210
213
|
return r.context ?? {};
|
|
211
214
|
}
|
|
212
|
-
async function prepareRoute(r, redirects = 0) {
|
|
215
|
+
async function prepareRoute(r, request, redirects = 0) {
|
|
216
|
+
if (!request.isCurrent()) return;
|
|
217
|
+
if (!request.claim(r.stack)) return;
|
|
213
218
|
const beforeLoad = metaFor(r.name)?.beforeLoad;
|
|
214
219
|
if (!beforeLoad) {
|
|
215
|
-
commitRoute(r);
|
|
220
|
+
commitRoute(r, request);
|
|
216
221
|
return;
|
|
217
222
|
}
|
|
218
223
|
if (redirects > 16) {
|
|
@@ -231,10 +236,11 @@ async function prepareRoute(r, redirects = 0) {
|
|
|
231
236
|
commitRoute({
|
|
232
237
|
...r,
|
|
233
238
|
context
|
|
234
|
-
});
|
|
239
|
+
}, request);
|
|
235
240
|
} catch (e) {
|
|
241
|
+
if (!request.isCurrent()) return;
|
|
236
242
|
if (e instanceof RouteRedirect) {
|
|
237
|
-
await prepareRoute(e.route, redirects + 1);
|
|
243
|
+
await prepareRoute(e.route, request, redirects + 1);
|
|
238
244
|
return;
|
|
239
245
|
}
|
|
240
246
|
console.warn(`[octane-xplat] beforeLoad('${r.name}') rejected: ${e?.message ?? e}`);
|
|
@@ -244,13 +250,15 @@ function redirect(r) {
|
|
|
244
250
|
throw new RouteRedirect(r);
|
|
245
251
|
}
|
|
246
252
|
function pushRoute(r) {
|
|
253
|
+
const request = navigationRequests.begin(r.stack);
|
|
247
254
|
if (metaFor(r.name)?.beforeLoad) {
|
|
248
|
-
prepareRoute(r);
|
|
255
|
+
prepareRoute(r, request);
|
|
249
256
|
return;
|
|
250
257
|
}
|
|
251
|
-
commitRoute(r);
|
|
258
|
+
commitRoute(r, request);
|
|
252
259
|
}
|
|
253
|
-
function commitRoute(r) {
|
|
260
|
+
function commitRoute(r, request) {
|
|
261
|
+
if (!request.isCurrent()) return;
|
|
254
262
|
const C = screenFor(r.name);
|
|
255
263
|
if (!C) {
|
|
256
264
|
warnOnce("screen:" + r.name, `pushRoute('${r.name}') dropped — '${r.name}' isn't in the screen table. Call registerScreens({ ${r.name}: ... }) at boot.`);
|
|
@@ -262,10 +270,10 @@ function commitRoute(r) {
|
|
|
262
270
|
Promise.resolve().then(() => loader(r.params)).then((loaderData) => commitRoute({
|
|
263
271
|
...r,
|
|
264
272
|
loaderData
|
|
265
|
-
}), (loaderError) => commitRoute({
|
|
273
|
+
}, request), (loaderError) => commitRoute({
|
|
266
274
|
...r,
|
|
267
275
|
loaderError
|
|
268
|
-
}));
|
|
276
|
+
}, request));
|
|
269
277
|
return;
|
|
270
278
|
}
|
|
271
279
|
if (presentation === "modal") {
|
|
@@ -347,6 +355,7 @@ function pushModal(frame, r, C) {
|
|
|
347
355
|
const i = modalHosts.indexOf(entry);
|
|
348
356
|
if (i === -1) return;
|
|
349
357
|
modalHosts.splice(i, 1);
|
|
358
|
+
root.unmount?.();
|
|
350
359
|
emit();
|
|
351
360
|
};
|
|
352
361
|
const presenter = modalPresenter(frame);
|
|
@@ -380,7 +389,6 @@ function pushModal(frame, r, C) {
|
|
|
380
389
|
emit();
|
|
381
390
|
} catch (e) {
|
|
382
391
|
entry.dismiss();
|
|
383
|
-
root.unmount?.();
|
|
384
392
|
console.warn("[octane-xplat] modal pushRoute(" + r.name + ") threw: " + e?.message);
|
|
385
393
|
}
|
|
386
394
|
}
|
|
@@ -389,8 +397,10 @@ function pushModal(frame, r, C) {
|
|
|
389
397
|
* where back at the app root is a no-op; loud only when the stack
|
|
390
398
|
* itself doesn't exist. */
|
|
391
399
|
function popRoute(stack = "root") {
|
|
400
|
+
navigationRequests.invalidate(stack);
|
|
392
401
|
const modal = modalHosts[modalHosts.length - 1];
|
|
393
402
|
if (modal) {
|
|
403
|
+
navigationRequests.invalidate(modal.route.stack);
|
|
394
404
|
modal.dismiss();
|
|
395
405
|
modal.host.closeModal?.();
|
|
396
406
|
return;
|
|
@@ -456,7 +466,7 @@ function currentModalRoute() {
|
|
|
456
466
|
* `onDeepLink(pushDeepLink)` plus one `consumeInitialUrl()` call. */
|
|
457
467
|
function pushDeepLink(url) {
|
|
458
468
|
const r = matchUrl(routes, linkPath(url));
|
|
459
|
-
if (!r) {
|
|
469
|
+
if (!r || !screenFor(r.name)) {
|
|
460
470
|
warnOnce("link:" + url, `pushDeepLink('${url}') dropped — no route matches.`);
|
|
461
471
|
return false;
|
|
462
472
|
}
|