ngwr 14.7.0 → 14.9.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 (482) hide show
  1. package/README.md +66 -332
  2. package/alert/styles/_index.scss +10 -0
  3. package/avatar/styles/_index.scss +18 -7
  4. package/badge/styles/_index.scss +7 -0
  5. package/badge/styles/_tag.scss +7 -1
  6. package/bar-chart/styles/_index.scss +1 -0
  7. package/button/styles/_index.scss +6 -0
  8. package/calendar-heatmap/styles/_index.scss +1 -0
  9. package/cascader/styles/_rules.scss +87 -15
  10. package/checkbox/styles/_index.scss +4 -0
  11. package/command-palette/styles/_index.scss +1 -1
  12. package/date-picker/styles/_index.scss +30 -0
  13. package/density/styles/_index.scss +4 -2
  14. package/divider/styles/_index.scss +2 -0
  15. package/donut-chart/styles/_index.scss +10 -0
  16. package/dropdown/styles/_index.scss +67 -5
  17. package/editor/styles/_index.scss +441 -0
  18. package/event-calendar/styles/_index.scss +209 -35
  19. package/fesm2022/ngwr-action-sheet-testing.mjs.map +1 -1
  20. package/fesm2022/ngwr-action-sheet.mjs +3 -3
  21. package/fesm2022/ngwr-action-sheet.mjs.map +1 -1
  22. package/fesm2022/ngwr-affix.mjs +3 -3
  23. package/fesm2022/ngwr-affix.mjs.map +1 -1
  24. package/fesm2022/ngwr-alert.mjs +3 -3
  25. package/fesm2022/ngwr-alert.mjs.map +1 -1
  26. package/fesm2022/ngwr-anchor.mjs +3 -3
  27. package/fesm2022/ngwr-anchor.mjs.map +1 -1
  28. package/fesm2022/ngwr-aurora.mjs +3 -3
  29. package/fesm2022/ngwr-aurora.mjs.map +1 -1
  30. package/fesm2022/ngwr-avatar.mjs +3 -3
  31. package/fesm2022/ngwr-avatar.mjs.map +1 -1
  32. package/fesm2022/ngwr-back-top.mjs +3 -3
  33. package/fesm2022/ngwr-back-top.mjs.map +1 -1
  34. package/fesm2022/ngwr-badge.mjs +28 -13
  35. package/fesm2022/ngwr-badge.mjs.map +1 -1
  36. package/fesm2022/ngwr-bar-chart-testing.mjs.map +1 -1
  37. package/fesm2022/ngwr-bar-chart.mjs +31 -6
  38. package/fesm2022/ngwr-bar-chart.mjs.map +1 -1
  39. package/fesm2022/ngwr-blur-text-testing.mjs.map +1 -1
  40. package/fesm2022/ngwr-blur-text.mjs +3 -3
  41. package/fesm2022/ngwr-blur-text.mjs.map +1 -1
  42. package/fesm2022/ngwr-border-glow-testing.mjs.map +1 -1
  43. package/fesm2022/ngwr-border-glow.mjs +3 -3
  44. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  45. package/fesm2022/ngwr-breadcrumbs.mjs +6 -6
  46. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  47. package/fesm2022/ngwr-burger.mjs +3 -3
  48. package/fesm2022/ngwr-burger.mjs.map +1 -1
  49. package/fesm2022/ngwr-button-testing.mjs.map +1 -1
  50. package/fesm2022/ngwr-button.mjs +6 -6
  51. package/fesm2022/ngwr-button.mjs.map +1 -1
  52. package/fesm2022/ngwr-calendar-heatmap-testing.mjs.map +1 -1
  53. package/fesm2022/ngwr-calendar-heatmap.mjs +61 -6
  54. package/fesm2022/ngwr-calendar-heatmap.mjs.map +1 -1
  55. package/fesm2022/ngwr-calendar-testing.mjs.map +1 -1
  56. package/fesm2022/ngwr-calendar.mjs +3 -3
  57. package/fesm2022/ngwr-calendar.mjs.map +1 -1
  58. package/fesm2022/ngwr-card.mjs +9 -9
  59. package/fesm2022/ngwr-card.mjs.map +1 -1
  60. package/fesm2022/ngwr-carousel-testing.mjs.map +1 -1
  61. package/fesm2022/ngwr-carousel.mjs +6 -6
  62. package/fesm2022/ngwr-carousel.mjs.map +1 -1
  63. package/fesm2022/ngwr-cascader-testing.mjs.map +1 -1
  64. package/fesm2022/ngwr-cascader.mjs +4 -4
  65. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  66. package/fesm2022/ngwr-checkbox-testing.mjs.map +1 -1
  67. package/fesm2022/ngwr-checkbox.mjs +18 -8
  68. package/fesm2022/ngwr-checkbox.mjs.map +1 -1
  69. package/fesm2022/ngwr-circular-text-testing.mjs.map +1 -1
  70. package/fesm2022/ngwr-circular-text.mjs +3 -3
  71. package/fesm2022/ngwr-circular-text.mjs.map +1 -1
  72. package/fesm2022/ngwr-click-spark.mjs +3 -3
  73. package/fesm2022/ngwr-click-spark.mjs.map +1 -1
  74. package/fesm2022/ngwr-clipboard.mjs +3 -3
  75. package/fesm2022/ngwr-clipboard.mjs.map +1 -1
  76. package/fesm2022/ngwr-collapse-testing.mjs.map +1 -1
  77. package/fesm2022/ngwr-collapse.mjs +9 -9
  78. package/fesm2022/ngwr-collapse.mjs.map +1 -1
  79. package/fesm2022/ngwr-color-picker-testing.mjs.map +1 -1
  80. package/fesm2022/ngwr-color-picker.mjs +6 -6
  81. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  82. package/fesm2022/ngwr-command-palette-testing.mjs.map +1 -1
  83. package/fesm2022/ngwr-command-palette.mjs +3 -3
  84. package/fesm2022/ngwr-command-palette.mjs.map +1 -1
  85. package/fesm2022/ngwr-compare.mjs +3 -3
  86. package/fesm2022/ngwr-compare.mjs.map +1 -1
  87. package/fesm2022/ngwr-confetti.mjs +3 -3
  88. package/fesm2022/ngwr-confetti.mjs.map +1 -1
  89. package/fesm2022/ngwr-config.mjs.map +1 -1
  90. package/fesm2022/ngwr-context-menu-testing.mjs.map +1 -1
  91. package/fesm2022/ngwr-context-menu.mjs +12 -12
  92. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  93. package/fesm2022/ngwr-cookie.mjs +3 -3
  94. package/fesm2022/ngwr-cookie.mjs.map +1 -1
  95. package/fesm2022/ngwr-counter.mjs +6 -6
  96. package/fesm2022/ngwr-counter.mjs.map +1 -1
  97. package/fesm2022/ngwr-date-adapters-fns.mjs +3 -3
  98. package/fesm2022/ngwr-date-adapters-fns.mjs.map +1 -1
  99. package/fesm2022/ngwr-date-adapters-luxon.mjs +3 -3
  100. package/fesm2022/ngwr-date-adapters-luxon.mjs.map +1 -1
  101. package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -1
  102. package/fesm2022/ngwr-date-picker.mjs +721 -62
  103. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  104. package/fesm2022/ngwr-date.mjs +3 -3
  105. package/fesm2022/ngwr-date.mjs.map +1 -1
  106. package/fesm2022/ngwr-decrypt-text-testing.mjs.map +1 -1
  107. package/fesm2022/ngwr-decrypt-text.mjs +3 -3
  108. package/fesm2022/ngwr-decrypt-text.mjs.map +1 -1
  109. package/fesm2022/ngwr-density.mjs +6 -6
  110. package/fesm2022/ngwr-density.mjs.map +1 -1
  111. package/fesm2022/ngwr-descriptions.mjs +6 -6
  112. package/fesm2022/ngwr-descriptions.mjs.map +1 -1
  113. package/fesm2022/ngwr-dialog-testing.mjs.map +1 -1
  114. package/fesm2022/ngwr-dialog.mjs +15 -15
  115. package/fesm2022/ngwr-dialog.mjs.map +1 -1
  116. package/fesm2022/ngwr-directives.mjs +12 -12
  117. package/fesm2022/ngwr-directives.mjs.map +1 -1
  118. package/fesm2022/ngwr-divider.mjs +3 -3
  119. package/fesm2022/ngwr-divider.mjs.map +1 -1
  120. package/fesm2022/ngwr-donut-chart-testing.mjs.map +1 -1
  121. package/fesm2022/ngwr-donut-chart.mjs +48 -6
  122. package/fesm2022/ngwr-donut-chart.mjs.map +1 -1
  123. package/fesm2022/ngwr-drag-drop.mjs +6 -6
  124. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  125. package/fesm2022/ngwr-drawer-testing.mjs.map +1 -1
  126. package/fesm2022/ngwr-drawer.mjs +18 -18
  127. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  128. package/fesm2022/ngwr-dropdown-testing.mjs.map +1 -1
  129. package/fesm2022/ngwr-dropdown.mjs +174 -25
  130. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  131. package/fesm2022/ngwr-editor-testing.mjs +568 -0
  132. package/fesm2022/ngwr-editor-testing.mjs.map +1 -0
  133. package/fesm2022/ngwr-editor.mjs +2601 -0
  134. package/fesm2022/ngwr-editor.mjs.map +1 -0
  135. package/fesm2022/ngwr-empty.mjs +3 -3
  136. package/fesm2022/ngwr-empty.mjs.map +1 -1
  137. package/fesm2022/ngwr-event-calendar-testing.mjs.map +1 -1
  138. package/fesm2022/ngwr-event-calendar.mjs +14 -7
  139. package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
  140. package/fesm2022/ngwr-falling-text-testing.mjs.map +1 -1
  141. package/fesm2022/ngwr-falling-text.mjs +3 -3
  142. package/fesm2022/ngwr-falling-text.mjs.map +1 -1
  143. package/fesm2022/ngwr-file-upload-testing.mjs.map +1 -1
  144. package/fesm2022/ngwr-file-upload.mjs +3 -3
  145. package/fesm2022/ngwr-file-upload.mjs.map +1 -1
  146. package/fesm2022/ngwr-form-testing.mjs.map +1 -1
  147. package/fesm2022/ngwr-form.mjs +61 -10
  148. package/fesm2022/ngwr-form.mjs.map +1 -1
  149. package/fesm2022/ngwr-fuzzy-text-testing.mjs.map +1 -1
  150. package/fesm2022/ngwr-fuzzy-text.mjs +3 -3
  151. package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
  152. package/fesm2022/ngwr-gauge-testing.mjs.map +1 -1
  153. package/fesm2022/ngwr-gauge.mjs +35 -6
  154. package/fesm2022/ngwr-gauge.mjs.map +1 -1
  155. package/fesm2022/ngwr-glitch-text-testing.mjs.map +1 -1
  156. package/fesm2022/ngwr-glitch-text.mjs +3 -3
  157. package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
  158. package/fesm2022/ngwr-gradient-text-testing.mjs.map +1 -1
  159. package/fesm2022/ngwr-gradient-text.mjs +3 -3
  160. package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
  161. package/fesm2022/ngwr-graph-testing.mjs.map +1 -1
  162. package/fesm2022/ngwr-graph.mjs +6 -6
  163. package/fesm2022/ngwr-graph.mjs.map +1 -1
  164. package/fesm2022/ngwr-hotkey.mjs +6 -6
  165. package/fesm2022/ngwr-hotkey.mjs.map +1 -1
  166. package/fesm2022/ngwr-i18n-ar.mjs +31 -0
  167. package/fesm2022/ngwr-i18n-ar.mjs.map +1 -1
  168. package/fesm2022/ngwr-i18n-cs.mjs +31 -0
  169. package/fesm2022/ngwr-i18n-cs.mjs.map +1 -1
  170. package/fesm2022/ngwr-i18n-de.mjs +31 -0
  171. package/fesm2022/ngwr-i18n-de.mjs.map +1 -1
  172. package/fesm2022/ngwr-i18n-en.mjs +39 -0
  173. package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
  174. package/fesm2022/ngwr-i18n-es.mjs +31 -0
  175. package/fesm2022/ngwr-i18n-es.mjs.map +1 -1
  176. package/fesm2022/ngwr-i18n-fr.mjs +31 -0
  177. package/fesm2022/ngwr-i18n-fr.mjs.map +1 -1
  178. package/fesm2022/ngwr-i18n-he.mjs +31 -0
  179. package/fesm2022/ngwr-i18n-he.mjs.map +1 -1
  180. package/fesm2022/ngwr-i18n-hi.mjs +31 -0
  181. package/fesm2022/ngwr-i18n-hi.mjs.map +1 -1
  182. package/fesm2022/ngwr-i18n-id.mjs +31 -0
  183. package/fesm2022/ngwr-i18n-id.mjs.map +1 -1
  184. package/fesm2022/ngwr-i18n-it.mjs +31 -0
  185. package/fesm2022/ngwr-i18n-it.mjs.map +1 -1
  186. package/fesm2022/ngwr-i18n-ja.mjs +31 -0
  187. package/fesm2022/ngwr-i18n-ja.mjs.map +1 -1
  188. package/fesm2022/ngwr-i18n-ko.mjs +31 -0
  189. package/fesm2022/ngwr-i18n-ko.mjs.map +1 -1
  190. package/fesm2022/ngwr-i18n-nl.mjs +31 -0
  191. package/fesm2022/ngwr-i18n-nl.mjs.map +1 -1
  192. package/fesm2022/ngwr-i18n-pl.mjs +31 -0
  193. package/fesm2022/ngwr-i18n-pl.mjs.map +1 -1
  194. package/fesm2022/ngwr-i18n-pt.mjs +31 -0
  195. package/fesm2022/ngwr-i18n-pt.mjs.map +1 -1
  196. package/fesm2022/ngwr-i18n-ru.mjs +31 -0
  197. package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
  198. package/fesm2022/ngwr-i18n-sv.mjs +31 -0
  199. package/fesm2022/ngwr-i18n-sv.mjs.map +1 -1
  200. package/fesm2022/ngwr-i18n-tr.mjs +31 -0
  201. package/fesm2022/ngwr-i18n-tr.mjs.map +1 -1
  202. package/fesm2022/ngwr-i18n-uk.mjs +31 -0
  203. package/fesm2022/ngwr-i18n-uk.mjs.map +1 -1
  204. package/fesm2022/ngwr-i18n-vi.mjs +31 -0
  205. package/fesm2022/ngwr-i18n-vi.mjs.map +1 -1
  206. package/fesm2022/ngwr-i18n-zh-TW.mjs +31 -0
  207. package/fesm2022/ngwr-i18n-zh-TW.mjs.map +1 -1
  208. package/fesm2022/ngwr-i18n-zh.mjs +31 -0
  209. package/fesm2022/ngwr-i18n-zh.mjs.map +1 -1
  210. package/fesm2022/ngwr-i18n.mjs +9 -9
  211. package/fesm2022/ngwr-i18n.mjs.map +1 -1
  212. package/fesm2022/ngwr-icon-adapters-feather.mjs.map +1 -1
  213. package/fesm2022/ngwr-icon-adapters-lucide.mjs.map +1 -1
  214. package/fesm2022/ngwr-icon.mjs +6 -6
  215. package/fesm2022/ngwr-icon.mjs.map +1 -1
  216. package/fesm2022/ngwr-image-cropper-testing.mjs.map +1 -1
  217. package/fesm2022/ngwr-image-cropper.mjs +3 -3
  218. package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
  219. package/fesm2022/ngwr-input-number-testing.mjs.map +1 -1
  220. package/fesm2022/ngwr-input-number.mjs +15 -3
  221. package/fesm2022/ngwr-input-number.mjs.map +1 -1
  222. package/fesm2022/ngwr-input-otp-testing.mjs.map +1 -1
  223. package/fesm2022/ngwr-input-otp.mjs +3 -3
  224. package/fesm2022/ngwr-input-otp.mjs.map +1 -1
  225. package/fesm2022/ngwr-input-testing.mjs.map +1 -1
  226. package/fesm2022/ngwr-input.mjs +15 -15
  227. package/fesm2022/ngwr-input.mjs.map +1 -1
  228. package/fesm2022/ngwr-keyboard.mjs +3 -3
  229. package/fesm2022/ngwr-keyboard.mjs.map +1 -1
  230. package/fesm2022/ngwr-knob-testing.mjs.map +1 -1
  231. package/fesm2022/ngwr-knob.mjs +3 -3
  232. package/fesm2022/ngwr-knob.mjs.map +1 -1
  233. package/fesm2022/ngwr-layout.mjs +15 -15
  234. package/fesm2022/ngwr-layout.mjs.map +1 -1
  235. package/fesm2022/ngwr-lightbox-testing.mjs.map +1 -1
  236. package/fesm2022/ngwr-lightbox.mjs +3 -3
  237. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  238. package/fesm2022/ngwr-line-chart-testing.mjs.map +1 -1
  239. package/fesm2022/ngwr-line-chart.mjs +18 -7
  240. package/fesm2022/ngwr-line-chart.mjs.map +1 -1
  241. package/fesm2022/ngwr-list.mjs +6 -6
  242. package/fesm2022/ngwr-list.mjs.map +1 -1
  243. package/fesm2022/ngwr-loading-bar-router.mjs.map +1 -1
  244. package/fesm2022/ngwr-loading-bar.mjs +6 -6
  245. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  246. package/fesm2022/ngwr-markdown-testing.mjs.map +1 -1
  247. package/fesm2022/ngwr-markdown.mjs +798 -17
  248. package/fesm2022/ngwr-markdown.mjs.map +1 -1
  249. package/fesm2022/ngwr-marquee-testing.mjs.map +1 -1
  250. package/fesm2022/ngwr-marquee.mjs +3 -3
  251. package/fesm2022/ngwr-marquee.mjs.map +1 -1
  252. package/fesm2022/ngwr-media.mjs +3 -3
  253. package/fesm2022/ngwr-media.mjs.map +1 -1
  254. package/fesm2022/ngwr-mention-testing.mjs.map +1 -1
  255. package/fesm2022/ngwr-mention.mjs +6 -6
  256. package/fesm2022/ngwr-mention.mjs.map +1 -1
  257. package/fesm2022/ngwr-meta.mjs +6 -6
  258. package/fesm2022/ngwr-meta.mjs.map +1 -1
  259. package/fesm2022/ngwr-meter-group-testing.mjs +7 -3
  260. package/fesm2022/ngwr-meter-group-testing.mjs.map +1 -1
  261. package/fesm2022/ngwr-meter-group.mjs +26 -6
  262. package/fesm2022/ngwr-meter-group.mjs.map +1 -1
  263. package/fesm2022/ngwr-overlay.mjs +6 -6
  264. package/fesm2022/ngwr-overlay.mjs.map +1 -1
  265. package/fesm2022/ngwr-page-header.mjs +13 -5
  266. package/fesm2022/ngwr-page-header.mjs.map +1 -1
  267. package/fesm2022/ngwr-pagination-testing.mjs.map +1 -1
  268. package/fesm2022/ngwr-pagination.mjs +3 -3
  269. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  270. package/fesm2022/ngwr-pipes.mjs +21 -21
  271. package/fesm2022/ngwr-pipes.mjs.map +1 -1
  272. package/fesm2022/ngwr-platform.mjs +9 -9
  273. package/fesm2022/ngwr-platform.mjs.map +1 -1
  274. package/fesm2022/ngwr-popconfirm-testing.mjs.map +1 -1
  275. package/fesm2022/ngwr-popconfirm.mjs +6 -6
  276. package/fesm2022/ngwr-popconfirm.mjs.map +1 -1
  277. package/fesm2022/ngwr-popover-testing.mjs.map +1 -1
  278. package/fesm2022/ngwr-popover.mjs +578 -16
  279. package/fesm2022/ngwr-popover.mjs.map +1 -1
  280. package/fesm2022/ngwr-progress.mjs +3 -3
  281. package/fesm2022/ngwr-progress.mjs.map +1 -1
  282. package/fesm2022/ngwr-pull-to-refresh.mjs +3 -3
  283. package/fesm2022/ngwr-pull-to-refresh.mjs.map +1 -1
  284. package/fesm2022/ngwr-qr.mjs +3 -3
  285. package/fesm2022/ngwr-qr.mjs.map +1 -1
  286. package/fesm2022/ngwr-radio-testing.mjs.map +1 -1
  287. package/fesm2022/ngwr-radio.mjs +6 -6
  288. package/fesm2022/ngwr-radio.mjs.map +1 -1
  289. package/fesm2022/ngwr-rating-testing.mjs.map +1 -1
  290. package/fesm2022/ngwr-rating.mjs +3 -3
  291. package/fesm2022/ngwr-rating.mjs.map +1 -1
  292. package/fesm2022/ngwr-result.mjs +12 -12
  293. package/fesm2022/ngwr-result.mjs.map +1 -1
  294. package/fesm2022/ngwr-rotating-text-testing.mjs.map +1 -1
  295. package/fesm2022/ngwr-rotating-text.mjs +3 -3
  296. package/fesm2022/ngwr-rotating-text.mjs.map +1 -1
  297. package/fesm2022/ngwr-schema-form.mjs +3 -3
  298. package/fesm2022/ngwr-schema-form.mjs.map +1 -1
  299. package/fesm2022/ngwr-scroll.mjs +3 -3
  300. package/fesm2022/ngwr-scroll.mjs.map +1 -1
  301. package/fesm2022/ngwr-segmented-testing.mjs.map +1 -1
  302. package/fesm2022/ngwr-segmented.mjs +3 -3
  303. package/fesm2022/ngwr-segmented.mjs.map +1 -1
  304. package/fesm2022/ngwr-select-testing.mjs.map +1 -1
  305. package/fesm2022/ngwr-select.mjs +12 -12
  306. package/fesm2022/ngwr-select.mjs.map +1 -1
  307. package/fesm2022/ngwr-shiny-text-testing.mjs.map +1 -1
  308. package/fesm2022/ngwr-shiny-text.mjs +6 -6
  309. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  310. package/fesm2022/ngwr-sidebar.mjs +10 -3
  311. package/fesm2022/ngwr-sidebar.mjs.map +1 -1
  312. package/fesm2022/ngwr-skeleton.mjs +3 -3
  313. package/fesm2022/ngwr-skeleton.mjs.map +1 -1
  314. package/fesm2022/ngwr-slider-testing.mjs.map +1 -1
  315. package/fesm2022/ngwr-slider.mjs +3 -3
  316. package/fesm2022/ngwr-slider.mjs.map +1 -1
  317. package/fesm2022/ngwr-sparkline-testing.mjs.map +1 -1
  318. package/fesm2022/ngwr-sparkline.mjs +84 -10
  319. package/fesm2022/ngwr-sparkline.mjs.map +1 -1
  320. package/fesm2022/ngwr-speed-dial-testing.mjs.map +1 -1
  321. package/fesm2022/ngwr-speed-dial.mjs +3 -3
  322. package/fesm2022/ngwr-speed-dial.mjs.map +1 -1
  323. package/fesm2022/ngwr-spinner.mjs +3 -3
  324. package/fesm2022/ngwr-spinner.mjs.map +1 -1
  325. package/fesm2022/ngwr-splash-cursor-testing.mjs.map +1 -1
  326. package/fesm2022/ngwr-splash-cursor.mjs +3 -3
  327. package/fesm2022/ngwr-splash-cursor.mjs.map +1 -1
  328. package/fesm2022/ngwr-split-text-testing.mjs.map +1 -1
  329. package/fesm2022/ngwr-split-text.mjs +3 -3
  330. package/fesm2022/ngwr-split-text.mjs.map +1 -1
  331. package/fesm2022/ngwr-splitter-testing.mjs.map +1 -1
  332. package/fesm2022/ngwr-splitter.mjs +3 -3
  333. package/fesm2022/ngwr-splitter.mjs.map +1 -1
  334. package/fesm2022/ngwr-spotlight-card-testing.mjs.map +1 -1
  335. package/fesm2022/ngwr-spotlight-card.mjs +6 -6
  336. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  337. package/fesm2022/ngwr-squircle.mjs +6 -6
  338. package/fesm2022/ngwr-squircle.mjs.map +1 -1
  339. package/fesm2022/ngwr-star-border-testing.mjs.map +1 -1
  340. package/fesm2022/ngwr-star-border.mjs +3 -3
  341. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  342. package/fesm2022/ngwr-statistic.mjs +9 -9
  343. package/fesm2022/ngwr-statistic.mjs.map +1 -1
  344. package/fesm2022/ngwr-stepper-testing.mjs.map +1 -1
  345. package/fesm2022/ngwr-stepper.mjs +6 -6
  346. package/fesm2022/ngwr-stepper.mjs.map +1 -1
  347. package/fesm2022/ngwr-storage.mjs +3 -3
  348. package/fesm2022/ngwr-storage.mjs.map +1 -1
  349. package/fesm2022/ngwr-switch-testing.mjs.map +1 -1
  350. package/fesm2022/ngwr-switch.mjs +3 -3
  351. package/fesm2022/ngwr-switch.mjs.map +1 -1
  352. package/fesm2022/ngwr-table-testing.mjs.map +1 -1
  353. package/fesm2022/ngwr-table.mjs +18 -18
  354. package/fesm2022/ngwr-table.mjs.map +1 -1
  355. package/fesm2022/ngwr-tabs-router.mjs +3 -3
  356. package/fesm2022/ngwr-tabs-router.mjs.map +1 -1
  357. package/fesm2022/ngwr-tabs-testing.mjs.map +1 -1
  358. package/fesm2022/ngwr-tabs.mjs +6 -6
  359. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  360. package/fesm2022/ngwr-textarea-testing.mjs.map +1 -1
  361. package/fesm2022/ngwr-textarea.mjs +3 -3
  362. package/fesm2022/ngwr-textarea.mjs.map +1 -1
  363. package/fesm2022/ngwr-theme.mjs +3 -3
  364. package/fesm2022/ngwr-theme.mjs.map +1 -1
  365. package/fesm2022/ngwr-tilt-card-testing.mjs.map +1 -1
  366. package/fesm2022/ngwr-tilt-card.mjs +6 -6
  367. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  368. package/fesm2022/ngwr-timeline.mjs +6 -6
  369. package/fesm2022/ngwr-timeline.mjs.map +1 -1
  370. package/fesm2022/ngwr-toast-testing.mjs.map +1 -1
  371. package/fesm2022/ngwr-toast.mjs +9 -9
  372. package/fesm2022/ngwr-toast.mjs.map +1 -1
  373. package/fesm2022/ngwr-toolbar.mjs +10 -3
  374. package/fesm2022/ngwr-toolbar.mjs.map +1 -1
  375. package/fesm2022/ngwr-tour-testing.mjs.map +1 -1
  376. package/fesm2022/ngwr-tour.mjs +6 -6
  377. package/fesm2022/ngwr-tour.mjs.map +1 -1
  378. package/fesm2022/ngwr-transfer-testing.mjs.map +1 -1
  379. package/fesm2022/ngwr-transfer.mjs +3 -3
  380. package/fesm2022/ngwr-transfer.mjs.map +1 -1
  381. package/fesm2022/ngwr-tree-testing.mjs.map +1 -1
  382. package/fesm2022/ngwr-tree.mjs +3 -3
  383. package/fesm2022/ngwr-tree.mjs.map +1 -1
  384. package/fesm2022/ngwr-typewriter-testing.mjs.map +1 -1
  385. package/fesm2022/ngwr-typewriter.mjs +3 -3
  386. package/fesm2022/ngwr-typewriter.mjs.map +1 -1
  387. package/fesm2022/ngwr-typography.mjs +7 -3
  388. package/fesm2022/ngwr-typography.mjs.map +1 -1
  389. package/fesm2022/ngwr-utils.mjs.map +1 -1
  390. package/fesm2022/ngwr-validators.mjs.map +1 -1
  391. package/fesm2022/ngwr-version.mjs +1 -1
  392. package/fesm2022/ngwr-version.mjs.map +1 -1
  393. package/fesm2022/ngwr-virtual-scroll.mjs +3 -3
  394. package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
  395. package/fesm2022/ngwr-waves-testing.mjs.map +1 -1
  396. package/fesm2022/ngwr-waves.mjs +3 -3
  397. package/fesm2022/ngwr-waves.mjs.map +1 -1
  398. package/fesm2022/ngwr-window-testing.mjs.map +1 -1
  399. package/fesm2022/ngwr-window.mjs +12 -12
  400. package/fesm2022/ngwr-window.mjs.map +1 -1
  401. package/form/styles/_index.scss +16 -1
  402. package/gauge/styles/_index.scss +1 -0
  403. package/i18n/ar.json +32 -1
  404. package/i18n/cs.json +32 -1
  405. package/i18n/de.json +32 -1
  406. package/i18n/en.json +32 -1
  407. package/i18n/es.json +32 -1
  408. package/i18n/fr.json +32 -1
  409. package/i18n/he.json +32 -1
  410. package/i18n/hi.json +32 -1
  411. package/i18n/id.json +32 -1
  412. package/i18n/it.json +32 -1
  413. package/i18n/ja.json +32 -1
  414. package/i18n/ko.json +32 -1
  415. package/i18n/nl.json +32 -1
  416. package/i18n/pl.json +32 -1
  417. package/i18n/pt.json +32 -1
  418. package/i18n/ru.json +32 -1
  419. package/i18n/sv.json +32 -1
  420. package/i18n/tr.json +32 -1
  421. package/i18n/uk.json +32 -1
  422. package/i18n/vi.json +32 -1
  423. package/i18n/zh-TW.json +32 -1
  424. package/i18n/zh.json +32 -1
  425. package/input/styles/_index.scss +24 -1
  426. package/input-number/styles/_index.scss +69 -0
  427. package/input-otp/styles/_index.scss +5 -5
  428. package/line-chart/styles/_index.scss +30 -2
  429. package/llms-full.txt +14 -4
  430. package/llms.txt +188 -132
  431. package/mcp/providers.js +2 -2
  432. package/mcp/server.js +1 -1
  433. package/meter-group/styles/_index.scss +1 -0
  434. package/overlay/styles/_arrow.scss +30 -2
  435. package/package.json +43 -2
  436. package/page-header/styles/_index.scss +37 -1
  437. package/pagination/styles/_index.scss +9 -5
  438. package/popover/styles/_index.scss +73 -5
  439. package/progress/styles/_index.scss +4 -0
  440. package/radio/styles/_index.scss +4 -1
  441. package/schematics/use/symbol-map.json +1 -0
  442. package/select/styles/_index.scss +51 -12
  443. package/sidebar/styles/_index.scss +44 -2
  444. package/skeleton/styles/_index.scss +3 -0
  445. package/skills/ngwr/SKILL.md +5 -5
  446. package/skills/ngwr/references/catalog.md +2 -0
  447. package/skills/ngwr/references/setup.md +3 -3
  448. package/sparkline/styles/_index.scss +19 -0
  449. package/styles.scss +1 -0
  450. package/table/styles/_index.scss +7 -0
  451. package/textarea/styles/_index.scss +12 -3
  452. package/theme/styles/_colors.scss +39 -13
  453. package/theme/styles/_contrast.scss +9 -7
  454. package/toast/styles/_index.scss +4 -0
  455. package/toolbar/styles/_index.scss +35 -1
  456. package/tree/styles/_index.scss +46 -7
  457. package/types/ngwr-badge.d.ts +22 -7
  458. package/types/ngwr-bar-chart.d.ts +19 -1
  459. package/types/ngwr-calendar-heatmap.d.ts +29 -1
  460. package/types/ngwr-checkbox.d.ts +2 -0
  461. package/types/ngwr-config.d.ts +12 -0
  462. package/types/ngwr-date-picker.d.ts +308 -43
  463. package/types/ngwr-donut-chart.d.ts +24 -1
  464. package/types/ngwr-dropdown.d.ts +22 -2
  465. package/types/ngwr-editor-testing.d.ts +378 -0
  466. package/types/ngwr-editor.d.ts +449 -0
  467. package/types/ngwr-event-calendar.d.ts +8 -0
  468. package/types/ngwr-form.d.ts +35 -5
  469. package/types/ngwr-gauge.d.ts +20 -1
  470. package/types/ngwr-input-number.d.ts +7 -0
  471. package/types/ngwr-line-chart.d.ts +9 -1
  472. package/types/ngwr-markdown.d.ts +61 -2
  473. package/types/ngwr-meter-group-testing.d.ts +3 -2
  474. package/types/ngwr-meter-group.d.ts +14 -1
  475. package/types/ngwr-page-header.d.ts +10 -2
  476. package/types/ngwr-popover.d.ts +154 -3
  477. package/types/ngwr-sidebar.d.ts +7 -0
  478. package/types/ngwr-sparkline.d.ts +43 -1
  479. package/types/ngwr-toolbar.d.ts +7 -0
  480. package/types/ngwr-typography.d.ts +4 -0
  481. package/types/ngwr-version.d.ts +1 -1
  482. package/typography/styles/_index.scss +16 -0
