@miethe/ui 0.2.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +863 -9
  3. package/dist/components/content-viewer/ArticleViewer.d.ts +42 -0
  4. package/dist/components/content-viewer/ArticleViewer.d.ts.map +1 -0
  5. package/dist/components/content-viewer/ArticleViewer.js +321 -0
  6. package/dist/components/content-viewer/ArticleViewer.js.map +1 -0
  7. package/dist/components/content-viewer/FrontmatterHeader.d.ts +32 -0
  8. package/dist/components/content-viewer/FrontmatterHeader.d.ts.map +1 -0
  9. package/dist/components/content-viewer/FrontmatterHeader.js +95 -0
  10. package/dist/components/content-viewer/FrontmatterHeader.js.map +1 -0
  11. package/dist/components/content-viewer/callouts/Callout.d.ts +43 -0
  12. package/dist/components/content-viewer/callouts/Callout.d.ts.map +1 -0
  13. package/dist/components/content-viewer/callouts/Callout.js +86 -0
  14. package/dist/components/content-viewer/callouts/Callout.js.map +1 -0
  15. package/dist/components/content-viewer/callouts/index.d.ts +2 -0
  16. package/dist/components/content-viewer/callouts/index.d.ts.map +1 -0
  17. package/dist/components/content-viewer/callouts/index.js +2 -0
  18. package/dist/components/content-viewer/callouts/index.js.map +1 -0
  19. package/dist/components/content-viewer/index.d.ts +21 -0
  20. package/dist/components/content-viewer/index.d.ts.map +1 -0
  21. package/dist/components/content-viewer/index.js +29 -0
  22. package/dist/components/content-viewer/index.js.map +1 -0
  23. package/dist/components/content-viewer/plugins/index.d.ts +5 -0
  24. package/dist/components/content-viewer/plugins/index.d.ts.map +1 -0
  25. package/dist/components/content-viewer/plugins/index.js +5 -0
  26. package/dist/components/content-viewer/plugins/index.js.map +1 -0
  27. package/dist/components/content-viewer/plugins/lowlightLoader.d.ts +63 -0
  28. package/dist/components/content-viewer/plugins/lowlightLoader.d.ts.map +1 -0
  29. package/dist/components/content-viewer/plugins/lowlightLoader.js +120 -0
  30. package/dist/components/content-viewer/plugins/lowlightLoader.js.map +1 -0
  31. package/dist/components/content-viewer/plugins/rehypeCodeHighlight.d.ts +44 -0
  32. package/dist/components/content-viewer/plugins/rehypeCodeHighlight.d.ts.map +1 -0
  33. package/dist/components/content-viewer/plugins/rehypeCodeHighlight.js +122 -0
  34. package/dist/components/content-viewer/plugins/rehypeCodeHighlight.js.map +1 -0
  35. package/dist/components/content-viewer/plugins/rehypeExternalLinks.d.ts +59 -0
  36. package/dist/components/content-viewer/plugins/rehypeExternalLinks.d.ts.map +1 -0
  37. package/dist/components/content-viewer/plugins/rehypeExternalLinks.js +79 -0
  38. package/dist/components/content-viewer/plugins/rehypeExternalLinks.js.map +1 -0
  39. package/dist/components/content-viewer/plugins/rehypeHeadingIds.d.ts +37 -0
  40. package/dist/components/content-viewer/plugins/rehypeHeadingIds.d.ts.map +1 -0
  41. package/dist/components/content-viewer/plugins/rehypeHeadingIds.js +82 -0
  42. package/dist/components/content-viewer/plugins/rehypeHeadingIds.js.map +1 -0
  43. package/dist/components/content-viewer/plugins/remarkCallouts.d.ts +39 -0
  44. package/dist/components/content-viewer/plugins/remarkCallouts.d.ts.map +1 -0
  45. package/dist/components/content-viewer/plugins/remarkCallouts.js +77 -0
  46. package/dist/components/content-viewer/plugins/remarkCallouts.js.map +1 -0
  47. package/dist/components/content-viewer/plugins/slugify.d.ts +24 -0
  48. package/dist/components/content-viewer/plugins/slugify.d.ts.map +1 -0
  49. package/dist/components/content-viewer/plugins/slugify.js +31 -0
  50. package/dist/components/content-viewer/plugins/slugify.js.map +1 -0
  51. package/dist/components/content-viewer/sanitize.d.ts +75 -0
  52. package/dist/components/content-viewer/sanitize.d.ts.map +1 -0
  53. package/dist/components/content-viewer/sanitize.js +252 -0
  54. package/dist/components/content-viewer/sanitize.js.map +1 -0
  55. package/dist/components/content-viewer/types.d.ts +315 -0
  56. package/dist/components/content-viewer/types.d.ts.map +1 -0
  57. package/dist/components/content-viewer/types.js +8 -0
  58. package/dist/components/content-viewer/types.js.map +1 -0
  59. package/dist/components/content-viewer/variants.d.ts +71 -0
  60. package/dist/components/content-viewer/variants.d.ts.map +1 -0
  61. package/dist/components/content-viewer/variants.js +105 -0
  62. package/dist/components/content-viewer/variants.js.map +1 -0
  63. package/dist/content-viewer/ContentPane.d.ts +44 -1
  64. package/dist/content-viewer/ContentPane.d.ts.map +1 -1
  65. package/dist/content-viewer/ContentPane.js +139 -5
  66. package/dist/content-viewer/ContentPane.js.map +1 -1
  67. package/dist/content-viewer/FileTree.d.ts +23 -1
  68. package/dist/content-viewer/FileTree.d.ts.map +1 -1
  69. package/dist/content-viewer/FileTree.js +20 -5
  70. package/dist/content-viewer/FileTree.js.map +1 -1
  71. package/dist/content-viewer/index.d.ts +2 -0
  72. package/dist/content-viewer/index.d.ts.map +1 -1
  73. package/dist/content-viewer/index.js +2 -0
  74. package/dist/content-viewer/index.js.map +1 -1
  75. package/dist/diff/DiffViewer.js +3 -3
  76. package/dist/diff/DiffViewer.js.map +1 -1
  77. package/dist/discovery/discovery-card.d.ts +25 -0
  78. package/dist/discovery/discovery-card.d.ts.map +1 -0
  79. package/dist/discovery/discovery-card.js +265 -0
  80. package/dist/discovery/discovery-card.js.map +1 -0
  81. package/dist/discovery/index.d.ts +3 -0
  82. package/dist/discovery/index.d.ts.map +1 -0
  83. package/dist/discovery/index.js +3 -0
  84. package/dist/discovery/index.js.map +1 -0
  85. package/dist/display/ContextInfoCard.d.ts +61 -0
  86. package/dist/display/ContextInfoCard.d.ts.map +1 -0
  87. package/dist/display/ContextInfoCard.js +45 -0
  88. package/dist/display/ContextInfoCard.js.map +1 -0
  89. package/dist/display/index.d.ts +2 -0
  90. package/dist/display/index.d.ts.map +1 -1
  91. package/dist/display/index.js +1 -0
  92. package/dist/display/index.js.map +1 -1
  93. package/dist/editor/CodeEditor.d.ts +39 -0
  94. package/dist/editor/CodeEditor.d.ts.map +1 -0
  95. package/dist/editor/CodeEditor.js +114 -0
  96. package/dist/editor/CodeEditor.js.map +1 -0
  97. package/dist/editor/MarkdownEditor.d.ts +3 -2
  98. package/dist/editor/MarkdownEditor.d.ts.map +1 -1
  99. package/dist/editor/MarkdownEditor.js +32 -80
  100. package/dist/editor/MarkdownEditor.js.map +1 -1
  101. package/dist/editor/SplitPreview.d.ts +10 -1
  102. package/dist/editor/SplitPreview.d.ts.map +1 -1
  103. package/dist/editor/SplitPreview.js +4 -2
  104. package/dist/editor/SplitPreview.js.map +1 -1
  105. package/dist/editor/codeLanguages.d.ts +28 -0
  106. package/dist/editor/codeLanguages.d.ts.map +1 -0
  107. package/dist/editor/codeLanguages.js +54 -0
  108. package/dist/editor/codeLanguages.js.map +1 -0
  109. package/dist/editor/index.d.ts +2 -0
  110. package/dist/editor/index.d.ts.map +1 -1
  111. package/dist/editor/index.js +6 -0
  112. package/dist/editor/index.js.map +1 -1
  113. package/dist/editor/theme.d.ts +16 -0
  114. package/dist/editor/theme.d.ts.map +1 -0
  115. package/dist/editor/theme.js +82 -0
  116. package/dist/editor/theme.js.map +1 -0
  117. package/dist/filters/filter-bar.d.ts +14 -0
  118. package/dist/filters/filter-bar.d.ts.map +1 -0
  119. package/dist/filters/filter-bar.js +47 -0
  120. package/dist/filters/filter-bar.js.map +1 -0
  121. package/dist/filters/filter-slot-config.d.ts +239 -0
  122. package/dist/filters/filter-slot-config.d.ts.map +1 -0
  123. package/dist/filters/filter-slot-config.js +24 -0
  124. package/dist/filters/filter-slot-config.js.map +1 -0
  125. package/dist/filters/index.d.ts +2 -0
  126. package/dist/filters/index.d.ts.map +1 -1
  127. package/dist/filters/index.js +1 -0
  128. package/dist/filters/index.js.map +1 -1
  129. package/dist/primitives/BatchReadinessPill.d.ts +22 -0
  130. package/dist/primitives/BatchReadinessPill.d.ts.map +1 -0
  131. package/dist/primitives/BatchReadinessPill.js +20 -0
  132. package/dist/primitives/BatchReadinessPill.js.map +1 -0
  133. package/dist/primitives/Card.d.ts +28 -0
  134. package/dist/primitives/Card.d.ts.map +1 -0
  135. package/dist/primitives/Card.js +30 -0
  136. package/dist/primitives/Card.js.map +1 -0
  137. package/dist/primitives/CollectionPicker.d.ts +47 -0
  138. package/dist/primitives/CollectionPicker.d.ts.map +1 -0
  139. package/dist/primitives/CollectionPicker.js +105 -0
  140. package/dist/primitives/CollectionPicker.js.map +1 -0
  141. package/dist/primitives/CreateEntityDialog.d.ts +144 -0
  142. package/dist/primitives/CreateEntityDialog.d.ts.map +1 -0
  143. package/dist/primitives/CreateEntityDialog.js +379 -0
  144. package/dist/primitives/CreateEntityDialog.js.map +1 -0
  145. package/dist/primitives/EffectiveStatusChips.d.ts +43 -0
  146. package/dist/primitives/EffectiveStatusChips.d.ts.map +1 -0
  147. package/dist/primitives/EffectiveStatusChips.js +23 -0
  148. package/dist/primitives/EffectiveStatusChips.js.map +1 -0
  149. package/dist/primitives/FormField.d.ts +29 -0
  150. package/dist/primitives/FormField.d.ts.map +1 -0
  151. package/dist/primitives/FormField.js +27 -0
  152. package/dist/primitives/FormField.js.map +1 -0
  153. package/dist/primitives/Label.d.ts +20 -0
  154. package/dist/primitives/Label.d.ts.map +1 -0
  155. package/dist/primitives/Label.js +21 -0
  156. package/dist/primitives/Label.js.map +1 -0
  157. package/dist/primitives/MismatchBadge.d.ts +34 -0
  158. package/dist/primitives/MismatchBadge.d.ts.map +1 -0
  159. package/dist/primitives/MismatchBadge.js +28 -0
  160. package/dist/primitives/MismatchBadge.js.map +1 -0
  161. package/dist/primitives/PlanningNodeTypeIcon.d.ts +33 -0
  162. package/dist/primitives/PlanningNodeTypeIcon.d.ts.map +1 -0
  163. package/dist/primitives/PlanningNodeTypeIcon.js +35 -0
  164. package/dist/primitives/PlanningNodeTypeIcon.js.map +1 -0
  165. package/dist/primitives/SecretField.d.ts +28 -0
  166. package/dist/primitives/SecretField.d.ts.map +1 -0
  167. package/dist/primitives/SecretField.js +65 -0
  168. package/dist/primitives/SecretField.js.map +1 -0
  169. package/dist/primitives/Spinner.d.ts +16 -0
  170. package/dist/primitives/Spinner.d.ts.map +1 -0
  171. package/dist/primitives/Spinner.js +34 -0
  172. package/dist/primitives/Spinner.js.map +1 -0
  173. package/dist/primitives/StatusChip.d.ts +17 -0
  174. package/dist/primitives/StatusChip.d.ts.map +1 -0
  175. package/dist/primitives/StatusChip.js +22 -0
  176. package/dist/primitives/StatusChip.js.map +1 -0
  177. package/dist/primitives/Switch.d.ts +32 -0
  178. package/dist/primitives/Switch.d.ts.map +1 -0
  179. package/dist/primitives/Switch.js +43 -0
  180. package/dist/primitives/Switch.js.map +1 -0
  181. package/dist/primitives/index.d.ts +28 -0
  182. package/dist/primitives/index.d.ts.map +1 -1
  183. package/dist/primitives/index.js +16 -0
  184. package/dist/primitives/index.js.map +1 -1
  185. package/dist/primitives/variants.d.ts +18 -0
  186. package/dist/primitives/variants.d.ts.map +1 -0
  187. package/dist/primitives/variants.js +33 -0
  188. package/dist/primitives/variants.js.map +1 -0
  189. package/dist/utils/type-colors.d.ts.map +1 -1
  190. package/dist/utils/type-colors.js +4 -0
  191. package/dist/utils/type-colors.js.map +1 -1
  192. package/package.json +40 -6
