aksos-react-native-epub-reader 0.0.0-stage → 0.1.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.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +338 -2
  3. package/lib/EpubReader.d.ts +63 -0
  4. package/lib/EpubReader.js +199 -0
  5. package/lib/EpubReaderView.d.ts +24 -0
  6. package/lib/EpubReaderView.js +504 -0
  7. package/lib/assets/page-turn-1.wav +0 -0
  8. package/lib/assets/page-turn-2.wav +0 -0
  9. package/lib/assets/page-turn-3.wav +0 -0
  10. package/lib/assets/page-turn-4.wav +0 -0
  11. package/lib/engine/html.d.ts +1 -0
  12. package/lib/engine/html.js +5 -0
  13. package/lib/index.d.ts +6 -0
  14. package/lib/index.js +30 -0
  15. package/lib/sound.d.ts +1 -0
  16. package/lib/sound.js +71 -0
  17. package/lib/themes.d.ts +56 -0
  18. package/lib/themes.js +166 -0
  19. package/lib/types.d.ts +133 -0
  20. package/lib/types.js +2 -0
  21. package/lib/ui/AppearanceSheet.d.ts +15 -0
  22. package/lib/ui/AppearanceSheet.js +127 -0
  23. package/lib/ui/ContentsSheet.d.ts +27 -0
  24. package/lib/ui/ContentsSheet.js +87 -0
  25. package/lib/ui/CustomizeSheet.d.ts +16 -0
  26. package/lib/ui/CustomizeSheet.js +139 -0
  27. package/lib/ui/Glass.d.ts +15 -0
  28. package/lib/ui/Glass.js +27 -0
  29. package/lib/ui/HighlightMenu.d.ts +25 -0
  30. package/lib/ui/HighlightMenu.js +43 -0
  31. package/lib/ui/Icons.d.ts +17 -0
  32. package/lib/ui/Icons.js +193 -0
  33. package/lib/ui/LineGuide.d.ts +21 -0
  34. package/lib/ui/LineGuide.js +92 -0
  35. package/lib/ui/NoteEditor.d.ts +12 -0
  36. package/lib/ui/NoteEditor.js +61 -0
  37. package/lib/ui/Scrubber.d.ts +15 -0
  38. package/lib/ui/Scrubber.js +86 -0
  39. package/lib/ui/SearchSheet.d.ts +14 -0
  40. package/lib/ui/SearchSheet.js +67 -0
  41. package/lib/ui/Sheet.d.ts +19 -0
  42. package/lib/ui/Sheet.js +38 -0
  43. package/lib/ui/Slider.d.ts +14 -0
  44. package/lib/ui/Slider.js +53 -0
  45. package/package.json +75 -5
  46. package/src/EpubReader.tsx +256 -0
  47. package/src/EpubReaderView.tsx +721 -0
  48. package/src/assets/page-turn-1.wav +0 -0
  49. package/src/assets/page-turn-2.wav +0 -0
  50. package/src/assets/page-turn-3.wav +0 -0
  51. package/src/assets/page-turn-4.wav +0 -0
  52. package/src/engine/html.ts +2 -0
  53. package/src/engine/reader.js +1696 -0
  54. package/src/index.ts +6 -0
  55. package/src/sound.ts +66 -0
  56. package/src/themes.ts +188 -0
  57. package/src/types.ts +138 -0
  58. package/src/ui/AppearanceSheet.tsx +167 -0
  59. package/src/ui/ContentsSheet.tsx +144 -0
  60. package/src/ui/CustomizeSheet.tsx +189 -0
  61. package/src/ui/Glass.tsx +37 -0
  62. package/src/ui/HighlightMenu.tsx +64 -0
  63. package/src/ui/Icons.tsx +246 -0
  64. package/src/ui/LineGuide.tsx +87 -0
  65. package/src/ui/NoteEditor.tsx +55 -0
  66. package/src/ui/Scrubber.tsx +78 -0
  67. package/src/ui/SearchSheet.tsx +79 -0
  68. package/src/ui/Sheet.tsx +69 -0
  69. package/src/ui/Slider.tsx +30 -0
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.CustomizeSheet = CustomizeSheet;
37
+ const react_1 = __importStar(require("react"));
38
+ const react_native_1 = require("react-native");
39
+ const themes_1 = require("../themes");
40
+ const Icons_1 = require("./Icons");
41
+ const Sheet_1 = require("./Sheet");
42
+ const Slider_1 = require("./Slider");
43
+ const COLUMN_LABEL = { auto: 'Auto Set', '1': 'One', '2': 'Two' };
44
+ const GREEN = { true: '#34c759' };
45
+ function Toggle(props) {
46
+ return (react_1.default.createElement(react_native_1.View, { style: styles.toggleBox },
47
+ react_1.default.createElement(react_native_1.Switch, { ...props })));
48
+ }
49
+ /** "Customize Theme" sheet: font, bold, spacing, margins, columns, justify, sound. */
50
+ function CustomizeSheet({ visible, colors, page, settings: s, sample, onChange, onReset, onClose }) {
51
+ const [fonts, setFonts] = (0, react_1.useState)(false);
52
+ const [columnsMenu, setColumnsMenu] = (0, react_1.useState)(false);
53
+ const off = !s.customize;
54
+ const font = (0, themes_1.getFont)(s.fontId);
55
+ const previewFont = s.fontId === 'system' ? undefined : themes_1.serifFont;
56
+ const border = { borderTopWidth: react_native_1.StyleSheet.hairlineWidth, borderColor: colors.separator };
57
+ const sliderRow = (label, icon, value, min, max, step, show, key) => (react_1.default.createElement(react_native_1.View, { style: [styles.sliderBlock, border, off && styles.dim], pointerEvents: off ? 'none' : 'auto' },
58
+ react_1.default.createElement(react_native_1.Text, { style: [styles.caption, { color: colors.subtext }] }, label),
59
+ react_1.default.createElement(react_native_1.View, { style: styles.sliderRow },
60
+ react_1.default.createElement(Icons_1.Icon, { name: icon, color: colors.text, size: 24 }),
61
+ react_1.default.createElement(react_native_1.View, { style: { flex: 1, marginHorizontal: 12 } },
62
+ react_1.default.createElement(Slider_1.Slider, { value: value, min: min, max: max, step: step, onChange: (v) => onChange({ [key]: v }), color: colors.text, track: colors.separator, thumbColor: "#ffffff" })),
63
+ react_1.default.createElement(react_native_1.Text, { style: [styles.value, { color: colors.subtext }] }, show))));
64
+ const row = (icon, label, right, onPress, top = true, iconActive = false) => {
65
+ const content = (react_1.default.createElement(react_1.default.Fragment, null,
66
+ react_1.default.createElement(react_native_1.View, { style: styles.rowIcon },
67
+ react_1.default.createElement(Icons_1.Icon, { name: icon, color: colors.text, size: 22, active: iconActive })),
68
+ react_1.default.createElement(react_native_1.Text, { style: [styles.label, { color: colors.text }] }, label),
69
+ right));
70
+ return onPress ? (react_1.default.createElement(react_native_1.Pressable, { style: [styles.line, top && border], onPress: onPress }, content)) : (react_1.default.createElement(react_native_1.View, { style: [styles.line, top && border] }, content));
71
+ };
72
+ const close = () => {
73
+ setFonts(false);
74
+ setColumnsMenu(false);
75
+ onClose();
76
+ };
77
+ return (react_1.default.createElement(Sheet_1.Sheet, { visible: visible, colors: colors, onClose: close, closeIcon: "check", title: "Customize Theme", height: "92%" },
78
+ react_1.default.createElement(react_native_1.View, { style: [styles.preview, { backgroundColor: page.bg }] },
79
+ react_1.default.createElement(react_native_1.Text, { style: [styles.aa, { color: page.fg, fontFamily: previewFont }] }, "Aa"),
80
+ react_1.default.createElement(react_native_1.Text, { numberOfLines: 4, style: {
81
+ color: page.fg, fontFamily: previewFont, fontSize: Math.min(s.fontSize, 22),
82
+ lineHeight: Math.min(s.fontSize, 22) * (s.customize ? s.lineHeight : 1.5),
83
+ fontWeight: s.bold ? '700' : '400', textAlign: s.justify ? 'justify' : 'auto'
84
+ } }, sample)),
85
+ react_1.default.createElement(react_native_1.ScrollView, { contentContainerStyle: styles.pad },
86
+ react_1.default.createElement(react_native_1.View, { style: [styles.group, { backgroundColor: colors.card }] },
87
+ row('textSize', 'Font', react_1.default.createElement(react_native_1.View, { style: styles.value2 },
88
+ react_1.default.createElement(react_native_1.Text, { style: { color: colors.subtext, fontSize: 17 } }, font.name),
89
+ react_1.default.createElement(Icons_1.Icon, { name: fonts ? 'chevronUp' : 'chevronRight', color: colors.subtext, size: 18 })), () => setFonts((v) => !v), false),
90
+ fonts &&
91
+ themes_1.FONTS.map((f) => (react_1.default.createElement(react_native_1.Pressable, { key: f.id, onPress: () => {
92
+ onChange({ fontId: f.id });
93
+ setFonts(false);
94
+ }, style: [styles.line, border] },
95
+ react_1.default.createElement(react_native_1.View, { style: styles.check }, s.fontId === f.id && react_1.default.createElement(Icons_1.Icon, { name: "check", color: colors.text, size: 20 })),
96
+ react_1.default.createElement(react_native_1.Text, { style: [styles.label, { color: colors.text }] }, f.name)))),
97
+ row('bold', 'Bold Text', react_1.default.createElement(Toggle, { value: s.bold, onValueChange: (v) => onChange({ bold: v }), trackColor: GREEN }))),
98
+ react_1.default.createElement(react_native_1.Text, { style: [styles.heading, { color: colors.text }] }, "Accessibility & Layout Options"),
99
+ react_1.default.createElement(react_native_1.View, { style: [styles.group, { backgroundColor: colors.card }] },
100
+ row('sliders', 'Customize', react_1.default.createElement(Toggle, { value: s.customize, onValueChange: (v) => onChange({ customize: v }), trackColor: GREEN }), undefined, false),
101
+ sliderRow('LINE SPACING', 'lineSpacing', s.lineHeight, 1.1, 2.2, 0.05, s.lineHeight.toFixed(2), 'lineHeight'),
102
+ sliderRow('CHARACTER SPACING', 'charSpacing', s.letterSpacing, -50, 100, 5, `${s.letterSpacing}%`, 'letterSpacing'),
103
+ sliderRow('WORD SPACING', 'wordSpacing', s.wordSpacing, -50, 100, 5, `${s.wordSpacing}%`, 'wordSpacing'),
104
+ sliderRow('MARGINS', 'margins', s.margins, -50, 100, 5, `${s.margins}%`, 'margins')),
105
+ react_1.default.createElement(react_native_1.View, { style: [styles.group, { backgroundColor: colors.card, marginTop: 16 }] },
106
+ row('columns', 'Columns', react_1.default.createElement(react_native_1.View, { style: styles.value2 },
107
+ react_1.default.createElement(react_native_1.Text, { style: { color: colors.subtext, fontSize: 17 } }, COLUMN_LABEL[String(s.columns)]),
108
+ react_1.default.createElement(Icons_1.Icon, { name: columnsMenu ? 'chevronUp' : 'chevronDown', color: colors.subtext, size: 18 })), () => setColumnsMenu((v) => !v), false),
109
+ columnsMenu &&
110
+ ['auto', 1, 2].map((c) => (react_1.default.createElement(react_native_1.Pressable, { key: String(c), style: [styles.line, border], onPress: () => {
111
+ onChange({ columns: c });
112
+ setColumnsMenu(false);
113
+ } },
114
+ react_1.default.createElement(react_native_1.View, { style: styles.check }, s.columns === c && react_1.default.createElement(Icons_1.Icon, { name: "check", color: colors.text, size: 20 })),
115
+ react_1.default.createElement(react_native_1.Text, { style: [styles.label, { color: colors.text }] }, COLUMN_LABEL[String(c)])))),
116
+ row('justify', 'Justify Text', react_1.default.createElement(Toggle, { value: s.justify, onValueChange: (v) => onChange({ justify: v }), trackColor: GREEN })),
117
+ row(s.pageSound ? 'sound' : 'soundOff', 'Page Turn Sound', react_1.default.createElement(Toggle, { value: s.pageSound, onValueChange: (v) => onChange({ pageSound: v }), trackColor: GREEN }))),
118
+ react_1.default.createElement(react_native_1.Pressable, { onPress: onReset, style: [styles.reset, { backgroundColor: colors.card }] },
119
+ react_1.default.createElement(react_native_1.Text, { style: { color: '#ff3b30', fontSize: 18, fontWeight: '600' } }, "Reset Theme")))));
120
+ }
121
+ const styles = react_native_1.StyleSheet.create({
122
+ preview: { paddingHorizontal: 22, paddingTop: 12, paddingBottom: 18, marginBottom: 10 },
123
+ aa: { fontSize: 34, textAlign: 'right', marginBottom: 6 },
124
+ pad: { paddingHorizontal: 16, paddingBottom: 40 },
125
+ group: { borderRadius: 24, overflow: 'hidden' },
126
+ line: { flexDirection: 'row', alignItems: 'center', minHeight: 56, paddingHorizontal: 18 },
127
+ rowIcon: { width: 34, height: 28, alignItems: 'flex-start', justifyContent: 'center' },
128
+ toggleBox: { height: 31, minWidth: 51, alignItems: 'center', justifyContent: 'center' },
129
+ label: { flex: 1, fontSize: 18, lineHeight: 24 },
130
+ check: { width: 34, height: 24, justifyContent: 'center' },
131
+ value2: { flexDirection: 'row', alignItems: 'center', gap: 4 },
132
+ heading: { fontSize: 22, fontWeight: '700', marginTop: 26, marginBottom: 10, marginStart: 4 },
133
+ sliderBlock: { paddingHorizontal: 18, paddingTop: 10, paddingBottom: 6 },
134
+ dim: { opacity: 0.45 },
135
+ caption: { fontSize: 14, marginBottom: 2 },
136
+ sliderRow: { flexDirection: 'row', alignItems: 'center' },
137
+ value: { width: 50, textAlign: 'right', fontSize: 17, lineHeight: 22 },
138
+ reset: { marginTop: 18, height: 58, borderRadius: 29, alignItems: 'center', justifyContent: 'center' }
139
+ });
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import type { StyleProp, ViewStyle } from 'react-native';
3
+ interface Props {
4
+ style?: StyleProp<ViewStyle>;
5
+ /** translucent tint drawn over the blur (use ChromeColors.glass or .sheetGlass) */
6
+ background: string;
7
+ border?: string;
8
+ dark: boolean;
9
+ /** blur strength 0..100 */
10
+ intensity?: number;
11
+ children?: React.ReactNode;
12
+ }
13
+ /** Frosted glass surface: blurs the book behind it so reading is not interrupted. */
14
+ export declare function Glass({ style, background, border, dark, intensity, children }: Props): React.JSX.Element;
15
+ export {};
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Glass = Glass;
7
+ const react_1 = __importDefault(require("react"));
8
+ const react_native_1 = require("react-native");
9
+ // expo-blur is optional: with it the controls are frosted glass, without it they are plain translucent.
10
+ let BlurView = null;
11
+ try {
12
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
13
+ BlurView = require('expo-blur').BlurView;
14
+ }
15
+ catch {
16
+ BlurView = null;
17
+ }
18
+ /** Frosted glass surface: blurs the book behind it so reading is not interrupted. */
19
+ function Glass({ style, background, border, dark, intensity = 38, children }) {
20
+ const base = { overflow: 'hidden', borderWidth: border ? react_native_1.StyleSheet.hairlineWidth : 0, borderColor: border };
21
+ if (BlurView) {
22
+ return (react_1.default.createElement(BlurView, { intensity: intensity, tint: dark ? 'dark' : 'light', style: [base, style] },
23
+ react_1.default.createElement(react_native_1.View, { style: [react_native_1.StyleSheet.absoluteFill, { backgroundColor: background }], pointerEvents: "none" }),
24
+ children));
25
+ }
26
+ return react_1.default.createElement(react_native_1.View, { style: [base, { backgroundColor: background }, style] }, children);
27
+ }
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import type { ChromeColors } from '../themes';
3
+ import type { Highlight, HighlightColor } from '../types';
4
+ interface Props {
5
+ highlight: Highlight;
6
+ rect: {
7
+ x: number;
8
+ y: number;
9
+ width: number;
10
+ height: number;
11
+ };
12
+ screen: {
13
+ width: number;
14
+ height: number;
15
+ };
16
+ colors: ChromeColors;
17
+ onColor: (c: HighlightColor) => void;
18
+ onToggleUnderline: () => void;
19
+ onNote: () => void;
20
+ onDelete: () => void;
21
+ onDismiss: () => void;
22
+ }
23
+ /** Floating glass palette shown over a highlight, like Apple Books. */
24
+ export declare function HighlightMenu({ highlight, rect, screen, colors, onColor, onToggleUnderline, onNote, onDelete, onDismiss }: Props): React.JSX.Element;
25
+ export {};
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.HighlightMenu = HighlightMenu;
7
+ const react_1 = __importDefault(require("react"));
8
+ const react_native_1 = require("react-native");
9
+ const themes_1 = require("../themes");
10
+ const Glass_1 = require("./Glass");
11
+ const Icons_1 = require("./Icons");
12
+ const W = 316;
13
+ const H = 50;
14
+ /** Floating glass palette shown over a highlight, like Apple Books. */
15
+ function HighlightMenu({ highlight, rect, screen, colors, onColor, onToggleUnderline, onNote, onDelete, onDismiss }) {
16
+ const left = Math.max(8, Math.min(screen.width - W - 8, rect.x + rect.width / 2 - W / 2));
17
+ const above = rect.y - H - 10;
18
+ const top = above > 60 ? above : rect.y + rect.height + 10;
19
+ return (react_1.default.createElement(react_1.default.Fragment, null,
20
+ react_1.default.createElement(react_native_1.Pressable, { style: react_native_1.StyleSheet.absoluteFill, onPress: onDismiss, accessibilityLabel: "Dismiss" }),
21
+ react_1.default.createElement(Glass_1.Glass, { dark: colors.dark, background: colors.sheetGlass, border: colors.glassBorder, intensity: 55, style: [styles.menu, { left, top }] },
22
+ Object.keys(themes_1.HIGHLIGHT_COLORS).map((c) => (react_1.default.createElement(react_native_1.Pressable, { key: c, onPress: () => onColor(c), hitSlop: 4, accessibilityLabel: `${c} highlight` },
23
+ react_1.default.createElement(react_native_1.View, { style: [styles.dot, { backgroundColor: themes_1.HIGHLIGHT_COLORS[c], borderWidth: highlight.color === c ? 2 : 0, borderColor: colors.text }] })))),
24
+ react_1.default.createElement(react_native_1.Pressable, { onPress: onToggleUnderline, hitSlop: 6, accessibilityLabel: "Underline" },
25
+ react_1.default.createElement(Icons_1.Icon, { name: "underline", color: colors.text, size: 22, active: highlight.style === 'underline', strokeWidth: highlight.style === 'underline' ? 2.4 : 1.8 })),
26
+ react_1.default.createElement(react_native_1.Pressable, { onPress: onNote, hitSlop: 6, accessibilityLabel: "Note" },
27
+ react_1.default.createElement(Icons_1.Icon, { name: "pencil", color: colors.text, size: 22 })),
28
+ react_1.default.createElement(react_native_1.Pressable, { onPress: onDelete, hitSlop: 6, accessibilityLabel: "Remove highlight" },
29
+ react_1.default.createElement(Icons_1.Icon, { name: "trash", color: "#ff3b30", size: 22 })))));
30
+ }
31
+ const styles = react_native_1.StyleSheet.create({
32
+ menu: {
33
+ position: 'absolute',
34
+ width: W,
35
+ height: H,
36
+ borderRadius: 25,
37
+ flexDirection: 'row',
38
+ alignItems: 'center',
39
+ justifyContent: 'space-around',
40
+ paddingHorizontal: 12
41
+ },
42
+ dot: { width: 26, height: 26, borderRadius: 13 }
43
+ });
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ /**
3
+ * Vector icon set (24 x 24 grid, rounded strokes). Every icon takes the colour it is drawn in, so it follows the
4
+ * theme (light / dark / any page colour). Some icons carry state: `active` fills or closes them
5
+ * (bookmark, rotation lock, line guide).
6
+ */
7
+ export type IconName = 'close' | 'check' | 'chevronRight' | 'chevronUp' | 'chevronDown' | 'list' | 'search' | 'textSize' | 'share' | 'bookmark' | 'rotationLock' | 'lineGuide' | 'undo' | 'sun' | 'sunLow' | 'moon' | 'contrast' | 'pageSlide' | 'pageCurl' | 'pageFade' | 'pageScroll' | 'sliders' | 'lineSpacing' | 'charSpacing' | 'wordSpacing' | 'margins' | 'columns' | 'bold' | 'justify' | 'trash' | 'pencil' | 'underline' | 'highlighter' | 'sound' | 'soundOff';
8
+ interface Props {
9
+ name: IconName;
10
+ color: string;
11
+ size?: number;
12
+ /** filled / closed state for bookmark, rotation lock, line guide */
13
+ active?: boolean;
14
+ strokeWidth?: number;
15
+ }
16
+ export declare function Icon({ name, color, size, active, strokeWidth }: Props): React.JSX.Element;
17
+ export {};
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.Icon = Icon;
40
+ const react_1 = __importDefault(require("react"));
41
+ const react_native_svg_1 = __importStar(require("react-native-svg"));
42
+ const RAYS = [0, 45, 90, 135, 180, 225, 270, 315].map((deg) => {
43
+ const a = (deg * Math.PI) / 180;
44
+ return { x1: 12 + 6.6 * Math.cos(a), y1: 12 + 6.6 * Math.sin(a), x2: 12 + 9.2 * Math.cos(a), y2: 12 + 9.2 * Math.sin(a) };
45
+ });
46
+ function Icon({ name, color, size = 24, active = false, strokeWidth = 1.8 }) {
47
+ const p = { stroke: color, strokeWidth, strokeLinecap: 'round', strokeLinejoin: 'round', fill: 'none' };
48
+ let body = null;
49
+ switch (name) {
50
+ case 'close':
51
+ body = react_1.default.createElement(react_native_svg_1.Path, { d: "M6 6 L18 18 M18 6 L6 18", ...p });
52
+ break;
53
+ case 'check':
54
+ body = react_1.default.createElement(react_native_svg_1.Path, { d: "M5 12.5 L10 17.5 L19 7", ...p });
55
+ break;
56
+ case 'chevronRight':
57
+ body = react_1.default.createElement(react_native_svg_1.Path, { d: "M9 5.5 L15.5 12 L9 18.5", ...p });
58
+ break;
59
+ case 'chevronUp':
60
+ body = react_1.default.createElement(react_native_svg_1.Path, { d: "M5.5 15 L12 8.5 L18.5 15", ...p });
61
+ break;
62
+ case 'chevronDown':
63
+ body = react_1.default.createElement(react_native_svg_1.Path, { d: "M5.5 9 L12 15.5 L18.5 9", ...p });
64
+ break;
65
+ case 'list':
66
+ body = (react_1.default.createElement(react_native_svg_1.G, null, [7, 12, 17].map((y) => (react_1.default.createElement(react_native_svg_1.G, { key: y },
67
+ react_1.default.createElement(react_native_svg_1.Circle, { cx: 4.8, cy: y, r: 1.25, fill: color }),
68
+ react_1.default.createElement(react_native_svg_1.Path, { d: `M9 ${y} H20`, ...p }))))));
69
+ break;
70
+ case 'search':
71
+ body = (react_1.default.createElement(react_native_svg_1.G, null,
72
+ react_1.default.createElement(react_native_svg_1.Circle, { cx: 10.8, cy: 10.8, r: 6.3, ...p }),
73
+ react_1.default.createElement(react_native_svg_1.Path, { d: "M15.6 15.6 L20.5 20.5", ...p })));
74
+ break;
75
+ case 'textSize':
76
+ body = (react_1.default.createElement(react_native_svg_1.G, null,
77
+ react_1.default.createElement(react_native_svg_1.Path, { d: "M2.8 18 L6.3 9.2 L9.8 18 M4.1 14.9 H8.5", ...p }),
78
+ react_1.default.createElement(react_native_svg_1.Path, { d: "M11.6 18 L16.6 5.6 L21.6 18 M13.5 13.6 H19.7", ...p })));
79
+ break;
80
+ case 'share':
81
+ body = (react_1.default.createElement(react_native_svg_1.G, null,
82
+ react_1.default.createElement(react_native_svg_1.Path, { d: "M8.5 10 H7 A1.7 1.7 0 0 0 5.3 11.7 V19 A1.7 1.7 0 0 0 7 20.7 H17 A1.7 1.7 0 0 0 18.7 19 V11.7 A1.7 1.7 0 0 0 17 10 H15.5", ...p }),
83
+ react_1.default.createElement(react_native_svg_1.Path, { d: "M12 14.5 V3.5 M8.2 7.3 L12 3.5 L15.8 7.3", ...p })));
84
+ break;
85
+ case 'bookmark':
86
+ body = (react_1.default.createElement(react_native_svg_1.Path, { d: "M7.2 3.8 H16.8 A1.2 1.2 0 0 1 18 5 V20.2 L12 16.2 L6 20.2 V5 A1.2 1.2 0 0 1 7.2 3.8 Z", ...p, fill: active ? color : 'none' }));
87
+ break;
88
+ case 'rotationLock':
89
+ body = (react_1.default.createElement(react_native_svg_1.G, null,
90
+ react_1.default.createElement(react_native_svg_1.Path, { d: "M20.2 13 A8.2 8.2 0 1 1 17 5.9", ...p }),
91
+ react_1.default.createElement(react_native_svg_1.Path, { d: "M17.2 2.8 V6.2 H13.8", ...p }),
92
+ react_1.default.createElement(react_native_svg_1.Rect, { x: 9, y: 11.2, width: 6, height: 5, rx: 1.2, ...p, fill: active ? color : 'none' }),
93
+ react_1.default.createElement(react_native_svg_1.Path, { d: active ? 'M10.4 11.2 V10 A1.6 1.6 0 0 1 13.6 10 V11.2' : 'M10.4 11.2 V9.9 A1.6 1.6 0 0 1 13.6 9.9', ...p })));
94
+ break;
95
+ case 'lineGuide':
96
+ body = (react_1.default.createElement(react_native_svg_1.G, null,
97
+ react_1.default.createElement(react_native_svg_1.Path, { d: "M4 6.2 H20 M4 17.8 H20", ...p, opacity: 0.5 }),
98
+ react_1.default.createElement(react_native_svg_1.Rect, { x: 2.8, y: 9.2, width: 18.4, height: 5.6, rx: 2.8, ...p, fill: active ? color : 'none', fillOpacity: active ? 0.28 : 0 })));
99
+ break;
100
+ case 'undo':
101
+ body = react_1.default.createElement(react_native_svg_1.Path, { d: "M8.5 6 L4 10.5 L8.5 15 M4.5 10.5 H14.5 A5 5 0 0 1 14.5 20.5 H11", ...p });
102
+ break;
103
+ case 'sun':
104
+ body = (react_1.default.createElement(react_native_svg_1.G, null,
105
+ react_1.default.createElement(react_native_svg_1.Circle, { cx: 12, cy: 12, r: 3.9, ...p }),
106
+ RAYS.map((r, i) => (react_1.default.createElement(react_native_svg_1.Line, { key: i, x1: r.x1, y1: r.y1, x2: r.x2, y2: r.y2, ...p })))));
107
+ break;
108
+ case 'sunLow':
109
+ body = (react_1.default.createElement(react_native_svg_1.G, null,
110
+ react_1.default.createElement(react_native_svg_1.Circle, { cx: 12, cy: 12, r: 2.4, ...p }),
111
+ RAYS.map((r, i) => (react_1.default.createElement(react_native_svg_1.Line, { key: i, x1: 12 + (r.x1 - 12) * 0.8, y1: 12 + (r.y1 - 12) * 0.8, x2: 12 + (r.x2 - 12) * 0.62, y2: 12 + (r.y2 - 12) * 0.62, ...p })))));
112
+ break;
113
+ case 'moon':
114
+ body = react_1.default.createElement(react_native_svg_1.Path, { d: "M20 14.2 A8.4 8.4 0 1 1 9.8 4 A6.6 6.6 0 0 0 20 14.2 Z", ...p });
115
+ break;
116
+ case 'contrast':
117
+ body = (react_1.default.createElement(react_native_svg_1.G, null,
118
+ react_1.default.createElement(react_native_svg_1.Circle, { cx: 12, cy: 12, r: 8.2, ...p }),
119
+ react_1.default.createElement(react_native_svg_1.Path, { d: "M12 3.8 A8.2 8.2 0 0 1 12 20.2 Z", fill: color, stroke: color, strokeWidth: 1 })));
120
+ break;
121
+ case 'pageSlide':
122
+ body = (react_1.default.createElement(react_native_svg_1.G, null,
123
+ react_1.default.createElement(react_native_svg_1.Path, { d: "M9 5.2 H5.2 A1.9 1.9 0 0 0 3.3 7.1 V17.9 A1.9 1.9 0 0 0 5.2 19.8 H9", ...p, opacity: 0.55 }),
124
+ react_1.default.createElement(react_native_svg_1.Rect, { x: 8, y: 3.2, width: 12.7, height: 16.6, rx: 2.4, ...p })));
125
+ break;
126
+ case 'pageCurl':
127
+ body = (react_1.default.createElement(react_native_svg_1.G, null,
128
+ react_1.default.createElement(react_native_svg_1.Path, { d: "M6.7 3.5 H14.5 L20 9 V18.6 A1.9 1.9 0 0 1 18.1 20.5 H6.7 A1.9 1.9 0 0 1 4.8 18.6 V5.4 A1.9 1.9 0 0 1 6.7 3.5 Z", ...p }),
129
+ react_1.default.createElement(react_native_svg_1.Path, { d: "M14.5 3.5 V7.4 A1.6 1.6 0 0 0 16.1 9 H20", ...p })));
130
+ break;
131
+ case 'pageFade':
132
+ body = react_1.default.createElement(react_native_svg_1.Path, { d: "M13.2 2.8 L5.2 13.2 H11 L10.2 21.2 L18.8 10.4 H13 Z", ...p });
133
+ break;
134
+ case 'pageScroll':
135
+ body = (react_1.default.createElement(react_native_svg_1.G, null,
136
+ react_1.default.createElement(react_native_svg_1.Rect, { x: 5, y: 3, width: 14, height: 18, rx: 2.4, ...p }),
137
+ react_1.default.createElement(react_native_svg_1.Path, { d: "M9.4 9.6 L12 7 L14.6 9.6 M9.4 14.4 L12 17 L14.6 14.4", ...p })));
138
+ break;
139
+ case 'sliders':
140
+ body = (react_1.default.createElement(react_native_svg_1.G, null,
141
+ react_1.default.createElement(react_native_svg_1.Path, { d: "M3.5 8 H9.2 M14.8 8 H20.5 M3.5 16 H14.2 M19.8 16 H20.5", ...p }),
142
+ react_1.default.createElement(react_native_svg_1.Circle, { cx: 12, cy: 8, r: 2.8, ...p }),
143
+ react_1.default.createElement(react_native_svg_1.Circle, { cx: 17, cy: 16, r: 2.8, ...p })));
144
+ break;
145
+ case 'lineSpacing':
146
+ body = react_1.default.createElement(react_native_svg_1.Path, { d: "M10.5 6.5 H20.5 M10.5 12 H20.5 M10.5 17.5 H20.5 M5 4.5 V19.5 M2.9 6.6 L5 4.5 L7.1 6.6 M2.9 17.4 L5 19.5 L7.1 17.4", ...p });
147
+ break;
148
+ case 'charSpacing':
149
+ body = react_1.default.createElement(react_native_svg_1.Path, { d: "M7.6 13.6 L12 3.8 L16.4 13.6 M9.2 10.4 H14.8 M3.8 19.2 H20.2 M6.2 16.9 L3.8 19.2 L6.2 21.5 M17.8 16.9 L20.2 19.2 L17.8 21.5", ...p });
150
+ break;
151
+ case 'wordSpacing':
152
+ body = (react_1.default.createElement(react_native_svg_1.G, null,
153
+ react_1.default.createElement(react_native_svg_1.Rect, { x: 2.8, y: 4.5, width: 7, height: 4.2, rx: 1.2, ...p }),
154
+ react_1.default.createElement(react_native_svg_1.Rect, { x: 14.2, y: 4.5, width: 7, height: 4.2, rx: 1.2, ...p }),
155
+ react_1.default.createElement(react_native_svg_1.Path, { d: "M3.8 15.2 H20.2 M6.2 12.9 L3.8 15.2 L6.2 17.5 M17.8 12.9 L20.2 15.2 L17.8 17.5", ...p })));
156
+ break;
157
+ case 'margins':
158
+ body = (react_1.default.createElement(react_native_svg_1.G, null,
159
+ react_1.default.createElement(react_native_svg_1.Rect, { x: 3.8, y: 3, width: 16.4, height: 18, rx: 2.4, ...p }),
160
+ react_1.default.createElement(react_native_svg_1.Path, { d: "M8 7 V17 M16 7 V17", ...p })));
161
+ break;
162
+ case 'columns':
163
+ body = (react_1.default.createElement(react_native_svg_1.G, null,
164
+ react_1.default.createElement(react_native_svg_1.Rect, { x: 3.5, y: 4, width: 7.6, height: 16, rx: 1.8, ...p }),
165
+ react_1.default.createElement(react_native_svg_1.Rect, { x: 12.9, y: 4, width: 7.6, height: 16, rx: 1.8, ...p })));
166
+ break;
167
+ case 'bold':
168
+ body = react_1.default.createElement(react_native_svg_1.Path, { d: "M8 4.6 V19.4 M8 4.6 H13 A3.6 3.6 0 0 1 13 11.8 H8 M8 11.8 H14 A3.8 3.8 0 0 1 14 19.4 H8", ...p, strokeWidth: strokeWidth + 0.5 });
169
+ break;
170
+ case 'justify':
171
+ body = react_1.default.createElement(react_native_svg_1.Path, { d: "M4 6 H20 M4 10 H20 M4 14 H20 M4 18 H20", ...p });
172
+ break;
173
+ case 'trash':
174
+ body = react_1.default.createElement(react_native_svg_1.Path, { d: "M4.5 7 H19.5 M9.3 7 V4.6 H14.7 V7 M6.6 7 L7.6 19.6 A1.2 1.2 0 0 0 8.8 20.7 H15.2 A1.2 1.2 0 0 0 16.4 19.6 L17.4 7 M10.2 10.8 V16.4 M13.8 10.8 V16.4", ...p });
175
+ break;
176
+ case 'pencil':
177
+ body = react_1.default.createElement(react_native_svg_1.Path, { d: "M4 20 L5.2 15.2 L16.2 4.2 A2.2 2.2 0 0 1 19.4 7.4 L8.4 18.4 Z M14 6.4 L17.2 9.6", ...p });
178
+ break;
179
+ case 'highlighter':
180
+ body = react_1.default.createElement(react_native_svg_1.Path, { d: "M14.2 4.6 L19.4 9.8 L10.6 18.6 L5.4 13.4 Z M5.4 13.4 L4.2 17.6 L7.6 18.6 M3.5 21 H12.5", ...p });
181
+ break;
182
+ case 'underline':
183
+ body = react_1.default.createElement(react_native_svg_1.Path, { d: "M7.4 4.4 V11 A4.6 4.6 0 0 0 16.6 11 V4.4 M5 20 H19", ...p });
184
+ break;
185
+ case 'sound':
186
+ body = react_1.default.createElement(react_native_svg_1.Path, { d: "M4 9.5 H7.5 L12.5 5.2 V18.8 L7.5 14.5 H4 Z M16 9 A4.2 4.2 0 0 1 16 15 M18.6 6.6 A7.6 7.6 0 0 1 18.6 17.4", ...p });
187
+ break;
188
+ case 'soundOff':
189
+ body = react_1.default.createElement(react_native_svg_1.Path, { d: "M4 9.5 H7.5 L12.5 5.2 V18.8 L7.5 14.5 H4 Z M16.2 9.4 L21 14.6 M21 9.4 L16.2 14.6", ...p });
190
+ break;
191
+ }
192
+ return (react_1.default.createElement(react_native_svg_1.default, { width: size, height: size, viewBox: "0 0 24 24" }, body));
193
+ }
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ export type DimLevel = 'high' | 'medium' | 'low' | 'none';
3
+ /** Opacity of the page-coloured veil over everything except the guide line. */
4
+ export declare const DIM_ALPHA: Record<DimLevel, number>;
5
+ interface Props {
6
+ /** page background colour (#rrggbb) */
7
+ bg: string;
8
+ dark: boolean;
9
+ dim: DimLevel;
10
+ /** height of one line of text */
11
+ lineHeight: number;
12
+ /** vertical range the guide may move in */
13
+ minY: number;
14
+ maxY: number;
15
+ }
16
+ /**
17
+ * Line Guide: dims the page except for one line that can be dragged up and down.
18
+ * The veil ignores touches, so page turns and taps still reach the book.
19
+ */
20
+ export declare function LineGuide({ bg, dark, dim, lineHeight, minY, maxY }: Props): React.JSX.Element;
21
+ export {};
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.DIM_ALPHA = void 0;
37
+ exports.LineGuide = LineGuide;
38
+ const react_1 = __importStar(require("react"));
39
+ const react_native_1 = require("react-native");
40
+ /** Opacity of the page-coloured veil over everything except the guide line. */
41
+ exports.DIM_ALPHA = { high: 0.86, medium: 0.62, low: 0.36, none: 0 };
42
+ function rgba(hex, a) {
43
+ const v = [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16));
44
+ return `rgba(${v[0]},${v[1]},${v[2]},${a})`;
45
+ }
46
+ /**
47
+ * Line Guide: dims the page except for one line that can be dragged up and down.
48
+ * The veil ignores touches, so page turns and taps still reach the book.
49
+ */
50
+ function LineGuide({ bg, dark, dim, lineHeight, minY, maxY }) {
51
+ const h = Math.round(lineHeight) + 14;
52
+ const [y, setY] = (0, react_1.useState)(minY + 40);
53
+ const state = (0, react_1.useRef)({ start: 0, minY, maxY, h });
54
+ state.current.minY = minY;
55
+ state.current.maxY = maxY;
56
+ state.current.h = h;
57
+ const yRef = (0, react_1.useRef)(y);
58
+ yRef.current = y;
59
+ const pan = (0, react_1.useRef)(react_native_1.PanResponder.create({
60
+ onStartShouldSetPanResponder: () => true,
61
+ onMoveShouldSetPanResponder: () => true,
62
+ onPanResponderGrant: () => {
63
+ state.current.start = yRef.current;
64
+ },
65
+ onPanResponderMove: (_e, g) => {
66
+ const s = state.current;
67
+ setY(Math.max(s.minY, Math.min(s.maxY - s.h, s.start + g.dy)));
68
+ }
69
+ })).current;
70
+ const veil = rgba(bg, exports.DIM_ALPHA[dim]);
71
+ return (react_1.default.createElement(react_native_1.View, { style: react_native_1.StyleSheet.absoluteFill, pointerEvents: "box-none" },
72
+ dim !== 'none' && (react_1.default.createElement(react_1.default.Fragment, null,
73
+ react_1.default.createElement(react_native_1.View, { pointerEvents: "none", style: [styles.veil, { top: 0, height: y, backgroundColor: veil }] }),
74
+ react_1.default.createElement(react_native_1.View, { pointerEvents: "none", style: [styles.veil, { top: y + h, bottom: 0, backgroundColor: veil }] }))),
75
+ react_1.default.createElement(react_native_1.View, { ...pan.panHandlers, style: [
76
+ styles.band,
77
+ {
78
+ top: y,
79
+ height: h,
80
+ borderRadius: h / 2,
81
+ borderColor: dark ? 'rgba(255,255,255,0.35)' : 'rgba(0,0,0,0.22)',
82
+ backgroundColor: dark ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.03)'
83
+ }
84
+ ], accessibilityLabel: "Line guide" })));
85
+ }
86
+ const styles = react_native_1.StyleSheet.create({
87
+ veil: { position: 'absolute', left: 0, right: 0 },
88
+ band: {
89
+ position: 'absolute', left: 10, right: 10, borderWidth: react_native_1.StyleSheet.hairlineWidth * 2,
90
+ shadowColor: '#000', shadowOpacity: 0.35, shadowRadius: 8, shadowOffset: { width: 0, height: 3 }, elevation: 6
91
+ }
92
+ });
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import type { ChromeColors } from '../themes';
3
+ interface Props {
4
+ visible: boolean;
5
+ quote: string;
6
+ initial: string;
7
+ colors: ChromeColors;
8
+ onSave: (note: string) => void;
9
+ onCancel: () => void;
10
+ }
11
+ export declare function NoteEditor({ visible, quote, initial, colors, onSave, onCancel }: Props): React.JSX.Element;
12
+ export {};