@@ -495,6 +495,32 @@ const MAX_LABEL_LENGTH = 999;
495
495
  const MAX_DESTINATION_NESTING = 32;
496
496
  const BARE_URL_RE = /^https?:\/\/[^\s<>[\]()]*(?:\([^\s<>()]*\)[^\s<>[\]()]*)*/i;
497
497
  const EMAIL_AUTOLINK_RE = /^<([^\s@<>]+@[^\s@<>.]+\.[^\s@<>]+)>/;
498
+ /**
499
+ * Whitespace and control characters only: a hyphen has no business being
500
+ * stripped out of a host name. Written as escapes rather than literal bytes — a
501
+ * raw NUL inside a regex literal makes the file binary to every text tool.
502
+ * Stripping control characters is the entire point: a browser ignores them before
503
+ * resolving the scheme, so a check that reads the raw string sees a relative path
504
+ * and waves `java\u0000script:` straight through.
505
+ */
506
+ // eslint-disable-next-line no-control-regex
507
+ const URL_IGNORED_RE = /[\s\u0000-\u001f\u007f]/g;
508
+ /**
509
+ * The character references a CommonMark renderer decodes in a link destination
510
+ * that can spell a scheme: every numeric one, and the named ones for the colon
511
+ * and for the whitespace a browser strips (`&colon;`, `&Tab;`, `&NewLine;`).
512
+ * Matched without regard to case and with the semicolon optional, which is wider
513
+ * than any renderer decodes — the net only ever catches a URL nobody writes.
514
+ */
515
+ const SCHEME_REFERENCE_RE = /&(?:#x([0-9a-f]+)|#(\d+)|(colon|tab|newline));?/gi;
516
+ function decodeSchemeReferences(url) {
517
+ return url.replace(SCHEME_REFERENCE_RE, (_reference, hex, decimal, name) => {
518
+ if (name)
519
+ return name.toLowerCase() === 'colon' ? ':' : '\n';
520
+ const code = hex ? Number.parseInt(hex, 16) : Number(decimal);
521
+ return code > 0 && code <= 0x10ffff ? String.fromCodePoint(code) : '\ufffd';
522
+ });
523
+ }
498
524
  /**
499
525
  * A URL safe to put in `href` / `src`, or `null` to render the link as plain text.
500
526
  *
@@ -505,19 +531,16 @@ const EMAIL_AUTOLINK_RE = /^<([^\s@<>]+@[^\s@<>.]+\.[^\s@<>]+)>/;
505
531
  *
506
532
  * Whitespace and control characters are stripped before the scheme is read,
507
533
  * because `java\nscript:` and `java script:` are the same URL to a browser and
508
- * different strings to a naive check.
534
+ * different strings to a naive check. So are character references:
535
+ * `javascript&colon;` has no scheme to this check, but a CommonMark renderer
536
+ * decodes it in a destination, so any markdown the URL is written into — an
537
+ * editor's output, say — hands a browser `javascript:`. The scheme is read from
538
+ * the decoded form; what comes back is still the URL as written.
509
539
  */
510
540
  function safeMarkdownUrl(raw, kind) {
511
541
  const url = raw.trim();
512
- // Whitespace and control characters only: a hyphen has no business being
513
- // stripped out of a host name. Written as escapes rather than literal bytes —
514
- // a raw NUL inside a regex literal makes the file binary to every text tool.
515
- // Stripping control characters is the entire point here: a browser ignores them
516
- // before resolving the scheme, so a check that reads the raw string sees a
517
- // relative path and waves `java\u0000script:` straight through.
518
- // eslint-disable-next-line no-control-regex
519
- const bare = url.replace(/[\s\u0000-\u001f\u007f]/g, '');
520
- const scheme = SCHEME_RE.exec(bare);
542
+ const bare = url.replace(URL_IGNORED_RE, '');
543
+ const scheme = SCHEME_RE.exec(decodeSchemeReferences(bare).replace(URL_IGNORED_RE, ''));
521
544
  // No scheme at all: relative path, `#anchor`, `//host` — nothing executable.
522
545
  if (!scheme)
523
546
  return url;
@@ -1295,10 +1318,10 @@ class WrMarkdownHighlight {
1295
1318
  this.cache.delete(oldest.value);
1296
1319
  }
1297
1320
  }
1298
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrMarkdownHighlight, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1299
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrMarkdownHighlight, providedIn: 'root' });
1321
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrMarkdownHighlight, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1322
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrMarkdownHighlight, providedIn: 'root' });
1300
1323
  }