@@ -0,0 +1,86 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { cn } from '../../../primitives/utils';
4
+ // ============================================================================
5
+ // Icon labels (text-based; icon library optional in P2)
6
+ // ============================================================================
7
+ const TYPE_CONFIG = {
8
+ note: {
9
+ label: 'Note',
10
+ borderClass: 'border-l-blue-400',
11
+ bgClass: 'bg-blue-50 dark:bg-blue-950/30',
12
+ labelClass: 'text-blue-700 dark:text-blue-300',
13
+ role: 'note',
14
+ },
15
+ reference: {
16
+ label: 'Reference',
17
+ borderClass: 'border-l-purple-400',
18
+ bgClass: 'bg-purple-50 dark:bg-purple-950/30',
19
+ labelClass: 'text-purple-700 dark:text-purple-300',
20
+ role: 'complementary',
21
+ },
22
+ warning: {
23
+ label: 'Warning',
24
+ borderClass: 'border-l-amber-400',
25
+ bgClass: 'bg-amber-50 dark:bg-amber-950/30',
26
+ labelClass: 'text-amber-700 dark:text-amber-300',
27
+ role: 'alert',
28
+ },
29
+ info: {
30
+ label: 'Info',
31
+ borderClass: 'border-l-teal-400',
32
+ bgClass: 'bg-teal-50 dark:bg-teal-950/30',
33
+ labelClass: 'text-teal-700 dark:text-teal-300',
34
+ role: 'note',
35
+ },
36
+ };
37
+ // ============================================================================
38
+ // Base Callout component
39
+ // ============================================================================
40
+ /**
41
+ * Base callout renderer used by all type-specific variants.
42
+ * Accepts an explicit `type` prop for cases where the component is used
43
+ * without a type-specific wrapper.
44
+ */
45
+ export function Callout({ type, children, className }) {
46
+ const config = TYPE_CONFIG[type] ?? TYPE_CONFIG.note;
47
+ return (_jsxs("aside", { role: config.role, "aria-label": `${config.label} callout`, "data-callout-type": type, className: cn(
48
+ // Base layout
49
+ 'my-4 rounded-r-md border-l-4 px-4 py-3',
50
+ // Type-specific accent
51
+ config.borderClass, config.bgClass,
52
+ // CSS variable hooks (override in consumer stylesheet)
53
+ '[border-left-color:var(--callout-border-color,inherit)]', '[background-color:var(--callout-bg-color,inherit)]', className), children: [_jsx("p", { className: cn('mb-1 text-xs font-semibold uppercase tracking-wider', config.labelClass, '[color:var(--callout-label-color,inherit)]'), "aria-hidden": "true", children: config.label }), _jsx("div", { className: "text-sm text-foreground [&>*:last-child]:mb-0 [&>p]:mb-2", children: children })] }));
54
+ }
55
+ // ============================================================================
56
+ // Type-specific convenience components
57
+ // ============================================================================
58
+ /**
59
+ * Note callout — informational content that supplements the main text.
60
+ * @example `::: note\n...\n:::`
61
+ */
62
+ export function NoteCallout({ children, className }) {
63
+ return (_jsx(Callout, { type: "note", className: className, children: children }));
64
+ }
65
+ /**
66
+ * Reference callout — citations, sources, or cross-references.
67
+ * @example `::: reference\n...\n:::`
68
+ */
69
+ export function ReferenceCallout({ children, className }) {
70
+ return (_jsx(Callout, { type: "reference", className: className, children: children }));
71
+ }
72
+ /**
73
+ * Warning callout — potentially destructive or dangerous information.
74
+ * @example `::: warning\n...\n:::`
75
+ */
76
+ export function WarningCallout({ children, className }) {
77
+ return (_jsx(Callout, { type: "warning", className: className, children: children }));
78
+ }
79
+ /**
80
+ * Info callout — supplementary information or tips.
81
+ * @example `::: info\n...\n:::`
82
+ */
83
+ export function InfoCallout({ children, className }) {
84
+ return (_jsx(Callout, { type: "info", className: className, children: children }));
85
+ }
86
+ //# sourceMappingURL=Callout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Callout.js","sourceRoot":"","sources":["../../../../src/components/content-viewer/callouts/Callout.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAmBb,OAAO,EAAE,EAAE,EAAE,MAAM,2BAA2B,CAAC;AAE/C,+EAA+E;AAC/E,wDAAwD;AACxD,+EAA+E;AAE/E,MAAM,WAAW,GAab;IACF,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM;QACb,WAAW,EAAE,mBAAmB;QAChC,OAAO,EAAE,gCAAgC;QACzC,UAAU,EAAE,kCAAkC;QAC9C,IAAI,EAAE,MAAM;KACb;IACD,SAAS,EAAE;QACT,KAAK,EAAE,WAAW;QAClB,WAAW,EAAE,qBAAqB;QAClC,OAAO,EAAE,oCAAoC;QAC7C,UAAU,EAAE,sCAAsC;QAClD,IAAI,EAAE,eAAe;KACtB;IACD,OAAO,EAAE;QACP,KAAK,EAAE,SAAS;QAChB,WAAW,EAAE,oBAAoB;QACjC,OAAO,EAAE,kCAAkC;QAC3C,UAAU,EAAE,oCAAoC;QAChD,IAAI,EAAE,OAAO;KACd;IACD,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM;QACb,WAAW,EAAE,mBAAmB;QAChC,OAAO,EAAE,gCAAgC;QACzC,UAAU,EAAE,kCAAkC;QAC9C,IAAI,EAAE,MAAM;KACb;CACF,CAAC;AAEF,+EAA+E;AAC/E,yBAAyB;AACzB,+EAA+E;AAE/E;;;;GAIG;AACH,MAAM,UAAU,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAgB;IACjE,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC;IAErD,OAAO,CACL,iBACE,IAAI,EAAE,MAAM,CAAC,IAAI,gBACL,GAAG,MAAM,CAAC,KAAK,UAAU,uBAClB,IAAI,EACvB,SAAS,EAAE,EAAE;QACX,cAAc;QACd,wCAAwC;QACxC,uBAAuB;QACvB,MAAM,CAAC,WAAW,EAClB,MAAM,CAAC,OAAO;QACd,uDAAuD;QACvD,yDAAyD,EACzD,oDAAoD,EACpD,SAAS,CACV,aAGD,YACE,SAAS,EAAE,EAAE,CACX,qDAAqD,EACrD,MAAM,CAAC,UAAU,EACjB,4CAA4C,CAC7C,iBACW,MAAM,YAEjB,MAAM,CAAC,KAAK,GACX,EAEJ,cAAK,SAAS,EAAC,0DAA0D,YACtE,QAAQ,GACL,IACA,CACT,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,uCAAuC;AACvC,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,EAAE,QAAQ,EAAE,SAAS,EAA8B;IAC7E,OAAO,CACL,KAAC,OAAO,IAAC,IAAI,EAAC,MAAM,EAAC,SAAS,EAAE,SAAS,YACtC,QAAQ,GACD,CACX,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAAE,QAAQ,EAAE,SAAS,EAA8B;IAClF,OAAO,CACL,KAAC,OAAO,IAAC,IAAI,EAAC,WAAW,EAAC,SAAS,EAAE,SAAS,YAC3C,QAAQ,GACD,CACX,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,EAAE,QAAQ,EAAE,SAAS,EAA8B;IAChF,OAAO,CACL,KAAC,OAAO,IAAC,IAAI,EAAC,SAAS,EAAC,SAAS,EAAE,SAAS,YACzC,QAAQ,GACD,CACX,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,EAAE,QAAQ,EAAE,SAAS,EAA8B;IAC7E,OAAO,CACL,KAAC,OAAO,IAAC,IAAI,EAAC,MAAM,EAAC,SAAS,EAAE,SAAS,YACtC,QAAQ,GACD,CACX,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { Callout, NoteCallout, ReferenceCallout, WarningCallout, InfoCallout, } from './Callout';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/content-viewer/callouts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,WAAW,GACZ,MAAM,WAAW,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { Callout, NoteCallout, ReferenceCallout, WarningCallout, InfoCallout, } from './Callout';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/content-viewer/callouts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,WAAW,GACZ,MAAM,WAAW,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @miethe/ui — content-viewer component submodule
3
+ *
4
+ * Exports ArticleViewer + default callout components + frontmatter utilities.
5
+ * Import via:
6
+ * import { ArticleViewer } from '@miethe/ui';
7
+ * import { ArticleViewer } from '@miethe/ui/content-viewer'; // submodule path
8
+ */
9
+ export { ArticleViewer } from './ArticleViewer';
10
+ export { default as ArticleViewerDefault } from './ArticleViewer';
11
+ export { Callout, NoteCallout, ReferenceCallout, WarningCallout, InfoCallout } from './callouts';
12
+ export { FrontmatterHeader } from './FrontmatterHeader';
13
+ export { remarkCallouts, CALLOUT_TYPES } from './plugins';
14
+ export { rehypeExternalLinks, isExternalHref } from './plugins/rehypeExternalLinks';
15
+ export { createHighlightPlugin, warmHighlightCache } from './plugins/rehypeCodeHighlight';
16
+ export { createHeadingIdsPlugin, slugify } from './plugins/rehypeHeadingIds';
17
+ export { sanitizeWithRehype, sanitizeWithDOMPurify, warmDOMPurifyCache, ARTICLE_VIEWER_SCHEMA } from './sanitize';
18
+ export { detectFormat } from './ArticleViewer';
19
+ export { VARIANT_CLASSES, getVariantTokenNames, variantClass } from './variants';
20
+ export type { ArticleViewerProps, ArticleViewerComponents, CalloutProps, CalloutType, CalloutComponents, ContentFormat, ArticleVariant, VariantTokenShape, FrontmatterDisplayMode, FrontmatterData, FrontmatterHeaderProps, } from './types';
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/content-viewer/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAGlE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGjG,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAEpF,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAE1F,OAAO,EAAE,sBAAsB,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAG7E,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAGlH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG/C,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAGjF,YAAY,EACV,kBAAkB,EAClB,uBAAuB,EACvB,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,sBAAsB,EACtB,eAAe,EACf,sBAAsB,GACvB,MAAM,SAAS,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @miethe/ui — content-viewer component submodule
3
+ *
4
+ * Exports ArticleViewer + default callout components + frontmatter utilities.
5
+ * Import via:
6
+ * import { ArticleViewer } from '@miethe/ui';
7
+ * import { ArticleViewer } from '@miethe/ui/content-viewer'; // submodule path
8
+ */
9
+ // Main component
10
+ export { ArticleViewer } from './ArticleViewer';
11
+ export { default as ArticleViewerDefault } from './ArticleViewer';
12
+ // Callout components
13
+ export { Callout, NoteCallout, ReferenceCallout, WarningCallout, InfoCallout } from './callouts';
14
+ // FrontmatterHeader (PU2-02)
15
+ export { FrontmatterHeader } from './FrontmatterHeader';
16
+ // Plugins (exported for testing and advanced composition)
17
+ export { remarkCallouts, CALLOUT_TYPES } from './plugins';
18
+ export { rehypeExternalLinks, isExternalHref } from './plugins/rehypeExternalLinks';
19
+ // Code highlighting helpers (PU4-01) — import these to warm the highlight cache at app startup
20
+ export { createHighlightPlugin, warmHighlightCache } from './plugins/rehypeCodeHighlight';
21
+ // Heading ID plugin (PU4-04 / A-UCV-08)
22
+ export { createHeadingIdsPlugin, slugify } from './plugins/rehypeHeadingIds';
23
+ // Sanitization utilities (PU3-02 / PU3-03)
24
+ export { sanitizeWithRehype, sanitizeWithDOMPurify, warmDOMPurifyCache, ARTICLE_VIEWER_SCHEMA } from './sanitize';
25
+ // Format detection utility (PU3-01) — also re-exported from ArticleViewer
26
+ export { detectFormat } from './ArticleViewer';
27
+ // Variant utilities (PU2-05)
28
+ export { VARIANT_CLASSES, getVariantTokenNames, variantClass } from './variants';
29
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/content-viewer/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,iBAAiB;AACjB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAElE,qBAAqB;AACrB,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEjG,6BAA6B;AAC7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,0DAA0D;AAC1D,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpF,+FAA+F;AAC/F,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAC1F,wCAAwC;AACxC,OAAO,EAAE,sBAAsB,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAE7E,2CAA2C;AAC3C,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAElH,0EAA0E;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,6BAA6B;AAC7B,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { default as remarkCallouts, CALLOUT_TYPES } from './remarkCallouts';
2
+ export { rehypeExternalLinks, isExternalHref } from './rehypeExternalLinks';
3
+ export { createHighlightPlugin, warmHighlightCache, _resetHighlightCache } from './rehypeCodeHighlight';
4
+ export { createHeadingIdsPlugin, slugify } from './rehypeHeadingIds';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/content-viewer/plugins/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5E,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AACxG,OAAO,EAAE,sBAAsB,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { default as remarkCallouts, CALLOUT_TYPES } from './remarkCallouts';
2
+ export { rehypeExternalLinks, isExternalHref } from './rehypeExternalLinks';
3
+ export { createHighlightPlugin, warmHighlightCache, _resetHighlightCache } from './rehypeCodeHighlight';
4
+ export { createHeadingIdsPlugin, slugify } from './rehypeHeadingIds';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/content-viewer/plugins/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5E,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AACxG,OAAO,EAAE,sBAAsB,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * lowlightLoader — shared, dependency-light lowlight loader for code highlighting.
3
+ *
4
+ * This module owns the single lowlight instance + load state used by BOTH:
5
+ * - `rehypeCodeHighlight.ts` (markdown fenced-code highlighting via a rehype plugin), and
6
+ * - `ContentPane`'s `HighlightedDisplay` (raw code-file highlighting, via `highlightCodeToHast`).
7
+ *
8
+ * It is intentionally free of `unist-util-visit` (and any other static ESM-only
9
+ * dependency) so that importing it from a Client Component (ContentPane) does NOT
10
+ * drag the rehype/unist graph into that module's bundle — or into Jest's module
11
+ * loader (which does not transform `unist-util-visit`'s ESM).
12
+ *
13
+ * `lowlight` itself remains an optional peer dep: it is loaded via dynamic
14
+ * `import()` and the loader degrades gracefully to plain text when it is absent.
15
+ * Consumers that want highlighting install lowlight separately (`npm install lowlight`).
16
+ *
17
+ * @module lowlightLoader
18
+ */
19
+ import type { Root } from 'hast';
20
+ /**
21
+ * Minimal lowlight API surface we rely on.
22
+ * Defined locally to avoid needing @types/lowlight installed.
23
+ */
24
+ export interface LowlightAPI {
25
+ highlight(language: string, code: string): {
26
+ children: unknown[];
27
+ };
28
+ highlightAuto(code: string): {
29
+ children: unknown[];
30
+ };
31
+ listLanguages(): string[];
32
+ }
33
+ /**
34
+ * Return the currently-cached lowlight instance synchronously (or null).
35
+ * Used by the rehype plugin's synchronous transformer, which reads from the
36
+ * already-populated cache. Call {@link warmHighlightCache} first to populate it.
37
+ */
38
+ export declare function getLowlightInstance(): LowlightAPI | null;
39
+ /** Exposed for testing — resets the module-level load state */
40
+ export declare function _resetHighlightCache(): void;
41
+ /**
42
+ * Warm the lowlight cache by loading it asynchronously.
43
+ * Call at app startup when `codeHighlight=true` to ensure the cache is populated
44
+ * before the first render cycle, preventing the cold-cache plain-text fallback.
45
+ *
46
+ * This is a no-op when lowlight is not installed.
47
+ */
48
+ export declare function warmHighlightCache(): Promise<void>;
49
+ /**
50
+ * Highlight raw code to a hast Root using lowlight, or null if unavailable/unknown lang.
51
+ *
52
+ * Used by ContentPane's HighlightedDisplay to perform on-demand highlighting
53
+ * for non-markdown code files (e.g. .ts, .py, .json).
54
+ *
55
+ * - Returns null when lowlight is not installed (graceful degrade to plain text).
56
+ * - Returns null when languageName is null or not registered in the lowlight instance.
57
+ * - Never throws.
58
+ *
59
+ * @param code - Raw source code string to highlight.
60
+ * @param languageName - highlight.js language identifier (e.g. "typescript"), or null.
61
+ */
62
+ export declare function highlightCodeToHast(code: string, languageName: string | null): Promise<Root | null>;
63
+ //# sourceMappingURL=lowlightLoader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lowlightLoader.d.ts","sourceRoot":"","sources":["../../../../src/components/content-viewer/plugins/lowlightLoader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAMjC;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG;QAAE,QAAQ,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC;IACnE,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,QAAQ,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC;IACrD,aAAa,IAAI,MAAM,EAAE,CAAC;CAC3B;AA0DD;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,WAAW,GAAG,IAAI,CAExD;AAED,+DAA+D;AAC/D,wBAAgB,oBAAoB,IAAI,IAAI,CAG3C;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAExD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,GAAG,IAAI,GAC1B,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAWtB"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * lowlightLoader — shared, dependency-light lowlight loader for code highlighting.
3
+ *
4
+ * This module owns the single lowlight instance + load state used by BOTH:
5
+ * - `rehypeCodeHighlight.ts` (markdown fenced-code highlighting via a rehype plugin), and
6
+ * - `ContentPane`'s `HighlightedDisplay` (raw code-file highlighting, via `highlightCodeToHast`).
7
+ *
8
+ * It is intentionally free of `unist-util-visit` (and any other static ESM-only
9
+ * dependency) so that importing it from a Client Component (ContentPane) does NOT
10
+ * drag the rehype/unist graph into that module's bundle — or into Jest's module
11
+ * loader (which does not transform `unist-util-visit`'s ESM).
12
+ *
13
+ * `lowlight` itself remains an optional peer dep: it is loaded via dynamic
14
+ * `import()` and the loader degrades gracefully to plain text when it is absent.
15
+ * Consumers that want highlighting install lowlight separately (`npm install lowlight`).
16
+ *
17
+ * @module lowlightLoader
18
+ */
19
+ // ---------------------------------------------------------------------------
20
+ // Lazy lowlight loader — one attempt per session
21
+ // ---------------------------------------------------------------------------
22
+ let lowlightInstance = null;
23
+ let lowlightLoadAttempted = false;
24
+ /**
25
+ * Attempt to load lowlight via dynamic import().
26
+ *
27
+ * lowlight is an optional peer dep — consumers must install it separately.
28
+ * Using dynamic import() keeps it out of the base chunk while remaining
29
+ * compatible with ESM environments (no require() needed).
30
+ *
31
+ * Supports both lowlight v2 (preconfigured `lowlight` instance) and lowlight v3
32
+ * (`createLowlight(common)` factory). Returns the instance or null if unavailable.
33
+ */
34
+ async function tryLoadLowlight() {
35
+ if (lowlightLoadAttempted)
36
+ return lowlightInstance;
37
+ lowlightLoadAttempted = true;
38
+ try {
39
+ // lowlight is an optional peer dep with no guaranteed types at build time.
40
+ // @ts-expect-error — optional package; consumers install it separately
41
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
42
+ const mod = await import(/* webpackIgnore: true */ 'lowlight');
43
+ // v2 shape: mod.lowlight or mod.default or mod (has .highlight function directly)
44
+ const ll = mod?.lowlight ?? mod?.default ?? mod;
45
+ if (ll !== null &&
46
+ typeof ll === 'object' &&
47
+ typeof ll['highlight'] === 'function') {
48
+ // lowlight v2 path — instance has highlight() directly
49
+ lowlightInstance = ll;
50
+ }
51
+ else if (typeof mod?.createLowlight === 'function' && mod?.common) {
52
+ // lowlight v3 path — factory style: createLowlight(common)
53
+ lowlightInstance = mod.createLowlight(mod.common);
54
+ }
55
+ else {
56
+ console.warn('[@miethe/ui] codeHighlight=true: lowlight loaded but has unexpected shape. ' +
57
+ 'Code blocks will render as plain text. Install lowlight: npm install lowlight');
58
+ }
59
+ }
60
+ catch {
61
+ // Not installed — expected for consumers that don't opt in
62
+ console.warn('[@miethe/ui] codeHighlight=true: lowlight is not installed. ' +
63
+ 'Code blocks will render as plain text. Install it: npm install lowlight');
64
+ lowlightInstance = null;
65
+ }
66
+ return lowlightInstance;
67
+ }
68
+ /**
69
+ * Return the currently-cached lowlight instance synchronously (or null).
70
+ * Used by the rehype plugin's synchronous transformer, which reads from the
71
+ * already-populated cache. Call {@link warmHighlightCache} first to populate it.
72
+ */
73
+ export function getLowlightInstance() {
74
+ return lowlightInstance;
75
+ }
76
+ /** Exposed for testing — resets the module-level load state */
77
+ export function _resetHighlightCache() {
78
+ lowlightInstance = null;
79
+ lowlightLoadAttempted = false;
80
+ }
81
+ /**
82
+ * Warm the lowlight cache by loading it asynchronously.
83
+ * Call at app startup when `codeHighlight=true` to ensure the cache is populated
84
+ * before the first render cycle, preventing the cold-cache plain-text fallback.
85
+ *
86
+ * This is a no-op when lowlight is not installed.
87
+ */
88
+ export async function warmHighlightCache() {
89
+ await tryLoadLowlight();
90
+ }
91
+ /**
92
+ * Highlight raw code to a hast Root using lowlight, or null if unavailable/unknown lang.
93
+ *
94
+ * Used by ContentPane's HighlightedDisplay to perform on-demand highlighting
95
+ * for non-markdown code files (e.g. .ts, .py, .json).
96
+ *
97
+ * - Returns null when lowlight is not installed (graceful degrade to plain text).
98
+ * - Returns null when languageName is null or not registered in the lowlight instance.
99
+ * - Never throws.
100
+ *
101
+ * @param code - Raw source code string to highlight.
102
+ * @param languageName - highlight.js language identifier (e.g. "typescript"), or null.
103
+ */
104
+ export async function highlightCodeToHast(code, languageName) {
105
+ try {
106
+ const ll = await tryLoadLowlight();
107
+ if (!ll)
108
+ return null;
109
+ if (!languageName)
110
+ return null;
111
+ const known = ll.listLanguages();
112
+ if (!known.includes(languageName))
113
+ return null;
114
+ return ll.highlight(languageName, code);
115
+ }
116
+ catch {
117
+ return null;
118
+ }
119
+ }
120
+ //# sourceMappingURL=lowlightLoader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lowlightLoader.js","sourceRoot":"","sources":["../../../../src/components/content-viewer/plugins/lowlightLoader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAkBH,8EAA8E;AAC9E,iDAAiD;AACjD,8EAA8E;AAE9E,IAAI,gBAAgB,GAAuB,IAAI,CAAC;AAChD,IAAI,qBAAqB,GAAG,KAAK,CAAC;AAElC;;;;;;;;;GASG;AACH,KAAK,UAAU,eAAe;IAC5B,IAAI,qBAAqB;QAAE,OAAO,gBAAgB,CAAC;IACnD,qBAAqB,GAAG,IAAI,CAAC;IAE7B,IAAI,CAAC;QACH,2EAA2E;QAC3E,uEAAuE;QACvE,8DAA8D;QAC9D,MAAM,GAAG,GAAQ,MAAM,MAAM,CAAC,yBAAyB,CAAC,UAAU,CAAC,CAAC;QACpE,kFAAkF;QAClF,MAAM,EAAE,GAAY,GAAG,EAAE,QAAQ,IAAI,GAAG,EAAE,OAAO,IAAI,GAAG,CAAC;QACzD,IACE,EAAE,KAAK,IAAI;YACX,OAAO,EAAE,KAAK,QAAQ;YACtB,OAAQ,EAA8B,CAAC,WAAW,CAAC,KAAK,UAAU,EAClE,CAAC;YACD,uDAAuD;YACvD,gBAAgB,GAAG,EAAiB,CAAC;QACvC,CAAC;aAAM,IAAI,OAAO,GAAG,EAAE,cAAc,KAAK,UAAU,IAAI,GAAG,EAAE,MAAM,EAAE,CAAC;YACpE,2DAA2D;YAC3D,gBAAgB,GAAG,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAgB,CAAC;QACnE,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CACV,6EAA6E;gBAC3E,+EAA+E,CAClF,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,2DAA2D;QAC3D,OAAO,CAAC,IAAI,CACV,8DAA8D;YAC5D,yEAAyE,CAC5E,CAAC;QACF,gBAAgB,GAAG,IAAI,CAAC;IAC1B,CAAC;IAED,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,oBAAoB;IAClC,gBAAgB,GAAG,IAAI,CAAC;IACxB,qBAAqB,GAAG,KAAK,CAAC;AAChC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,eAAe,EAAE,CAAC;AAC1B,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAAY,EACZ,YAA2B;IAE3B,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,MAAM,eAAe,EAAE,CAAC;QACnC,IAAI,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QACrB,IAAI,CAAC,YAAY;YAAE,OAAO,IAAI,CAAC;QAC/B,MAAM,KAAK,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC;QACjC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC;YAAE,OAAO,IAAI,CAAC;QAC/C,OAAO,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,CAAoB,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * rehypeCodeHighlight — opt-in code syntax highlighting via lowlight
3
+ *
4
+ * Design: zero-cost default path.
5
+ *
6
+ * When `codeHighlight=false` (default), this module is NOT imported by ArticleViewer.
7
+ * When `codeHighlight=true`, `createHighlightPlugin()` is called; it returns a
8
+ * rehype plugin that highlights `pre > code` blocks using lowlight.
9
+ *
10
+ * Bundle strategy:
11
+ * - `lowlight` is a small (~15KB gzip) WASM-free highlighter built on highlight.js.
12
+ * - It is NOT listed as a hard dep — it is an optional peer dep gated on codeHighlight.
13
+ * - We load it via dynamic `import()` in `tryLoadLowlight()`, so bundlers can split
14
+ * it into a lazy chunk and ESM environments have no `require()` issues.
15
+ * Consumers must install lowlight separately: npm install lowlight
16
+ * - The plugin gracefully degrades to plain-text when lowlight is not available.
17
+ *
18
+ * Supported class convention (react-markdown / remark default):
19
+ * ```js → <code class="language-js">
20
+ * ```typescript → <code class="language-typescript">
21
+ * ``` (no lang) → no class; rendered as plain text
22
+ *
23
+ * @module rehypeCodeHighlight
24
+ */
25
+ import type { Root } from 'hast';
26
+ export { _resetHighlightCache, warmHighlightCache, highlightCodeToHast, } from './lowlightLoader';
27
+ export type { LowlightAPI } from './lowlightLoader';
28
+ /**
29
+ * Create a rehype plugin that applies syntax highlighting to `pre > code` blocks.
30
+ *
31
+ * Returns a function compatible with ReactMarkdown's `rehypePlugins` array.
32
+ *
33
+ * The plugin loads lowlight on first call. If lowlight is not installed,
34
+ * code blocks degrade gracefully to unstyled monospace text.
35
+ *
36
+ * @example
37
+ * ```tsx
38
+ * import { createHighlightPlugin } from '@miethe/ui/content-viewer';
39
+ * // Then pass codeHighlight={true} to ArticleViewer — it handles this internally.
40
+ * <ArticleViewer content={markdown} codeHighlight />
41
+ * ```
42
+ */
43
+ export declare function createHighlightPlugin(): () => (tree: Root) => void;
44
+ //# sourceMappingURL=rehypeCodeHighlight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rehypeCodeHighlight.d.ts","sourceRoot":"","sources":["../../../../src/components/content-viewer/plugins/rehypeCodeHighlight.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAiB,MAAM,MAAM,CAAC;AAShD,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAgEpD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAuBlE"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * rehypeCodeHighlight — opt-in code syntax highlighting via lowlight
3
+ *
4
+ * Design: zero-cost default path.
5
+ *
6
+ * When `codeHighlight=false` (default), this module is NOT imported by ArticleViewer.
7
+ * When `codeHighlight=true`, `createHighlightPlugin()` is called; it returns a
8
+ * rehype plugin that highlights `pre > code` blocks using lowlight.
9
+ *
10
+ * Bundle strategy:
11
+ * - `lowlight` is a small (~15KB gzip) WASM-free highlighter built on highlight.js.
12
+ * - It is NOT listed as a hard dep — it is an optional peer dep gated on codeHighlight.
13
+ * - We load it via dynamic `import()` in `tryLoadLowlight()`, so bundlers can split
14
+ * it into a lazy chunk and ESM environments have no `require()` issues.
15
+ * Consumers must install lowlight separately: npm install lowlight
16
+ * - The plugin gracefully degrades to plain-text when lowlight is not available.
17
+ *
18
+ * Supported class convention (react-markdown / remark default):
19
+ * ```js → <code class="language-js">
20
+ * ```typescript → <code class="language-typescript">
21
+ * ``` (no lang) → no class; rendered as plain text
22
+ *
23
+ * @module rehypeCodeHighlight
24
+ */
25
+ import { visit } from 'unist-util-visit';
26
+ import { getLowlightInstance } from './lowlightLoader';
27
+ // The lowlight loader (instance cache, dynamic import, graceful degrade) lives in
28
+ // `./lowlightLoader` so it can be imported by Client Components (ContentPane) without
29
+ // pulling `unist-util-visit` into their module graph. Re-export the shared API here so
30
+ // existing import sites (plugins/index.ts, content-viewer/index.ts) keep working.
31
+ export { _resetHighlightCache, warmHighlightCache, highlightCodeToHast, } from './lowlightLoader';
32
+ // ---------------------------------------------------------------------------
33
+ // Language extraction
34
+ // ---------------------------------------------------------------------------
35
+ /**
36
+ * Extract the language identifier from a code element's className.
37
+ * react-markdown generates `language-{lang}` class names for fenced code blocks.
38
+ * Returns null when no language class is present.
39
+ */
40
+ function extractLanguage(node) {
41
+ const classNames = (node.properties?.className ?? []);
42
+ for (const cls of classNames) {
43
+ if (typeof cls === 'string' && cls.startsWith('language-')) {
44
+ return cls.slice('language-'.length);
45
+ }
46
+ }
47
+ return null;
48
+ }
49
+ // ---------------------------------------------------------------------------
50
+ // Synchronous highlight application
51
+ // ---------------------------------------------------------------------------
52
+ /**
53
+ * Apply lowlight highlighting to a `pre > code` element's text content.
54
+ * Mutates the code element's children in place.
55
+ * Returns false when lowlight is unavailable or the node has no text.
56
+ */
57
+ function applyHighlight(codeNode, language, ll) {
58
+ const textNode = codeNode.children.find((child) => child.type === 'text');
59
+ const code = textNode?.value ?? '';
60
+ if (!code)
61
+ return false;
62
+ try {
63
+ const knownLangs = ll.listLanguages();
64
+ const result = language && knownLangs.includes(language)
65
+ ? ll.highlight(language, code)
66
+ : ll.highlightAuto(code);
67
+ // Replace children with highlighted hast nodes
68
+ codeNode.children = result.children;
69
+ // Add hljs class for theme CSS compatibility
70
+ const existingClasses = (codeNode.properties?.className ?? []);
71
+ codeNode.properties = {
72
+ ...codeNode.properties,
73
+ className: [...existingClasses, 'hljs'],
74
+ };
75
+ return true;
76
+ }
77
+ catch (err) {
78
+ // Per-block failure is non-fatal — leave children as plain text
79
+ console.warn('[ArticleViewer] Code highlighting failed for block:', err);
80
+ return false;
81
+ }
82
+ }
83
+ // ---------------------------------------------------------------------------
84
+ // Plugin factory
85
+ // ---------------------------------------------------------------------------
86
+ /**
87
+ * Create a rehype plugin that applies syntax highlighting to `pre > code` blocks.
88
+ *
89
+ * Returns a function compatible with ReactMarkdown's `rehypePlugins` array.
90
+ *
91
+ * The plugin loads lowlight on first call. If lowlight is not installed,
92
+ * code blocks degrade gracefully to unstyled monospace text.
93
+ *
94
+ * @example
95
+ * ```tsx
96
+ * import { createHighlightPlugin } from '@miethe/ui/content-viewer';
97
+ * // Then pass codeHighlight={true} to ArticleViewer — it handles this internally.
98
+ * <ArticleViewer content={markdown} codeHighlight />
99
+ * ```
100
+ */
101
+ export function createHighlightPlugin() {
102
+ return function rehypeCodeHighlightPlugin() {
103
+ return function transformer(tree) {
104
+ // Read from the already-populated cache (synchronous).
105
+ // Call warmHighlightCache() at startup to pre-populate before first render.
106
+ const ll = getLowlightInstance();
107
+ // Lowlight unavailable — silently degrade to plain text
108
+ if (!ll)
109
+ return;
110
+ visit(tree, 'element', (node, _index, parent) => {
111
+ if (node.tagName !== 'code' ||
112
+ !parent ||
113
+ parent.tagName !== 'pre') {
114
+ return;
115
+ }
116
+ const lang = extractLanguage(node);
117
+ applyHighlight(node, lang, ll);
118
+ });
119
+ };
120
+ };
121
+ }
122
+ //# sourceMappingURL=rehypeCodeHighlight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rehypeCodeHighlight.js","sourceRoot":"","sources":["../../../../src/components/content-viewer/plugins/rehypeCodeHighlight.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAGvD,kFAAkF;AAClF,sFAAsF;AACtF,uFAAuF;AACvF,kFAAkF;AAClF,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAG1B,8EAA8E;AAC9E,sBAAsB;AACtB,8EAA8E;AAE9E;;;;GAIG;AACH,SAAS,eAAe,CAAC,IAAa;IACpC,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,IAAI,EAAE,CAAwB,CAAC;IAC7E,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC3D,OAAO,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8EAA8E;AAC9E,oCAAoC;AACpC,8EAA8E;AAE9E;;;;GAIG;AACH,SAAS,cAAc,CAAC,QAAiB,EAAE,QAAuB,EAAE,EAAe;IACjF,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,EAAiB,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;IACzF,MAAM,IAAI,GAAG,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC;IACnC,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IAExB,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC;QACtC,MAAM,MAAM,GACV,QAAQ,IAAI,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACvC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC;YAC9B,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAE7B,+CAA+C;QAC/C,QAAQ,CAAC,QAAQ,GAAG,MAAM,CAAC,QAA+B,CAAC;QAE3D,6CAA6C;QAC7C,MAAM,eAAe,GAAG,CAAC,QAAQ,CAAC,UAAU,EAAE,SAAS,IAAI,EAAE,CAAwB,CAAC;QACtF,QAAQ,CAAC,UAAU,GAAG;YACpB,GAAG,QAAQ,CAAC,UAAU;YACtB,SAAS,EAAE,CAAC,GAAG,eAAe,EAAE,MAAM,CAAC;SACxC,CAAC;QAEF,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,gEAAgE;QAChE,OAAO,CAAC,IAAI,CAAC,qDAAqD,EAAE,GAAG,CAAC,CAAC;QACzE,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,iBAAiB;AACjB,8EAA8E;AAE9E;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,SAAS,yBAAyB;QACvC,OAAO,SAAS,WAAW,CAAC,IAAU;YACpC,uDAAuD;YACvD,4EAA4E;YAC5E,MAAM,EAAE,GAAG,mBAAmB,EAAE,CAAC;YAEjC,wDAAwD;YACxD,IAAI,CAAC,EAAE;gBAAE,OAAO;YAEhB,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,IAAa,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;gBACvD,IACE,IAAI,CAAC,OAAO,KAAK,MAAM;oBACvB,CAAC,MAAM;oBACN,MAAkB,CAAC,OAAO,KAAK,KAAK,EACrC,CAAC;oBACD,OAAO;gBACT,CAAC;gBACD,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;gBACnC,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YACjC,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * rehypeExternalLinks — shared rehype plugin for external link hardening (PU3-04)
3
+ *
4
+ * Adds `target="_blank"` and `rel="noopener noreferrer"` to every `<a>` element
5
+ * whose `href` is an absolute URL with an http, https, or mailto scheme.
6
+ *
7
+ * This plugin is intentionally written as a pure unified/rehype tree visitor so
8
+ * it works on both the markdown pipeline (via ReactMarkdown's `rehypePlugins`)
9
+ * and the HTML pipeline (unified + rehypeParse + this plugin + rehype-sanitize
10
+ * + rehypeStringify). A single implementation avoids per-component duplication.
11
+ *
12
+ * Scheme detection uses a strict allowlist: `http:`, `https:`, `mailto:`.
13
+ * Protocol-relative URLs (`//example.com`) are also treated as external.
14
+ *
15
+ * Note: The markdown path also uses the `components.a` override in
16
+ * `buildComponentMap()` for link hardening because ReactMarkdown does not
17
+ * thread rehype node attributes through to rendered anchors. The `components.a`
18
+ * override is kept for the markdown path; this plugin is the canonical
19
+ * implementation used for the HTML path and can be tested in isolation.
20
+ */
21
+ import type { Plugin } from 'unified';
22
+ interface HastProperties {
23
+ [key: string]: unknown;
24
+ }
25
+ interface HastElement {
26
+ type: 'element';
27
+ tagName: string;
28
+ properties?: HastProperties;
29
+ children: HastNode[];
30
+ }
31
+ interface HastRoot {
32
+ type: 'root';
33
+ children: HastNode[];
34
+ }
35
+ type HastNode = HastElement | HastRoot | {
36
+ type: string;
37
+ };
38
+ /**
39
+ * Returns true if `href` should be treated as an external link.
40
+ * Protocol-relative URLs (starting with `//`) are also considered external.
41
+ */
42
+ export declare function isExternalHref(href: string): boolean;
43
+ /**
44
+ * Unified/rehype plugin that adds `target="_blank"` and
45
+ * `rel="noopener noreferrer"` to external `<a>` elements.
46
+ *
47
+ * Usage (HTML pipeline):
48
+ * ```ts
49
+ * unified()
50
+ * .use(rehypeParse, { fragment: true })
51
+ * .use(rehypeExternalLinks)
52
+ * .use(rehypeSanitize) // sanitize AFTER link attrs are set (allowlist includes rel/target)
53
+ * .use(rehypeStringify)
54
+ * .process(htmlString);
55
+ * ```
56
+ */
57
+ export declare const rehypeExternalLinks: Plugin<[], HastRoot>;
58
+ export default rehypeExternalLinks;
59
+ //# sourceMappingURL=rehypeExternalLinks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rehypeExternalLinks.d.ts","sourceRoot":"","sources":["../../../../src/components/content-viewer/plugins/rehypeExternalLinks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,SAAS,CAAC;AAOnD,UAAU,cAAc;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,UAAU,WAAW;IACnB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,QAAQ,EAAE,QAAQ,EAAE,CAAC;CACtB;AAED,UAAU,QAAQ;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,EAAE,CAAC;CACtB;AAED,KAAK,QAAQ,GAAG,WAAW,GAAG,QAAQ,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAU1D;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CASpD;AAMD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,CAgBpD,CAAC;AAEF,eAAe,mBAAmB,CAAC"}