@omnitron-dev/prism 0.3.0 → 0.3.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.
Files changed (214) hide show
  1. package/README.md +148 -0
  2. package/dist/blocks/index.js +3 -1
  3. package/dist/blocks/index.js.map +1 -1
  4. package/dist/{chunk-S6SEGBX6.js → chunk-472SOF76.js} +4 -4
  5. package/dist/{chunk-S6SEGBX6.js.map → chunk-472SOF76.js.map} +1 -1
  6. package/dist/{chunk-Z5OSPAOC.js → chunk-4Z5DE5GK.js} +78 -75
  7. package/dist/chunk-4Z5DE5GK.js.map +1 -0
  8. package/dist/chunk-52PQL67Q.js +559 -0
  9. package/dist/chunk-52PQL67Q.js.map +1 -0
  10. package/dist/chunk-75FQ5IW3.js +590 -0
  11. package/dist/chunk-75FQ5IW3.js.map +1 -0
  12. package/dist/{chunk-6AHI4GSV.js → chunk-7G5D5PTC.js} +4 -3
  13. package/dist/chunk-7G5D5PTC.js.map +1 -0
  14. package/dist/chunk-BJE2AKD4.js +105 -0
  15. package/dist/chunk-BJE2AKD4.js.map +1 -0
  16. package/dist/chunk-FF5RF32O.js +248 -0
  17. package/dist/chunk-FF5RF32O.js.map +1 -0
  18. package/dist/{chunk-OBJ244BO.js → chunk-GMIE6III.js} +9 -42
  19. package/dist/chunk-GMIE6III.js.map +1 -0
  20. package/dist/chunk-GUGTDURV.js +826 -0
  21. package/dist/chunk-GUGTDURV.js.map +1 -0
  22. package/dist/chunk-HOXFSQUV.js +573 -0
  23. package/dist/chunk-HOXFSQUV.js.map +1 -0
  24. package/dist/chunk-JSQTYDPG.js +3 -0
  25. package/dist/chunk-JSQTYDPG.js.map +1 -0
  26. package/dist/{chunk-ZTATTUH7.js → chunk-KQ67XB6T.js} +213 -651
  27. package/dist/chunk-KQ67XB6T.js.map +1 -0
  28. package/dist/{chunk-WFD54GQQ.js → chunk-LOY2NPCO.js} +14 -573
  29. package/dist/chunk-LOY2NPCO.js.map +1 -0
  30. package/dist/{chunk-YQW43BDH.js → chunk-LSPFFEJT.js} +240 -1824
  31. package/dist/chunk-LSPFFEJT.js.map +1 -0
  32. package/dist/{chunk-BZOL7GMU.js → chunk-OKTLA23Q.js} +4 -4
  33. package/dist/chunk-OKTLA23Q.js.map +1 -0
  34. package/dist/chunk-PFT2BNYO.js +191 -0
  35. package/dist/chunk-PFT2BNYO.js.map +1 -0
  36. package/dist/chunk-PGHEP4JD.js +106 -0
  37. package/dist/chunk-PGHEP4JD.js.map +1 -0
  38. package/dist/chunk-PXXPLHIY.js +74 -0
  39. package/dist/chunk-PXXPLHIY.js.map +1 -0
  40. package/dist/chunk-SU3LVQ7N.js +518 -0
  41. package/dist/chunk-SU3LVQ7N.js.map +1 -0
  42. package/dist/chunk-YHE7HXSG.js +206 -0
  43. package/dist/chunk-YHE7HXSG.js.map +1 -0
  44. package/dist/cli/index.js +7 -2
  45. package/dist/cli/index.js.map +1 -1
  46. package/dist/components/accordion/accordion.d.ts.map +1 -1
  47. package/dist/components/admin-filters/admin-data-table.d.ts.map +1 -1
  48. package/dist/components/admin-filters/filter-toolbar.d.ts.map +1 -1
  49. package/dist/components/date-input/date-input.d.ts +27 -0
  50. package/dist/components/date-input/date-input.d.ts.map +1 -0
  51. package/dist/components/date-input/index.d.ts +4 -0
  52. package/dist/components/date-input/index.d.ts.map +1 -0
  53. package/dist/components/date-input/value.d.ts +9 -0
  54. package/dist/components/date-input/value.d.ts.map +1 -0
  55. package/dist/components/doc-layout/doc-sidebar.d.ts +4 -1
  56. package/dist/components/doc-layout/doc-sidebar.d.ts.map +1 -1
  57. package/dist/components/doc-layout/index.js +6 -0
  58. package/dist/components/doc-layout/index.js.map +1 -0
  59. package/dist/components/editor/editor.d.ts.map +1 -1
  60. package/dist/components/editor/icons/index.d.ts +32 -40
  61. package/dist/components/editor/icons/index.d.ts.map +1 -1
  62. package/dist/components/editor/index.js +3 -1
  63. package/dist/components/error-boundary/error-boundary.d.ts.map +1 -1
  64. package/dist/components/index.css +4 -0
  65. package/dist/components/index.css.map +1 -1
  66. package/dist/components/index.d.ts +4 -4
  67. package/dist/components/index.d.ts.map +1 -1
  68. package/dist/components/index.js +18 -8
  69. package/dist/components/knowledge-graph/edge-labels.d.ts +14 -0
  70. package/dist/components/knowledge-graph/edge-labels.d.ts.map +1 -0
  71. package/dist/components/knowledge-graph/graph.d.ts +56 -0
  72. package/dist/components/knowledge-graph/graph.d.ts.map +1 -0
  73. package/dist/components/knowledge-graph/index.css +176 -0
  74. package/dist/components/knowledge-graph/index.css.map +1 -0
  75. package/dist/components/knowledge-graph/index.d.ts +3 -0
  76. package/dist/components/knowledge-graph/index.d.ts.map +1 -0
  77. package/dist/components/knowledge-graph/index.js +795 -0
  78. package/dist/components/knowledge-graph/index.js.map +1 -0
  79. package/dist/components/knowledge-graph/label-layout.d.ts +28 -0
  80. package/dist/components/knowledge-graph/label-layout.d.ts.map +1 -0
  81. package/dist/components/knowledge-graph/label-store.d.ts +15 -0
  82. package/dist/components/knowledge-graph/label-store.d.ts.map +1 -0
  83. package/dist/components/knowledge-graph/model.d.ts +92 -0
  84. package/dist/components/knowledge-graph/model.d.ts.map +1 -0
  85. package/dist/components/lightbox/lightbox.d.ts.map +1 -1
  86. package/dist/components/map/Map.d.ts +19 -43
  87. package/dist/components/map/Map.d.ts.map +1 -1
  88. package/dist/components/map/MapCoverageLayer.d.ts +1 -1
  89. package/dist/components/map/MapCoverageLayer.d.ts.map +1 -1
  90. package/dist/components/map/MapMarker.d.ts +1 -1
  91. package/dist/components/map/MapMarker.d.ts.map +1 -1
  92. package/dist/components/map/MapPlaceSearch.d.ts +33 -0
  93. package/dist/components/map/MapPlaceSearch.d.ts.map +1 -0
  94. package/dist/components/map/MapPointPicker.d.ts +21 -12
  95. package/dist/components/map/MapPointPicker.d.ts.map +1 -1
  96. package/dist/components/map/coordinates.d.ts +10 -0
  97. package/dist/components/map/coordinates.d.ts.map +1 -0
  98. package/dist/components/map/index.css +4 -0
  99. package/dist/components/map/index.css.map +1 -0
  100. package/dist/components/map/index.d.ts +7 -2
  101. package/dist/components/map/index.d.ts.map +1 -1
  102. package/dist/components/map/index.js +3 -0
  103. package/dist/components/map/index.js.map +1 -0
  104. package/dist/components/nav-card/nav-card.d.ts.map +1 -1
  105. package/dist/components/rail/rail.d.ts.map +1 -1
  106. package/dist/components/research/diagram-image.d.ts +11 -0
  107. package/dist/components/research/diagram-image.d.ts.map +1 -0
  108. package/dist/components/research/diagram.d.ts +8 -0
  109. package/dist/components/research/diagram.d.ts.map +1 -0
  110. package/dist/components/research/document.d.ts +33 -0
  111. package/dist/components/research/document.d.ts.map +1 -0
  112. package/dist/components/research/frontmatter.d.ts +15 -0
  113. package/dist/components/research/frontmatter.d.ts.map +1 -0
  114. package/dist/components/research/index.css +51 -0
  115. package/dist/components/research/index.css.map +1 -0
  116. package/dist/components/research/index.d.ts +3 -0
  117. package/dist/components/research/index.d.ts.map +1 -0
  118. package/dist/components/research/index.js +6 -0
  119. package/dist/components/research/index.js.map +1 -0
  120. package/dist/components/research/parse.d.ts +29 -0
  121. package/dist/components/research/parse.d.ts.map +1 -0
  122. package/dist/components/research-editor/block-commands.d.ts +20 -0
  123. package/dist/components/research-editor/block-commands.d.ts.map +1 -0
  124. package/dist/components/research-editor/block-controls.d.ts +13 -0
  125. package/dist/components/research-editor/block-controls.d.ts.map +1 -0
  126. package/dist/components/research-editor/editor.d.ts +75 -0
  127. package/dist/components/research-editor/editor.d.ts.map +1 -0
  128. package/dist/components/research-editor/extensions.d.ts +14 -0
  129. package/dist/components/research-editor/extensions.d.ts.map +1 -0
  130. package/dist/components/research-editor/index.css +332 -0
  131. package/dist/components/research-editor/index.css.map +1 -0
  132. package/dist/components/research-editor/index.d.ts +5 -0
  133. package/dist/components/research-editor/index.d.ts.map +1 -0
  134. package/dist/components/research-editor/index.js +1592 -0
  135. package/dist/components/research-editor/index.js.map +1 -0
  136. package/dist/components/research-editor/math-input.d.ts +32 -0
  137. package/dist/components/research-editor/math-input.d.ts.map +1 -0
  138. package/dist/components/research-editor/math-markup.d.ts +4 -0
  139. package/dist/components/research-editor/math-markup.d.ts.map +1 -0
  140. package/dist/components/research-editor/math-navigation.d.ts +6 -0
  141. package/dist/components/research-editor/math-navigation.d.ts.map +1 -0
  142. package/dist/components/research-editor/math-node.d.ts +11 -0
  143. package/dist/components/research-editor/math-node.d.ts.map +1 -0
  144. package/dist/components/research-editor/source.d.ts +19 -0
  145. package/dist/components/research-editor/source.d.ts.map +1 -0
  146. package/dist/components/scrollbar/scrollbar.d.ts +4 -2
  147. package/dist/components/scrollbar/scrollbar.d.ts.map +1 -1
  148. package/dist/components/search-input/search-input.d.ts +0 -10
  149. package/dist/components/search-input/search-input.d.ts.map +1 -1
  150. package/dist/components/tiptap-renderer/tiptap-renderer.d.ts +4 -3
  151. package/dist/components/tiptap-renderer/tiptap-renderer.d.ts.map +1 -1
  152. package/dist/core/index.d.ts +1 -1
  153. package/dist/core/index.d.ts.map +1 -1
  154. package/dist/core/index.js +8 -4
  155. package/dist/core/provider.d.ts +7 -2
  156. package/dist/core/provider.d.ts.map +1 -1
  157. package/dist/forms/schema-provider.d.ts +3 -3
  158. package/dist/forms/schema-utils.d.ts +3 -3
  159. package/dist/hooks/index.js +9 -5
  160. package/dist/icons/context.d.ts +17 -0
  161. package/dist/icons/context.d.ts.map +1 -0
  162. package/dist/icons/controls.d.ts +51 -0
  163. package/dist/icons/controls.d.ts.map +1 -0
  164. package/dist/icons/index.d.ts +3 -0
  165. package/dist/icons/index.d.ts.map +1 -0
  166. package/dist/icons/index.js +4 -0
  167. package/dist/icons/index.js.map +1 -0
  168. package/dist/icons/theme.d.ts +4 -0
  169. package/dist/icons/theme.d.ts.map +1 -0
  170. package/dist/index.css +4 -0
  171. package/dist/index.css.map +1 -1
  172. package/dist/index.js +24 -13
  173. package/dist/index.js.map +1 -1
  174. package/dist/layouts/core/header-section.d.ts.map +1 -1
  175. package/dist/layouts/dashboard/labels.d.ts +12 -0
  176. package/dist/layouts/dashboard/labels.d.ts.map +1 -0
  177. package/dist/layouts/dashboard/layout.d.ts +7 -1
  178. package/dist/layouts/dashboard/layout.d.ts.map +1 -1
  179. package/dist/layouts/dashboard/sidenav.d.ts +7 -3
  180. package/dist/layouts/dashboard/sidenav.d.ts.map +1 -1
  181. package/dist/layouts/index.d.ts +5 -0
  182. package/dist/layouts/index.d.ts.map +1 -1
  183. package/dist/layouts/index.js +6 -1
  184. package/dist/layouts/panel-layout.d.ts +35 -0
  185. package/dist/layouts/panel-layout.d.ts.map +1 -0
  186. package/dist/layouts/sidebar-toggle.d.ts +11 -0
  187. package/dist/layouts/sidebar-toggle.d.ts.map +1 -0
  188. package/dist/state/stores/auth.d.ts +4 -16
  189. package/dist/state/stores/auth.d.ts.map +1 -1
  190. package/dist/state/stores/ui.d.ts +7 -105
  191. package/dist/state/stores/ui.d.ts.map +1 -1
  192. package/dist/theme/components/Button.d.ts.map +1 -1
  193. package/dist/theme/components/FormControls.d.ts +3 -12
  194. package/dist/theme/components/FormControls.d.ts.map +1 -1
  195. package/dist/theme/components/index.d.ts.map +1 -1
  196. package/dist/theme/create-theme.d.ts +5 -17
  197. package/dist/theme/create-theme.d.ts.map +1 -1
  198. package/dist/theme/index.js +6 -2
  199. package/dist/theme/mixins.d.ts +3 -1
  200. package/dist/theme/mixins.d.ts.map +1 -1
  201. package/dist/theme/palette/overrides.d.ts +23 -0
  202. package/dist/theme/palette/overrides.d.ts.map +1 -0
  203. package/dist/ui/index.d.ts +18 -0
  204. package/dist/ui/index.d.ts.map +1 -0
  205. package/dist/ui/index.js +148 -0
  206. package/dist/ui/index.js.map +1 -0
  207. package/package.json +92 -45
  208. package/dist/chunk-6AHI4GSV.js.map +0 -1
  209. package/dist/chunk-BZOL7GMU.js.map +0 -1
  210. package/dist/chunk-OBJ244BO.js.map +0 -1
  211. package/dist/chunk-WFD54GQQ.js.map +0 -1
  212. package/dist/chunk-YQW43BDH.js.map +0 -1
  213. package/dist/chunk-Z5OSPAOC.js.map +0 -1
  214. package/dist/chunk-ZTATTUH7.js.map +0 -1