1301
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrMarkdownHighlight, decorators: [{
1324
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrMarkdownHighlight, decorators: [{
1302
1325
  type: Injectable,
1303
1326
  args: [{ providedIn: 'root' }]
1304
1327
  }] });
@@ -1539,10 +1562,10 @@ class WrMarkdown {
1539
1562
  asCells(value) {
1540
1563
  return value;
1541
1564
  }
1542
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrMarkdown, deps: [], target: i0.ɵɵFactoryTarget.Component });
1543
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: WrMarkdown, isStandalone: true, selector: "wr-markdown", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, streaming: { classPropertyName: "streaming", publicName: "streaming", isSignal: true, isRequired: false, transformFunction: null }, copyable: { classPropertyName: "copyable", publicName: "copyable", isSignal: true, isRequired: false, transformFunction: null }, linkTarget: { classPropertyName: "linkTarget", publicName: "linkTarget", isSignal: true, isRequired: false, transformFunction: null }, headingIds: { classPropertyName: "headingIds", publicName: "headingIds", isSignal: true, isRequired: false, transformFunction: null }, headingIdPrefix: { classPropertyName: "headingIdPrefix", publicName: "headingIdPrefix", isSignal: true, isRequired: false, transformFunction: null }, copyLabel: { classPropertyName: "copyLabel", publicName: "copyLabel", isSignal: true, isRequired: false, transformFunction: null }, copiedLabel: { classPropertyName: "copiedLabel", publicName: "copiedLabel", isSignal: true, isRequired: false, transformFunction: null }, taskDoneLabel: { classPropertyName: "taskDoneLabel", publicName: "taskDoneLabel", isSignal: true, isRequired: false, transformFunction: null }, taskTodoLabel: { classPropertyName: "taskTodoLabel", publicName: "taskTodoLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.wr-markdown--streaming": "streaming()" }, classAttribute: "wr-markdown" }, ngImport: i0, template: "<!--\n Recursion runs through `ngTemplateOutlet` into these templates rather than\n through a child component, so the rendered DOM is exactly the document \u2014 no\n wrapper element between a `<ul>` and its `<li>`. See `asBlocks` for the whole\n reasoning.\n-->\n<ng-template #inlineList let-raw>\n @let nodes = asInlines(raw);\n\n @for (node of nodes; track $index) {\n @switch (node.kind) {\n @case ('text') {\n <!-- Wrapped, and not for tidiness: a bare interpolation on its own line is\n ONE text node that includes the indentation around it, so `a **b** c`\n rendered with a space inside every `<strong>`. Inside an element the\n whitespace becomes separate whitespace-only nodes, which Angular\n removes, and `<ng-container>` itself renders nothing. Prettier\n reformats the bare form back, so this also has to survive `--fix`. -->\n <ng-container>{{ node.value }}</ng-container>\n }\n @case ('code') {\n <!-- `dir=\"ltr\"` because code is not prose: under RTL the browser\n reorders `foo();` to `;foo()`. -->\n <code class=\"wr-markdown__code-inline\" dir=\"ltr\">{{ node.value }}</code>\n }\n @case ('strong') {\n <strong class=\"wr-markdown__strong\"\n ><ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: node.children }\"\n /></strong>\n }\n @case ('em') {\n <em class=\"wr-markdown__em\"\n ><ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: node.children }\"\n /></em>\n }\n @case ('del') {\n <del class=\"wr-markdown__del\"\n ><ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: node.children }\"\n /></del>\n }\n @case ('link') {\n <a\n class=\"wr-markdown__link\"\n [href]=\"hrefOf(node.href)\"\n [attr.title]=\"node.title\"\n [attr.target]=\"resolvedLinkTarget()\"\n [attr.rel]=\"linkRel()\"\n ><ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: node.children }\"\n /></a>\n }\n @case ('image') {\n <img\n class=\"wr-markdown__image\"\n [src]=\"node.src\"\n [alt]=\"node.alt\"\n [attr.title]=\"node.title\"\n loading=\"lazy\"\n decoding=\"async\"\n />\n }\n @case ('break') {\n <br />\n }\n }\n }\n</ng-template>\n\n<ng-template #itemList let-raw let-tight=\"tight\">\n @let items = asItems(raw);\n\n @for (item of items; track $index) {\n <li class=\"wr-markdown__item\" [class.wr-markdown__item--task]=\"item.checked !== null\">\n @if (item.checked !== null) {\n <!-- Presentational, with the state as text beside it: a real\n `<input type=\"checkbox\">` here would be an unlabelled form control,\n which is a serious axe violation, and making it operable would\n promise an interaction a renderer cannot honour. -->\n <span class=\"wr-markdown__task\" [class.wr-markdown__task--checked]=\"item.checked\" aria-hidden=\"true\"></span>\n <span class=\"wr-markdown__sr-only\">{{ item.checked ? resolvedTaskDoneLabel() : resolvedTaskTodoLabel() }}</span>\n }\n <ng-container\n [ngTemplateOutlet]=\"blockList\"\n [ngTemplateOutletContext]=\"{ $implicit: item.children, tight: tight }\"\n />\n </li>\n }\n</ng-template>\n\n<ng-template #blockList let-raw let-tight=\"tight\">\n @let list = asBlocks(raw);\n\n @for (block of list; track $index) {\n @switch (block.kind) {\n @case ('paragraph') {\n <!-- A tight list drops the `<p>`, which is what CommonMark specifies and\n what keeps a one-line list from being double-spaced. -->\n @if (tight) {\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n } @else {\n <p class=\"wr-markdown__paragraph\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </p>\n }\n }\n @case ('heading') {\n @switch (block.level) {\n @case (1) {\n <h1 class=\"wr-markdown__heading\" [attr.id]=\"idOf(block.id)\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </h1>\n }\n @case (2) {\n <h2 class=\"wr-markdown__heading\" [attr.id]=\"idOf(block.id)\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </h2>\n }\n @case (3) {\n <h3 class=\"wr-markdown__heading\" [attr.id]=\"idOf(block.id)\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </h3>\n }\n @case (4) {\n <h4 class=\"wr-markdown__heading\" [attr.id]=\"idOf(block.id)\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </h4>\n }\n @case (5) {\n <h5 class=\"wr-markdown__heading\" [attr.id]=\"idOf(block.id)\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </h5>\n }\n @default {\n <h6 class=\"wr-markdown__heading\" [attr.id]=\"idOf(block.id)\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </h6>\n }\n }\n }\n @case ('code') {\n @let highlighted = linesOf(block.code, block.language);\n\n <div class=\"wr-markdown__code-block\">\n <pre\n class=\"wr-markdown__pre\"\n dir=\"ltr\"\n tabindex=\"0\"\n ><code class=\"wr-markdown__code\" [attr.data-language]=\"block.language\">@if (highlighted) {@for (row of highlighted; track $index) {<span class=\"wr-markdown__line\">@for (span of row; track $index) {<span\n [style.color]=\"span.color\"\n [style.font-style]=\"span.fontStyle === 'italic' ? 'italic' : null\"\n [style.font-weight]=\"span.fontStyle === 'bold' ? 'bold' : null\"\n [style.text-decoration]=\"span.fontStyle === 'underline' ? 'underline' : null\"\n >{{ span.text }}</span>}</span>@if (!$last) {{{ newline }}}}} @else {{{ block.code }}}</code></pre>\n\n @if (resolvedCopyable() && block.closed) {\n <button\n type=\"button\"\n class=\"wr-markdown__copy\"\n [wrCopyToClipboard]=\"block.code\"\n [attr.aria-label]=\"isCopied(block) ? resolvedCopiedLabel() : resolvedCopyLabel()\"\n (copied)=\"onCopied(block)\"\n >\n <svg\n class=\"wr-markdown__copy-icon\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n @if (isCopied(block)) {\n <path d=\"M20 6 9 17l-5-5\" />\n } @else {\n <rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\" />\n <path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" />\n }\n </svg>\n </button>\n }\n </div>\n }\n @case ('quote') {\n <blockquote class=\"wr-markdown__quote\">\n <ng-container\n [ngTemplateOutlet]=\"blockList\"\n [ngTemplateOutletContext]=\"{ $implicit: block.children, tight: false }\"\n />\n </blockquote>\n }\n @case ('list') {\n @if (block.ordered) {\n <ol\n class=\"wr-markdown__list wr-markdown__list--ordered\"\n [attr.start]=\"block.start === 1 ? null : block.start\"\n >\n <ng-container\n [ngTemplateOutlet]=\"itemList\"\n [ngTemplateOutletContext]=\"{ $implicit: block.items, tight: block.tight }\"\n />\n </ol>\n } @else {\n <ul class=\"wr-markdown__list\">\n <ng-container\n [ngTemplateOutlet]=\"itemList\"\n [ngTemplateOutletContext]=\"{ $implicit: block.items, tight: block.tight }\"\n />\n </ul>\n }\n }\n @case ('table') {\n <!-- Its own scroller: a wide table must not push the page sideways, which\n is also what keeps the RTL layout gate quiet about it. -->\n <div class=\"wr-markdown__table-scroll\" tabindex=\"0\">\n <table class=\"wr-markdown__table\">\n <thead>\n <tr>\n @for (cell of block.head; track column; let column = $index) {\n <th class=\"wr-markdown__th\" scope=\"col\" [style.text-align]=\"block.align[column]\">\n <ng-container\n [ngTemplateOutlet]=\"inlineList\"\n [ngTemplateOutletContext]=\"{ $implicit: cell.inlines }\"\n />\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of block.rows; track $index) {\n <tr>\n @for (cell of asCells(row); track column; let column = $index) {\n <td class=\"wr-markdown__td\" [style.text-align]=\"block.align[column]\">\n <ng-container\n [ngTemplateOutlet]=\"inlineList\"\n [ngTemplateOutletContext]=\"{ $implicit: cell.inlines }\"\n />\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n @case ('rule') {\n <hr class=\"wr-markdown__rule\" />\n }\n }\n }\n</ng-template>\n\n<ng-container [ngTemplateOutlet]=\"blockList\" [ngTemplateOutletContext]=\"{ $implicit: blocks(), tight: false }\" />\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: WrCopyToClipboard, selector: "[wrCopyToClipboard]", inputs: ["wrCopyToClipboard"], outputs: ["copied", "copyFailed"] }], encapsulation: i0.ViewEncapsulation.None });
1565
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrMarkdown, deps: [], target: i0.ɵɵFactoryTarget.Component });
1566
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: WrMarkdown, isStandalone: true, selector: "wr-markdown", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, streaming: { classPropertyName: "streaming", publicName: "streaming", isSignal: true, isRequired: false, transformFunction: null }, copyable: { classPropertyName: "copyable", publicName: "copyable", isSignal: true, isRequired: false, transformFunction: null }, linkTarget: { classPropertyName: "linkTarget", publicName: "linkTarget", isSignal: true, isRequired: false, transformFunction: null }, headingIds: { classPropertyName: "headingIds", publicName: "headingIds", isSignal: true, isRequired: false, transformFunction: null }, headingIdPrefix: { classPropertyName: "headingIdPrefix", publicName: "headingIdPrefix", isSignal: true, isRequired: false, transformFunction: null }, copyLabel: { classPropertyName: "copyLabel", publicName: "copyLabel", isSignal: true, isRequired: false, transformFunction: null }, copiedLabel: { classPropertyName: "copiedLabel", publicName: "copiedLabel", isSignal: true, isRequired: false, transformFunction: null }, taskDoneLabel: { classPropertyName: "taskDoneLabel", publicName: "taskDoneLabel", isSignal: true, isRequired: false, transformFunction: null }, taskTodoLabel: { classPropertyName: "taskTodoLabel", publicName: "taskTodoLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.wr-markdown--streaming": "streaming()" }, classAttribute: "wr-markdown" }, ngImport: i0, template: "<!--\n Recursion runs through `ngTemplateOutlet` into these templates rather than\n through a child component, so the rendered DOM is exactly the document \u2014 no\n wrapper element between a `<ul>` and its `<li>`. See `asBlocks` for the whole\n reasoning.\n-->\n<ng-template #inlineList let-raw>\n @let nodes = asInlines(raw);\n\n @for (node of nodes; track $index) {\n @switch (node.kind) {\n @case ('text') {\n <!-- Wrapped, and not for tidiness: a bare interpolation on its own line is\n ONE text node that includes the indentation around it, so `a **b** c`\n rendered with a space inside every `<strong>`. Inside an element the\n whitespace becomes separate whitespace-only nodes, which Angular\n removes, and `<ng-container>` itself renders nothing. Prettier\n reformats the bare form back, so this also has to survive `--fix`. -->\n <ng-container>{{ node.value }}</ng-container>\n }\n @case ('code') {\n <!-- `dir=\"ltr\"` because code is not prose: under RTL the browser\n reorders `foo();` to `;foo()`. -->\n <code class=\"wr-markdown__code-inline\" dir=\"ltr\">{{ node.value }}</code>\n }\n @case ('strong') {\n <strong class=\"wr-markdown__strong\"\n ><ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: node.children }\"\n /></strong>\n }\n @case ('em') {\n <em class=\"wr-markdown__em\"\n ><ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: node.children }\"\n /></em>\n }\n @case ('del') {\n <del class=\"wr-markdown__del\"\n ><ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: node.children }\"\n /></del>\n }\n @case ('link') {\n <a\n class=\"wr-markdown__link\"\n [href]=\"hrefOf(node.href)\"\n [attr.title]=\"node.title\"\n [attr.target]=\"resolvedLinkTarget()\"\n [attr.rel]=\"linkRel()\"\n ><ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: node.children }\"\n /></a>\n }\n @case ('image') {\n <img\n class=\"wr-markdown__image\"\n [src]=\"node.src\"\n [alt]=\"node.alt\"\n [attr.title]=\"node.title\"\n loading=\"lazy\"\n decoding=\"async\"\n />\n }\n @case ('break') {\n <br />\n }\n }\n }\n</ng-template>\n\n<ng-template #itemList let-raw let-tight=\"tight\">\n @let items = asItems(raw);\n\n @for (item of items; track $index) {\n <li class=\"wr-markdown__item\" [class.wr-markdown__item--task]=\"item.checked !== null\">\n @if (item.checked !== null) {\n <!-- Presentational, with the state as text beside it: a real\n `<input type=\"checkbox\">` here would be an unlabelled form control,\n which is a serious axe violation, and making it operable would\n promise an interaction a renderer cannot honour. -->\n <span class=\"wr-markdown__task\" [class.wr-markdown__task--checked]=\"item.checked\" aria-hidden=\"true\"></span>\n <span class=\"wr-markdown__sr-only\">{{ item.checked ? resolvedTaskDoneLabel() : resolvedTaskTodoLabel() }}</span>\n }\n <ng-container\n [ngTemplateOutlet]=\"blockList\"\n [ngTemplateOutletContext]=\"{ $implicit: item.children, tight: tight }\"\n />\n </li>\n }\n</ng-template>\n\n<ng-template #blockList let-raw let-tight=\"tight\">\n @let list = asBlocks(raw);\n\n @for (block of list; track $index) {\n @switch (block.kind) {\n @case ('paragraph') {\n <!-- A tight list drops the `<p>`, which is what CommonMark specifies and\n what keeps a one-line list from being double-spaced. -->\n @if (tight) {\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n } @else {\n <p class=\"wr-markdown__paragraph\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </p>\n }\n }\n @case ('heading') {\n @switch (block.level) {\n @case (1) {\n <h1 class=\"wr-markdown__heading\" [attr.id]=\"idOf(block.id)\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </h1>\n }\n @case (2) {\n <h2 class=\"wr-markdown__heading\" [attr.id]=\"idOf(block.id)\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </h2>\n }\n @case (3) {\n <h3 class=\"wr-markdown__heading\" [attr.id]=\"idOf(block.id)\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </h3>\n }\n @case (4) {\n <h4 class=\"wr-markdown__heading\" [attr.id]=\"idOf(block.id)\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </h4>\n }\n @case (5) {\n <h5 class=\"wr-markdown__heading\" [attr.id]=\"idOf(block.id)\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </h5>\n }\n @default {\n <h6 class=\"wr-markdown__heading\" [attr.id]=\"idOf(block.id)\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </h6>\n }\n }\n }\n @case ('code') {\n @let highlighted = linesOf(block.code, block.language);\n\n <div class=\"wr-markdown__code-block\">\n <pre\n class=\"wr-markdown__pre\"\n dir=\"ltr\"\n tabindex=\"0\"\n ><code class=\"wr-markdown__code\" [attr.data-language]=\"block.language\">@if (highlighted) {@for (row of highlighted; track $index) {<span class=\"wr-markdown__line\">@for (span of row; track $index) {<span\n [style.color]=\"span.color\"\n [style.font-style]=\"span.fontStyle === 'italic' ? 'italic' : null\"\n [style.font-weight]=\"span.fontStyle === 'bold' ? 'bold' : null\"\n [style.text-decoration]=\"span.fontStyle === 'underline' ? 'underline' : null\"\n >{{ span.text }}</span>}</span>@if (!$last) {{{ newline }}}}} @else {{{ block.code }}}</code></pre>\n\n @if (resolvedCopyable() && block.closed) {\n <button\n type=\"button\"\n class=\"wr-markdown__copy\"\n [wrCopyToClipboard]=\"block.code\"\n [attr.aria-label]=\"isCopied(block) ? resolvedCopiedLabel() : resolvedCopyLabel()\"\n (copied)=\"onCopied(block)\"\n >\n <svg\n class=\"wr-markdown__copy-icon\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n @if (isCopied(block)) {\n <path d=\"M20 6 9 17l-5-5\" />\n } @else {\n <rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\" />\n <path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" />\n }\n </svg>\n </button>\n }\n </div>\n }\n @case ('quote') {\n <blockquote class=\"wr-markdown__quote\">\n <ng-container\n [ngTemplateOutlet]=\"blockList\"\n [ngTemplateOutletContext]=\"{ $implicit: block.children, tight: false }\"\n />\n </blockquote>\n }\n @case ('list') {\n @if (block.ordered) {\n <ol\n class=\"wr-markdown__list wr-markdown__list--ordered\"\n [attr.start]=\"block.start === 1 ? null : block.start\"\n >\n <ng-container\n [ngTemplateOutlet]=\"itemList\"\n [ngTemplateOutletContext]=\"{ $implicit: block.items, tight: block.tight }\"\n />\n </ol>\n } @else {\n <ul class=\"wr-markdown__list\">\n <ng-container\n [ngTemplateOutlet]=\"itemList\"\n [ngTemplateOutletContext]=\"{ $implicit: block.items, tight: block.tight }\"\n />\n </ul>\n }\n }\n @case ('table') {\n <!-- Its own scroller: a wide table must not push the page sideways, which\n is also what keeps the RTL layout gate quiet about it. -->\n <div class=\"wr-markdown__table-scroll\" tabindex=\"0\">\n <table class=\"wr-markdown__table\">\n <thead>\n <tr>\n @for (cell of block.head; track column; let column = $index) {\n <th class=\"wr-markdown__th\" scope=\"col\" [style.text-align]=\"block.align[column]\">\n <ng-container\n [ngTemplateOutlet]=\"inlineList\"\n [ngTemplateOutletContext]=\"{ $implicit: cell.inlines }\"\n />\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of block.rows; track $index) {\n <tr>\n @for (cell of asCells(row); track column; let column = $index) {\n <td class=\"wr-markdown__td\" [style.text-align]=\"block.align[column]\">\n <ng-container\n [ngTemplateOutlet]=\"inlineList\"\n [ngTemplateOutletContext]=\"{ $implicit: cell.inlines }\"\n />\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n @case ('rule') {\n <hr class=\"wr-markdown__rule\" />\n }\n }\n }\n</ng-template>\n\n<ng-container [ngTemplateOutlet]=\"blockList\" [ngTemplateOutletContext]=\"{ $implicit: blocks(), tight: false }\" />\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: WrCopyToClipboard, selector: "[wrCopyToClipboard]", inputs: ["wrCopyToClipboard"], outputs: ["copied", "copyFailed"] }], encapsulation: i0.ViewEncapsulation.None });
1544
1567
  }
