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.
- package/LICENSE +21 -0
- package/README.md +338 -2
- package/lib/EpubReader.d.ts +63 -0
- package/lib/EpubReader.js +199 -0
- package/lib/EpubReaderView.d.ts +24 -0
- package/lib/EpubReaderView.js +504 -0
- package/lib/assets/page-turn-1.wav +0 -0
- package/lib/assets/page-turn-2.wav +0 -0
- package/lib/assets/page-turn-3.wav +0 -0
- package/lib/assets/page-turn-4.wav +0 -0
- package/lib/engine/html.d.ts +1 -0
- package/lib/engine/html.js +5 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +30 -0
- package/lib/sound.d.ts +1 -0
- package/lib/sound.js +71 -0
- package/lib/themes.d.ts +56 -0
- package/lib/themes.js +166 -0
- package/lib/types.d.ts +133 -0
- package/lib/types.js +2 -0
- package/lib/ui/AppearanceSheet.d.ts +15 -0
- package/lib/ui/AppearanceSheet.js +127 -0
- package/lib/ui/ContentsSheet.d.ts +27 -0
- package/lib/ui/ContentsSheet.js +87 -0
- package/lib/ui/CustomizeSheet.d.ts +16 -0
- package/lib/ui/CustomizeSheet.js +139 -0
- package/lib/ui/Glass.d.ts +15 -0
- package/lib/ui/Glass.js +27 -0
- package/lib/ui/HighlightMenu.d.ts +25 -0
- package/lib/ui/HighlightMenu.js +43 -0
- package/lib/ui/Icons.d.ts +17 -0
- package/lib/ui/Icons.js +193 -0
- package/lib/ui/LineGuide.d.ts +21 -0
- package/lib/ui/LineGuide.js +92 -0
- package/lib/ui/NoteEditor.d.ts +12 -0
- package/lib/ui/NoteEditor.js +61 -0
- package/lib/ui/Scrubber.d.ts +15 -0
- package/lib/ui/Scrubber.js +86 -0
- package/lib/ui/SearchSheet.d.ts +14 -0
- package/lib/ui/SearchSheet.js +67 -0
- package/lib/ui/Sheet.d.ts +19 -0
- package/lib/ui/Sheet.js +38 -0
- package/lib/ui/Slider.d.ts +14 -0
- package/lib/ui/Slider.js +53 -0
- package/package.json +75 -5
- package/src/EpubReader.tsx +256 -0
- package/src/EpubReaderView.tsx +721 -0
- package/src/assets/page-turn-1.wav +0 -0
- package/src/assets/page-turn-2.wav +0 -0
- package/src/assets/page-turn-3.wav +0 -0
- package/src/assets/page-turn-4.wav +0 -0
- package/src/engine/html.ts +2 -0
- package/src/engine/reader.js +1696 -0
- package/src/index.ts +6 -0
- package/src/sound.ts +66 -0
- package/src/themes.ts +188 -0
- package/src/types.ts +138 -0
- package/src/ui/AppearanceSheet.tsx +167 -0
- package/src/ui/ContentsSheet.tsx +144 -0
- package/src/ui/CustomizeSheet.tsx +189 -0
- package/src/ui/Glass.tsx +37 -0
- package/src/ui/HighlightMenu.tsx +64 -0
- package/src/ui/Icons.tsx +246 -0
- package/src/ui/LineGuide.tsx +87 -0
- package/src/ui/NoteEditor.tsx +55 -0
- package/src/ui/Scrubber.tsx +78 -0
- package/src/ui/SearchSheet.tsx +79 -0
- package/src/ui/Sheet.tsx +69 -0
- 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 {};
|
package/lib/ui/Glass.js
ADDED
|
@@ -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 {};
|
package/lib/ui/Icons.js
ADDED
|
@@ -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 {};
|