@nanogiants/react-native-render-html 1.0.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/dist/index.js ADDED
@@ -0,0 +1,1093 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ RenderHTML: () => RenderHTML
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+
27
+ // src/RenderHTML.tsx
28
+ var import_htmlparser2 = require("htmlparser2");
29
+ var import_react5 = require("react");
30
+ var import_react_native7 = require("react-native");
31
+
32
+ // src/context/HtmlProvider.tsx
33
+ var import_react = require("react");
34
+ var import_react_native = require("react-native");
35
+ var import_jsx_runtime = require("react/jsx-runtime");
36
+ var HtmlContext = (0, import_react.createContext)(null);
37
+ var HtmlProvider = (options) => {
38
+ const baseStyle = (0, import_react.useMemo)(() => {
39
+ return {
40
+ ...options.baseStyle
41
+ };
42
+ }, [options.baseStyle]);
43
+ const tagsStyles = (0, import_react.useMemo)(() => {
44
+ return {
45
+ // BLOCK RENDERER TAGS
46
+ thead: {
47
+ text: {
48
+ ...baseStyle,
49
+ ...options.tagStyles?.thead?.text
50
+ },
51
+ block: {
52
+ ...options.tagStyles?.thead?.block
53
+ }
54
+ },
55
+ tbody: {
56
+ text: {
57
+ ...baseStyle,
58
+ ...options.tagStyles?.tbody?.text
59
+ },
60
+ block: {
61
+ ...options.tagStyles?.tbody?.block
62
+ }
63
+ },
64
+ tfoot: {
65
+ text: {
66
+ ...baseStyle,
67
+ ...options.tagStyles?.tfoot?.text
68
+ },
69
+ block: {
70
+ ...options.tagStyles?.tfoot?.block
71
+ }
72
+ },
73
+ blockquote: {
74
+ text: {
75
+ ...baseStyle,
76
+ fontStyle: "italic",
77
+ ...options.tagStyles?.blockquote?.text
78
+ },
79
+ block: {
80
+ borderLeftWidth: 4,
81
+ borderLeftColor: "black",
82
+ marginLeft: 8,
83
+ paddingLeft: 12,
84
+ backgroundColor: "#cccccc",
85
+ ...options.tagStyles?.blockquote?.block
86
+ }
87
+ },
88
+ ul: {
89
+ text: {
90
+ ...baseStyle,
91
+ ...options.tagStyles?.ul?.text
92
+ },
93
+ block: {
94
+ paddingLeft: 12,
95
+ paddingVertical: 0,
96
+ gap: options.listGap ?? 0,
97
+ ...options.tagStyles?.ul?.block
98
+ }
99
+ },
100
+ ol: {
101
+ text: {
102
+ ...baseStyle,
103
+ ...options.tagStyles?.ol?.text
104
+ },
105
+ block: {
106
+ paddingLeft: 12,
107
+ paddingVertical: 0,
108
+ gap: options.listGap ?? 0,
109
+ ...options.tagStyles?.ol?.block
110
+ }
111
+ },
112
+ dl: {
113
+ text: {
114
+ ...baseStyle,
115
+ ...options.tagStyles?.dl?.text
116
+ },
117
+ block: {
118
+ ...options.tagStyles?.dl?.block
119
+ }
120
+ },
121
+ div: {
122
+ text: {
123
+ ...baseStyle,
124
+ ...options.tagStyles?.div?.text
125
+ },
126
+ block: {
127
+ ...options.tagStyles?.div?.block
128
+ }
129
+ },
130
+ main: {
131
+ text: {
132
+ ...baseStyle,
133
+ ...options.tagStyles?.main?.text
134
+ },
135
+ block: {
136
+ ...options.tagStyles?.main?.block
137
+ }
138
+ },
139
+ section: {
140
+ text: {
141
+ ...baseStyle,
142
+ ...options.tagStyles?.section?.text
143
+ },
144
+ block: {
145
+ marginVertical: 8,
146
+ ...options.tagStyles?.section?.block
147
+ }
148
+ },
149
+ article: {
150
+ text: {
151
+ ...baseStyle,
152
+ ...options.tagStyles?.article?.text
153
+ },
154
+ block: {
155
+ marginVertical: 8,
156
+ ...options.tagStyles?.article?.block
157
+ }
158
+ },
159
+ aside: {
160
+ text: {
161
+ ...baseStyle,
162
+ ...options.tagStyles?.aside?.text
163
+ },
164
+ block: {
165
+ ...options.tagStyles?.aside?.block
166
+ }
167
+ },
168
+ nav: {
169
+ text: {
170
+ ...baseStyle,
171
+ ...options.tagStyles?.nav?.text
172
+ },
173
+ block: {
174
+ ...options.tagStyles?.nav?.block
175
+ }
176
+ },
177
+ header: {
178
+ text: {
179
+ ...baseStyle,
180
+ ...options.tagStyles?.header?.text
181
+ },
182
+ block: {
183
+ marginBottom: 8,
184
+ ...options.tagStyles?.header?.block
185
+ }
186
+ },
187
+ footer: {
188
+ text: {
189
+ ...baseStyle,
190
+ ...options.tagStyles?.footer?.text
191
+ },
192
+ block: {
193
+ marginTop: 8,
194
+ ...options.tagStyles?.footer?.block
195
+ }
196
+ },
197
+ hr: {
198
+ text: {
199
+ ...options.tagStyles?.hr?.text
200
+ },
201
+ block: {
202
+ borderBottomWidth: 1,
203
+ borderBottomColor: "black",
204
+ marginVertical: 12,
205
+ ...options.tagStyles?.hr?.block
206
+ }
207
+ },
208
+ br: {
209
+ text: {
210
+ ...options.tagStyles?.br?.text
211
+ },
212
+ block: {
213
+ height: 16,
214
+ ...options.tagStyles?.br?.block
215
+ }
216
+ },
217
+ img: {
218
+ text: {
219
+ ...options.tagStyles?.img?.text
220
+ },
221
+ block: {
222
+ marginVertical: 8,
223
+ flex: 1,
224
+ width: void 0,
225
+ height: 100,
226
+ ...options.tagStyles?.img?.block
227
+ }
228
+ },
229
+ table: {
230
+ text: {
231
+ ...options.tagStyles?.table?.text
232
+ },
233
+ block: {
234
+ marginVertical: 8,
235
+ ...options.tagStyles?.table?.block
236
+ }
237
+ },
238
+ tr: {
239
+ text: {
240
+ ...baseStyle,
241
+ ...options.tagStyles?.tr?.text
242
+ },
243
+ block: {
244
+ ...options.tagStyles?.tr?.block
245
+ }
246
+ },
247
+ // TEXT RENDERER TAGS
248
+ h1: {
249
+ text: {
250
+ ...baseStyle,
251
+ fontSize: 32,
252
+ lineHeight: 38.4,
253
+ ...options.tagStyles?.h1?.text
254
+ },
255
+ block: {
256
+ marginTop: 12,
257
+ marginBottom: 8,
258
+ ...options.tagStyles?.h1?.block
259
+ }
260
+ },
261
+ h2: {
262
+ text: {
263
+ ...baseStyle,
264
+ fontSize: 24,
265
+ lineHeight: 28.8,
266
+ ...options.tagStyles?.h2?.text
267
+ },
268
+ block: {
269
+ marginTop: 10,
270
+ marginBottom: 6,
271
+ ...options.tagStyles?.h2?.block
272
+ }
273
+ },
274
+ h3: {
275
+ text: {
276
+ ...baseStyle,
277
+ fontSize: 18.72,
278
+ lineHeight: 22.46,
279
+ ...options.tagStyles?.h3?.text
280
+ },
281
+ block: {
282
+ marginTop: 8,
283
+ marginBottom: 6,
284
+ ...options.tagStyles?.h3?.block
285
+ }
286
+ },
287
+ h4: {
288
+ text: {
289
+ ...baseStyle,
290
+ fontSize: 16,
291
+ lineHeight: 19.2,
292
+ ...options.tagStyles?.h4?.text
293
+ },
294
+ block: {
295
+ marginTop: 8,
296
+ marginBottom: 4,
297
+ ...options.tagStyles?.h4?.block
298
+ }
299
+ },
300
+ h5: {
301
+ text: {
302
+ ...baseStyle,
303
+ fontSize: 13.28,
304
+ lineHeight: 15.94,
305
+ ...options.tagStyles?.h5?.text
306
+ },
307
+ block: {
308
+ marginTop: 6,
309
+ marginBottom: 4,
310
+ ...options.tagStyles?.h5?.block
311
+ }
312
+ },
313
+ h6: {
314
+ text: {
315
+ ...baseStyle,
316
+ fontSize: 10.72,
317
+ lineHeight: 12.86,
318
+ ...options.tagStyles?.h6?.text
319
+ },
320
+ block: {
321
+ marginTop: 6,
322
+ marginBottom: 4,
323
+ ...options.tagStyles?.h6?.block
324
+ }
325
+ },
326
+ p: {
327
+ text: {
328
+ ...baseStyle,
329
+ ...options.tagStyles?.p?.text
330
+ },
331
+ block: {
332
+ marginTop: 8,
333
+ marginBottom: 8,
334
+ ...options.tagStyles?.p?.block
335
+ }
336
+ },
337
+ a: {
338
+ text: {
339
+ ...baseStyle,
340
+ textDecorationLine: "underline",
341
+ ...options.tagStyles?.a?.text
342
+ }
343
+ },
344
+ li: {
345
+ text: {
346
+ ...baseStyle,
347
+ ...options.tagStyles?.li?.text
348
+ },
349
+ block: {
350
+ paddingLeft: 0,
351
+ ...options.tagStyles?.li?.block
352
+ }
353
+ },
354
+ pre: {
355
+ text: {
356
+ ...baseStyle,
357
+ fontFamily: "monospace",
358
+ backgroundColor: "#bbbbbb",
359
+ ...options.tagStyles?.pre?.text
360
+ }
361
+ },
362
+ code: {
363
+ text: {
364
+ ...baseStyle,
365
+ fontFamily: "monospace",
366
+ backgroundColor: "#bbbbbb",
367
+ ...options.tagStyles?.code?.text
368
+ }
369
+ },
370
+ // inline text styles
371
+ b: {
372
+ text: {
373
+ fontWeight: "bold",
374
+ ...options.tagStyles?.b?.text
375
+ }
376
+ },
377
+ strong: {
378
+ text: {
379
+ fontWeight: "bold",
380
+ ...options.tagStyles?.strong?.text
381
+ }
382
+ },
383
+ i: {
384
+ text: {
385
+ fontStyle: "italic",
386
+ ...options.tagStyles?.i?.text
387
+ }
388
+ },
389
+ em: {
390
+ text: {
391
+ fontStyle: "italic",
392
+ ...options.tagStyles?.em?.text
393
+ }
394
+ },
395
+ u: {
396
+ text: {
397
+ textDecorationLine: "underline",
398
+ ...options.tagStyles?.u?.text
399
+ }
400
+ },
401
+ mark: {
402
+ text: {
403
+ ...baseStyle,
404
+ backgroundColor: "#fff59d",
405
+ ...options.tagStyles?.mark?.text
406
+ }
407
+ },
408
+ small: {
409
+ text: {
410
+ ...baseStyle,
411
+ fontSize: Math.max(baseStyle.fontSize - 2, 12),
412
+ ...options.tagStyles?.small?.text
413
+ }
414
+ },
415
+ s: {
416
+ text: {
417
+ ...baseStyle,
418
+ textDecorationLine: "line-through",
419
+ ...options.tagStyles?.s?.text
420
+ }
421
+ },
422
+ del: {
423
+ text: {
424
+ ...baseStyle,
425
+ textDecorationLine: "line-through",
426
+ ...options.tagStyles?.del?.text
427
+ }
428
+ },
429
+ sup: {
430
+ text: {
431
+ ...baseStyle,
432
+ textAlignVertical: "top",
433
+ fontSize: Math.max(baseStyle.fontSize - 4, 10),
434
+ ...options.tagStyles?.sup?.text
435
+ }
436
+ },
437
+ sub: {
438
+ text: {
439
+ ...baseStyle,
440
+ textAlignVertical: "bottom",
441
+ fontSize: Math.max(baseStyle.fontSize - 4, 10),
442
+ ...options.tagStyles?.sub?.text
443
+ }
444
+ },
445
+ th: {
446
+ text: {
447
+ ...baseStyle,
448
+ fontWeight: "bold",
449
+ padding: 8,
450
+ borderWidth: 1,
451
+ borderColor: "black",
452
+ ...options.tagStyles?.th?.text
453
+ }
454
+ },
455
+ td: {
456
+ text: {
457
+ ...baseStyle,
458
+ padding: 8,
459
+ ...options.tagStyles?.td?.text
460
+ }
461
+ },
462
+ dt: {
463
+ text: {
464
+ ...baseStyle,
465
+ ...options.tagStyles?.dt?.text
466
+ }
467
+ },
468
+ dd: {
469
+ text: {
470
+ ...baseStyle,
471
+ marginLeft: 20,
472
+ ...options.tagStyles?.dd?.text
473
+ }
474
+ },
475
+ span: {
476
+ text: {
477
+ ...baseStyle,
478
+ ...options.tagStyles?.span?.text
479
+ }
480
+ }
481
+ };
482
+ }, [baseStyle, options.tagStyles, options.listGap]);
483
+ const getStyle = (0, import_react.useCallback)(
484
+ (node) => {
485
+ if (node.type === "tag") {
486
+ const classStyle = node.attribs.class ? options.classesStyles?.[node.attribs.class] || {} : {};
487
+ return {
488
+ text: {
489
+ ...tagsStyles[node.tagName].text,
490
+ ...classStyle.text
491
+ },
492
+ block: {
493
+ ...tagsStyles[node.tagName].block ?? {},
494
+ ...classStyle.block
495
+ }
496
+ };
497
+ }
498
+ return {
499
+ text: {},
500
+ block: {}
501
+ };
502
+ },
503
+ [tagsStyles, options.classesStyles]
504
+ );
505
+ const renderImage = (0, import_react.useMemo)(() => {
506
+ if (options.renderImage) {
507
+ return options.renderImage;
508
+ }
509
+ return (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Image, { ...props });
510
+ }, [options.renderImage]);
511
+ const renderText = (0, import_react.useMemo)(() => {
512
+ if (options.renderTextComponent) {
513
+ return options.renderTextComponent;
514
+ }
515
+ return (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Text, { ...props });
516
+ }, [options.renderTextComponent]);
517
+ const providerValue = (0, import_react.useMemo)(
518
+ () => ({
519
+ getStyle,
520
+ baseStyle,
521
+ tagsStyles,
522
+ overrideExternalLinkTintColor: options.overrideExternalLinkTintColor,
523
+ onLinkPress: options.onLinkPress,
524
+ markerColor: options.markerColor,
525
+ renderImage,
526
+ renderText
527
+ }),
528
+ [
529
+ getStyle,
530
+ baseStyle,
531
+ tagsStyles,
532
+ options.overrideExternalLinkTintColor,
533
+ options.onLinkPress,
534
+ options.markerColor,
535
+ renderImage,
536
+ renderText
537
+ ]
538
+ );
539
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HtmlContext.Provider, { value: providerValue, children: options.children });
540
+ };
541
+ var useHtmlContext = () => {
542
+ const context = (0, import_react.useContext)(HtmlContext);
543
+ if (!context) {
544
+ throw new Error("useHtml must be used within a HtmlProvider");
545
+ }
546
+ return context;
547
+ };
548
+
549
+ // src/HTMLValidator.ts
550
+ var cleanUlNodesUtil = (nodes) => {
551
+ return nodes.map((node) => {
552
+ if (node.type !== "tag") {
553
+ return node;
554
+ }
555
+ if (node.name === "ul" || node.name === "ol") {
556
+ if (!node.children) {
557
+ return node;
558
+ }
559
+ node.children = node.children.filter((child) => {
560
+ return child.type !== "text" || child.type === "text" && child.data.trim() !== "";
561
+ });
562
+ }
563
+ if (node.children) {
564
+ node.children = cleanUlNodesUtil(node.children);
565
+ return node;
566
+ }
567
+ return node;
568
+ });
569
+ };
570
+ var HTMLValidator = class {
571
+ constructor(nodes) {
572
+ this.nodes = nodes;
573
+ }
574
+ cleanup() {
575
+ this.nodes = cleanUlNodesUtil(this.nodes);
576
+ return this.nodes;
577
+ }
578
+ };
579
+
580
+ // src/renderers/_NodeRenderer.tsx
581
+ var import_react_native6 = require("react-native");
582
+
583
+ // src/context/AlignedWidthItem.tsx
584
+ var import_react_native2 = require("react-native");
585
+
586
+ // src/context/AlignedWidthProvider.tsx
587
+ var import_react2 = require("react");
588
+ var import_jsx_runtime2 = require("react/jsx-runtime");
589
+ var AlignedWidthContext = (0, import_react2.createContext)(void 0);
590
+ var AlignedWidthProvider = ({ children }) => {
591
+ const [colWidths, setColWidths] = (0, import_react2.useState)({});
592
+ const getLayoutHandlerForIndex = (colIdx) => {
593
+ return (event) => {
594
+ const { width } = event.nativeEvent.layout;
595
+ setColWidths((prev) => {
596
+ const previousWidth = prev[colIdx] || 0;
597
+ return {
598
+ ...prev,
599
+ [colIdx]: Math.max(previousWidth, width)
600
+ };
601
+ });
602
+ };
603
+ };
604
+ const getWidthStyle = (colIdx) => {
605
+ return {
606
+ minWidth: colWidths[colIdx] || void 0,
607
+ width: colWidths[colIdx] || void 0
608
+ };
609
+ };
610
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
611
+ AlignedWidthContext.Provider,
612
+ {
613
+ value: {
614
+ getLayoutHandlerForIndex,
615
+ getWidthStyle
616
+ },
617
+ children
618
+ }
619
+ );
620
+ };
621
+ var useAlignedWidth = () => {
622
+ const context = (0, import_react2.useContext)(AlignedWidthContext);
623
+ if (!context) {
624
+ throw new Error("useAlignedWidth must be used within a AlignedWidthProvider");
625
+ }
626
+ return context;
627
+ };
628
+
629
+ // src/context/AlignedWidthItem.tsx
630
+ var import_jsx_runtime3 = require("react/jsx-runtime");
631
+ var AlignedWidthItem = ({ children, index, style }) => {
632
+ const { getLayoutHandlerForIndex, getWidthStyle } = useAlignedWidth();
633
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native2.View, { style: [getWidthStyle(index), style], onLayout: getLayoutHandlerForIndex(index), children });
634
+ };
635
+
636
+ // src/types.ts
637
+ var rendererTypeMap = {
638
+ // Elements rendered with a View (block)
639
+ thead: "block",
640
+ tbody: "block",
641
+ tfoot: "block",
642
+ blockquote: "block",
643
+ ul: "block",
644
+ ol: "block",
645
+ dl: "block",
646
+ li: "block",
647
+ div: "block",
648
+ hr: "block",
649
+ br: "block",
650
+ pre: "block",
651
+ code: "block",
652
+ img: "block",
653
+ table: "block",
654
+ tr: "block",
655
+ dt: "block",
656
+ dd: "block",
657
+ p: "block",
658
+ h1: "block",
659
+ h2: "block",
660
+ h3: "block",
661
+ h4: "block",
662
+ h5: "block",
663
+ h6: "block",
664
+ main: "block",
665
+ section: "block",
666
+ article: "block",
667
+ aside: "block",
668
+ nav: "block",
669
+ header: "block",
670
+ footer: "block",
671
+ // All other elements are text
672
+ b: "text",
673
+ strong: "text",
674
+ i: "text",
675
+ em: "text",
676
+ u: "text",
677
+ mark: "text",
678
+ small: "text",
679
+ s: "text",
680
+ del: "text",
681
+ sup: "text",
682
+ sub: "text",
683
+ span: "text",
684
+ a: "text",
685
+ th: "text",
686
+ td: "text"
687
+ };
688
+
689
+ // src/utils.ts
690
+ var isTextRenderer = (node) => {
691
+ if (!node) {
692
+ return false;
693
+ }
694
+ if (node.type === "tag") {
695
+ return rendererTypeMap[node.tagName] === "text";
696
+ }
697
+ return node.type === "text";
698
+ };
699
+ var concatTextNodes = (children) => {
700
+ let result = "";
701
+ for (const child of children) {
702
+ if (child.type === "text") {
703
+ result += child.data;
704
+ }
705
+ if (child.type === "tag" && Array.isArray(child.children)) {
706
+ result += concatTextNodes(child.children);
707
+ }
708
+ }
709
+ return result;
710
+ };
711
+ var isList = (child) => {
712
+ return child.type === "tag" && (child.tagName === "ol" || child.tagName === "ul");
713
+ };
714
+ var isExternalURL = (url) => {
715
+ if (!url) {
716
+ return false;
717
+ }
718
+ return url.startsWith("https://") || url.startsWith("http://");
719
+ };
720
+
721
+ // src/renderers/_DefaultBlockRenderer.tsx
722
+ var import_react_native3 = require("react-native");
723
+ var import_jsx_runtime4 = require("react/jsx-runtime");
724
+ var import_react3 = require("react");
725
+ var DefaultBlockRenderer = ({
726
+ node,
727
+ viewProps = {},
728
+ textProps = {}
729
+ }) => {
730
+ const { getStyle } = useHtmlContext();
731
+ const { style: viewStyle, ...restViewProps } = viewProps;
732
+ const { style: textStyle, ...restTextProps } = textProps;
733
+ const groupedChildren = groupByInlineBlock(node.children);
734
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native3.View, { ...restViewProps, style: [getStyle(node).block, viewStyle], children: groupedChildren.map((childrenGroup, index) => {
735
+ if (childrenGroup.type === "text") {
736
+ return /* @__PURE__ */ (0, import_react3.createElement)(
737
+ import_react_native3.Text,
738
+ {
739
+ ...restTextProps,
740
+ key: `${node.type}-${index}`,
741
+ style: [getStyle(node).text, textStyle]
742
+ },
743
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NodesRenderer, { nodes: childrenGroup.nodes })
744
+ );
745
+ }
746
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NodesRenderer, { nodes: childrenGroup.nodes }, `${node.type}-${index}`);
747
+ }) });
748
+ };
749
+ function groupByInlineBlock(arr) {
750
+ const result = [];
751
+ let currentGroup = [];
752
+ for (const item of arr) {
753
+ const isTextNode = item.type === "text";
754
+ const isTextTag = item.type === "tag" && rendererTypeMap[item.name] === "text";
755
+ if (isTextNode || isTextTag) {
756
+ currentGroup.push(item);
757
+ } else {
758
+ if (currentGroup.length) {
759
+ result.push({
760
+ type: "text",
761
+ nodes: currentGroup
762
+ });
763
+ currentGroup = [];
764
+ }
765
+ result.push({
766
+ type: "block",
767
+ nodes: [item]
768
+ });
769
+ }
770
+ }
771
+ if (currentGroup.length) {
772
+ result.push({
773
+ type: "text",
774
+ nodes: currentGroup
775
+ });
776
+ }
777
+ return result;
778
+ }
779
+
780
+ // src/renderers/_DefaultTextRenderer.tsx
781
+ var import_jsx_runtime5 = require("react/jsx-runtime");
782
+ var DefaultTextRenderer = ({ node, textProps = {} }) => {
783
+ const { style, ...restProps } = textProps;
784
+ const { getStyle, renderText } = useHtmlContext();
785
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children: renderText({
786
+ ...restProps,
787
+ style: [getStyle(node).text, style],
788
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(NodesRenderer, { nodes: node.children })
789
+ }) });
790
+ };
791
+
792
+ // src/assets.ts
793
+ var EXTERNAL_LINK_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAAAXNSR0IB2cksfwAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+kJCwwjMljq2h8AAAD4SURBVEjH7dY9SgNBGMbxn7vpIngXwc5SbG39KjxCLDyCnY0nUFGIH0Uu4CU8gXZ2iYU2IsRmiiCz+u4sBpQ8sLwMDPPf53mWYVnoP2sH44bn8evmXgfQM+5n1jW20lz6LXc9DDHFByYRR2foBw4/xkM64xLbuMYy1iNvN8H7N/mPMcg4Gab1KOeoCTQK7KuTkyluZ9LJgqrCTmqcYx932E3dtNJPjnJxwWqamzjoCqpxlYlrEIw7BGqChHqtWnRygb3STqKgkwS5KS0+egWdpnlUAmkDesJhlzuqMifNDdQU3Vr6hKPql4BesIKNFqBXvC3+Bf62PgFLzkKE8ZczlwAAAABJRU5ErkJggg==";
794
+ var UL_MARKER_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAwCAYAAAAsJjtLAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAACKADAAQAAAABAAAAMAAAAAAE1YgVAAAAZklEQVQ4EWNgGAWjITC4QoDxiYRE/H9GxgkM//8LIDuNkYHhAZDfAFJw/z8DgwKyJJzNyPiBCackSBXQVCa4ahwMaigAOgSH6QwgnzD9//+/EOolVHVAjf8YGBpRBUd5oyEw8CEAAGO5FkZ9+flOAAAAAElFTkSuQmCC";
795
+
796
+ // src/renderers/ATagRenderer.tsx
797
+ var import_jsx_runtime6 = require("react/jsx-runtime");
798
+ var ATagRenderer = ({ node }) => {
799
+ const { overrideExternalLinkTintColor, onLinkPress, getStyle, renderImage, renderText } = useHtmlContext();
800
+ const text = concatTextNodes(node.children);
801
+ if (!text) {
802
+ return null;
803
+ }
804
+ const style = getStyle(node);
805
+ const fontSize = style.text?.fontSize ?? 18;
806
+ const isExternal = node.attribs.href ? isExternalURL(node.attribs.href) : false;
807
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: renderText({
808
+ accessible: true,
809
+ onPress: () => {
810
+ onLinkPress?.({
811
+ url: node.attribs.href,
812
+ title: text
813
+ });
814
+ },
815
+ accessibilityRole: "link",
816
+ accessibilityHint: isExternal ? "External link" : void 0,
817
+ importantForAccessibility: "yes",
818
+ accessibilityElementsHidden: false,
819
+ style: style.text,
820
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
821
+ text,
822
+ isExternal ? renderImage({
823
+ source: { uri: EXTERNAL_LINK_URI },
824
+ style: {
825
+ tintColor: overrideExternalLinkTintColor ?? style.text.color ?? "black",
826
+ height: fontSize,
827
+ width: fontSize,
828
+ paddingTop: 5
829
+ }
830
+ }) : null
831
+ ] })
832
+ }) });
833
+ };
834
+
835
+ // src/renderers/ImgTagRenderer.tsx
836
+ var import_react4 = require("react");
837
+ var import_react_native4 = require("react-native");
838
+ var import_jsx_runtime7 = require("react/jsx-runtime");
839
+ var ImgTagRenderer = ({ node }) => {
840
+ const { getStyle, renderImage } = useHtmlContext();
841
+ const [size, setSize] = (0, import_react4.useState)(null);
842
+ const [containerWidth, setContainerWidth] = (0, import_react4.useState)(0);
843
+ const { src, alt } = node.attribs || {};
844
+ (0, import_react4.useEffect)(() => {
845
+ if (!src) {
846
+ return;
847
+ }
848
+ import_react_native4.Image.getSize(
849
+ src,
850
+ (width, height) => {
851
+ setSize({ w: width, h: height });
852
+ },
853
+ () => {
854
+ }
855
+ );
856
+ }, [src]);
857
+ if (!size) return null;
858
+ const { w, h } = size;
859
+ const finalWidth = Math.min(w, containerWidth);
860
+ const ratio = h / w;
861
+ const imageStyle = {
862
+ ...getStyle(node).block,
863
+ width: finalWidth,
864
+ height: finalWidth * ratio
865
+ };
866
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
867
+ import_react_native4.View,
868
+ {
869
+ onLayout: (e) => {
870
+ const width = e.nativeEvent.layout.width;
871
+ setContainerWidth(width);
872
+ },
873
+ style: { width: "100%" },
874
+ children: renderImage({
875
+ source: { uri: src },
876
+ style: imageStyle,
877
+ alt
878
+ })
879
+ }
880
+ );
881
+ };
882
+
883
+ // src/renderers/LiTagRenderer.tsx
884
+ var import_react_native5 = require("react-native");
885
+ var import_jsx_runtime8 = require("react/jsx-runtime");
886
+ var LiTagRenderer = ({ node }) => {
887
+ const { getStyle, markerColor, renderImage, renderText } = useHtmlContext();
888
+ const isParentOl = node.parent?.type === "tag" && node.parent?.tagName === "ol";
889
+ const parentLiTags = node.parent?.children || [];
890
+ const currentIndex = parentLiTags.indexOf(node) + 1;
891
+ const items = node.children;
892
+ const style = getStyle(node);
893
+ const { lineHeight = 20, fontSize = 16 } = style.text;
894
+ const markerHeight = 5;
895
+ const markerColorResult = markerColor ?? style.text.color ?? "pink";
896
+ const renderMarker = () => {
897
+ if (isParentOl) {
898
+ return renderText({ style: [style.text], children: `${currentIndex}.` });
899
+ } else {
900
+ return renderImage({
901
+ source: { uri: UL_MARKER_URI },
902
+ style: {
903
+ width: markerHeight,
904
+ height: lineHeight,
905
+ tintColor: markerColorResult
906
+ }
907
+ });
908
+ }
909
+ };
910
+ const nestedLists = items.filter((child) => isList(child));
911
+ const mainContent = items.filter((child) => !isList(child));
912
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native5.View, { children: [
913
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
914
+ import_react_native5.View,
915
+ {
916
+ style: {
917
+ flexDirection: "row"
918
+ },
919
+ children: [
920
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
921
+ import_react_native5.View,
922
+ {
923
+ style: {
924
+ marginRight: 8,
925
+ marginBottom: lineHeight - fontSize
926
+ },
927
+ children: renderMarker()
928
+ }
929
+ ),
930
+ renderText({
931
+ accessible: true,
932
+ accessibilityLabel: `List item ${currentIndex} of ${parentLiTags.length}: ${concatTextNodes(mainContent)}`,
933
+ style: [style.text, { flex: 1 }],
934
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(NodesRenderer, { nodes: mainContent })
935
+ })
936
+ ]
937
+ }
938
+ ),
939
+ nestedLists.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native5.View, { style: { width: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(NodesRenderer, { nodes: nestedLists }) })
940
+ ] });
941
+ };
942
+
943
+ // src/renderers/PTagRenderer.tsx
944
+ var import_jsx_runtime9 = require("react/jsx-runtime");
945
+ var PTagRenderer = ({ node }) => {
946
+ const { getStyle } = useHtmlContext();
947
+ const isFirstChild = !node.previousSibling;
948
+ const isLastChild = !node.nextSibling;
949
+ const style = getStyle(node);
950
+ const marginTop = isFirstChild ? 0 : style.block.marginTop;
951
+ const marginBottom = isLastChild ? 0 : style.block.marginBottom;
952
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
953
+ DefaultBlockRenderer,
954
+ {
955
+ node,
956
+ viewProps: {
957
+ style: {
958
+ marginTop,
959
+ marginBottom
960
+ }
961
+ }
962
+ }
963
+ );
964
+ };
965
+
966
+ // src/renderers/_NodeRenderer.tsx
967
+ var import_jsx_runtime10 = require("react/jsx-runtime");
968
+ var NodeRenderer = ({ node }) => {
969
+ const { getStyle } = useHtmlContext();
970
+ if (node.type === "tag") {
971
+ switch (node.tagName) {
972
+ case "thead":
973
+ case "tbody":
974
+ case "tfoot":
975
+ case "blockquote":
976
+ case "ul":
977
+ case "ol":
978
+ case "dl":
979
+ case "dt":
980
+ case "dd":
981
+ case "div":
982
+ case "main":
983
+ case "section":
984
+ case "article":
985
+ case "aside":
986
+ case "nav":
987
+ case "header":
988
+ case "footer":
989
+ case "tr":
990
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DefaultBlockRenderer, { node });
991
+ case "h1":
992
+ case "h2":
993
+ case "h3":
994
+ case "h4":
995
+ case "h5":
996
+ case "h6":
997
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
998
+ DefaultBlockRenderer,
999
+ {
1000
+ node,
1001
+ textProps: {
1002
+ accessible: true,
1003
+ accessibilityRole: "header"
1004
+ }
1005
+ }
1006
+ );
1007
+ case "p":
1008
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PTagRenderer, { node });
1009
+ case "li":
1010
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(LiTagRenderer, { node });
1011
+ case "hr":
1012
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native6.View, { style: [getStyle(node).block] });
1013
+ case "br":
1014
+ if (isTextRenderer(node.prev)) {
1015
+ return null;
1016
+ }
1017
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native6.View, { style: [getStyle(node).block] });
1018
+ case "table":
1019
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AlignedWidthProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DefaultBlockRenderer, { node }) });
1020
+ case "img":
1021
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ImgTagRenderer, { node });
1022
+ // text renderers
1023
+ case "b":
1024
+ case "strong":
1025
+ case "i":
1026
+ case "em":
1027
+ case "u":
1028
+ case "mark":
1029
+ case "small":
1030
+ case "s":
1031
+ case "del":
1032
+ case "sup":
1033
+ case "sub":
1034
+ case "span":
1035
+ case "pre":
1036
+ case "code":
1037
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DefaultTextRenderer, { node });
1038
+ case "a":
1039
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ATagRenderer, { node });
1040
+ case "th":
1041
+ case "td": {
1042
+ const currentIndex = node.parent?.children.indexOf(node) || 0;
1043
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(AlignedWidthItem, { index: currentIndex, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DefaultTextRenderer, { node }) });
1044
+ }
1045
+ default:
1046
+ return null;
1047
+ }
1048
+ }
1049
+ if (node.type === "text") {
1050
+ const text = node.data.replace(/\s+/g, " ").replace(/ /g, " ");
1051
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native6.Text, { children: text });
1052
+ }
1053
+ return null;
1054
+ };
1055
+
1056
+ // src/renderers/_NodesRenderer.tsx
1057
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1058
+ var NodesRenderer = ({ nodes }) => {
1059
+ return nodes.map((node, index) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NodeRenderer, { node }, `${node.type}-${index}`));
1060
+ };
1061
+
1062
+ // src/RenderHTML.tsx
1063
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1064
+ var RenderHTML = (props) => {
1065
+ const nodes = (0, import_react5.useMemo)(() => {
1066
+ if (!props.html) {
1067
+ return [];
1068
+ }
1069
+ const cleaned = props.html.replace(/\n/g, "");
1070
+ const n = (0, import_htmlparser2.parseDocument)(cleaned);
1071
+ return new HTMLValidator(n.children).cleanup();
1072
+ }, [props.html]);
1073
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native7.View, { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1074
+ HtmlProvider,
1075
+ {
1076
+ tagStyles: props.tagStyles,
1077
+ baseStyle: props.baseStyle,
1078
+ classesStyles: props.classesStyles,
1079
+ listGap: props.listGap,
1080
+ overrideExternalLinkTintColor: props.overrideExternalLinkTintColor,
1081
+ markerColor: props.markerColor,
1082
+ onLinkPress: props.onLinkPress,
1083
+ renderImage: props.renderImage,
1084
+ renderTextComponent: props.renderTextComponent,
1085
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(NodesRenderer, { nodes })
1086
+ }
1087
+ ) });
1088
+ };
1089
+ // Annotate the CommonJS export names for ESM import in node:
1090
+ 0 && (module.exports = {
1091
+ RenderHTML
1092
+ });
1093
+ //# sourceMappingURL=index.js.map