@ankhorage/expo-runtime 3.0.13 → 3.1.1
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/CHANGELOG.md +13 -0
- package/README.md +1 -1
- package/dist/ExpoZoraIconFontProvider.web.d.ts.map +1 -1
- package/dist/ExpoZoraIconFontProvider.web.js +2 -0
- package/dist/ExpoZoraIconFontProvider.web.js.map +1 -1
- package/dist/platform.d.ts +7 -0
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +7 -0
- package/dist/platform.js.map +1 -1
- package/dist/reader/navigation/resolveReaderKeyboardIntent.d.ts +9 -0
- package/dist/reader/navigation/resolveReaderKeyboardIntent.d.ts.map +1 -0
- package/dist/reader/navigation/resolveReaderKeyboardIntent.js +19 -0
- package/dist/reader/navigation/resolveReaderKeyboardIntent.js.map +1 -0
- package/dist/reader/navigation/resolveReaderNavigationIntent.d.ts +11 -0
- package/dist/reader/navigation/resolveReaderNavigationIntent.d.ts.map +1 -0
- package/dist/reader/navigation/resolveReaderNavigationIntent.js +16 -0
- package/dist/reader/navigation/resolveReaderNavigationIntent.js.map +1 -0
- package/package.json +22 -2
- package/src/ExpoZoraIconFontProvider.web.test.tsx +1 -0
- package/src/ExpoZoraIconFontProvider.web.tsx +2 -0
- package/src/platform.test.ts +24 -46
- package/src/platform.ts +10 -0
- package/src/reader/navigation/resolveReaderKeyboardIntent.test.ts +38 -0
- package/src/reader/navigation/resolveReaderKeyboardIntent.ts +20 -0
- package/src/reader/navigation/resolveReaderNavigationIntent.test.ts +48 -0
- package/src/reader/navigation/resolveReaderNavigationIntent.ts +23 -0
- package/src/reader/rendererPackages.test.ts +22 -0
- package/src/resolveExpoRuntimePlan.test.ts +9 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @ankhorage/expo-runtime
|
|
2
2
|
|
|
3
|
+
## 3.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 979cb5b: Pin the audited EPUB/PDF renderer foundations and document the isolated DOM, content-safety, and deterministic fixture contract for the reader adapter.
|
|
8
|
+
- 162fb2a: Update Ankhorage dependencies: `@ankhorage/contracts`.
|
|
9
|
+
|
|
10
|
+
## 3.1.0
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- 955498a: Expose the five canonical static icon provider packages through the Expo platform contract, including Material Design Icons.
|
|
15
|
+
|
|
3
16
|
## 3.0.13
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
# EXPO-RUNTIME
|
|
5
5
|
|
|
6
|
-
         
