@guidelytech/react-native 0.5.0 → 0.6.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/dist/index.cjs +181 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -6
- package/dist/index.d.ts +15 -6
- package/dist/index.js +197 -55
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -54,7 +54,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
54
54
|
var import_react8 = require("react");
|
|
55
55
|
var import_react_native11 = require("react-native");
|
|
56
56
|
|
|
57
|
-
// ../shared/dist/chunk-
|
|
57
|
+
// ../shared/dist/chunk-OLWGMDRX.js
|
|
58
58
|
function fnv1a(input) {
|
|
59
59
|
let h = 2166136261;
|
|
60
60
|
for (let i = 0; i < input.length; i++) {
|
|
@@ -360,6 +360,13 @@ function sanitizeProperties(props) {
|
|
|
360
360
|
var SOURCEMAP_MAX_FILE_BYTES = 25 * 1024 * 1024;
|
|
361
361
|
var MEDIA_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
|
|
362
362
|
var MEDIA_VIDEO_MAX_BYTES = 200 * 1024 * 1024;
|
|
363
|
+
var MEDIA_FILE_MAX_BYTES = 50 * 1024 * 1024;
|
|
364
|
+
var MEDIA_MAX_BYTES = Math.max(MEDIA_IMAGE_MAX_BYTES, MEDIA_VIDEO_MAX_BYTES, MEDIA_FILE_MAX_BYTES);
|
|
365
|
+
var FILE_LINK_CLASS = "gd-file";
|
|
366
|
+
var PDF_BLOCK_CLASS = "gd-pdf";
|
|
367
|
+
function isFileLink(className, href) {
|
|
368
|
+
return !!className && className.split(/\s+/).includes(FILE_LINK_CLASS) && isSafeMediaUrl(href);
|
|
369
|
+
}
|
|
363
370
|
var YOUTUBE_ID = /^[A-Za-z0-9_-]{11}$/;
|
|
364
371
|
var VIMEO_ID = /^\d{1,12}$/;
|
|
365
372
|
var VIMEO_HASH = /^[0-9a-f]{6,20}$/i;
|
|
@@ -500,8 +507,45 @@ function isArticleListed(collections, article, member) {
|
|
|
500
507
|
}
|
|
501
508
|
return true;
|
|
502
509
|
}
|
|
510
|
+
var CAPTURE_SCREENSHOT_MAX_BYTES = 8 * 1024 * 1024;
|
|
503
511
|
|
|
504
|
-
// ../sdk-core/dist/chunk-
|
|
512
|
+
// ../sdk-core/dist/chunk-CYAG6ZYX.js
|
|
513
|
+
function readJson(store, key, fallback) {
|
|
514
|
+
const raw = store.get(key);
|
|
515
|
+
if (raw == null) return fallback;
|
|
516
|
+
try {
|
|
517
|
+
return JSON.parse(raw);
|
|
518
|
+
} catch {
|
|
519
|
+
return fallback;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
function writeJson(store, key, value) {
|
|
523
|
+
try {
|
|
524
|
+
store.set(key, JSON.stringify(value));
|
|
525
|
+
} catch {
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
var KEYS = {
|
|
529
|
+
anon: "guidely:anon",
|
|
530
|
+
seen: "guidely:seen",
|
|
531
|
+
config: (key) => `guidely:config:${key}`,
|
|
532
|
+
etag: (key) => `guidely:etag:${key}`,
|
|
533
|
+
state: (key) => `guidely:state:${key}`,
|
|
534
|
+
user: (key) => `guidely:user:${key}`,
|
|
535
|
+
queue: (key) => `guidely:queue:${key}`,
|
|
536
|
+
session: "guidely:session",
|
|
537
|
+
active: "guidely:active",
|
|
538
|
+
authoring: "guidely:authoring",
|
|
539
|
+
/** How-to capture session marker ({ token, … }) and its not-yet-uploaded steps. */
|
|
540
|
+
capture: "guidely:capture",
|
|
541
|
+
capturePending: "guidely:capture:pending",
|
|
542
|
+
/** Messenger conversations this browser can read: [{ id, token }]. */
|
|
543
|
+
conversations: (key) => `guidely:conversations:${key}`,
|
|
544
|
+
/** Announcement ids opened in the messenger's News tab. */
|
|
545
|
+
newsSeen: (key) => `guidely:news:${key}`
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
// ../sdk-core/dist/chunk-AKNE7D5M.js
|
|
505
549
|
var __defProp2 = Object.defineProperty;
|
|
506
550
|
var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
507
551
|
var __publicField2 = (obj, key, value) => __defNormalProp2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
@@ -523,7 +567,8 @@ var Api = class {
|
|
|
523
567
|
const f = this.fetcher;
|
|
524
568
|
if (!f) throw new Error("fetch is not available");
|
|
525
569
|
const headers = { ...options.headers, "X-Guidely-Key": this.key, Accept: "application/json" };
|
|
526
|
-
|
|
570
|
+
const form = typeof FormData !== "undefined" && options.body instanceof FormData;
|
|
571
|
+
if (options.body !== void 0 && !form) headers["Content-Type"] = "application/json";
|
|
527
572
|
if (options.etag) headers["If-None-Match"] = options.etag;
|
|
528
573
|
const ac = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
529
574
|
const timer = ac ? setTimeout(() => ac.abort(), options.timeoutMs ?? 1e4) : null;
|
|
@@ -531,7 +576,7 @@ var Api = class {
|
|
|
531
576
|
const res = await f(this.url(path, options.params), {
|
|
532
577
|
method,
|
|
533
578
|
headers,
|
|
534
|
-
body: options.body === void 0 ? void 0 : JSON.stringify(options.body),
|
|
579
|
+
body: options.body === void 0 ? void 0 : form ? options.body : JSON.stringify(options.body),
|
|
535
580
|
keepalive: options.keepalive,
|
|
536
581
|
signal: ac?.signal,
|
|
537
582
|
credentials: "omit",
|
|
@@ -556,6 +601,10 @@ var Api = class {
|
|
|
556
601
|
post(path, body, options) {
|
|
557
602
|
return this.request("POST", path, { body, ...options });
|
|
558
603
|
}
|
|
604
|
+
/** Multipart POST (file uploads). No Content-Type header: the browser adds it with the boundary. */
|
|
605
|
+
postForm(path, form, options) {
|
|
606
|
+
return this.request("POST", path, { body: form, ...options });
|
|
607
|
+
}
|
|
559
608
|
/**
|
|
560
609
|
* POST that may answer with server-sent events. Each event is passed to `onEvent`; a JSON answer is
|
|
561
610
|
* returned instead. No timeout: Scout replies can take a while and the server keeps the stream alive.
|
|
@@ -598,10 +647,10 @@ var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
|
598
647
|
function backoffMs(attempt, baseMs = 1e3, maxMs = 3e4) {
|
|
599
648
|
return Math.min(maxMs, baseMs * 2 ** Math.max(0, attempt));
|
|
600
649
|
}
|
|
601
|
-
async function
|
|
650
|
+
async function withRetry(send, attempts = 3, baseMs = 500) {
|
|
602
651
|
for (let i = 0; i < attempts; i++) {
|
|
603
652
|
try {
|
|
604
|
-
const res = await
|
|
653
|
+
const res = await send();
|
|
605
654
|
if (res.ok || res.status >= 400 && res.status < 500 && res.status !== 429) return res;
|
|
606
655
|
} catch {
|
|
607
656
|
}
|
|
@@ -609,6 +658,9 @@ async function postWithRetry(api, path, body, attempts = 3, baseMs = 500) {
|
|
|
609
658
|
}
|
|
610
659
|
return null;
|
|
611
660
|
}
|
|
661
|
+
function postWithRetry(api, path, body, attempts = 3, baseMs = 500) {
|
|
662
|
+
return withRetry(() => api.post(path, body), attempts, baseMs);
|
|
663
|
+
}
|
|
612
664
|
async function readEventStream(body, onEvent) {
|
|
613
665
|
const reader = body.getReader();
|
|
614
666
|
const decoder = new TextDecoder();
|
|
@@ -643,36 +695,7 @@ async function readEventStream(body, onEvent) {
|
|
|
643
695
|
if (buffer.trim()) dispatch(buffer);
|
|
644
696
|
}
|
|
645
697
|
|
|
646
|
-
// ../sdk-core/dist/chunk-
|
|
647
|
-
function readJson(store, key, fallback) {
|
|
648
|
-
const raw = store.get(key);
|
|
649
|
-
if (raw == null) return fallback;
|
|
650
|
-
try {
|
|
651
|
-
return JSON.parse(raw);
|
|
652
|
-
} catch {
|
|
653
|
-
return fallback;
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
function writeJson(store, key, value) {
|
|
657
|
-
try {
|
|
658
|
-
store.set(key, JSON.stringify(value));
|
|
659
|
-
} catch {
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
var KEYS = {
|
|
663
|
-
anon: "guidely:anon",
|
|
664
|
-
seen: "guidely:seen",
|
|
665
|
-
config: (key) => `guidely:config:${key}`,
|
|
666
|
-
etag: (key) => `guidely:etag:${key}`,
|
|
667
|
-
state: (key) => `guidely:state:${key}`,
|
|
668
|
-
user: (key) => `guidely:user:${key}`,
|
|
669
|
-
queue: (key) => `guidely:queue:${key}`,
|
|
670
|
-
session: "guidely:session",
|
|
671
|
-
active: "guidely:active",
|
|
672
|
-
authoring: "guidely:authoring",
|
|
673
|
-
/** Messenger conversations this browser can read: [{ id, token }]. */
|
|
674
|
-
conversations: (key) => `guidely:conversations:${key}`
|
|
675
|
-
};
|
|
698
|
+
// ../sdk-core/dist/chunk-GDF6RCHQ.js
|
|
676
699
|
var EventQueue = class {
|
|
677
700
|
constructor(opts) {
|
|
678
701
|
__publicField2(this, "opts", opts);
|
|
@@ -1754,7 +1777,7 @@ var PersistentStore = class {
|
|
|
1754
1777
|
|
|
1755
1778
|
// src/core/client.ts
|
|
1756
1779
|
var SDK_NAME = "@guidelytech/react-native";
|
|
1757
|
-
var SDK_VERSION = "0.
|
|
1780
|
+
var SDK_VERSION = "0.6.1";
|
|
1758
1781
|
var DEFAULT_API_URL = "https://guidelytech.com";
|
|
1759
1782
|
var PAGE_SCOPED = /* @__PURE__ */ new Set(["page_load", "url_match", "element_click", "element_visible", "delay"]);
|
|
1760
1783
|
var nowIso = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -2973,6 +2996,8 @@ function parseHtml(html) {
|
|
|
2973
2996
|
const lists = [];
|
|
2974
2997
|
let current = null;
|
|
2975
2998
|
let skipping = null;
|
|
2999
|
+
let pdf = null;
|
|
3000
|
+
let fileLink = null;
|
|
2976
3001
|
const media = (block) => {
|
|
2977
3002
|
flush();
|
|
2978
3003
|
blocks.push({ level: 1, runs: [], ...block });
|
|
@@ -3007,12 +3032,30 @@ function parseHtml(html) {
|
|
|
3007
3032
|
if (last && last.bold === run.bold && last.italic === run.italic && last.underline === run.underline && last.code === run.code && last.href === run.href) last.text += text;
|
|
3008
3033
|
else current.runs.push(run);
|
|
3009
3034
|
};
|
|
3035
|
+
const size = (attrs, name) => {
|
|
3036
|
+
const n = Number(attr(attrs, name));
|
|
3037
|
+
return n > 0 ? n : void 0;
|
|
3038
|
+
};
|
|
3039
|
+
const endPdf = (p) => {
|
|
3040
|
+
const name = p.name.replace(/\s+/g, " ").trim();
|
|
3041
|
+
if (p.href && p.pages.length) media({ kind: "pdf", href: p.href, alt: name || "PDF", pages: p.pages });
|
|
3042
|
+
else if (p.href) media({ kind: "file", href: p.href, alt: name || "Open PDF" });
|
|
3043
|
+
else for (const page of p.pages) media({ kind: "image", src: page.src, alt: page.alt, ...page.width && page.height ? { width: page.width, height: page.height } : {} });
|
|
3044
|
+
};
|
|
3010
3045
|
const re = /<!--[\s\S]*?-->|<\/?([a-zA-Z][a-zA-Z0-9]*)\b([^>]*)>|([^<]+|<)/g;
|
|
3011
3046
|
let m;
|
|
3012
3047
|
while (m = re.exec(html || "")) {
|
|
3013
3048
|
const [token, rawTag, attrs = "", text] = m;
|
|
3014
3049
|
if (text !== void 0) {
|
|
3015
3050
|
if (skipping) continue;
|
|
3051
|
+
if (pdf) {
|
|
3052
|
+
if (pdf.inLink) pdf.name += decodeEntities(text);
|
|
3053
|
+
continue;
|
|
3054
|
+
}
|
|
3055
|
+
if (fileLink) {
|
|
3056
|
+
fileLink.name += decodeEntities(text);
|
|
3057
|
+
continue;
|
|
3058
|
+
}
|
|
3016
3059
|
push(decodeEntities(text.replace(/\s+/g, " ")));
|
|
3017
3060
|
continue;
|
|
3018
3061
|
}
|
|
@@ -3036,6 +3079,44 @@ function parseHtml(html) {
|
|
|
3036
3079
|
if (!token.endsWith("/>")) skipping = tag;
|
|
3037
3080
|
continue;
|
|
3038
3081
|
}
|
|
3082
|
+
if (pdf) {
|
|
3083
|
+
if (tag === "div") {
|
|
3084
|
+
pdf.depth += closing ? -1 : 1;
|
|
3085
|
+
if (pdf.depth === 0) {
|
|
3086
|
+
endPdf(pdf);
|
|
3087
|
+
pdf = null;
|
|
3088
|
+
}
|
|
3089
|
+
} else if (tag === "a") {
|
|
3090
|
+
if (closing) pdf.inLink = false;
|
|
3091
|
+
else if (!pdf.href && isFileLink(attr(attrs, "class"), attr(attrs, "href"))) {
|
|
3092
|
+
pdf.href = attr(attrs, "href");
|
|
3093
|
+
pdf.inLink = true;
|
|
3094
|
+
}
|
|
3095
|
+
} else if (tag === "img" && !closing) {
|
|
3096
|
+
const src = attr(attrs, "src");
|
|
3097
|
+
const w = size(attrs, "width");
|
|
3098
|
+
const h = size(attrs, "height");
|
|
3099
|
+
if (isSafeMediaUrl(src)) pdf.pages.push({ src, alt: attr(attrs, "alt") ?? "", ...w && h ? { width: w, height: h } : {} });
|
|
3100
|
+
}
|
|
3101
|
+
continue;
|
|
3102
|
+
}
|
|
3103
|
+
if (fileLink) {
|
|
3104
|
+
if (closing && tag === "a") {
|
|
3105
|
+
media({ kind: "file", href: fileLink.href, alt: fileLink.name.replace(/\s+/g, " ").trim() || "Open PDF" });
|
|
3106
|
+
fileLink = null;
|
|
3107
|
+
}
|
|
3108
|
+
continue;
|
|
3109
|
+
}
|
|
3110
|
+
if (!closing && tag === "div" && (attr(attrs, "class") ?? "").split(/\s+/).includes(PDF_BLOCK_CLASS)) {
|
|
3111
|
+
flush();
|
|
3112
|
+
pdf = { depth: 1, name: "", inLink: false, pages: [] };
|
|
3113
|
+
continue;
|
|
3114
|
+
}
|
|
3115
|
+
if (!closing && tag === "a" && isFileLink(attr(attrs, "class"), attr(attrs, "href"))) {
|
|
3116
|
+
flush();
|
|
3117
|
+
fileLink = { href: attr(attrs, "href"), name: "" };
|
|
3118
|
+
continue;
|
|
3119
|
+
}
|
|
3039
3120
|
if (closing) {
|
|
3040
3121
|
if (tag === "b" || tag === "strong") style.bold = Math.max(0, style.bold - 1);
|
|
3041
3122
|
else if (tag === "i" || tag === "em") style.italic = Math.max(0, style.italic - 1);
|
|
@@ -3104,11 +3185,13 @@ function parseHtml(html) {
|
|
|
3104
3185
|
}
|
|
3105
3186
|
}
|
|
3106
3187
|
}
|
|
3188
|
+
if (pdf) endPdf(pdf);
|
|
3189
|
+
if (fileLink) media({ kind: "file", href: fileLink.href, alt: fileLink.name.replace(/\s+/g, " ").trim() || "Open PDF" });
|
|
3107
3190
|
flush();
|
|
3108
3191
|
return blocks;
|
|
3109
3192
|
}
|
|
3110
3193
|
function htmlToText(html) {
|
|
3111
|
-
return parseHtml(html).map((b) => b.kind === "image" || b.kind === "video" ? b.alt ?? "" : (b.marker ? `${b.marker} ` : "") + b.runs.map((r) => r.text).join("")).filter(Boolean).join("\n");
|
|
3194
|
+
return parseHtml(html).map((b) => b.kind === "image" || b.kind === "video" || b.kind === "pdf" || b.kind === "file" ? b.alt ?? "" : (b.marker ? `${b.marker} ` : "") + b.runs.map((r) => r.text).join("")).filter(Boolean).join("\n");
|
|
3112
3195
|
}
|
|
3113
3196
|
|
|
3114
3197
|
// src/ui/RichText.tsx
|
|
@@ -3144,6 +3227,48 @@ function BodyVideo({ block, palette: p, onLink }) {
|
|
|
3144
3227
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: { color: p.primary, fontFamily: p.fontFamily, fontWeight: "600" }, children: block.alt })
|
|
3145
3228
|
] });
|
|
3146
3229
|
}
|
|
3230
|
+
var PAGE_RATIO = 1 / 1.414;
|
|
3231
|
+
var pageRatio = (p) => p.width && p.height ? p.width / p.height : PAGE_RATIO;
|
|
3232
|
+
function PdfBadge() {
|
|
3233
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: styles2.badge, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: styles2.badgeText, children: "PDF" }) });
|
|
3234
|
+
}
|
|
3235
|
+
function BodyFile({ block, palette: p, onLink }) {
|
|
3236
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.Pressable, { accessibilityRole: "link", accessibilityLabel: `${block.alt}, PDF`, onPress: () => onLink(block.href), style: ({ pressed }) => [styles2.video, { borderColor: p.border, backgroundColor: p.surface, opacity: pressed ? 0.7 : 1 }], children: [
|
|
3237
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PdfBadge, {}),
|
|
3238
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { numberOfLines: 2, ellipsizeMode: "middle", style: [styles2.flex, { color: p.text, fontFamily: p.fontFamily, fontWeight: "600" }], children: block.alt })
|
|
3239
|
+
] });
|
|
3240
|
+
}
|
|
3241
|
+
function BodyPdf({ block, palette: p, onLink }) {
|
|
3242
|
+
const pages = block.pages ?? [];
|
|
3243
|
+
const [width, setWidth] = (0, import_react.useState)(0);
|
|
3244
|
+
const [index, setIndex] = (0, import_react.useState)(0);
|
|
3245
|
+
const [reading, setReading] = (0, import_react.useState)(false);
|
|
3246
|
+
const height = width ? Math.max(...pages.map((pg) => width / pageRatio(pg))) : 0;
|
|
3247
|
+
const onScroll = (e) => width && setIndex(Math.round(e.nativeEvent.contentOffset.x / width));
|
|
3248
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.View, { style: [styles2.pdf, { borderColor: p.border, backgroundColor: p.surface }], children: [
|
|
3249
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.Pressable, { accessibilityRole: "button", accessibilityLabel: `Read ${block.alt} full screen`, onPress: () => setReading(true), style: ({ pressed }) => [styles2.pdfHeader, { opacity: pressed ? 0.7 : 1 }], children: [
|
|
3250
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PdfBadge, {}),
|
|
3251
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { numberOfLines: 1, ellipsizeMode: "middle", style: [styles2.flex, { color: p.text, fontFamily: p.fontFamily, fontWeight: "600" }], children: block.alt }),
|
|
3252
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: { color: p.muted, fontSize: 16 }, children: "\u2922" })
|
|
3253
|
+
] }),
|
|
3254
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.View, { style: styles2.pdfPages, onLayout: (e) => setWidth(e.nativeEvent.layout.width), children: [
|
|
3255
|
+
width > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.ScrollView, { horizontal: true, pagingEnabled: true, showsHorizontalScrollIndicator: false, onScroll, scrollEventThrottle: 32, accessibilityLabel: `${block.alt}, page ${index + 1} of ${pages.length}`, children: pages.map((pg, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Pressable, { onPress: () => setReading(true), accessibilityRole: "imagebutton", accessibilityLabel: pg.alt || `Page ${i + 1}`, accessibilityHint: "Opens the document full screen", style: { width, height, alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Image, { source: { uri: pg.src }, resizeMode: "contain", style: [styles2.page, { width: Math.min(width, height * pageRatio(pg)), aspectRatio: pageRatio(pg) }] }) }, i)) }),
|
|
3256
|
+
pages.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { pointerEvents: "none", style: styles2.count, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.Text, { style: styles2.countText, children: [
|
|
3257
|
+
index + 1,
|
|
3258
|
+
" / ",
|
|
3259
|
+
pages.length
|
|
3260
|
+
] }) })
|
|
3261
|
+
] }),
|
|
3262
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Modal, { visible: reading, animationType: "slide", presentationStyle: "fullScreen", onRequestClose: () => setReading(false), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.View, { style: styles2.reader, children: [
|
|
3263
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.View, { style: styles2.readerBar, children: [
|
|
3264
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { numberOfLines: 1, ellipsizeMode: "middle", style: [styles2.flex, styles2.readerTitle], accessibilityRole: "header", children: block.alt }),
|
|
3265
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Pressable, { accessibilityRole: "link", onPress: () => onLink(block.href), style: styles2.readerBtn, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: styles2.readerBtnText, children: "Open PDF \u2197" }) }),
|
|
3266
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Pressable, { accessibilityRole: "button", accessibilityLabel: "Close", onPress: () => setReading(false), style: styles2.readerBtn, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: styles2.readerBtnText, children: "Done" }) })
|
|
3267
|
+
] }),
|
|
3268
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.ScrollView, { contentContainerStyle: styles2.readerPages, children: pages.map((pg, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Image, { source: { uri: pg.src }, accessible: true, accessibilityLabel: pg.alt || `Page ${i + 1}`, resizeMode: "contain", style: [styles2.readerPage, { aspectRatio: pageRatio(pg) }] }, i)) })
|
|
3269
|
+
] }) })
|
|
3270
|
+
] });
|
|
3271
|
+
}
|
|
3147
3272
|
function RichText({ html, palette: p, onLink, size = 15 }) {
|
|
3148
3273
|
const blocks = (0, import_react.useMemo)(() => parseHtml(html), [html]);
|
|
3149
3274
|
if (!blocks.length) return null;
|
|
@@ -3151,6 +3276,8 @@ function RichText({ html, palette: p, onLink, size = 15 }) {
|
|
|
3151
3276
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: styles2.wrap, children: blocks.map((b, i) => {
|
|
3152
3277
|
if (b.kind === "image") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BodyImage, { block: b, palette: p }, i);
|
|
3153
3278
|
if (b.kind === "video") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BodyVideo, { block: b, palette: p, onLink }, i);
|
|
3279
|
+
if (b.kind === "pdf") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BodyPdf, { block: b, palette: p, onLink }, i);
|
|
3280
|
+
if (b.kind === "file") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BodyFile, { block: b, palette: p, onLink }, i);
|
|
3154
3281
|
const runs = b.runs.map((r, j) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: runStyle(r, p), onPress: r.href ? () => onLink(r.href) : void 0, accessibilityRole: r.href ? "link" : void 0, children: r.text }, j));
|
|
3155
3282
|
if (b.kind === "list-item") {
|
|
3156
3283
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.View, { style: [styles2.li, { paddingLeft: (b.level - 1) * 14 }], children: [
|
|
@@ -3172,7 +3299,22 @@ var styles2 = import_react_native2.StyleSheet.create({
|
|
|
3172
3299
|
flex: { flex: 1 },
|
|
3173
3300
|
image: { width: "100%", borderRadius: 6 },
|
|
3174
3301
|
video: { flexDirection: "row", alignItems: "center", gap: 8, paddingVertical: 12, paddingHorizontal: 14, borderWidth: 1, borderRadius: 8 },
|
|
3175
|
-
play: { fontSize: 14 }
|
|
3302
|
+
play: { fontSize: 14 },
|
|
3303
|
+
badge: { backgroundColor: "#e5484d", borderRadius: 4, paddingHorizontal: 5, paddingVertical: 3 },
|
|
3304
|
+
badgeText: { color: "#fff", fontSize: 9, fontWeight: "700", letterSpacing: 0.4 },
|
|
3305
|
+
pdf: { borderWidth: 1, borderRadius: 10, overflow: "hidden" },
|
|
3306
|
+
pdfHeader: { flexDirection: "row", alignItems: "center", gap: 8, minHeight: 44, paddingHorizontal: 12 },
|
|
3307
|
+
pdfPages: { marginHorizontal: 10, marginBottom: 10 },
|
|
3308
|
+
page: { backgroundColor: "#fff", borderRadius: 3 },
|
|
3309
|
+
count: { position: "absolute", right: 8, bottom: 8, backgroundColor: "rgba(17,17,17,0.72)", borderRadius: 999, paddingHorizontal: 8, paddingVertical: 2 },
|
|
3310
|
+
countText: { color: "#fff", fontSize: 11, fontWeight: "500", fontVariant: ["tabular-nums"] },
|
|
3311
|
+
reader: { flex: 1, backgroundColor: "#0b0b0d" },
|
|
3312
|
+
readerBar: { flexDirection: "row", alignItems: "center", gap: 8, paddingTop: import_react_native2.Platform.OS === "ios" ? 52 : 12, paddingBottom: 10, paddingHorizontal: 16 },
|
|
3313
|
+
readerTitle: { color: "#fff", fontSize: 16, fontWeight: "600" },
|
|
3314
|
+
readerBtn: { minHeight: 36, justifyContent: "center", paddingHorizontal: 12, borderRadius: 8, backgroundColor: "rgba(255,255,255,0.12)" },
|
|
3315
|
+
readerBtnText: { color: "#fff", fontWeight: "600" },
|
|
3316
|
+
readerPages: { gap: 12, paddingHorizontal: 12, paddingBottom: 32 },
|
|
3317
|
+
readerPage: { width: "100%", backgroundColor: "#fff", borderRadius: 2 }
|
|
3176
3318
|
});
|
|
3177
3319
|
|
|
3178
3320
|
// src/ui/Checklist.tsx
|