1545
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrMarkdown, decorators: [{
1568
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrMarkdown, decorators: [{
1546
1569
  type: Component,
1547
1570
  args: [{ selector: 'wr-markdown', imports: [NgTemplateOutlet, WrCopyToClipboard], encapsulation: ViewEncapsulation.None, host: {
1548
1571
  class: 'wr-markdown',
@@ -1550,6 +1573,764 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
1550
1573
  }, template: "<!--\n Recursion runs through `ngTemplateOutlet` into these templates rather than\n through a child component, so the rendered DOM is exactly the document \u2014 no\n wrapper element between a `<ul>` and its `<li>`. See `asBlocks` for the whole\n reasoning.\n-->\n<ng-template #inlineList let-raw>\n @let nodes = asInlines(raw);\n\n @for (node of nodes; track $index) {\n @switch (node.kind) {\n @case ('text') {\n <!-- Wrapped, and not for tidiness: a bare interpolation on its own line is\n ONE text node that includes the indentation around it, so `a **b** c`\n rendered with a space inside every `<strong>`. Inside an element the\n whitespace becomes separate whitespace-only nodes, which Angular\n removes, and `<ng-container>` itself renders nothing. Prettier\n reformats the bare form back, so this also has to survive `--fix`. -->\n <ng-container>{{ node.value }}</ng-container>\n }\n @case ('code') {\n <!-- `dir=\"ltr\"` because code is not prose: under RTL the browser\n reorders `foo();` to `;foo()`. -->\n <code class=\"wr-markdown__code-inline\" dir=\"ltr\">{{ node.value }}</code>\n }\n @case ('strong') {\n <strong class=\"wr-markdown__strong\"\n ><ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: node.children }\"\n /></strong>\n }\n @case ('em') {\n <em class=\"wr-markdown__em\"\n ><ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: node.children }\"\n /></em>\n }\n @case ('del') {\n <del class=\"wr-markdown__del\"\n ><ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: node.children }\"\n /></del>\n }\n @case ('link') {\n <a\n class=\"wr-markdown__link\"\n [href]=\"hrefOf(node.href)\"\n [attr.title]=\"node.title\"\n [attr.target]=\"resolvedLinkTarget()\"\n [attr.rel]=\"linkRel()\"\n ><ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: node.children }\"\n /></a>\n }\n @case ('image') {\n <img\n class=\"wr-markdown__image\"\n [src]=\"node.src\"\n [alt]=\"node.alt\"\n [attr.title]=\"node.title\"\n loading=\"lazy\"\n decoding=\"async\"\n />\n }\n @case ('break') {\n <br />\n }\n }\n }\n</ng-template>\n\n<ng-template #itemList let-raw let-tight=\"tight\">\n @let items = asItems(raw);\n\n @for (item of items; track $index) {\n <li class=\"wr-markdown__item\" [class.wr-markdown__item--task]=\"item.checked !== null\">\n @if (item.checked !== null) {\n <!-- Presentational, with the state as text beside it: a real\n `<input type=\"checkbox\">` here would be an unlabelled form control,\n which is a serious axe violation, and making it operable would\n promise an interaction a renderer cannot honour. -->\n <span class=\"wr-markdown__task\" [class.wr-markdown__task--checked]=\"item.checked\" aria-hidden=\"true\"></span>\n <span class=\"wr-markdown__sr-only\">{{ item.checked ? resolvedTaskDoneLabel() : resolvedTaskTodoLabel() }}</span>\n }\n <ng-container\n [ngTemplateOutlet]=\"blockList\"\n [ngTemplateOutletContext]=\"{ $implicit: item.children, tight: tight }\"\n />\n </li>\n }\n</ng-template>\n\n<ng-template #blockList let-raw let-tight=\"tight\">\n @let list = asBlocks(raw);\n\n @for (block of list; track $index) {\n @switch (block.kind) {\n @case ('paragraph') {\n <!-- A tight list drops the `<p>`, which is what CommonMark specifies and\n what keeps a one-line list from being double-spaced. -->\n @if (tight) {\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n } @else {\n <p class=\"wr-markdown__paragraph\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </p>\n }\n }\n @case ('heading') {\n @switch (block.level) {\n @case (1) {\n <h1 class=\"wr-markdown__heading\" [attr.id]=\"idOf(block.id)\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </h1>\n }\n @case (2) {\n <h2 class=\"wr-markdown__heading\" [attr.id]=\"idOf(block.id)\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </h2>\n }\n @case (3) {\n <h3 class=\"wr-markdown__heading\" [attr.id]=\"idOf(block.id)\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </h3>\n }\n @case (4) {\n <h4 class=\"wr-markdown__heading\" [attr.id]=\"idOf(block.id)\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </h4>\n }\n @case (5) {\n <h5 class=\"wr-markdown__heading\" [attr.id]=\"idOf(block.id)\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </h5>\n }\n @default {\n <h6 class=\"wr-markdown__heading\" [attr.id]=\"idOf(block.id)\">\n <ng-container [ngTemplateOutlet]=\"inlineList\" [ngTemplateOutletContext]=\"{ $implicit: block.inlines }\" />\n </h6>\n }\n }\n }\n @case ('code') {\n @let highlighted = linesOf(block.code, block.language);\n\n <div class=\"wr-markdown__code-block\">\n <pre\n class=\"wr-markdown__pre\"\n dir=\"ltr\"\n tabindex=\"0\"\n ><code class=\"wr-markdown__code\" [attr.data-language]=\"block.language\">@if (highlighted) {@for (row of highlighted; track $index) {<span class=\"wr-markdown__line\">@for (span of row; track $index) {<span\n [style.color]=\"span.color\"\n [style.font-style]=\"span.fontStyle === 'italic' ? 'italic' : null\"\n [style.font-weight]=\"span.fontStyle === 'bold' ? 'bold' : null\"\n [style.text-decoration]=\"span.fontStyle === 'underline' ? 'underline' : null\"\n >{{ span.text }}</span>}</span>@if (!$last) {{{ newline }}}}} @else {{{ block.code }}}</code></pre>\n\n @if (resolvedCopyable() && block.closed) {\n <button\n type=\"button\"\n class=\"wr-markdown__copy\"\n [wrCopyToClipboard]=\"block.code\"\n [attr.aria-label]=\"isCopied(block) ? resolvedCopiedLabel() : resolvedCopyLabel()\"\n (copied)=\"onCopied(block)\"\n >\n <svg\n class=\"wr-markdown__copy-icon\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n @if (isCopied(block)) {\n <path d=\"M20 6 9 17l-5-5\" />\n } @else {\n <rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\" />\n <path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" />\n }\n </svg>\n </button>\n }\n </div>\n }\n @case ('quote') {\n <blockquote class=\"wr-markdown__quote\">\n <ng-container\n [ngTemplateOutlet]=\"blockList\"\n [ngTemplateOutletContext]=\"{ $implicit: block.children, tight: false }\"\n />\n </blockquote>\n }\n @case ('list') {\n @if (block.ordered) {\n <ol\n class=\"wr-markdown__list wr-markdown__list--ordered\"\n [attr.start]=\"block.start === 1 ? null : block.start\"\n >\n <ng-container\n [ngTemplateOutlet]=\"itemList\"\n [ngTemplateOutletContext]=\"{ $implicit: block.items, tight: block.tight }\"\n />\n </ol>\n } @else {\n <ul class=\"wr-markdown__list\">\n <ng-container\n [ngTemplateOutlet]=\"itemList\"\n [ngTemplateOutletContext]=\"{ $implicit: block.items, tight: block.tight }\"\n />\n </ul>\n }\n }\n @case ('table') {\n <!-- Its own scroller: a wide table must not push the page sideways, which\n is also what keeps the RTL layout gate quiet about it. -->\n <div class=\"wr-markdown__table-scroll\" tabindex=\"0\">\n <table class=\"wr-markdown__table\">\n <thead>\n <tr>\n @for (cell of block.head; track column; let column = $index) {\n <th class=\"wr-markdown__th\" scope=\"col\" [style.text-align]=\"block.align[column]\">\n <ng-container\n [ngTemplateOutlet]=\"inlineList\"\n [ngTemplateOutletContext]=\"{ $implicit: cell.inlines }\"\n />\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of block.rows; track $index) {\n <tr>\n @for (cell of asCells(row); track column; let column = $index) {\n <td class=\"wr-markdown__td\" [style.text-align]=\"block.align[column]\">\n <ng-container\n [ngTemplateOutlet]=\"inlineList\"\n [ngTemplateOutletContext]=\"{ $implicit: cell.inlines }\"\n />\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n @case ('rule') {\n <hr class=\"wr-markdown__rule\" />\n }\n }\n }\n</ng-template>\n\n<ng-container [ngTemplateOutlet]=\"blockList\" [ngTemplateOutletContext]=\"{ $implicit: blocks(), tight: false }\" />\n" }]
1551
1574
  }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], streaming: [{ type: i0.Input, args: [{ isSignal: true, alias: "streaming", required: false }] }], copyable: [{ type: i0.Input, args: [{ isSignal: true, alias: "copyable", required: false }] }], linkTarget: [{ type: i0.Input, args: [{ isSignal: true, alias: "linkTarget", required: false }] }], headingIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "headingIds", required: false }] }], headingIdPrefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "headingIdPrefix", required: false }] }], copyLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "copyLabel", required: false }] }], copiedLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "copiedLabel", required: false }] }], taskDoneLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "taskDoneLabel", required: false }] }], taskTodoLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "taskTodoLabel", required: false }] }] } });