|
|
7
7
|
|
|
8
8
|
Declarative runtime integration for Expo apps: maps app capabilities to permissions, packages, config plugins, providers, and adapters
|
|
9
9
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoZoraIconFontProvider.web.d.ts","sourceRoot":"","sources":["../src/ExpoZoraIconFontProvider.web.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ExpoZoraIconFontProvider.web.d.ts","sourceRoot":"","sources":["../src/ExpoZoraIconFontProvider.web.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,MAAM,OAAO,CAAC;AAc1B,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CACpC;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,6BAA6B,4BAY5E"}
|
|
@@ -6,6 +6,7 @@ import fontAwesome6Brands from '@react-native-vector-icons/fontawesome6/fonts/Fo
|
|
|
6
6
|
import fontAwesome6Regular from '@react-native-vector-icons/fontawesome6/fonts/FontAwesome6_Regular.ttf';
|
|
7
7
|
import fontAwesome6Solid from '@react-native-vector-icons/fontawesome6/fonts/FontAwesome6_Solid.ttf';
|
|
8
8
|
import ionicons from '@react-native-vector-icons/ionicons/fonts/Ionicons.ttf';
|
|
9
|
+
import materialDesignIcons from '@react-native-vector-icons/material-design-icons/fonts/MaterialDesignIcons.ttf';
|
|
9
10
|
import { useFonts } from 'expo-font';
|
|
10
11
|
import React from 'react';
|
|
11
12
|
const ZORA_ICON_FONTS = {
|
|
@@ -17,6 +18,7 @@ const ZORA_ICON_FONTS = {
|
|
|
17
18
|
'FontAwesome6Free-Regular': fontAwesome6Regular,
|
|
18
19
|
'FontAwesome6Free-Solid': fontAwesome6Solid,
|
|
19
20
|
Ionicons: ionicons,
|
|
21
|
+
MaterialDesignIcons: materialDesignIcons,
|
|
20
22
|
};
|
|
21
23
|
export function ExpoZoraIconFontProvider(props) {
|
|
22
24
|
const [loaded, error] = useFonts(ZORA_ICON_FONTS);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoZoraIconFontProvider.web.js","sourceRoot":"","sources":["../src/ExpoZoraIconFontProvider.web.tsx"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,8DAA8D,CAAC;AACvF,OAAO,kBAAkB,MAAM,uEAAuE,CAAC;AACvG,OAAO,mBAAmB,MAAM,wEAAwE,CAAC;AACzG,OAAO,iBAAiB,MAAM,sEAAsE,CAAC;AACrG,OAAO,kBAAkB,MAAM,uEAAuE,CAAC;AACvG,OAAO,mBAAmB,MAAM,wEAAwE,CAAC;AACzG,OAAO,iBAAiB,MAAM,sEAAsE,CAAC;AACrG,OAAO,QAAQ,MAAM,wDAAwD,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,eAAe,GAAG;IACtB,WAAW,EAAE,WAAW;IACxB,4BAA4B,EAAE,kBAAkB;IAChD,0BAA0B,EAAE,mBAAmB;IAC/C,wBAAwB,EAAE,iBAAiB;IAC3C,4BAA4B,EAAE,kBAAkB;IAChD,0BAA0B,EAAE,mBAAmB;IAC/C,wBAAwB,EAAE,iBAAiB;IAC3C,QAAQ,EAAE,QAAQ;
|
|
1
|
+
{"version":3,"file":"ExpoZoraIconFontProvider.web.js","sourceRoot":"","sources":["../src/ExpoZoraIconFontProvider.web.tsx"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,8DAA8D,CAAC;AACvF,OAAO,kBAAkB,MAAM,uEAAuE,CAAC;AACvG,OAAO,mBAAmB,MAAM,wEAAwE,CAAC;AACzG,OAAO,iBAAiB,MAAM,sEAAsE,CAAC;AACrG,OAAO,kBAAkB,MAAM,uEAAuE,CAAC;AACvG,OAAO,mBAAmB,MAAM,wEAAwE,CAAC;AACzG,OAAO,iBAAiB,MAAM,sEAAsE,CAAC;AACrG,OAAO,QAAQ,MAAM,wDAAwD,CAAC;AAC9E,OAAO,mBAAmB,MAAM,gFAAgF,CAAC;AACjH,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,eAAe,GAAG;IACtB,WAAW,EAAE,WAAW;IACxB,4BAA4B,EAAE,kBAAkB;IAChD,0BAA0B,EAAE,mBAAmB;IAC/C,wBAAwB,EAAE,iBAAiB;IAC3C,4BAA4B,EAAE,kBAAkB;IAChD,0BAA0B,EAAE,mBAAmB;IAC/C,wBAAwB,EAAE,iBAAiB;IAC3C,QAAQ,EAAE,QAAQ;IAClB,mBAAmB,EAAE,mBAAmB;CAChC,CAAC;AAMX,MAAM,UAAU,wBAAwB,CAAC,KAAoC;IAC3E,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,QAAQ,CAAC,eAAe,CAAC,CAAC;IAElD,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,KAAK,CAAC;IACd,CAAC;IAED,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;AAC/B,CAAC","sourcesContent":["import fontAwesome from '@react-native-vector-icons/fontawesome/fonts/FontAwesome.ttf';\nimport fontAwesome5Brands from '@react-native-vector-icons/fontawesome5/fonts/FontAwesome5_Brands.ttf';\nimport fontAwesome5Regular from '@react-native-vector-icons/fontawesome5/fonts/FontAwesome5_Regular.ttf';\nimport fontAwesome5Solid from '@react-native-vector-icons/fontawesome5/fonts/FontAwesome5_Solid.ttf';\nimport fontAwesome6Brands from '@react-native-vector-icons/fontawesome6/fonts/FontAwesome6_Brands.ttf';\nimport fontAwesome6Regular from '@react-native-vector-icons/fontawesome6/fonts/FontAwesome6_Regular.ttf';\nimport fontAwesome6Solid from '@react-native-vector-icons/fontawesome6/fonts/FontAwesome6_Solid.ttf';\nimport ionicons from '@react-native-vector-icons/ionicons/fonts/Ionicons.ttf';\nimport materialDesignIcons from '@react-native-vector-icons/material-design-icons/fonts/MaterialDesignIcons.ttf';\nimport { useFonts } from 'expo-font';\nimport React from 'react';\n\nconst ZORA_ICON_FONTS = {\n FontAwesome: fontAwesome,\n 'FontAwesome5Brands-Regular': fontAwesome5Brands,\n 'FontAwesome5Free-Regular': fontAwesome5Regular,\n 'FontAwesome5Free-Solid': fontAwesome5Solid,\n 'FontAwesome6Brands-Regular': fontAwesome6Brands,\n 'FontAwesome6Free-Regular': fontAwesome6Regular,\n 'FontAwesome6Free-Solid': fontAwesome6Solid,\n Ionicons: ionicons,\n MaterialDesignIcons: materialDesignIcons,\n} as const;\n\nexport interface ExpoZoraIconFontProviderProps {\n readonly children: React.ReactNode;\n}\n\nexport function ExpoZoraIconFontProvider(props: ExpoZoraIconFontProviderProps) {\n const [loaded, error] = useFonts(ZORA_ICON_FONTS);\n\n if (error) {\n throw error;\n }\n\n if (!loaded) {\n return null;\n }\n\n return <>{props.children}</>;\n}\n"]}
|
package/dist/platform.d.ts
CHANGED
|
@@ -40,6 +40,13 @@ export declare const EXPO_PLATFORM: {
|
|
|
40
40
|
};
|
|
41
41
|
readonly ui: {
|
|
42
42
|
readonly svg: ExpoPlatformPackage;
|
|
43
|
+
readonly iconProviders: {
|
|
44
|
+
readonly Ionicons: ExpoPlatformPackage;
|
|
45
|
+
readonly FontAwesome: ExpoPlatformPackage;
|
|
46
|
+
readonly FontAwesome5: ExpoPlatformPackage;
|
|
47
|
+
readonly FontAwesome6: ExpoPlatformPackage;
|
|
48
|
+
readonly MaterialDesignIcons: ExpoPlatformPackage;
|
|
49
|
+
};
|
|
43
50
|
};
|
|
44
51
|
readonly packages: {
|
|
45
52
|
readonly metroRuntime: ExpoPlatformPackage;
|
package/dist/platform.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAMD;;;;;;GAMG;AACH,eAAO,MAAM,aAAa
|
|
1
|
+
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAMD;;;;;;GAMG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgFhB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,OAAO,aAAa,CAAC"}
|
package/dist/platform.js
CHANGED
|
@@ -39,6 +39,13 @@ export const EXPO_PLATFORM = {
|
|
|
39
39
|
},
|
|
40
40
|
ui: {
|
|
41
41
|
svg: definePackage('react-native-svg', '15.15.4'),
|
|
42
|
+
iconProviders: {
|
|
43
|
+
Ionicons: definePackage('@react-native-vector-icons/ionicons', '^13.1.3'),
|
|
44
|
+
FontAwesome: definePackage('@react-native-vector-icons/fontawesome', '^13.1.3'),
|
|
45
|
+
FontAwesome5: definePackage('@react-native-vector-icons/fontawesome5', '^13.1.3'),
|
|
46
|
+
FontAwesome6: definePackage('@react-native-vector-icons/fontawesome6', '^13.1.3'),
|
|
47
|
+
MaterialDesignIcons: definePackage('@react-native-vector-icons/material-design-icons', '^13.1.3'),
|
|
48
|
+
},
|
|
42
49
|
},
|
|
43
50
|
packages: {
|
|
44
51
|
metroRuntime: definePackage('@expo/metro-runtime', '~57.0.14'),
|
package/dist/platform.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAKA,SAAS,aAAa,CAAC,IAAY,EAAE,OAAe;IAClD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC3B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,GAAG,EAAE,EAAE;IACP,YAAY,EAAE,uBAAuB;IACrC,OAAO,EAAE;QACP,IAAI,EAAE,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC;QACtC,KAAK,EAAE,aAAa,CAAC,OAAO,EAAE,QAAQ,CAAC;QACvC,QAAQ,EAAE,aAAa,CAAC,WAAW,EAAE,QAAQ,CAAC;QAC9C,WAAW,EAAE,aAAa,CAAC,cAAc,EAAE,QAAQ,CAAC;QACpD,cAAc,EAAE,aAAa,CAAC,kBAAkB,EAAE,SAAS,CAAC;KAC7D;IACD,OAAO,EAAE;QACP,IAAI,EAAE;YACJ,GAAG,EAAE,EAAE;YACP,OAAO,EAAE,MAAM;SAChB;QACD,SAAS,EAAE,aAAa,CAAC,aAAa,EAAE,UAAU,CAAC;QACnD,UAAU,EAAE,aAAa,CAAC,YAAY,EAAE,QAAQ,CAAC;QACjD,UAAU,EAAE,aAAa,CAAC,aAAa,EAAE,QAAQ,CAAC;KACnD;IACD,UAAU,EAAE;QACV,UAAU,EAAE,aAAa,CAAC,aAAa,EAAE,UAAU,CAAC;QACpD,OAAO,EAAE,aAAa,CAAC,sBAAsB,EAAE,SAAS,CAAC;QACzD,QAAQ,EAAE,aAAa,CAAC,gCAAgC,EAAE,QAAQ,CAAC;KACpE;IACD,SAAS,EAAE;QACT,UAAU,EAAE,aAAa,CAAC,yBAAyB,EAAE,OAAO,CAAC;QAC7D,QAAQ,EAAE,aAAa,CAAC,uBAAuB,EAAE,QAAQ,CAAC;QAC1D,cAAc,EAAE,aAAa,CAAC,8BAA8B,EAAE,SAAS,CAAC;KACzE;IACD,EAAE,EAAE;QACF,GAAG,EAAE,aAAa,CAAC,kBAAkB,EAAE,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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","sourcesContent":["export interface ExpoPlatformPackage {\n readonly name: string;\n readonly version: string;\n}\n\nfunction definePackage(name: string, version: string): ExpoPlatformPackage {\n return { name, version };\n}\n\n/**\n * The canonical Ankhorage projection of the supported Expo platform.\n *\n * Package versions come from Expo SDK 57's bundled native module map. Keep this\n * structure as the only hand-maintained Expo compatibility authority in this\n * repository; generated manifests and runtime planning derive from it.\n */\nexport const EXPO_PLATFORM = {\n sdk: 57,\n architecture: 'new-architecture-only',\n runtime: {\n expo: definePackage('expo', '57.0.18'),\n react: definePackage('react', '19.2.3'),\n reactDom: definePackage('react-dom', '19.2.3'),\n reactNative: definePackage('react-native', '0.86.3'),\n reactNativeWeb: definePackage('react-native-web', '~0.21.0'),\n },\n tooling: {\n node: {\n lts: 24,\n version: '24.x',\n },\n nodeTypes: definePackage('@types/node', '^24.13.3'),\n typescript: definePackage('typescript', '~6.0.3'),\n expoDoctor: definePackage('expo-doctor', '1.20.4'),\n },\n navigation: {\n expoRouter: definePackage('expo-router', '~57.0.17'),\n screens: definePackage('react-native-screens', '~4.26.0'),\n safeArea: definePackage('react-native-safe-area-context', '~5.7.0'),\n },\n animation: {\n reanimated: definePackage('react-native-reanimated', '4.5.1'),\n worklets: definePackage('react-native-worklets', '0.10.1'),\n gestureHandler: definePackage('react-native-gesture-handler', '~2.32.0'),\n },\n ui: {\n svg: definePackage('react-native-svg', '15.15.4'),\n iconProviders: {\n Ionicons: definePackage('@react-native-vector-icons/ionicons', '^13.1.3'),\n FontAwesome: definePackage('@react-native-vector-icons/fontawesome', '^13.1.3'),\n FontAwesome5: definePackage('@react-native-vector-icons/fontawesome5', '^13.1.3'),\n FontAwesome6: definePackage('@react-native-vector-icons/fontawesome6', '^13.1.3'),\n MaterialDesignIcons: definePackage(\n '@react-native-vector-icons/material-design-icons',\n '^13.1.3',\n ),\n },\n },\n packages: {\n metroRuntime: definePackage('@expo/metro-runtime', '~57.0.14'),\n asset: definePackage('expo-asset', '~57.0.15'),\n audio: definePackage('expo-audio', '~57.0.4'),\n authSession: definePackage('expo-auth-session', '~57.0.10'),\n camera: definePackage('expo-camera', '~57.0.4'),\n constants: definePackage('expo-constants', '~57.0.16'),\n crypto: definePackage('expo-crypto', '~57.0.2'),\n devClient: definePackage('expo-dev-client', '~57.0.16'),\n documentPicker: definePackage('expo-document-picker', '~57.0.1'),\n fileSystem: definePackage('expo-file-system', '~57.0.6'),\n font: definePackage('expo-font', '~57.0.2'),\n imagePicker: definePackage('expo-image-picker', '~57.0.14'),\n linearGradient: definePackage('expo-linear-gradient', '~57.0.1'),\n linking: definePackage('expo-linking', '~57.0.8'),\n localization: definePackage('expo-localization', '~57.0.1'),\n location: definePackage('expo-location', '~57.0.14'),\n mediaLibrary: definePackage('expo-media-library', '~57.0.4'),\n notifications: definePackage('expo-notifications', '~57.0.15'),\n secureStore: definePackage('expo-secure-store', '~57.0.2'),\n splashScreen: definePackage('expo-splash-screen', '~57.0.8'),\n statusBar: definePackage('expo-status-bar', '~57.0.1'),\n updates: definePackage('expo-updates', '~57.0.19'),\n webBrowser: definePackage('expo-web-browser', '~57.0.2'),\n },\n platforms: {\n android: {\n minimumVersion: 7,\n minimumApiLevel: 24,\n compileSdk: 36,\n targetSdk: 36,\n edgeToEdge: true,\n },\n ios: {\n minimumVersion: '16.4',\n minimumXcodeVersion: '26.4',\n },\n },\n} as const;\n\nexport type ExpoPlatform = typeof EXPO_PLATFORM;\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function resolveReaderKeyboardIntent(input: {
|
|
2
|
+
canGoNext: boolean;
|
|
3
|
+
canGoPrevious: boolean;
|
|
4
|
+
direction: 'ltr' | 'rtl';
|
|
5
|
+
hasModifier?: boolean;
|
|
6
|
+
isInteractiveTarget?: boolean;
|
|
7
|
+
key: string;
|
|
8
|
+
}): 'next' | 'previous' | null;
|
|
9
|
+
//# sourceMappingURL=resolveReaderKeyboardIntent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveReaderKeyboardIntent.d.ts","sourceRoot":"","sources":["../../../src/reader/navigation/resolveReaderKeyboardIntent.ts"],"names":[],"mappings":"AAAA,wBAAgB,2BAA2B,CAAC,KAAK,EAAE;IACjD,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,EAAE,KAAK,GAAG,KAAK,CAAC;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,GAAG,EAAE,MAAM,CAAC;CACb,GAAG,MAAM,GAAG,UAAU,GAAG,IAAI,CAY7B"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function resolveReaderKeyboardIntent(input) {
|
|
2
|
+
if (input.hasModifier || input.isInteractiveTarget)
|
|
3
|
+
return null;
|
|
4
|
+
let intent = null;
|
|
5
|
+
if (input.key === 'PageUp')
|
|
6
|
+
intent = 'previous';
|
|
7
|
+
if (input.key === 'PageDown')
|
|
8
|
+
intent = 'next';
|
|
9
|
+
if (input.key === 'ArrowLeft')
|
|
10
|
+
intent = input.direction === 'ltr' ? 'previous' : 'next';
|
|
11
|
+
if (input.key === 'ArrowRight')
|
|
12
|
+
intent = input.direction === 'ltr' ? 'next' : 'previous';
|
|
13
|
+
if (intent === 'next')
|
|
14
|
+
return input.canGoNext ? intent : null;
|
|
15
|
+
if (intent === 'previous')
|
|
16
|
+
return input.canGoPrevious ? intent : null;
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=resolveReaderKeyboardIntent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveReaderKeyboardIntent.js","sourceRoot":"","sources":["../../../src/reader/navigation/resolveReaderKeyboardIntent.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,2BAA2B,CAAC,KAO3C;IACC,IAAI,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,mBAAmB;QAAE,OAAO,IAAI,CAAC;IAEhE,IAAI,MAAM,GAA+B,IAAI,CAAC;IAC9C,IAAI,KAAK,CAAC,GAAG,KAAK,QAAQ;QAAE,MAAM,GAAG,UAAU,CAAC;IAChD,IAAI,KAAK,CAAC,GAAG,KAAK,UAAU;QAAE,MAAM,GAAG,MAAM,CAAC;IAC9C,IAAI,KAAK,CAAC,GAAG,KAAK,WAAW;QAAE,MAAM,GAAG,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC;IACxF,IAAI,KAAK,CAAC,GAAG,KAAK,YAAY;QAAE,MAAM,GAAG,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC;IAEzF,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9D,IAAI,MAAM,KAAK,UAAU;QAAE,OAAO,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IACtE,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["export function resolveReaderKeyboardIntent(input: {\n canGoNext: boolean;\n canGoPrevious: boolean;\n direction: 'ltr' | 'rtl';\n hasModifier?: boolean;\n isInteractiveTarget?: boolean;\n key: string;\n}): 'next' | 'previous' | null {\n if (input.hasModifier || input.isInteractiveTarget) return null;\n\n let intent: 'next' | 'previous' | null = null;\n if (input.key === 'PageUp') intent = 'previous';\n if (input.key === 'PageDown') intent = 'next';\n if (input.key === 'ArrowLeft') intent = input.direction === 'ltr' ? 'previous' : 'next';\n if (input.key === 'ArrowRight') intent = input.direction === 'ltr' ? 'next' : 'previous';\n\n if (intent === 'next') return input.canGoNext ? intent : null;\n if (intent === 'previous') return input.canGoPrevious ? intent : null;\n return null;\n}\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare function resolveReaderNavigationIntent(input: {
|
|
2
|
+
canGoNext: boolean;
|
|
3
|
+
canGoPrevious: boolean;
|
|
4
|
+
deltaX: number;
|
|
5
|
+
deltaY: number;
|
|
6
|
+
direction: 'ltr' | 'rtl';
|
|
7
|
+
hasSelection?: boolean;
|
|
8
|
+
isInteractiveTarget?: boolean;
|
|
9
|
+
viewportWidth: number;
|
|
10
|
+
}): 'next' | 'previous' | null;
|
|
11
|
+
//# sourceMappingURL=resolveReaderNavigationIntent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveReaderNavigationIntent.d.ts","sourceRoot":"","sources":["../../../src/reader/navigation/resolveReaderNavigationIntent.ts"],"names":[],"mappings":"AAAA,wBAAgB,6BAA6B,CAAC,KAAK,EAAE;IACnD,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,KAAK,GAAG,KAAK,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,MAAM,GAAG,UAAU,GAAG,IAAI,CAa7B"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function resolveReaderNavigationIntent(input) {
|
|
2
|
+
if (input.hasSelection || input.isInteractiveTarget)
|
|
3
|
+
return null;
|
|
4
|
+
const horizontalDistance = Math.abs(input.deltaX);
|
|
5
|
+
const verticalDistance = Math.abs(input.deltaY);
|
|
6
|
+
const distanceThreshold = Math.max(48, input.viewportWidth * 0.15);
|
|
7
|
+
if (horizontalDistance <= verticalDistance * 1.25)
|
|
8
|
+
return null;
|
|
9
|
+
if (horizontalDistance <= distanceThreshold)
|
|
10
|
+
return null;
|
|
11
|
+
const movesForward = input.direction === 'ltr' ? input.deltaX < 0 : input.deltaX > 0;
|
|
12
|
+
if (movesForward)
|
|
13
|
+
return input.canGoNext ? 'next' : null;
|
|
14
|
+
return input.canGoPrevious ? 'previous' : null;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=resolveReaderNavigationIntent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveReaderNavigationIntent.js","sourceRoot":"","sources":["../../../src/reader/navigation/resolveReaderNavigationIntent.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,6BAA6B,CAAC,KAS7C;IACC,IAAI,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,mBAAmB;QAAE,OAAO,IAAI,CAAC;IAEjE,MAAM,kBAAkB,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAChD,MAAM,iBAAiB,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IAEnE,IAAI,kBAAkB,IAAI,gBAAgB,GAAG,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/D,IAAI,kBAAkB,IAAI,iBAAiB;QAAE,OAAO,IAAI,CAAC;IAEzD,MAAM,YAAY,GAAG,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IACrF,IAAI,YAAY;QAAE,OAAO,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IACzD,OAAO,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AACjD,CAAC","sourcesContent":["export function resolveReaderNavigationIntent(input: {\n canGoNext: boolean;\n canGoPrevious: boolean;\n deltaX: number;\n deltaY: number;\n direction: 'ltr' | 'rtl';\n hasSelection?: boolean;\n isInteractiveTarget?: boolean;\n viewportWidth: number;\n}): 'next' | 'previous' | null {\n if (input.hasSelection || input.isInteractiveTarget) return null;\n\n const horizontalDistance = Math.abs(input.deltaX);\n const verticalDistance = Math.abs(input.deltaY);\n const distanceThreshold = Math.max(48, input.viewportWidth * 0.15);\n\n if (horizontalDistance <= verticalDistance * 1.25) return null;\n if (horizontalDistance <= distanceThreshold) return null;\n\n const movesForward = input.direction === 'ltr' ? input.deltaX < 0 : input.deltaX > 0;\n if (movesForward) return input.canGoNext ? 'next' : null;\n return input.canGoPrevious ? 'previous' : null;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ankhorage/expo-runtime",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.1.1",
|
|
5
5
|
"description": "Declarative runtime integration for Expo apps: maps app capabilities to permissions, packages, config plugins, providers, and adapters",
|
|
6
6
|
"homepage": "https://github.com/ankhorage/expo-runtime#readme",
|
|
7
7
|
"bugs": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"runtime"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@ankhorage/contracts": "^8.0.
|
|
28
|
+
"@ankhorage/contracts": "^8.0.1"
|
|
29
29
|
},
|
|
30
30
|
"files": [
|
|
31
31
|
"dist",
|
|
@@ -127,10 +127,13 @@
|
|
|
127
127
|
"peerDependencies": {
|
|
128
128
|
"@ankhorage/permissions": "^0.2.3",
|
|
129
129
|
"@ankhorage/zora": "^3.0.2",
|
|
130
|
+
"@readium/navigator": "2.8.2",
|
|
130
131
|
"@react-native-vector-icons/fontawesome": "^13.1.3",
|
|
131
132
|
"@react-native-vector-icons/fontawesome5": "^13.1.3",
|
|
132
133
|
"@react-native-vector-icons/fontawesome6": "^13.1.3",
|
|
133
134
|
"@react-native-vector-icons/ionicons": "^13.1.3",
|
|
135
|
+
"@react-native-vector-icons/material-design-icons": "^13.1.3",
|
|
136
|
+
"@zip.js/zip.js": "2.9.0",
|
|
134
137
|
"expo": "57.0.18",
|
|
135
138
|
"expo-camera": "~57.0.4",
|
|
136
139
|
"expo-constants": "~57.0.16",
|
|
@@ -138,6 +141,7 @@
|
|
|
138
141
|
"expo-file-system": "~57.0.6",
|
|
139
142
|
"expo-font": "~57.0.2",
|
|
140
143
|
"expo-image-picker": "~57.0.14",
|
|
144
|
+
"pdfjs-dist": "6.3.289",
|
|
141
145
|
"react": "19.2.3",
|
|
142
146
|
"react-native": "0.86.3"
|
|
143
147
|
},
|
|
@@ -148,6 +152,9 @@
|
|
|
148
152
|
"@ankhorage/zora": {
|
|
149
153
|
"optional": true
|
|
150
154
|
},
|
|
155
|
+
"@readium/navigator": {
|
|
156
|
+
"optional": true
|
|
157
|
+
},
|
|
151
158
|
"@react-native-vector-icons/fontawesome": {
|
|
152
159
|
"optional": true
|
|
153
160
|
},
|
|
@@ -160,6 +167,12 @@
|
|
|
160
167
|
"@react-native-vector-icons/ionicons": {
|
|
161
168
|
"optional": true
|
|
162
169
|
},
|
|
170
|
+
"@react-native-vector-icons/material-design-icons": {
|
|
171
|
+
"optional": true
|
|
172
|
+
},
|
|
173
|
+
"@zip.js/zip.js": {
|
|
174
|
+
"optional": true
|
|
175
|
+
},
|
|
163
176
|
"expo": {
|
|
164
177
|
"optional": true
|
|
165
178
|
},
|
|
@@ -181,6 +194,9 @@
|
|
|
181
194
|
"expo-image-picker": {
|
|
182
195
|
"optional": true
|
|
183
196
|
},
|
|
197
|
+
"pdfjs-dist": {
|
|
198
|
+
"optional": true
|
|
199
|
+
},
|
|
184
200
|
"react": {
|
|
185
201
|
"optional": true
|
|
186
202
|
},
|
|
@@ -193,11 +209,14 @@
|
|
|
193
209
|
"@ankhorage/paradox": "^0.1.24",
|
|
194
210
|
"@ankhorage/permissions": "^0.2.3",
|
|
195
211
|
"@ankhorage/zora": "^3.0.2",
|
|
212
|
+
"@readium/navigator": "2.8.2",
|
|
196
213
|
"@react-native-picker/picker": "2.11.4",
|
|
197
214
|
"@react-native-vector-icons/fontawesome": "^13.1.3",
|
|
198
215
|
"@react-native-vector-icons/fontawesome5": "^13.1.3",
|
|
199
216
|
"@react-native-vector-icons/fontawesome6": "^13.1.3",
|
|
200
217
|
"@react-native-vector-icons/ionicons": "^13.1.3",
|
|
218
|
+
"@react-native-vector-icons/material-design-icons": "^13.1.3",
|
|
219
|
+
"@zip.js/zip.js": "2.9.0",
|
|
201
220
|
"@types/bun": "^1.4.0",
|
|
202
221
|
"@types/node": "^24.13.3",
|
|
203
222
|
"@types/pngjs": "^6.0.5",
|
|
@@ -215,6 +234,7 @@
|
|
|
215
234
|
"react-native": "0.86.3",
|
|
216
235
|
"react-native-safe-area-context": "~5.7.0",
|
|
217
236
|
"react-native-web": "~0.21.0",
|
|
237
|
+
"pdfjs-dist": "6.3.289",
|
|
218
238
|
"playwright-core": "^1.62.1",
|
|
219
239
|
"pngjs": "^7.0.0",
|
|
220
240
|
"typescript": "~6.0.3"
|
|
@@ -31,6 +31,7 @@ describe('ExpoZoraIconFontProvider Web', () => {
|
|
|
31
31
|
['FontAwesome6Free-Regular', 'FontAwesome6_Regular.ttf'],
|
|
32
32
|
['FontAwesome6Free-Solid', 'FontAwesome6_Solid.ttf'],
|
|
33
33
|
['Ionicons', 'Ionicons.ttf'],
|
|
34
|
+
['MaterialDesignIcons', 'MaterialDesignIcons.ttf'],
|
|
34
35
|
]);
|
|
35
36
|
expect(React.isValidElement(element)).toBe(true);
|
|
36
37
|
if (!React.isValidElement(element)) {
|
|
@@ -6,6 +6,7 @@ import fontAwesome6Brands from '@react-native-vector-icons/fontawesome6/fonts/Fo
|
|
|
6
6
|
import fontAwesome6Regular from '@react-native-vector-icons/fontawesome6/fonts/FontAwesome6_Regular.ttf';
|
|
7
7
|
import fontAwesome6Solid from '@react-native-vector-icons/fontawesome6/fonts/FontAwesome6_Solid.ttf';
|
|
8
8
|
import ionicons from '@react-native-vector-icons/ionicons/fonts/Ionicons.ttf';
|
|
9
|
+
import materialDesignIcons from '@react-native-vector-icons/material-design-icons/fonts/MaterialDesignIcons.ttf';
|
|
9
10
|
import { useFonts } from 'expo-font';
|
|
10
11
|
import React from 'react';
|
|
11
12
|
|
|
@@ -18,6 +19,7 @@ const ZORA_ICON_FONTS = {
|
|
|
18
19
|
'FontAwesome6Free-Regular': fontAwesome6Regular,
|
|
19
20
|
'FontAwesome6Free-Solid': fontAwesome6Solid,
|
|
20
21
|
Ionicons: ionicons,
|
|
22
|
+
MaterialDesignIcons: materialDesignIcons,
|
|
21
23
|
} as const;
|
|
22
24
|
|
|
23
25
|
export interface ExpoZoraIconFontProviderProps {
|
package/src/platform.test.ts
CHANGED
|
@@ -22,55 +22,33 @@ describe('EXPO_PLATFORM', () => {
|
|
|
22
22
|
expect('tvos' in EXPO_PLATFORM.platforms).toBe(false);
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
-
test('keeps
|
|
26
|
-
expect(EXPO_PLATFORM.runtime.expo).
|
|
27
|
-
expect(EXPO_PLATFORM.runtime.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
expect(EXPO_PLATFORM.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
});
|
|
35
|
-
expect(EXPO_PLATFORM.tooling.node).toEqual({ lts: 24, version: '24.x' });
|
|
36
|
-
expect(EXPO_PLATFORM.tooling.expoDoctor.version).toBe('1.20.4');
|
|
37
|
-
expect(EXPO_PLATFORM.animation.worklets.version).toBe('0.10.1');
|
|
25
|
+
test('keeps runtime and tooling package identities in one contract', () => {
|
|
26
|
+
expect(EXPO_PLATFORM.runtime.expo.name).toBe('expo');
|
|
27
|
+
expect(Number(EXPO_PLATFORM.runtime.expo.version.split('.')[0])).toBe(EXPO_PLATFORM.sdk);
|
|
28
|
+
expect(EXPO_PLATFORM.runtime.reactNative.name).toBe('react-native');
|
|
29
|
+
expect(EXPO_PLATFORM.packages.crypto.name).toBe('expo-crypto');
|
|
30
|
+
expect(EXPO_PLATFORM.tooling.node.lts).toBe(24);
|
|
31
|
+
expect(EXPO_PLATFORM.tooling.node.version).toBe(`${EXPO_PLATFORM.tooling.node.lts}.x`);
|
|
32
|
+
expect(EXPO_PLATFORM.tooling.expoDoctor.name).toBe('expo-doctor');
|
|
33
|
+
expect(EXPO_PLATFORM.animation.worklets.name).toBe('react-native-worklets');
|
|
38
34
|
});
|
|
39
35
|
});
|
|
40
36
|
|
|
41
|
-
describe('EXPO_PLATFORM
|
|
42
|
-
test('
|
|
43
|
-
expect(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
secureStore: EXPO_PLATFORM.packages.secureStore.version,
|
|
57
|
-
splashScreen: EXPO_PLATFORM.packages.splashScreen.version,
|
|
58
|
-
updates: EXPO_PLATFORM.packages.updates.version,
|
|
59
|
-
}).toEqual({
|
|
60
|
-
asset: '~57.0.15',
|
|
61
|
-
authSession: '~57.0.10',
|
|
62
|
-
constants: '~57.0.16',
|
|
63
|
-
devClient: '~57.0.16',
|
|
64
|
-
fileSystem: '~57.0.6',
|
|
65
|
-
font: '~57.0.2',
|
|
66
|
-
imagePicker: '~57.0.14',
|
|
67
|
-
linking: '~57.0.8',
|
|
68
|
-
location: '~57.0.14',
|
|
69
|
-
metroRuntime: '~57.0.14',
|
|
70
|
-
notifications: '~57.0.15',
|
|
71
|
-
secureStore: '~57.0.2',
|
|
72
|
-
splashScreen: '~57.0.8',
|
|
73
|
-
updates: '~57.0.19',
|
|
37
|
+
describe('EXPO_PLATFORM icon providers', () => {
|
|
38
|
+
test('owns the complete static provider package inventory', () => {
|
|
39
|
+
expect(
|
|
40
|
+
Object.fromEntries(
|
|
41
|
+
Object.entries(EXPO_PLATFORM.ui.iconProviders).map(([provider, dependency]) => [
|
|
42
|
+
provider,
|
|
43
|
+
dependency.name,
|
|
44
|
+
]),
|
|
45
|
+
),
|
|
46
|
+
).toEqual({
|
|
47
|
+
Ionicons: '@react-native-vector-icons/ionicons',
|
|
48
|
+
FontAwesome: '@react-native-vector-icons/fontawesome',
|
|
49
|
+
FontAwesome5: '@react-native-vector-icons/fontawesome5',
|
|
50
|
+
FontAwesome6: '@react-native-vector-icons/fontawesome6',
|
|
51
|
+
MaterialDesignIcons: '@react-native-vector-icons/material-design-icons',
|
|
74
52
|
});
|
|
75
53
|
});
|
|
76
54
|
});
|
package/src/platform.ts
CHANGED
|
@@ -45,6 +45,16 @@ export const EXPO_PLATFORM = {
|
|
|
45
45
|
},
|
|
46
46
|
ui: {
|
|
47
47
|
svg: definePackage('react-native-svg', '15.15.4'),
|
|
48
|
+
iconProviders: {
|
|
49
|
+
Ionicons: definePackage('@react-native-vector-icons/ionicons', '^13.1.3'),
|
|
50
|
+
FontAwesome: definePackage('@react-native-vector-icons/fontawesome', '^13.1.3'),
|
|
51
|
+
FontAwesome5: definePackage('@react-native-vector-icons/fontawesome5', '^13.1.3'),
|
|
52
|
+
FontAwesome6: definePackage('@react-native-vector-icons/fontawesome6', '^13.1.3'),
|
|
53
|
+
MaterialDesignIcons: definePackage(
|
|
54
|
+
'@react-native-vector-icons/material-design-icons',
|
|
55
|
+
'^13.1.3',
|
|
56
|
+
),
|
|
57
|
+
},
|
|
48
58
|
},
|
|
49
59
|
packages: {
|
|
50
60
|
metroRuntime: definePackage('@expo/metro-runtime', '~57.0.14'),
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
import { resolveReaderKeyboardIntent } from './resolveReaderKeyboardIntent';
|
|
4
|
+
|
|
5
|
+
const defaultInput = {
|
|
6
|
+
canGoNext: true,
|
|
7
|
+
canGoPrevious: true,
|
|
8
|
+
direction: 'ltr' as const,
|
|
9
|
+
key: 'ArrowRight',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
describe('resolveReaderKeyboardIntent', () => {
|
|
13
|
+
test('maps directional keys in LTR and RTL publications', () => {
|
|
14
|
+
expect(resolveReaderKeyboardIntent(defaultInput)).toBe('next');
|
|
15
|
+
expect(resolveReaderKeyboardIntent({ ...defaultInput, key: 'ArrowLeft' })).toBe('previous');
|
|
16
|
+
expect(resolveReaderKeyboardIntent({ ...defaultInput, direction: 'rtl' })).toBe('previous');
|
|
17
|
+
expect(
|
|
18
|
+
resolveReaderKeyboardIntent({ ...defaultInput, direction: 'rtl', key: 'ArrowLeft' }),
|
|
19
|
+
).toBe('next');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('keeps PageUp and PageDown tied to logical page order', () => {
|
|
23
|
+
expect(resolveReaderKeyboardIntent({ ...defaultInput, key: 'PageUp' })).toBe('previous');
|
|
24
|
+
expect(
|
|
25
|
+
resolveReaderKeyboardIntent({ ...defaultInput, direction: 'rtl', key: 'PageDown' }),
|
|
26
|
+
).toBe('next');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('ignores modified, interactive, unsupported, and boundary input', () => {
|
|
30
|
+
expect(resolveReaderKeyboardIntent({ ...defaultInput, hasModifier: true })).toBeNull();
|
|
31
|
+
expect(resolveReaderKeyboardIntent({ ...defaultInput, isInteractiveTarget: true })).toBeNull();
|
|
32
|
+
expect(resolveReaderKeyboardIntent({ ...defaultInput, key: 'Enter' })).toBeNull();
|
|
33
|
+
expect(resolveReaderKeyboardIntent({ ...defaultInput, canGoNext: false })).toBeNull();
|
|
34
|
+
expect(
|
|
35
|
+
resolveReaderKeyboardIntent({ ...defaultInput, canGoPrevious: false, key: 'ArrowLeft' }),
|
|
36
|
+
).toBeNull();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function resolveReaderKeyboardIntent(input: {
|
|
2
|
+
canGoNext: boolean;
|
|
3
|
+
canGoPrevious: boolean;
|
|
4
|
+
direction: 'ltr' | 'rtl';
|
|
5
|
+
hasModifier?: boolean;
|
|
6
|
+
isInteractiveTarget?: boolean;
|
|
7
|
+
key: string;
|
|
8
|
+
}): 'next' | 'previous' | null {
|
|
9
|
+
if (input.hasModifier || input.isInteractiveTarget) return null;
|
|
10
|
+
|
|
11
|
+
let intent: 'next' | 'previous' | null = null;
|
|
12
|
+
if (input.key === 'PageUp') intent = 'previous';
|
|
13
|
+
if (input.key === 'PageDown') intent = 'next';
|
|
14
|
+
if (input.key === 'ArrowLeft') intent = input.direction === 'ltr' ? 'previous' : 'next';
|
|
15
|
+
if (input.key === 'ArrowRight') intent = input.direction === 'ltr' ? 'next' : 'previous';
|
|
16
|
+
|
|
17
|
+
if (intent === 'next') return input.canGoNext ? intent : null;
|
|
18
|
+
if (intent === 'previous') return input.canGoPrevious ? intent : null;
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
import { resolveReaderNavigationIntent } from './resolveReaderNavigationIntent';
|
|
4
|
+
|
|
5
|
+
const defaultInput = {
|
|
6
|
+
canGoNext: true,
|
|
7
|
+
canGoPrevious: true,
|
|
8
|
+
deltaX: -49,
|
|
9
|
+
deltaY: 0,
|
|
10
|
+
direction: 'ltr' as const,
|
|
11
|
+
viewportWidth: 300,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
describe('resolveReaderNavigationIntent', () => {
|
|
15
|
+
test('maps one qualified LTR swipe to its logical page direction', () => {
|
|
16
|
+
expect(resolveReaderNavigationIntent(defaultInput)).toBe('next');
|
|
17
|
+
expect(resolveReaderNavigationIntent({ ...defaultInput, deltaX: 49 })).toBe('previous');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('inverts horizontal navigation for RTL publications', () => {
|
|
21
|
+
expect(resolveReaderNavigationIntent({ ...defaultInput, direction: 'rtl' })).toBe('previous');
|
|
22
|
+
expect(resolveReaderNavigationIntent({ ...defaultInput, deltaX: 49, direction: 'rtl' })).toBe(
|
|
23
|
+
'next',
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('requires horizontal intent and a strict responsive distance threshold', () => {
|
|
28
|
+
expect(resolveReaderNavigationIntent({ ...defaultInput, deltaX: -100, deltaY: 80 })).toBeNull();
|
|
29
|
+
expect(resolveReaderNavigationIntent({ ...defaultInput, deltaX: -48 })).toBeNull();
|
|
30
|
+
expect(
|
|
31
|
+
resolveReaderNavigationIntent({ ...defaultInput, deltaX: -60, viewportWidth: 400 }),
|
|
32
|
+
).toBeNull();
|
|
33
|
+
expect(
|
|
34
|
+
resolveReaderNavigationIntent({ ...defaultInput, deltaX: -61, viewportWidth: 400 }),
|
|
35
|
+
).toBe('next');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('does not claim selection, interactive content, or a document boundary', () => {
|
|
39
|
+
expect(resolveReaderNavigationIntent({ ...defaultInput, hasSelection: true })).toBeNull();
|
|
40
|
+
expect(
|
|
41
|
+
resolveReaderNavigationIntent({ ...defaultInput, isInteractiveTarget: true }),
|
|
42
|
+
).toBeNull();
|
|
43
|
+
expect(resolveReaderNavigationIntent({ ...defaultInput, canGoNext: false })).toBeNull();
|
|
44
|
+
expect(
|
|
45
|
+
resolveReaderNavigationIntent({ ...defaultInput, canGoPrevious: false, deltaX: 49 }),
|
|
46
|
+
).toBeNull();
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function resolveReaderNavigationIntent(input: {
|
|
2
|
+
canGoNext: boolean;
|
|
3
|
+
canGoPrevious: boolean;
|
|
4
|
+
deltaX: number;
|
|
5
|
+
deltaY: number;
|
|
6
|
+
direction: 'ltr' | 'rtl';
|
|
7
|
+
hasSelection?: boolean;
|
|
8
|
+
isInteractiveTarget?: boolean;
|
|
9
|
+
viewportWidth: number;
|
|
10
|
+
}): 'next' | 'previous' | null {
|
|
11
|
+
if (input.hasSelection || input.isInteractiveTarget) return null;
|
|
12
|
+
|
|
13
|
+
const horizontalDistance = Math.abs(input.deltaX);
|
|
14
|
+
const verticalDistance = Math.abs(input.deltaY);
|
|
15
|
+
const distanceThreshold = Math.max(48, input.viewportWidth * 0.15);
|
|
16
|
+
|
|
17
|
+
if (horizontalDistance <= verticalDistance * 1.25) return null;
|
|
18
|
+
if (horizontalDistance <= distanceThreshold) return null;
|
|
19
|
+
|
|
20
|
+
const movesForward = input.direction === 'ltr' ? input.deltaX < 0 : input.deltaX > 0;
|
|
21
|
+
if (movesForward) return input.canGoNext ? 'next' : null;
|
|
22
|
+
return input.canGoPrevious ? 'previous' : null;
|
|
23
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
describe('reader renderer package boundary', () => {
|
|
4
|
+
test('provides the EPUB navigator and archive APIs required by the driver', async () => {
|
|
5
|
+
const [{ EpubNavigator }, { BlobReader, ZipReader }] = await Promise.all([
|
|
6
|
+
import('@readium/navigator'),
|
|
7
|
+
import('@zip.js/zip.js'),
|
|
8
|
+
]);
|
|
9
|
+
|
|
10
|
+
expect(EpubNavigator).toBeFunction();
|
|
11
|
+
expect(BlobReader).toBeFunction();
|
|
12
|
+
expect(ZipReader).toBeFunction();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test('provides the PDF loading, worker, and protected-document APIs', async () => {
|
|
16
|
+
const { getDocument, PasswordException, PDFWorker } = await import('pdfjs-dist');
|
|
17
|
+
|
|
18
|
+
expect(getDocument).toBeFunction();
|
|
19
|
+
expect(PasswordException).toBeFunction();
|
|
20
|
+
expect(PDFWorker).toBeFunction();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -2,6 +2,7 @@ import { Permission } from '@ankhorage/permissions';
|
|
|
2
2
|
import { EXPO_PERMISSION_SUPPORT } from '@ankhorage/permissions/expo/manifest';
|
|
3
3
|
import { describe, expect, test } from 'bun:test';
|
|
4
4
|
|
|
5
|
+
import { GENERATED_RUNTIME_DEPENDENCY_VERSIONS } from './expoRuntimePlanningMetadata';
|
|
5
6
|
import { EXPO_PLATFORM } from './platform';
|
|
6
7
|
import { type ExpoRuntimePlanningManifest, resolveExpoRuntimePlan } from './resolveExpoRuntimePlan';
|
|
7
8
|
|
|
@@ -200,8 +201,14 @@ describe('resolveExpoRuntimePlan platform-neutral permissions', () => {
|
|
|
200
201
|
});
|
|
201
202
|
|
|
202
203
|
const SUPPORTED_PERMISSION_DEPENDENCIES = [
|
|
203
|
-
{
|
|
204
|
-
|
|
204
|
+
{
|
|
205
|
+
name: '@ankhorage/expo-runtime',
|
|
206
|
+
version: GENERATED_RUNTIME_DEPENDENCY_VERSIONS['@ankhorage/expo-runtime'],
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: '@ankhorage/permissions',
|
|
210
|
+
version: GENERATED_RUNTIME_DEPENDENCY_VERSIONS['@ankhorage/permissions'],
|
|
211
|
+
},
|
|
205
212
|
{ name: 'expo-asset', version: EXPO_PLATFORM.packages.asset.version },
|
|
206
213
|
{ name: 'expo-audio', version: EXPO_PLATFORM.packages.audio.version },
|
|
207
214
|
{ name: 'expo-location', version: EXPO_PLATFORM.packages.location.version },
|