@@ -0,0 +1,826 @@
1
+ import { styled, alpha } from '@mui/material/styles';
2
+ import { createContext, useContext, Fragment, useState, useCallback } from 'react';
3
+ import { jsx, jsxs } from 'react/jsx-runtime';
4
+
5
+ // src/components/content-renderer/classes.ts
6
+ var PREFIX = "prism-content";
7
+ var contentClasses = {
8
+ root: `${PREFIX}__root`,
9
+ compact: `${PREFIX}__compact`,
10
+ tiptap: `${PREFIX}__tiptap`,
11
+ markdown: `${PREFIX}__markdown`,
12
+ image: `${PREFIX}__image`,
13
+ link: `${PREFIX}__link`,
14
+ checkbox: `${PREFIX}__checkbox`,
15
+ codeBlock: `${PREFIX}__code-block`,
16
+ codeBlockTitle: `${PREFIX}__code-block-title`,
17
+ codeBlockCopy: `${PREFIX}__code-block-copy`,
18
+ codeBlockHighlight: `${PREFIX}__code-block-highlight`,
19
+ codeInline: `${PREFIX}__code-inline`,
20
+ spoiler: `${PREFIX}__spoiler`,
21
+ admonition: `${PREFIX}__admonition`,
22
+ admonitionNote: `${PREFIX}__admonition-note`,
23
+ admonitionTip: `${PREFIX}__admonition-tip`,
24
+ admonitionWarning: `${PREFIX}__admonition-warning`,
25
+ admonitionDanger: `${PREFIX}__admonition-danger`,
26
+ admonitionInfo: `${PREFIX}__admonition-info`,
27
+ admonitionCaution: `${PREFIX}__admonition-caution`,
28
+ admonitionTitle: `${PREFIX}__admonition-title`,
29
+ admonitionContent: `${PREFIX}__admonition-content`,
30
+ tabs: `${PREFIX}__tabs`,
31
+ tabsHeader: `${PREFIX}__tabs-header`,
32
+ tabsTab: `${PREFIX}__tabs-tab`,
33
+ tabsTabActive: `${PREFIX}__tabs-tab-active`,
34
+ tabsPanel: `${PREFIX}__tabs-panel`,
35
+ figure: `${PREFIX}__figure`,
36
+ figcaption: `${PREFIX}__figcaption`,
37
+ kbd: `${PREFIX}__kbd`
38
+ };
39
+ var MARGIN = "0.75em";
40
+ var CODE_FONT = "'JetBrains Mono', 'Fira Code', 'Cascadia Code', Menlo, Monaco, 'Courier New', monospace";
41
+ var ContentRoot = styled("div")(({ theme }) => ({
42
+ // General spacing between adjacent elements
43
+ "> * + *": {
44
+ marginTop: 0,
45
+ marginBottom: MARGIN
46
+ },
47
+ // ─── Headings ───────────────────────────────────────────────
48
+ "& h1, & h2, & h3, & h4, & h5, & h6": {
49
+ scrollMarginTop: 100
50
+ // Account for sticky header on anchor jump
51
+ },
52
+ // Heading margins. Top margins are applied via the adjacent-sibling
53
+ // combinator (`* + hN`) rather than a `:first-child` reset: a heading
54
+ // takes its top margin ONLY when it follows another element, so a
55
+ // heading at the very top of its container carries none. This is
56
+ // SSR-safe (avoids Emotion's `:first-child` warning) and yields the
57
+ // same result the previous `& > :first-child:is(h1,h2,h3)` reset did.
58
+ h1: { ...theme.typography.h1, marginTop: 0, marginBottom: 12 },
59
+ h2: { ...theme.typography.h2, marginTop: 0, marginBottom: 12 },
60
+ h3: { ...theme.typography.h3, marginTop: 0, marginBottom: 8 },
61
+ h4: { ...theme.typography.h4, marginTop: 0, marginBottom: 8 },
62
+ h5: { ...theme.typography.h5, marginTop: 0, marginBottom: 8 },
63
+ h6: { ...theme.typography.h6, marginTop: 0, marginBottom: 8 },
64
+ "& * + h1, & * + h2": { marginTop: 40 },
65
+ "& * + h3": { marginTop: 32 },
66
+ "& * + h4, & * + h5, & * + h6": { marginTop: 24 },
67
+ // ─── Paragraph ──────────────────────────────────────────────
68
+ p: {
69
+ ...theme.typography.body1,
70
+ marginBottom: "1.25rem",
71
+ lineHeight: 1.8
72
+ },
73
+ // ─── Horizontal rule ───────────────────────────────────────
74
+ hr: {
75
+ flexShrink: 0,
76
+ borderWidth: 0,
77
+ margin: "2em 0",
78
+ borderStyle: "solid",
79
+ borderBottomWidth: "thin",
80
+ borderColor: theme.palette.divider
81
+ },
82
+ // ─── Images ─────────────────────────────────────────────────
83
+ [`& .${contentClasses.image}`]: {
84
+ width: "100%",
85
+ height: "auto",
86
+ maxWidth: "100%",
87
+ margin: "auto auto 1.25em",
88
+ borderRadius: Number(theme.shape.borderRadius) * 2
89
+ },
90
+ // Plain img fallback
91
+ "& img:not([class])": {
92
+ maxWidth: "100%",
93
+ height: "auto",
94
+ borderRadius: Number(theme.shape.borderRadius) * 2,
95
+ marginBottom: "1.25em"
96
+ },
97
+ // ─── Links ──────────────────────────────────────────────────
98
+ "& a": {
99
+ color: theme.palette.primary.main,
100
+ textDecoration: "none",
101
+ "&:hover": {
102
+ textDecoration: "underline"
103
+ }
104
+ },
105
+ // ─── Lists ──────────────────────────────────────────────────
106
+ "& ul": {
107
+ listStyleType: "disc"
108
+ },
109
+ "& ul, & ol": {
110
+ paddingLeft: 24,
111
+ marginBottom: "1.25rem",
112
+ "& > li": {
113
+ lineHeight: 2,
114
+ // Markdown wraps every list-item body in a `<p>`. With
115
+ // `display: inline-block` (the previous setting), Chromium
116
+ // refuses to render the `<li>`'s ::marker at all — the
117
+ // disc/decimal vanishes and the list looks like a series of
118
+ // bullet-less paragraphs. `display: inline` collapses the
119
+ // `<p>` into inline flow so the marker positions normally;
120
+ // `margin: 0` keeps the LI height tight against the marker
121
+ // baseline. Multi-paragraph list items (rare here, but
122
+ // possible) still render — subsequent `<p>` siblings get a
123
+ // line break by the inline-flow rules.
124
+ "& > p": {
125
+ margin: 0,
126
+ display: "inline"
127
+ }
128
+ }
129
+ },
130
+ // Nested lists
131
+ "& ul ul, & ol ol, & ul ol, & ol ul": {
132
+ marginBottom: 0
133
+ },
134
+ // ─── Task list (TipTap taskList / GFM checkboxes) ──────────
135
+ '& ul[data-type="taskList"]': {
136
+ listStyle: "none",
137
+ paddingLeft: 4,
138
+ "& li": {
139
+ display: "flex",
140
+ alignItems: "flex-start",
141
+ gap: 8,
142
+ "& > label": {
143
+ marginTop: 4
144
+ }
145
+ }
146
+ },
147
+ // ─── Blockquote ─────────────────────────────────────────────
148
+ "& blockquote": {
149
+ lineHeight: 1.6,
150
+ fontSize: "1em",
151
+ margin: "24px 0",
152
+ position: "relative",
153
+ padding: theme.spacing(2.5, 3, 2.5, 7),
154
+ color: theme.palette.text.secondary,
155
+ borderLeft: `4px solid ${theme.palette.primary.main}`,
156
+ borderRadius: Number(theme.shape.borderRadius) * 2,
157
+ backgroundColor: alpha(theme.palette.primary.main, 0.04),
158
+ "& p": {
159
+ margin: 0,
160
+ fontSize: "inherit"
161
+ },
162
+ "& p + p": {
163
+ marginTop: 8
164
+ },
165
+ "&::before": {
166
+ left: 16,
167
+ top: 8,
168
+ display: "block",
169
+ fontSize: "2.5em",
170
+ content: '"\\201C"',
171
+ position: "absolute",
172
+ color: alpha(theme.palette.primary.main, 0.3),
173
+ lineHeight: 1
174
+ }
175
+ },
176
+ // ─── Inline code ────────────────────────────────────────────
177
+ [`& .${contentClasses.codeInline}`]: {
178
+ padding: theme.spacing(0.25, 0.75),
179
+ color: theme.palette.text.secondary,
180
+ fontSize: theme.typography.body2.fontSize,
181
+ borderRadius: Number(theme.shape.borderRadius) / 2,
182
+ backgroundColor: alpha(theme.palette.grey[500], 0.2),
183
+ fontFamily: CODE_FONT
184
+ },
185
+ // Fallback for code not inside pre
186
+ "& :not(pre) > code:not([class])": {
187
+ padding: theme.spacing(0.25, 0.75),
188
+ color: theme.palette.text.secondary,
189
+ fontSize: theme.typography.body2.fontSize,
190
+ borderRadius: Number(theme.shape.borderRadius) / 2,
191
+ backgroundColor: alpha(theme.palette.grey[500], 0.2),
192
+ fontFamily: CODE_FONT
193
+ },
194
+ // ─── Code block ─────────────────────────────────────────────
195
+ [`& .${contentClasses.codeBlock}`]: {
196
+ position: "relative",
197
+ marginBottom: "1.25rem",
198
+ "& pre": {
199
+ overflowX: "auto",
200
+ padding: theme.spacing(3),
201
+ color: theme.palette.common.white,
202
+ borderRadius: Number(theme.shape.borderRadius) * 1.5,
203
+ fontFamily: CODE_FONT,
204
+ fontSize: theme.typography.body2.fontSize,
205
+ lineHeight: 1.7,
206
+ backgroundColor: theme.palette.grey[900],
207
+ ...theme.palette.mode === "dark" && {
208
+ backgroundColor: alpha(theme.palette.grey[800], 0.9)
209
+ },
210
+ "& code": {
211
+ fontSize: "inherit",
212
+ fontFamily: "inherit",
213
+ backgroundColor: "transparent",
214
+ padding: 0,
215
+ borderRadius: 0,
216
+ color: "inherit"
217
+ }
218
+ }
219
+ },
220
+ // Fallback for bare pre blocks
221
+ "& pre:not([class])": {
222
+ overflowX: "auto",
223
+ padding: theme.spacing(3),
224
+ color: theme.palette.common.white,
225
+ borderRadius: Number(theme.shape.borderRadius) * 1.5,
226
+ fontFamily: CODE_FONT,
227
+ fontSize: theme.typography.body2.fontSize,
228
+ lineHeight: 1.7,
229
+ backgroundColor: theme.palette.grey[900],
230
+ marginBottom: "1.25rem",
231
+ ...theme.palette.mode === "dark" && {
232
+ backgroundColor: alpha(theme.palette.grey[800], 0.9)
233
+ },
234
+ "& code": {
235
+ fontSize: "inherit",
236
+ fontFamily: "inherit",
237
+ backgroundColor: "transparent",
238
+ padding: 0,
239
+ color: "inherit"
240
+ }
241
+ },
242
+ // ─── Table ──────────────────────────────────────────────────
243
+ "& table": {
244
+ width: "100%",
245
+ borderCollapse: "collapse",
246
+ fontSize: theme.typography.body2.fontSize,
247
+ border: `1px solid ${theme.palette.divider}`,
248
+ marginBottom: "1.25rem",
249
+ "& th, & td": {
250
+ padding: theme.spacing(1, 1.5),
251
+ border: `1px solid ${theme.palette.divider}`,
252
+ verticalAlign: "top"
253
+ },
254
+ "& th": {
255
+ fontWeight: 700,
256
+ backgroundColor: alpha(theme.palette.grey[500], 0.08)
257
+ },
258
+ // Zebra rows. `:nth-of-type` (not `:nth-child`) is SSR-safe and
259
+ // exactly equivalent here — a `<tbody>` contains only `<tr>`
260
+ // children, so type-position and child-position coincide.
261
+ "& tbody tr:nth-of-type(odd)": {
262
+ backgroundColor: alpha(theme.palette.grey[500], 0.04)
263
+ }
264
+ },
265
+ // ─── Checkbox (GFM task lists) ──────────────────────────────
266
+ [`& .${contentClasses.checkbox}`]: {
267
+ cursor: "pointer",
268
+ position: "relative",
269
+ "&:before": {
270
+ content: '""',
271
+ top: -2,
272
+ left: -2,
273
+ width: 17,
274
+ height: 17,
275
+ borderRadius: 3,
276
+ position: "absolute",
277
+ backgroundColor: theme.palette.grey[300],
278
+ ...theme.palette.mode === "dark" && {
279
+ backgroundColor: theme.palette.grey[700]
280
+ }
281
+ },
282
+ "&:checked": {
283
+ "&:before": {
284
+ backgroundColor: theme.palette.primary.main
285
+ },
286
+ "&:after": {
287
+ top: 1,
288
+ left: 5,
289
+ width: 4,
290
+ height: 9,
291
+ content: '""',
292
+ position: "absolute",
293
+ borderStyle: "solid",
294
+ transform: "rotate(45deg)",
295
+ borderWidth: "0 2px 2px 0",
296
+ borderColor: theme.palette.common.white
297
+ }
298
+ }
299
+ },
300
+ // ─── Details / Summary ──────────────────────────────────────
301
+ "& details": {
302
+ marginBottom: "1rem",
303
+ "& summary": {
304
+ cursor: "pointer",
305
+ fontWeight: 600,
306
+ marginBottom: 8
307
+ }
308
+ },
309
+ // ─── Definition list ────────────────────────────────────────
310
+ "& dl": {
311
+ marginBottom: "1.25rem",
312
+ "& dt": {
313
+ fontWeight: 700,
314
+ marginTop: 12
315
+ },
316
+ "& dd": {
317
+ marginLeft: 24,
318
+ marginBottom: 4
319
+ }
320
+ },
321
+ // ─── Kbd (keyboard shortcut) ────────────────────────────────
322
+ "& kbd": {
323
+ display: "inline-block",
324
+ padding: theme.spacing(0.25, 0.5),
325
+ fontSize: "0.8em",
326
+ fontFamily: CODE_FONT,
327
+ borderRadius: 4,
328
+ border: `1px solid ${theme.palette.divider}`,
329
+ boxShadow: `0 1px 0 ${alpha(theme.palette.grey[500], 0.1)}`,
330
+ backgroundColor: alpha(theme.palette.grey[500], 0.06)
331
+ },
332
+ // ─── Mark (highlight) ──────────────────────────────────────
333
+ "& mark": {
334
+ padding: theme.spacing(0, 0.5),
335
+ borderRadius: 2,
336
+ backgroundColor: alpha(theme.palette.warning.main, 0.3)
337
+ },
338
+ // ─── Sup / Sub ──────────────────────────────────────────────
339
+ "& sup, & sub": {
340
+ fontSize: "0.75em"
341
+ },
342
+ // ─── Spoiler (||hidden text||) ────────────────────────────
343
+ [`& .${contentClasses.spoiler}`]: {
344
+ backgroundColor: theme.palette.text.primary,
345
+ color: theme.palette.text.primary,
346
+ borderRadius: 4,
347
+ padding: theme.spacing(0, 0.5),
348
+ cursor: "pointer",
349
+ transition: "all 0.15s ease",
350
+ userSelect: "none",
351
+ '&:hover, &[data-revealed="true"]': {
352
+ backgroundColor: "transparent",
353
+ color: "inherit",
354
+ userSelect: "auto"
355
+ }
356
+ },
357
+ // ─── Admonition (callout) ─────────────────────────────────
358
+ [`& .${contentClasses.admonition}`]: {
359
+ margin: theme.spacing(2, 0),
360
+ padding: theme.spacing(1.5, 2),
361
+ borderRadius: theme.shape.borderRadius,
362
+ borderLeft: `4px solid ${theme.palette.divider}`,
363
+ backgroundColor: alpha(theme.palette.text.primary, 0.04),
364
+ "& > :last-child": { marginBottom: 0 }
365
+ },
366
+ [`& .${contentClasses.admonitionTitle}`]: {
367
+ fontWeight: 600,
368
+ textTransform: "uppercase",
369
+ fontSize: "0.75rem",
370
+ letterSpacing: "0.05em",
371
+ marginBottom: theme.spacing(0.75),
372
+ opacity: 0.85
373
+ },
374
+ [`& .${contentClasses.admonitionContent}`]: {
375
+ "& p:last-child": { marginBottom: 0 }
376
+ },
377
+ [`& .${contentClasses.admonitionNote}`]: {
378
+ borderLeftColor: theme.palette.text.secondary,
379
+ backgroundColor: alpha(theme.palette.text.primary, 0.04)
380
+ },
381
+ [`& .${contentClasses.admonitionTip}`]: {
382
+ borderLeftColor: theme.palette.success.main,
383
+ backgroundColor: alpha(theme.palette.success.main, 0.08)
384
+ },
385
+ [`& .${contentClasses.admonitionWarning}`]: {
386
+ borderLeftColor: theme.palette.warning.main,
387
+ backgroundColor: alpha(theme.palette.warning.main, 0.08)
388
+ },
389
+ [`& .${contentClasses.admonitionDanger}`]: {
390
+ borderLeftColor: theme.palette.error.main,
391
+ backgroundColor: alpha(theme.palette.error.main, 0.08)
392
+ },
393
+ [`& .${contentClasses.admonitionInfo}`]: {
394
+ borderLeftColor: theme.palette.info.main,
395
+ backgroundColor: alpha(theme.palette.info.main, 0.08)
396
+ },
397
+ [`& .${contentClasses.admonitionCaution}`]: {
398
+ borderLeftColor: theme.palette.warning.dark,
399
+ backgroundColor: alpha(theme.palette.warning.dark, 0.08)
400
+ },
401
+ // ─── Tabs ───────────────────────────────────────────────────
402
+ [`& .${contentClasses.tabs}`]: {
403
+ margin: theme.spacing(2, 0),
404
+ border: `1px solid ${theme.palette.divider}`,
405
+ borderRadius: theme.shape.borderRadius,
406
+ overflow: "hidden"
407
+ },
408
+ [`& .${contentClasses.tabsHeader}`]: {
409
+ display: "flex",
410
+ gap: 0,
411
+ borderBottom: `1px solid ${theme.palette.divider}`,
412
+ backgroundColor: alpha(theme.palette.text.primary, 0.03)
413
+ },
414
+ [`& .${contentClasses.tabsTab}`]: {
415
+ appearance: "none",
416
+ background: "transparent",
417
+ border: "none",
418
+ padding: theme.spacing(1, 2),
419
+ fontFamily: "inherit",
420
+ fontSize: "0.8125rem",
421
+ fontWeight: 500,
422
+ color: theme.palette.text.secondary,
423
+ cursor: "pointer",
424
+ borderBottom: "2px solid transparent",
425
+ transition: "all 0.15s ease",
426
+ "&:hover": { color: theme.palette.text.primary }
427
+ },
428
+ [`& .${contentClasses.tabsTabActive}`]: {
429
+ color: theme.palette.text.primary,
430
+ borderBottomColor: theme.palette.primary.main
431
+ },
432
+ [`& .${contentClasses.tabsPanel}`]: {
433
+ padding: theme.spacing(2),
434
+ // No `:first-child` reset needed: headings only take a top margin
435
+ // when preceded by a sibling (see heading rules above) and
436
+ // paragraphs carry only a bottom margin, so the panel's first
437
+ // child never has an excess top margin. (SSR-safe.)
438
+ "& > :last-child": { marginBottom: 0 }
439
+ },
440
+ // ─── Code block — title + copy button ───────────────────────
441
+ [`& .${contentClasses.codeBlockTitle}`]: {
442
+ display: "flex",
443
+ alignItems: "center",
444
+ justifyContent: "space-between",
445
+ gap: theme.spacing(1),
446
+ padding: theme.spacing(0.75, 1.5),
447
+ fontSize: "0.75rem",
448
+ fontFamily: 'ui-monospace, "SF Mono", Menlo, Consolas, monospace',
449
+ color: theme.palette.text.secondary,
450
+ backgroundColor: alpha(theme.palette.text.primary, 0.06),
451
+ borderTopLeftRadius: theme.shape.borderRadius,
452
+ borderTopRightRadius: theme.shape.borderRadius
453
+ },
454
+ [`& .${contentClasses.codeBlockCopy}`]: {
455
+ appearance: "none",
456
+ background: "transparent",
457
+ border: "none",
458
+ color: "inherit",
459
+ cursor: "pointer",
460
+ padding: theme.spacing(0.25, 0.75),
461
+ fontSize: "0.875rem",
462
+ borderRadius: theme.shape.borderRadius,
463
+ "&:hover": { backgroundColor: alpha(theme.palette.text.primary, 0.08) }
464
+ },
465
+ // ─── Figure ─────────────────────────────────────────────────
466
+ [`& .${contentClasses.figure}`]: {
467
+ margin: theme.spacing(2, 0),
468
+ textAlign: "center"
469
+ },
470
+ [`& .${contentClasses.figcaption}`]: {
471
+ fontSize: "0.8125rem",
472
+ color: theme.palette.text.secondary,
473
+ marginTop: theme.spacing(0.75)
474
+ },
475
+ // ─── kbd ────────────────────────────────────────────────────
476
+ [`& .${contentClasses.kbd}`]: {
477
+ display: "inline-block",
478
+ padding: theme.spacing(0, 0.5),
479
+ fontFamily: 'ui-monospace, "SF Mono", Menlo, Consolas, monospace',
480
+ fontSize: "0.8em",
481
+ color: theme.palette.text.primary,
482
+ border: `1px solid ${theme.palette.divider}`,
483
+ borderBottomWidth: 2,
484
+ borderRadius: 4,
485
+ backgroundColor: alpha(theme.palette.text.primary, 0.04),
486
+ boxShadow: `0 1px 0 ${alpha(theme.palette.text.primary, 0.15)}`,
487
+ minWidth: "1.5em",
488
+ textAlign: "center"
489
+ },
490
+ // ─── Compact mode (chat messages, comments, etc.) ─────────
491
+ [`&.${contentClasses.compact}`]: {
492
+ "> * + *": { marginTop: 0, marginBottom: 2 },
493
+ // (Dropped an SSR-unsafe `& > :first-child:not(p)` 4px top-margin
494
+ // tweak — cosmetically negligible in compact mode, and `:first-child`
495
+ // triggered Emotion's SSR warning.)
496
+ "& h1, & h2, & h3, & h4, & h5, & h6": { marginTop: 0, marginBottom: 2 },
497
+ h1: { fontSize: "1.25rem", fontWeight: 600, marginTop: 0, marginBottom: 2 },
498
+ h2: { fontSize: "1.125rem", fontWeight: 600, marginTop: 0, marginBottom: 2 },
499
+ h3: { fontSize: "1rem", fontWeight: 600, marginTop: 0, marginBottom: 2 },
500
+ "h4, h5, h6": { fontSize: "0.875rem", fontWeight: 600, marginTop: 0, marginBottom: 2 },
501
+ p: {
502
+ fontSize: "0.8125rem",
503
+ lineHeight: 1.5,
504
+ marginBottom: 2,
505
+ "&:last-child": { marginBottom: 0 }
506
+ },
507
+ hr: { margin: "4px 0" },
508
+ "& blockquote": {
509
+ margin: "4px 0",
510
+ padding: theme.spacing(0.5, 0, 0.5, 1.5),
511
+ borderRadius: 0,
512
+ backgroundColor: "transparent",
513
+ "&::before": { display: "none" }
514
+ },
515
+ "& ul, & ol": {
516
+ paddingLeft: 20,
517
+ marginBottom: 2,
518
+ "& > li": { lineHeight: 1.5, fontSize: "0.8125rem" }
519
+ },
520
+ "& img:not([class])": { marginBottom: 4 },
521
+ [`& .${contentClasses.codeBlock}`]: { marginBottom: 4 },
522
+ [`& .${contentClasses.codeBlock} pre, & pre:not([class])`]: {
523
+ padding: theme.spacing(1.5),
524
+ fontSize: "0.75rem",
525
+ lineHeight: 1.5,
526
+ marginBottom: 4
527
+ },
528
+ [`& .${contentClasses.codeInline}, & :not(pre) > code:not([class])`]: {
529
+ fontSize: "0.75rem"
530
+ },
531
+ "& table": {
532
+ fontSize: "0.75rem",
533
+ marginBottom: 4
534
+ }
535
+ }
536
+ }));
537
+ function isSafeHref(url) {
538
+ if (typeof url !== "string" || url.length === 0) return false;
539
+ if (/[\x00-\x1f\x7f]/.test(url)) return false;
540
+ if (url !== url.trim() || url.includes("\\") || url.startsWith("//")) return false;
541
+ if (url.startsWith("#")) return true;
542
+ if (url.startsWith("/") && !url.startsWith("//") && !url.startsWith("/\\")) return true;
543
+ const lower = url.toLowerCase().trimStart();
544
+ if (lower.startsWith("http://") || lower.startsWith("https://")) return true;
545
+ return !/^[a-z][a-z0-9+.-]*:/i.test(url);
546
+ }
547
+ function sanitizeHref(url) {
548
+ return isSafeHref(url) ? url : void 0;
549
+ }
550
+ function sanitizeEmbedSrc(url) {
551
+ if (typeof url !== "string") return void 0;
552
+ if (!isSafeHref(url)) return void 0;
553
+ const lower = url.toLowerCase();
554
+ if (lower.startsWith("https://www.youtube.com/") || lower.startsWith("https://www.youtube-nocookie.com/")) {
555
+ return url;
556
+ }
557
+ return void 0;
558
+ }
559
+ var customNodeRegistry = /* @__PURE__ */ new Map();
560
+ function registerTipTapNode(type, component) {
561
+ customNodeRegistry.set(type, component);
562
+ }
563
+ var TipTapContext = createContext({});
564
+ function renderMarks(text, marks = [], ctx) {
565
+ return marks.reduce((acc, mark) => {
566
+ switch (mark.type) {
567
+ case "bold":
568
+ return /* @__PURE__ */ jsx("strong", { children: acc });
569
+ case "italic":
570
+ return /* @__PURE__ */ jsx("em", { children: acc });
571
+ case "code":
572
+ return /* @__PURE__ */ jsx("code", { className: contentClasses.codeInline, children: acc });
573
+ case "underline":
574
+ return /* @__PURE__ */ jsx("u", { children: acc });
575
+ case "strike":
576
+ return /* @__PURE__ */ jsx("s", { children: acc });
577
+ case "link": {
578
+ const safeHref = sanitizeHref(mark.attrs?.href) ?? "#";
579
+ const Link = ctx?.linkComponent;
580
+ if (Link && safeHref.startsWith("/") && !safeHref.startsWith("//")) {
581
+ return /* @__PURE__ */ jsx(Link, { to: safeHref, className: contentClasses.link, children: acc });
582
+ }
583
+ return /* @__PURE__ */ jsx("a", { href: safeHref, target: mark.attrs?.target ?? "_blank", rel: "noopener noreferrer", children: acc });
584
+ }
585
+ case "internalLink": {
586
+ const to = sanitizeHref(mark.attrs?.to ?? mark.attrs?.href) ?? "#";
587
+ const Link = ctx?.linkComponent;
588
+ return Link ? /* @__PURE__ */ jsx(Link, { to, className: contentClasses.link, children: acc }) : /* @__PURE__ */ jsx("a", { href: to, children: acc });
589
+ }
590
+ case "highlight":
591
+ return /* @__PURE__ */ jsx("mark", { style: mark.attrs?.color ? { backgroundColor: mark.attrs.color } : void 0, children: acc });
592
+ case "subscript":
593
+ return /* @__PURE__ */ jsx("sub", { children: acc });
594
+ case "superscript":
595
+ return /* @__PURE__ */ jsx("sup", { children: acc });
596
+ case "textStyle":
597
+ return /* @__PURE__ */ jsx("span", { style: { color: mark.attrs?.color }, children: acc });
598
+ case "kbd":
599
+ return /* @__PURE__ */ jsx("kbd", { className: contentClasses.kbd, children: acc });
600
+ default:
601
+ return acc;
602
+ }
603
+ }, text);
604
+ }
605
+ function slugify(nodes) {
606
+ if (!nodes) return void 0;
607
+ const text = nodes.map((n) => n.text ?? "").join("");
608
+ if (!text) return void 0;
609
+ return text.toLowerCase().replace(/[^a-z0-9а-яё]+/gi, "-").replace(/^-|-$/g, "");
610
+ }
611
+ function CodeBlock({ node }) {
612
+ const language = node.attrs?.language;
613
+ const title = node.attrs?.title;
614
+ const code = node.content?.map((n) => n.text ?? "").join("\n") ?? "";
615
+ const [copied, setCopied] = useState(false);
616
+ const onCopy = useCallback(() => {
617
+ navigator.clipboard?.writeText(code).then(
618
+ () => {
619
+ setCopied(true);
620
+ setTimeout(() => setCopied(false), 1500);
621
+ },
622
+ () => {
623
+ }
624
+ );
625
+ }, [code]);
626
+ return /* @__PURE__ */ jsxs("div", { className: contentClasses.codeBlock, "data-language": language ?? void 0, children: [
627
+ (title || language) && /* @__PURE__ */ jsxs("div", { className: contentClasses.codeBlockTitle, children: [
628
+ /* @__PURE__ */ jsx("span", { children: title ?? language }),
629
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: onCopy, className: contentClasses.codeBlockCopy, "aria-label": "Copy code", children: copied ? "\u2713" : "\u29C9" })
630
+ ] }),
631
+ /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { className: language ? `language-${language}` : void 0, children: code }) })
632
+ ] });
633
+ }
634
+ var ADMONITION_LABEL = {
635
+ note: "Note",
636
+ tip: "Tip",
637
+ warning: "Warning",
638
+ danger: "Danger",
639
+ info: "Info",
640
+ caution: "Caution"
641
+ };
642
+ var ADMONITION_CLASS = {
643
+ note: contentClasses.admonitionNote,
644
+ tip: contentClasses.admonitionTip,
645
+ warning: contentClasses.admonitionWarning,
646
+ danger: contentClasses.admonitionDanger,
647
+ info: contentClasses.admonitionInfo,
648
+ caution: contentClasses.admonitionCaution
649
+ };
650
+ function Admonition({ node }) {
651
+ const kind = String(node.attrs?.kind ?? "note");
652
+ const title = node.attrs?.title ?? ADMONITION_LABEL[kind] ?? kind;
653
+ const variantClass = ADMONITION_CLASS[kind] ?? contentClasses.admonitionNote;
654
+ return /* @__PURE__ */ jsxs("aside", { className: `${contentClasses.admonition} ${variantClass}`, "data-kind": kind, children: [
655
+ /* @__PURE__ */ jsx("div", { className: contentClasses.admonitionTitle, children: title }),
656
+ /* @__PURE__ */ jsx("div", { className: contentClasses.admonitionContent, children: node.content?.map(renderNode) })
657
+ ] });
658
+ }
659
+ function Tabs({ node }) {
660
+ const items = (node.content ?? []).filter((c) => c.type === "tabItem");
661
+ const [active, setActive] = useState(0);
662
+ if (items.length === 0) return null;
663
+ const safeActive = Math.min(active, items.length - 1);
664
+ return /* @__PURE__ */ jsxs("div", { className: contentClasses.tabs, children: [
665
+ /* @__PURE__ */ jsx("div", { className: contentClasses.tabsHeader, role: "tablist", children: items.map((item, i) => {
666
+ const label = item.attrs?.label ?? item.attrs?.value ?? `Tab ${i + 1}`;
667
+ const isActive = i === safeActive;
668
+ return /* @__PURE__ */ jsx(
669
+ "button",
670
+ {
671
+ type: "button",
672
+ role: "tab",
673
+ "aria-selected": isActive,
674
+ className: `${contentClasses.tabsTab} ${isActive ? contentClasses.tabsTabActive : ""}`,
675
+ onClick: () => setActive(i),
676
+ children: label
677
+ },
678
+ i
679
+ );
680
+ }) }),
681
+ /* @__PURE__ */ jsx("div", { className: contentClasses.tabsPanel, role: "tabpanel", children: items[safeActive]?.content?.map(renderNode) })
682
+ ] });
683
+ }
684
+ function renderNode(node, index) {
685
+ return /* @__PURE__ */ jsx(ScopedNode, { node, index }, index);
686
+ }
687
+ function ScopedNode({ node, index }) {
688
+ const context = useContext(TipTapContext);
689
+ const CustomRenderer = context.nodeRenderers?.[node.type] ?? (context.inheritRegisteredNodes !== false ? customNodeRegistry.get(node.type) : void 0);
690
+ if (CustomRenderer) return /* @__PURE__ */ jsx(CustomRenderer, { node }, index);
691
+ switch (node.type) {
692
+ case "text":
693
+ return /* @__PURE__ */ jsx(TextNode, { node }, index);
694
+ case "paragraph":
695
+ return /* @__PURE__ */ jsx("p", { children: node.content?.map(renderNode) }, index);
696
+ case "heading": {
697
+ const level = Math.min(Math.max(node.attrs?.level ?? 2, 1), 6);
698
+ const Tag = `h${level}`;
699
+ const id = node.attrs?.id ?? slugify(node.content);
700
+ return /* @__PURE__ */ jsx(Tag, { id, children: node.content?.map(renderNode) }, index);
701
+ }
702
+ case "bulletList":
703
+ return /* @__PURE__ */ jsx("ul", { children: node.content?.map(renderNode) }, index);
704
+ case "orderedList":
705
+ return /* @__PURE__ */ jsx("ol", { start: node.attrs?.start ?? 1, children: node.content?.map(renderNode) }, index);
706
+ case "listItem":
707
+ return /* @__PURE__ */ jsx("li", { children: node.content?.map(renderNode) }, index);
708
+ case "taskList":
709
+ return /* @__PURE__ */ jsx("ul", { "data-type": "taskList", children: node.content?.map(renderNode) }, index);
710
+ case "taskItem": {
711
+ const checked = node.attrs?.checked ?? false;
712
+ return /* @__PURE__ */ jsxs("li", { "data-type": "taskItem", "data-checked": checked, children: [
713
+ /* @__PURE__ */ jsx("label", { children: /* @__PURE__ */ jsx("input", { type: "checkbox", checked, readOnly: true, className: contentClasses.checkbox }) }),
714
+ /* @__PURE__ */ jsx("div", { children: node.content?.map(renderNode) })
715
+ ] }, index);
716
+ }
717
+ case "blockquote":
718
+ return /* @__PURE__ */ jsx("blockquote", { children: node.content?.map(renderNode) }, index);
719
+ case "codeBlock":
720
+ return /* @__PURE__ */ jsx(CodeBlock, { node }, index);
721
+ case "horizontalRule":
722
+ return /* @__PURE__ */ jsx("hr", {}, index);
723
+ case "image": {
724
+ const safeSrc = sanitizeHref(node.attrs?.src);
725
+ if (!safeSrc) return null;
726
+ return /* @__PURE__ */ jsx(
727
+ "img",
728
+ {
729
+ src: safeSrc,
730
+ alt: node.attrs?.alt ?? "",
731
+ title: node.attrs?.title,
732
+ className: contentClasses.image,
733
+ loading: "lazy"
734
+ },
735
+ index
736
+ );
737
+ }
738
+ case "figure":
739
+ return /* @__PURE__ */ jsx("figure", { className: contentClasses.figure, children: node.content?.map(renderNode) }, index);
740
+ case "figcaption":
741
+ return /* @__PURE__ */ jsx("figcaption", { className: contentClasses.figcaption, children: node.content?.map(renderNode) }, index);
742
+ case "hardBreak":
743
+ return /* @__PURE__ */ jsx("br", {}, index);
744
+ // ─── Admonition / Tabs ──────────────────────────────────
745
+ case "admonition":
746
+ return /* @__PURE__ */ jsx(Admonition, { node }, index);
747
+ case "tabs":
748
+ return /* @__PURE__ */ jsx(Tabs, { node }, index);
749
+ case "tabItem":
750
+ return /* @__PURE__ */ jsx("section", { "data-type": "tabItem", children: node.content?.map(renderNode) }, index);
751
+ // ─── Table ──────────────────────────────────────────────
752
+ case "table":
753
+ return /* @__PURE__ */ jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsx("table", { children: /* @__PURE__ */ jsx("tbody", { children: node.content?.map(renderNode) }) }) }, index);
754
+ case "tableRow":
755
+ return /* @__PURE__ */ jsx("tr", { children: node.content?.map(renderNode) }, index);
756
+ case "tableCell":
757
+ return /* @__PURE__ */ jsx("td", { colSpan: node.attrs?.colspan ?? 1, rowSpan: node.attrs?.rowspan ?? 1, children: node.content?.map(renderNode) }, index);
758
+ case "tableHeader":
759
+ return /* @__PURE__ */ jsx("th", { colSpan: node.attrs?.colspan ?? 1, rowSpan: node.attrs?.rowspan ?? 1, children: node.content?.map(renderNode) }, index);
760
+ // ─── Details / Summary (collapsible) ────────────────────
761
+ case "details":
762
+ return /* @__PURE__ */ jsx("details", { open: node.attrs?.open, children: node.content?.map(renderNode) }, index);
763
+ case "detailsSummary":
764
+ return /* @__PURE__ */ jsx("summary", { children: node.content?.map(renderNode) }, index);
765
+ case "detailsContent":
766
+ return /* @__PURE__ */ jsx("div", { children: node.content?.map(renderNode) }, index);
767
+ // ─── YouTube embed ──────────────────────────────────────
768
+ case "youtube": {
769
+ const safeSrc = sanitizeEmbedSrc(node.attrs?.src);
770
+ if (!safeSrc) return null;
771
+ return /* @__PURE__ */ jsx("div", { style: { position: "relative", paddingBottom: "56.25%", height: 0, marginBottom: "1.25rem" }, children: /* @__PURE__ */ jsx(
772
+ "iframe",
773
+ {
774
+ src: safeSrc,
775
+ title: "YouTube video",
776
+ allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
777
+ allowFullScreen: true,
778
+ style: {
779
+ position: "absolute",
780
+ top: 0,
781
+ left: 0,
782
+ width: "100%",
783
+ height: "100%",
784
+ border: "none",
785
+ borderRadius: 8
786
+ }
787
+ }
788
+ ) }, index);
789
+ }
790
+ default:
791
+ if (node.content) {
792
+ return /* @__PURE__ */ jsx(Fragment, { children: node.content.map(renderNode) }, index);
793
+ }
794
+ return null;
795
+ }
796
+ }
797
+ function TextNode({ node }) {
798
+ const ctx = useContext(TipTapContext);
799
+ return /* @__PURE__ */ jsx(Fragment, { children: renderMarks(node.text ?? "", node.marks, ctx) });
800
+ }
801
+ function TipTapRenderer({
802
+ content,
803
+ className,
804
+ sx,
805
+ compact,
806
+ linkComponent,
807
+ nodeRenderers,
808
+ inheritRegisteredNodes
809
+ }) {
810
+ if (!content || !("content" in content) || !Array.isArray(content.content)) {
811
+ return null;
812
+ }
813
+ const ctxValue = { linkComponent, nodeRenderers, inheritRegisteredNodes };
814
+ return /* @__PURE__ */ jsx(TipTapContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsx(
815
+ ContentRoot,
816
+ {
817
+ className: [contentClasses.root, contentClasses.tiptap, compact && contentClasses.compact, className].filter(Boolean).join(" "),
818
+ sx,
819
+ children: content.content.map(renderNode)
820
+ }
821
+ ) });
822
+ }
823
+
824
+ export { ContentRoot, TipTapRenderer, contentClasses, registerTipTapNode };
825
+ //# sourceMappingURL=chunk-GUGTDURV.js.map
826
+ //# sourceMappingURL=chunk-GUGTDURV.js.map