1552
1575
 
1576
+ /**
1577
+ * @license
1578
+ *
1579
+ * Use of this source code is governed by an MIT-style license that can be
1580
+ * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
1581
+ */
1582
+ /**
1583
+ * A block tree back to markdown — the inverse of {@link parseMarkdown}.
1584
+ *
1585
+ * **Written against this library's parser, not against CommonMark.** The two
1586
+ * disagree in places (no setext headings, no indented code, no entities, a
1587
+ * simplified reading of emphasis), and a serializer that escapes for the wrong
1588
+ * dialect writes text that comes back as something else. So every escape here is
1589
+ * derived from a question `parseMarkdown` actually asks — several of them by
1590
+ * calling the parser's own predicates — and the spec holds the pair to one
1591
+ * property: `parseMarkdown(serializeMarkdown(tree))` returns `tree`.
1592
+ *
1593
+ * **What markdown cannot say is normalised, never guessed at.** The output is the
1594
+ * nearest document this dialect can express, and reading it back gives a tree
1595
+ * that serializes to the same string. The losses, all of them structural:
1596
+ *
1597
+ * - Whitespace at the edges of a paragraph, heading or cell is dropped, and so is
1598
+ * whitespace just inside `**` / `*` / `~~` — a delimiter next to a space is not
1599
+ * a delimiter. A soft line break inside a text node becomes a space, and a hard
1600
+ * break at the very end of a block (a trailing `\` stays literal) is dropped;
1601
+ * inside a heading or a table cell every hard break becomes a space.
1602
+ * - An empty paragraph, an empty list and a table with no header cell vanish.
1603
+ * - Two adjacent lists of the same kind merge on the way back — there is no
1604
+ * raw-HTML comment to put between them. A single-item list with one block
1605
+ * cannot be loose, and a loose list nested in a tight one loosens it. Nesting
1606
+ * deeper than the parser's twelve levels reads back as text.
1607
+ * - Inline marks are rewritten in one canonical nesting — link outside strong
1608
+ * outside strikethrough outside emphasis — which is also how a mark SET, the
1609
+ * shape an editor holds, becomes a tree. An image carries no emphasis (none of
1610
+ * it paints on an image); where an emphasis run touches a strong one and
1611
+ * neither can switch to `_`, the emphasis is dropped rather than written as
1612
+ * markup that reads back as literal asterisks.
1613
+ * - A link or image whose URL `safeMarkdownUrl` refuses is written as its text,
1614
+ * exactly as the renderer would show it. A destination is percent-encoded
1615
+ * where this parser cannot carry a character (`<`, `>`, an unbalanced
1616
+ * parenthesis, a `\` it would read as an escape — and `[`, `]`, a backtick for
1617
+ * an image inside a link label), loses a tab or line break the way a browser's
1618
+ * URL parser does, a title that cannot be delimited is dropped, and a link
1619
+ * whose label is too long for the parser's label cap is written as plain text.
1620
+ * - A fence's info string keeps its first word, lowercased, and `closed` is not
1621
+ * written: a serialized fence is always closed. A tab that indents a line reads
1622
+ * back as four spaces, as the parser expands it. Heading ids are the parser's,
1623
+ * recomputed on the way back.
1624
+ *
1625
+ * @param blocks a block tree, typically from {@link parseMarkdown} or an editor
1626
+ * @returns markdown, with no trailing newline; `''` for an empty tree
1627
+ */
1628
+ function serializeMarkdown(blocks) {
1629
+ return joinBlocks(blocks.map(renderBlock), false);
1630
+ }
1631
+ /** The largest number `LIST_RE` reads as an ordinal: `\d{1,9}`. */
1632
+ const MAX_ORDINAL = 999999999;
1633
+ const DELIMITER_ROW = {
1634
+ start: ':--',
1635
+ center: ':-:',
1636
+ end: '--:',
1637
+ none: '---',
1638
+ };
1639
+ function renderBlock(block) {
1640
+ const text = blockText(block);
1641
+ return text ? { block, text } : null;
1642
+ }
1643
+ function blockText(block) {
1644
+ switch (block.kind) {
1645
+ case 'paragraph':
1646
+ return inlineMarkdown(block.inlines, 'paragraph').split('\n').map(escapeLineStart).join('\n');
1647
+ case 'heading':
1648
+ return headingText(block.level, block.inlines);
1649
+ case 'code':
1650
+ return codeBlock(block.language, block.code);
1651
+ case 'quote': {
1652
+ const body = joinBlocks(block.children.map(renderBlock), false);
1653
+ // A lone `>` is how an empty quote is written, and it reads back as one.
1654
+ return body
1655
+ .split('\n')
1656
+ .map(line => (line ? `> ${line}` : '>'))
1657
+ .join('\n');
1658
+ }
1659
+ case 'list':
1660
+ return listText(block.ordered, block.start, block.tight, block.items);
1661
+ case 'table':
1662
+ return tableText(block.head, block.rows, block.align);
1663
+ case 'rule':
1664
+ return '---';
1665
+ }
1666
+ }
1667
+ /**
1668
+ * Blocks joined the way the parser will split them again.
1669
+ *
1670
+ * A blank line is the safe separator, and between two siblings at one level it is
1671
+ * always correct but for one case: a blank line followed by ANY list marker marks
1672
+ * the list before it loose, even when the marker starts a list of the other kind.
1673
+ * So a tight list that is followed by a list is joined by a single newline. Inside
1674
+ * a tight list item a single newline is wanted everywhere, and is used wherever
1675
+ * the parser would still end the first block there.
1676
+ */
1677
+ function joinBlocks(parts, tight) {
1678
+ let out = '';
1679
+ let previous = null;
1680
+ for (const part of parts) {
1681
+ if (!part)
1682
+ continue;
1683
+ if (previous)
1684
+ out += separator(previous, part, tight);
1685
+ out += part.text;
1686
+ previous = part;
1687
+ }
1688
+ return out;
1689
+ }
1690
+ function separator(previous, next, tight) {
1691
+ const tightList = previous.block.kind === 'list' && !previous.text.includes('\n\n');
1692
+ if (tightList && next.block.kind === 'list')
1693
+ return '\n';
1694
+ return tight && endsBefore(previous, next) ? '\n' : '\n\n';
1695
+ }
1696
+ /**
1697
+ * Does `previous` end where `next` begins, with no blank line between them?
1698
+ *
1699
+ * Each case is the parser's own stopping rule, asked through its own predicates: a
1700
+ * paragraph runs until a line interrupts it, a quote swallows any line that does
1701
+ * not start a block (lazy continuation), a list swallows the same and continues on
1702
+ * a marker of its own kind, and a table runs while a line has a pipe. A heading, a
1703
+ * rule and a closed fence end themselves.
1704
+ */
1705
+ function endsBefore(previous, next) {
1706
+ const lines = next.text.split('\n');
1707
+ const first = lines[0];
1708
+ switch (previous.block.kind) {
1709
+ case 'paragraph': {
1710
+ // A last line holding a pipe, over a `---`, is a table header and its
1711
+ // delimiter row — which is the parser's answer before it asks anything else.
1712
+ const last = previous.text.slice(previous.text.lastIndexOf('\n') + 1);
1713
+ return (interruptsParagraph(first) || isTableStart(lines, 0)) && !isTableStart([last, first], 0);
1714
+ }
1715
+ case 'quote':
1716
+ return startsBlock(first) && !QUOTE_RE.test(first);
1717
+ case 'list': {
1718
+ const start = matchListStart(first);
1719
+ return startsBlock(first) && (!start || RULE_RE.test(first) || start.ordered !== previous.block.ordered);
1720
+ }
1721
+ case 'table':
1722
+ return !first.includes('|') || startsBlock(first);
1723
+ default:
1724
+ return true;
1725
+ }
1726
+ }
1727
+ function headingText(level, inlines) {
1728
+ const hashes = '#'.repeat(Math.min(Math.max(Math.trunc(level) || 1, 1), 6));
1729
+ // A `#` run at the end, after whitespace, is a closing sequence and the parser
1730
+ // strips it — `# Issue #` would come back as "Issue". `# C#` keeps its sharp.
1731
+ const text = inlineMarkdown(inlines, 'heading').replace(/(^|[ \t])(#*)#$/, '$1$2\\#');
1732
+ return text ? `${hashes} ${text}` : hashes;
1733
+ }
1734
+ function codeBlock(language, raw) {
1735
+ const info = (language ?? '').trim().split(/\s+/)[0].toLowerCase();
1736
+ // A backtick fence absorbs an info string that starts with a backtick into its
1737
+ // own run, so that one info string takes a tilde fence instead.
1738
+ const char = info.startsWith('`') ? '~' : '`';
1739
+ const code = raw.replace(/\r\n?/g, '\n');
1740
+ // Longer than any run of the fence character anywhere in the code, so no line
1741
+ // of it can close the fence early.
1742
+ const longest = (code.match(char === '`' ? /`+/g : /~+/g) ?? []).reduce((max, run) => Math.max(max, run.length), 0);
1743
+ const fence = char.repeat(Math.max(3, longest + 1));
1744
+ return code ? `${fence}${info}\n${code}\n${fence}` : `${fence}${info}\n${fence}`;
1745
+ }
1746
+ function listText(ordered, start, tight, items) {
1747
+ const first = Math.min(Math.max(Math.trunc(start) || 0, 0), MAX_ORDINAL);
1748
+ return items
1749
+ .map((item, index) => listItem(item, ordered ? `${Math.min(first + index, MAX_ORDINAL)}. ` : '- ', tight))
1750
+ .join(tight ? '\n' : '\n\n');
1751
+ }
1752
+ function listItem(item, marker, tight) {
1753
+ const task = item.checked === null ? '' : item.checked ? '[x] ' : '[ ] ';
1754
+ const bare = (marker + task).trimEnd();
1755
+ const body = joinBlocks(item.children.map(renderBlock), tight);
1756
+ if (!body)
1757
+ return bare;
1758
+ // Continuation lines sit at the item's content column, which for `- ` is 2 and
1759
+ // for `10. ` is 4 — the parser dedents by exactly the marker's width.
1760
+ const pad = ' '.repeat(marker.length);
1761
+ const lines = body.split('\n');
1762
+ const head = marker + task + lines[0];
1763
+ const indented = (rest) => rest.map(line => (line ? pad + line : line));
1764
+ // `- ---` is a thematic break, not an item holding one, so a first line that
1765
+ // would read that way moves under a bare marker.
1766
+ return RULE_RE.test(head) ? [bare, ...indented(lines)].join('\n') : [head, ...indented(lines.slice(1))].join('\n');
1767
+ }
1768
+ function tableText(head, rows, align) {
1769
+ const width = Math.min(head.length, MAX_TABLE_COLUMNS);
1770
+ if (!width)
1771
+ return '';
1772
+ const columns = Array.from({ length: width }, (_, index) => index);
1773
+ const row = (cells) => `| ${columns.map(index => cellText(cells[index]?.inlines ?? [])).join(' | ')} |`;
1774
+ const delimiter = `| ${columns.map(index => DELIMITER_ROW[align[index] ?? 'none']).join(' | ')} |`;
1775
+ return [row(head), delimiter, ...rows.map(row)].join('\n');
1776
+ }
1777
+ /**
1778
+ * A cell's inline markdown with every pipe escaped — inside code spans, URLs and
1779
+ * titles too. The row is split on pipes BEFORE any inline parsing, and the split
1780
+ * turns `\|` into `|` and touches nothing else, so escaping every pipe is its
1781
+ * exact inverse.
1782
+ */
1783
+ function cellText(inlines) {
1784
+ return inlineMarkdown(inlines, 'cell').replace(/\|/g, '\\|');
1785
+ }
1786
+ /**
1787
+ * A backslash before the first character of a line that would otherwise start a
1788
+ * block, or turn the line above it into a table header.
1789
+ *
1790
+ * Every such character is ASCII punctuation, which the parser unescapes, except
1791
+ * the digits of an ordered marker — there the delimiter is escaped instead,
1792
+ * `1986\.`. The test runs on the line as the parser will see it, with indent tabs
1793
+ * expanded, because the parser expands them before it looks.
1794
+ */
1795
+ function escapeLineStart(line) {
1796
+ const indent = /^[ \t]*/.exec(line)[0];
1797
+ const probe = indent.replace(/\t/g, ' ') + line.slice(indent.length);
1798
+ if (!startsBlock(probe) && !TABLE_DELIM_RE.test(probe))
1799
+ return line;
1800
+ const ordinal = /^\d{1,9}(?=[.)])/.exec(line.slice(indent.length));
1801
+ const at = indent.length + (ordinal ? ordinal[0].length : 0);
1802
+ return `${line.slice(0, at)}\\${line.slice(at)}`;
1803
+ }
1804
+ /** Outermost first. Emphasis never contains strong, which is the nesting `*x **y** z*` breaks on. */
1805
+ const LEVELS = ['link', 'strong', 'del', 'em'];
1806
+ const EMPHASIS = ['strong', 'del', 'em'];
1807
+ const NO_MARKS = { link: null, strong: false, del: false, em: false };
1808
+ /** The parser's own "word character" for `_` flanking. */
1809
+ const WORD_CHAR = /[\p{L}\p{N}]/u;
1810
+ /** A soft break and the indentation around it: whitespace once rendered. */
1811
+ const SOFT_BREAK_RE = /\s*[\r\n]\s*/g;
1812
+ /** What another renderer would decode as an entity; this one does not, so `\&` keeps it literal everywhere. */
1813
+ const ENTITY_RE = /^&(?:#\d+|#x[\da-f]+|[a-z][a-z\d]*);/i;
1814
+ function inlineMarkdown(nodes, context) {
1815
+ let leaves = settle(flatten(nodes, NO_MARKS, context, []), context);
1816
+ // A link whose label is past the parser's cap is not a link on the way back.
1817
+ // Its leaves lose the mark and the run is laid out again, since unwrapping it
1818
+ // can put two emphasis runs next to each other.
1819
+ for (;;) {
1820
+ const state = { tooLong: null };
1821
+ const out = renderNodes(group(leaves, 0, 0), state);
1822
+ if (!state.tooLong)
1823
+ return out;
1824
+ const [from, to] = state.tooLong;
1825
+ leaves = settle(leaves.map((leaf, index) => index >= from && index < to ? { ...leaf, marks: { ...leaf.marks, link: null } } : leaf), context);
1826
+ }
1827
+ }
1828
+ function flatten(nodes, marks, context, out) {
1829
+ for (const node of nodes) {
1830
+ switch (node.kind) {
1831
+ case 'text':
1832
+ out.push({ kind: 'text', value: node.value.replace(SOFT_BREAK_RE, ' '), marks });
1833
+ break;
1834
+ case 'code':
1835
+ // The parser reads a newline inside a code span as a space.
1836
+ out.push({ kind: 'code', value: node.value.replace(/\r\n?|\n/g, ' '), marks });
1837
+ break;
1838
+ case 'break':
1839
+ out.push(context === 'paragraph' ? { kind: 'break', marks } : { kind: 'text', value: ' ', marks });
1840
+ break;
1841
+ case 'image': {
1842
+ const src = safeMarkdownUrl(node.src, 'image');
1843
+ const alt = node.alt.replace(SOFT_BREAK_RE, ' ');
1844
+ const inLabel = marks.link !== null;
1845
+ // A refused source renders its alt as text, so that is what is written.
1846
+ out.push(src
1847
+ ? {
1848
+ kind: 'image',
1849
+ src: encodeUrl(src, inLabel),
1850
+ alt,
1851
+ title: writableTitle(node.title, inLabel),
1852
+ marks: { ...NO_MARKS, link: marks.link },
1853
+ }
1854
+ : { kind: 'text', value: alt, marks });
1855
+ break;
1856
+ }
1857
+ case 'link': {
1858
+ // No link inside a link, and no link the reader would refuse anyway. The
1859
+ // attributes are stored as they will be WRITTEN, so two links that differ
1860
+ // only in what cannot be written are one link here, as they will be on the
1861
+ // way back.
1862
+ const href = marks.link ? null : safeMarkdownUrl(node.href, 'link');
1863
+ const next = href
1864
+ ? { ...marks, link: { href: encodeUrl(href, false), title: writableTitle(node.title, false) } }
1865
+ : marks;
1866
+ flatten(node.children, next, context, out);
1867
+ break;
1868
+ }
1869
+ default:
1870
+ flatten(node.children, { ...marks, [node.kind]: true }, context, out);
1871
+ }
1872
+ }
1873
+ return out;
1874
+ }
1875
+ /**
1876
+ * The leaves in canonical form: merged, with whitespace outside emphasis, trimmed
1877
+ * at the block's edges, and no code span that would open a line as a fence.
1878
+ */
1879
+ function settle(leaves, context) {
1880
+ let current = leaves;
1881
+ // A code span turned into text can bring a space to the edge of a node, so the
1882
+ // pass runs again until nothing more is unfenced.
1883
+ for (;;) {
1884
+ const out = trimBlock(merge(moveEdgesOut(merge(current))));
1885
+ if (context !== 'paragraph')
1886
+ return out;
1887
+ const unfenced = unfence(out);
1888
+ if (unfenced.every((leaf, index) => leaf === out[index]))
1889
+ return out;
1890
+ current = unfenced;
1891
+ }
1892
+ }
1893
+ function sameLink(a, b) {
1894
+ return a === b || (!!a && !!b && a.href === b.href && a.title === b.title);
1895
+ }
1896
+ function sameMarks(a, b) {
1897
+ return a.strong === b.strong && a.del === b.del && a.em === b.em && sameLink(a.link, b.link);
1898
+ }
1899
+ /** Adjacent text (or code) with the same marks is one node; an empty one is none. */
1900
+ function merge(leaves) {
1901
+ const out = [];
1902
+ for (const leaf of leaves) {
1903
+ if ((leaf.kind === 'text' || leaf.kind === 'code') && !leaf.value)
1904
+ continue;
1905
+ const last = out[out.length - 1];
1906
+ if (last &&
1907
+ (last.kind === 'text' || last.kind === 'code') &&
1908
+ last.kind === leaf.kind &&
1909
+ sameMarks(last.marks, leaf.marks)) {
1910
+ out[out.length - 1] = { ...last, value: last.value + leaf.value };
1911
+ }
1912
+ else {
1913
+ out.push(leaf);
1914
+ }
1915
+ }
1916
+ return out;
1917
+ }
1918
+ /**
1919
+ * Whitespace and hard breaks at the edge of an emphasis run lose that mark.
1920
+ *
1921
+ * The parser refuses an opener followed by whitespace and a closer preceded by it,
1922
+ * so `** bold **` is literal asterisks; the same text written `**bold**` with the
1923
+ * spaces outside is what was meant. A link keeps its edges — `[` and `]` have no
1924
+ * flanking rule.
1925
+ *
1926
+ * The unit is the NODE the mark will become, not the run of leaves carrying it:
1927
+ * the canonical nesting cuts a strong run wherever a link begins or ends, and an
1928
+ * emphasis run wherever strong or strikethrough changes, and each piece gets
1929
+ * delimiters of its own. Outer marks go first, so an inner node is measured
1930
+ * against leaves that are already final.
1931
+ */
1932
+ function moveEdgesOut(leaves) {
1933
+ let out = [...leaves];
1934
+ for (const mark of EMPHASIS) {
1935
+ const outer = EMPHASIS.slice(0, EMPHASIS.indexOf(mark));
1936
+ const sameNode = (a, b) => b.marks[mark] && sameLink(a.marks.link, b.marks.link) && outer.every(name => a.marks[name] === b.marks[name]);
1937
+ const next = [];
1938
+ let i = 0;
1939
+ while (i < out.length) {
1940
+ if (!out[i].marks[mark]) {
1941
+ next.push(out[i]);
1942
+ i++;
1943
+ continue;
1944
+ }
1945
+ let j = i;
1946
+ while (j < out.length && sameNode(out[i], out[j]))
1947
+ j++;
1948
+ next.push(...trimRun(out.slice(i, j), mark));
1949
+ i = j;
1950
+ }
1951
+ out = next;
1952
+ }
1953
+ return out;
1954
+ }
1955
+ function trimRun(run, mark) {
1956
+ const body = [...run];
1957
+ const head = [];
1958
+ const tail = [];
1959
+ const unmark = (leaf) => ({ ...leaf, marks: { ...leaf.marks, [mark]: false } });
1960
+ while (body.length) {
1961
+ const leaf = body[0];
1962
+ if (leaf.kind === 'break') {
1963
+ head.push(unmark(leaf));
1964
+ body.shift();
1965
+ continue;
1966
+ }
1967
+ if (leaf.kind !== 'text')
1968
+ break;
1969
+ const space = /^\s*/.exec(leaf.value)[0];
1970
+ if (!space)
1971
+ break;
1972
+ head.push(unmark({ ...leaf, value: space }));
1973
+ if (space.length < leaf.value.length) {
1974
+ body[0] = { ...leaf, value: leaf.value.slice(space.length) };
1975
+ break;
1976
+ }
1977
+ body.shift();
1978
+ }
1979
+ while (body.length) {
1980
+ const leaf = body[body.length - 1];
1981
+ if (leaf.kind === 'break') {
1982
+ tail.unshift(unmark(leaf));
1983
+ body.pop();
1984
+ continue;
1985
+ }
1986
+ if (leaf.kind !== 'text')
1987
+ break;
1988
+ const space = /\s*$/.exec(leaf.value)[0];
1989
+ if (!space)
1990
+ break;
1991
+ tail.unshift(unmark({ ...leaf, value: space }));
1992
+ if (space.length < leaf.value.length) {
1993
+ body[body.length - 1] = { ...leaf, value: leaf.value.slice(0, -space.length) };
1994
+ break;
1995
+ }
1996
+ body.pop();
1997
+ }
1998
+ return [...head, ...body, ...tail];
1999
+ }
2000
+ /**
2001
+ * What the parser's trim would take anyway: leading whitespace, and trailing
2002
+ * whitespace and hard breaks (a `\` at the end of a block stays a literal
2003
+ * backslash). Content inside a link label is past its reach and stays.
2004
+ */
2005
+ function trimBlock(leaves) {
2006
+ const out = [...leaves];
2007
+ let start = 0;
2008
+ let end = out.length;
2009
+ while (start < end) {
2010
+ const leaf = out[start];
2011
+ if (leaf.kind !== 'text' || leaf.marks.link)
2012
+ break;
2013
+ const value = leaf.value.replace(/^\s+/, '');
2014
+ if (value) {
2015
+ out[start] = { ...leaf, value };
2016
+ break;
2017
+ }
2018
+ start++;
2019
+ }
2020
+ while (end > start) {
2021
+ const leaf = out[end - 1];
2022
+ if (leaf.marks.link || (leaf.kind !== 'text' && leaf.kind !== 'break'))
2023
+ break;
2024
+ if (leaf.kind === 'break') {
2025
+ end--;
2026
+ continue;
2027
+ }
2028
+ const value = leaf.value.replace(/\s+$/, '');
2029
+ if (value) {
2030
+ out[end - 1] = { ...leaf, value };
2031
+ break;
2032
+ }
2033
+ end--;
2034
+ }
2035
+ return out.slice(start, end);
2036
+ }
2037
+ /**
2038
+ * A code span that opens a paragraph line and needs three or more backticks would
2039
+ * read back as a fence. Nothing can be put in front of it, so it keeps its text
2040
+ * and loses the code mark. It takes a value holding both a single and a double
2041
+ * backtick run to get here.
2042
+ */
2043
+ function unfence(leaves) {
2044
+ const blank = (leaf) => leaf.kind === 'text' && !leaf.value.trim();
2045
+ return leaves.map((leaf, index) => {
2046
+ if (leaf.kind !== 'code' || ticks(leaf.value) < 3)
2047
+ return leaf;
2048
+ let k = index - 1;
2049
+ while (k >= 0 && blank(leaves[k])) {
2050
+ if (!sameMarks(leaves[k].marks, leaf.marks))
2051
+ return leaf;
2052
+ k--;
2053
+ }
2054
+ const opensLine = k < 0 ? sameMarks(leaf.marks, NO_MARKS) : leaves[k].kind === 'break' && sameMarks(leaves[k].marks, leaf.marks);
2055
+ return opensLine ? { kind: 'text', value: leaf.value, marks: leaf.marks } : leaf;
2056
+ });
2057
+ }
2058
+ /**
2059
+ * Leaves to a tree, one mark level at a time in {@link LEVELS} order: a maximal
2060
+ * run sharing the mark becomes one node, and what is inside it is grouped by the
2061
+ * next level. Two leaves painted the same way always land in the same shape.
2062
+ */
2063
+ function group(leaves, level, offset) {
2064
+ if (level === LEVELS.length)
2065
+ return [...leaves];
2066
+ const mark = LEVELS[level];
2067
+ const key = (leaf) => (mark === 'link' ? leaf.marks.link : leaf.marks[mark]);
2068
+ const same = (a, b) => mark === 'link' ? sameLink(a.marks.link, b.marks.link) : a.marks[mark] === b.marks[mark];
2069
+ const out = [];
2070
+ let i = 0;
2071
+ while (i < leaves.length) {
2072
+ let j = i + 1;
2073
+ while (j < leaves.length && same(leaves[i], leaves[j]))
2074
+ j++;
2075
+ const children = group(leaves.slice(i, j), level + 1, offset + i);
2076
+ const on = key(leaves[i]);
2077
+ if (!on) {
2078
+ out.push(...children);
2079
+ }
2080
+ else if (mark === 'link') {
2081
+ out.push({ kind: 'link', link: on, from: offset + i, to: offset + j, children });
2082
+ }
2083
+ else {
2084
+ out.push({ kind: mark, children });
2085
+ }
2086
+ i = j;
2087
+ }
2088
+ return out;
2089
+ }
2090
+ function renderNodes(nodes, state) {
2091
+ const [list, chars] = delimiters(nodes);
2092
+ let out = '';
2093
+ list.forEach((node, index) => {
2094
+ out += renderNode(node, chars[index], list[index + 1], state);
2095
+ });
2096
+ return out;
2097
+ }
2098
+ function renderNode(node, char, next, state) {
2099
+ switch (node.kind) {
2100
+ case 'text':
2101
+ return escapeText(node.value, next?.kind === 'link');
2102
+ case 'code':
2103
+ return codeSpan(node.value);
2104
+ case 'break':
2105
+ return '\\\n';
2106
+ case 'image':
2107
+ return `![${escapeText(node.alt, false)}](${destination(node.src, node.title)})`;
2108
+ case 'link': {
2109
+ const auto = autolink(node.link, node.children);
2110
+ if (auto)
2111
+ return auto;
2112
+ const label = renderNodes(node.children, state);
2113
+ if (label.length >= MAX_LABEL_LENGTH) {
2114
+ state.tooLong ??= [node.from, node.to];
2115
+ return label;
2116
+ }
2117
+ return `[${label}](${destination(node.link.href, node.link.title)})`;
2118
+ }
2119
+ case 'del':
2120
+ return `~~${renderNodes(node.children, state)}~~`;
2121
+ default: {
2122
+ const delimiter = node.kind === 'strong' ? char.repeat(2) : char;
2123
+ return delimiter + renderNodes(node.children, state) + delimiter;
2124
+ }
2125
+ }
2126
+ }
2127
+ /**
2128
+ * The delimiter character of every strong and emphasis node in a sibling list.
2129
+ *
2130
+ * `*` unless it would touch another `*` run: `*a***b**` reads as one run of three
2131
+ * and parses wrong. The canonical nesting means the only neighbours that can clash
2132
+ * are an emphasis and a strong, so one of them switches to `_` — the emphasis
2133
+ * first — where `_` flanking allows it: no letter or digit against it from
2134
+ * outside, and no `_` neighbour to clash with in turn. Where neither can switch,
2135
+ * the emphasis is dropped and the list is laid out again; its children are
2136
+ * leaves, so the drop cannot create a clash of its own.
2137
+ */
2138
+ function delimiters(nodes) {
2139
+ let list = nodes;
2140
+ for (;;) {
2141
+ const chars = list.map(node => (node.kind === 'strong' || node.kind === 'em' ? '*' : null));
2142
+ const drop = settleClashes(list, chars);
2143
+ if (drop < 0)
2144
+ return [list, chars];
2145
+ const dropped = list[drop];
2146
+ list = [...list.slice(0, drop), ...dropped.children, ...list.slice(drop + 1)];
2147
+ }
2148
+ }
2149
+ /** Index of an emphasis node to drop, or -1 once every clash is settled. */
2150
+ function settleClashes(list, chars) {
2151
+ for (let i = 0; i + 1 < list.length; i++) {
2152
+ if (!chars[i] || chars[i] !== chars[i + 1])
2153
+ continue;
2154
+ const emFirst = list[i].kind === 'em';
2155
+ const switched = (emFirst ? [i, i + 1] : [i + 1, i]).find(k => canUnderscore(list, chars, k));
2156
+ if (switched === undefined)
2157
+ return emFirst ? i : i + 1;
2158
+ chars[switched] = '_';
2159
+ }
2160
+ return -1;
2161
+ }
2162
+ function canUnderscore(list, chars, k) {
2163
+ const before = k > 0 ? edgeChar(list[k - 1], chars[k - 1], 'end') : '';
2164
+ const after = k + 1 < list.length ? edgeChar(list[k + 1], chars[k + 1], 'start') : '';
2165
+ return chars[k - 1] !== '_' && chars[k + 1] !== '_' && !WORD_CHAR.test(before) && !WORD_CHAR.test(after);
2166
+ }
2167
+ /**
2168
+ * The character a node puts next to its neighbour — only ever asked whether it is
2169
+ * a letter or a digit. Escaping inserts a backslash before punctuation and never
2170
+ * before a word character, so the raw text answers that question for text.
2171
+ */
2172
+ function edgeChar(node, char, side) {
2173
+ switch (node.kind) {
2174
+ case 'text':
2175
+ return side === 'start' ? node.value[0] : node.value[node.value.length - 1];
2176
+ case 'strong':
2177
+ case 'em':
2178
+ return char ?? '';
2179
+ default:
2180
+ return '';
2181
+ }
2182
+ }
2183
+ /**
2184
+ * Text with every character the parser would read as syntax escaped — and no
2185
+ * more, so prose stays prose. `snake_case` keeps its underscores, `2 * 3` its
2186
+ * star, `a < b` its bracket: in those positions the parser can never read them as
2187
+ * markup. The ends of the string are treated as the worst case, since whatever is
2188
+ * written next to it is not known here.
2189
+ */
2190
+ function escapeText(value, beforeLink) {
2191
+ let out = '';
2192
+ for (let i = 0; i < value.length; i++) {
2193
+ const char = value[i];
2194
+ if (mustEscape(value, i, beforeLink))
2195
+ out += '\\';
2196
+ out += char;
2197
+ }
2198
+ // A bare URL in plain text would come back as a link. The escaped colon is
2199
+ // invisible once parsed, and it stops `BARE_URL_RE` from matching.
2200
+ return out.replace(/(https?):(?=\/\/)/gi, '$1\\:');
2201
+ }
2202
+ function mustEscape(value, i, beforeLink) {
2203
+ const prev = value[i - 1];
2204
+ const next = value[i + 1];
2205
+ const space = (c) => c !== undefined && /\s/.test(c);
2206
+ const word = (c) => c !== undefined && WORD_CHAR.test(c);
2207
+ switch (value[i]) {
2208
+ case '\\':
2209
+ case '`':
2210
+ case '[':
2211
+ case ']':
2212
+ return true;
2213
+ // Between two spaces a star can neither open (followed by whitespace) nor
2214
+ // close (preceded by it).
2215
+ case '*':
2216
+ return !(space(prev) && space(next));
2217
+ // Between two word characters an underscore is never a delimiter.
2218
+ case '_':
2219
+ return !(word(prev) && word(next));
2220
+ // Strikethrough needs a pair; a single tilde between other characters is text.
2221
+ case '~':
2222
+ return prev === undefined || prev === '~' || next === undefined || next === '~';
2223
+ // An autolink needs a scheme or an address right after the bracket.
2224
+ case '<':
2225
+ return !space(next);
2226
+ // `!` followed by a link's `[` would turn the link into an image.
2227
+ case '!':
2228
+ return beforeLink && next === undefined;
2229
+ case '&':
2230
+ return ENTITY_RE.test(value.slice(i));
2231
+ default:
2232
+ return false;
2233
+ }
2234
+ }
2235
+ /** The shortest backtick run that does not occur inside the value. */
2236
+ function ticks(value) {
2237
+ const runs = new Set((value.match(/`+/g) ?? []).map(run => run.length));
2238
+ let length = 1;
2239
+ while (runs.has(length))
2240
+ length++;
2241
+ return length;
2242
+ }
2243
+ /**
2244
+ * A code span, padded where the parser would otherwise eat a character: it strips
2245
+ * one space from each end when both are present, and a backtick at either end
2246
+ * would merge into the fence.
2247
+ */
2248
+ function codeSpan(value) {
2249
+ const fence = '`'.repeat(ticks(value));
2250
+ const pad = codeSpanValue(value) !== value || value.startsWith('`') || value.endsWith('`');
2251
+ return pad ? `${fence} ${value} ${fence}` : `${fence}${value}${fence}`;
2252
+ }
2253
+ /** `<https://…>` or `<name@host>` when the label IS the address — the form the parser reads back identically. */
2254
+ function autolink(link, children) {
2255
+ const only = children.length === 1 ? children[0] : null;
2256
+ if (link.title !== null || only?.kind !== 'text')
2257
+ return null;
2258
+ const whole = (re, value) => re.exec(`<${value}>`)?.[0].length === value.length + 2;
2259
+ if (only.value === link.href && whole(AUTOLINK_RE, link.href))
2260
+ return `<${link.href}>`;
2261
+ if (`mailto:${only.value}` === link.href && whole(EMAIL_AUTOLINK_RE, only.value))
2262
+ return `<${only.value}>`;
2263
+ return null;
2264
+ }
2265
+ /**
2266
+ * A URL as this parser will read it back, and as a browser resolves it.
2267
+ *
2268
+ * The destination scan counts parentheses and ends at a line break, so an angle
2269
+ * bracket and an unbalanced parenthesis are percent-encoded — to a browser the
2270
+ * same address. A tab or a line break is removed rather than encoded: the URL
2271
+ * parser strips them, so the address never had them, and `%0A` would be a
2272
+ * different one. A backslash is kept as it is — the parser keeps it, and in an
2273
+ * http(s) URL a browser reads it as `/`, which `%5C` is not — except where the
2274
+ * scan would take it for an escape and skip what follows: before a parenthesis,
2275
+ * and at the very end, where it would swallow the closing one. Inside a link label
2276
+ * the label scan also runs over an image's destination, so its brackets and
2277
+ * backticks are encoded too. Spaces are not encoded: {@link destination} carries
2278
+ * them in the `<…>` form.
2279
+ */
2280
+ function encodeUrl(url, inLabel) {
2281
+ const out = url
2282
+ .replace(/[\t\r\n]/g, '')
2283
+ .replace(/\\(?=[()]|$)/g, percent)
2284
+ .replace(inLabel ? /[<>[\]`]/g : /[<>]/g, percent);
2285
+ return balanced(out) ? out : out.replace(/[()]/g, percent);
2286
+ }
2287
+ function percent(char) {
2288
+ return `%${char.charCodeAt(0).toString(16).toUpperCase().padStart(2, '0')}`;
2289
+ }
2290
+ /** Parentheses the destination scan accepts: balanced, never closing early, and under its nesting cap. */
2291
+ function balanced(url) {
2292
+ let depth = 0;
2293
+ for (const char of url) {
2294
+ if (char === '(' && ++depth >= MAX_DESTINATION_NESTING)
2295
+ return false;
2296
+ if (char === ')' && --depth < 0)
2297
+ return false;
2298
+ }
2299
+ return depth === 0;
2300
+ }
2301
+ /**
2302
+ * The title as it can be written, or `null` when it cannot: a line break becomes a
2303
+ * space, and the destination scan runs through the title counting parentheses (a
2304
+ * backslash skipping the next character), so one that would close the scan early
2305
+ * or leave it open is dropped. Inside a link label the label scan runs through it
2306
+ * as well, so a bracket, a backtick or a backslash drops it there.
2307
+ */
2308
+ function writableTitle(raw, inLabel) {
2309
+ if (raw === null)
2310
+ return null;
2311
+ const title = raw.replace(SOFT_BREAK_RE, ' ');
2312
+ if (inLabel && /[[\]`\\]/.test(title))
2313
+ return null;
2314
+ let depth = 1;
2315
+ for (let i = 0; i < title.length; i++) {
2316
+ const char = title[i];
2317
+ if (char === '\\') {
2318
+ i++;
2319
+ continue;
2320
+ }
2321
+ if (char === '(' && ++depth > MAX_DESTINATION_NESTING)
2322
+ return null;
2323
+ if (char === ')' && --depth === 0)
2324
+ return null;
2325
+ }
2326
+ return depth === 1 ? title : null;
2327
+ }
2328
+ /** An encoded URL and a writable title, inside the parentheses. */
2329
+ function destination(url, title) {
2330
+ const target = /\s/.test(url) ? `<${url}>` : url;
2331
+ return title === null ? target : `${target} "${title}"`;
2332
+ }
2333
+
1553
2334
  /**
1554
2335
  * @license
1555
2336
  *
@@ -1598,5 +2379,5 @@ function provideWrMarkdownHighlighter(highlighter) {
1598
2379
  * Generated bundle index. Do not edit.
1599
2380
  */
1600
2381
 
1601
- export { WR_MARKDOWN_HIGHLIGHTER, WrMarkdown, WrMarkdownHighlight, parseInlines, parseMarkdown, plainText, provideWrMarkdownHighlighter, safeMarkdownUrl };
2382
+ export { WR_MARKDOWN_HIGHLIGHTER, WrMarkdown, WrMarkdownHighlight, parseInlines, parseMarkdown, plainText, provideWrMarkdownHighlighter, safeMarkdownUrl, serializeMarkdown };
1602
2383
  //# sourceMappingURL=ngwr-markdown.mjs.map