@ojiepermana/angular 22.1.13 → 22.2.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 (252) hide show
  1. package/README.md +8 -6
  2. package/SUPPORT.md +3 -3
  3. package/chart/README.md +1 -1
  4. package/component/README.md +2 -2
  5. package/component/calendar/README.md +3 -15
  6. package/component/drawer/README.md +1 -2
  7. package/fesm2022/ojiepermana-angular-chart-area.mjs +352 -137
  8. package/fesm2022/ojiepermana-angular-chart-bar.mjs +744 -524
  9. package/fesm2022/ojiepermana-angular-chart-core.mjs +1140 -1344
  10. package/fesm2022/ojiepermana-angular-chart-line.mjs +393 -147
  11. package/fesm2022/ojiepermana-angular-chart-pie.mjs +408 -179
  12. package/fesm2022/ojiepermana-angular-chart-primitives.mjs +1262 -920
  13. package/fesm2022/ojiepermana-angular-chart-radar.mjs +473 -205
  14. package/fesm2022/ojiepermana-angular-chart-radial.mjs +425 -182
  15. package/fesm2022/ojiepermana-angular-chart-scatter.mjs +386 -210
  16. package/fesm2022/ojiepermana-angular-chart.mjs +3 -19
  17. package/fesm2022/ojiepermana-angular-component-accordion.mjs +485 -243
  18. package/fesm2022/ojiepermana-angular-component-alert-dialog.mjs +963 -325
  19. package/fesm2022/ojiepermana-angular-component-alert.mjs +266 -103
  20. package/fesm2022/ojiepermana-angular-component-aspect-ratio.mjs +80 -35
  21. package/fesm2022/ojiepermana-angular-component-avatar.mjs +402 -135
  22. package/fesm2022/ojiepermana-angular-component-badge.mjs +109 -59
  23. package/fesm2022/ojiepermana-angular-component-breadcrumb.mjs +410 -142
  24. package/fesm2022/ojiepermana-angular-component-button-group.mjs +249 -96
  25. package/fesm2022/ojiepermana-angular-component-button.mjs +153 -75
  26. package/fesm2022/ojiepermana-angular-component-calendar.mjs +531 -418
  27. package/fesm2022/ojiepermana-angular-component-card.mjs +457 -171
  28. package/fesm2022/ojiepermana-angular-component-carousel.mjs +642 -272
  29. package/fesm2022/ojiepermana-angular-component-checkbox.mjs +312 -108
  30. package/fesm2022/ojiepermana-angular-component-collapsible.mjs +299 -115
  31. package/fesm2022/ojiepermana-angular-component-combobox.mjs +396 -183
  32. package/fesm2022/ojiepermana-angular-component-command.mjs +807 -347
  33. package/fesm2022/ojiepermana-angular-component-composer.mjs +807 -330
  34. package/fesm2022/ojiepermana-angular-component-context-menu.mjs +196 -161
  35. package/fesm2022/ojiepermana-angular-component-date-picker.mjs +650 -338
  36. package/fesm2022/ojiepermana-angular-component-dialog.mjs +710 -316
  37. package/fesm2022/ojiepermana-angular-component-drawer.mjs +2 -5
  38. package/fesm2022/ojiepermana-angular-component-dropdown-menu.mjs +1212 -646
  39. package/fesm2022/ojiepermana-angular-component-editor.mjs +987 -502
  40. package/fesm2022/ojiepermana-angular-component-empty.mjs +350 -137
  41. package/fesm2022/ojiepermana-angular-component-form.mjs +813 -434
  42. package/fesm2022/ojiepermana-angular-component-hover-card.mjs +486 -277
  43. package/fesm2022/ojiepermana-angular-component-icon.mjs +241 -140
  44. package/fesm2022/ojiepermana-angular-component-input-group.mjs +449 -176
  45. package/fesm2022/ojiepermana-angular-component-input-otp.mjs +891 -488
  46. package/fesm2022/ojiepermana-angular-component-input.mjs +86 -55
  47. package/fesm2022/ojiepermana-angular-component-item.mjs +713 -261
  48. package/fesm2022/ojiepermana-angular-component-kanban.mjs +714 -216
  49. package/fesm2022/ojiepermana-angular-component-kbd.mjs +124 -52
  50. package/fesm2022/ojiepermana-angular-component-label.mjs +82 -31
  51. package/fesm2022/ojiepermana-angular-component-menubar.mjs +479 -329
  52. package/fesm2022/ojiepermana-angular-component-native-select.mjs +167 -65
  53. package/fesm2022/ojiepermana-angular-component-navigation-menu.mjs +683 -380
  54. package/fesm2022/ojiepermana-angular-component-pagination.mjs +277 -94
  55. package/fesm2022/ojiepermana-angular-component-pillbox.mjs +1283 -607
  56. package/fesm2022/ojiepermana-angular-component-popover.mjs +291 -204
  57. package/fesm2022/ojiepermana-angular-component-progress.mjs +176 -53
  58. package/fesm2022/ojiepermana-angular-component-radio.mjs +449 -142
  59. package/fesm2022/ojiepermana-angular-component-resizable.mjs +659 -453
  60. package/fesm2022/ojiepermana-angular-component-scroll-area.mjs +117 -39
  61. package/fesm2022/ojiepermana-angular-component-segmented-control.mjs +351 -172
  62. package/fesm2022/ojiepermana-angular-component-select.mjs +475 -345
  63. package/fesm2022/ojiepermana-angular-component-separator.mjs +102 -35
  64. package/fesm2022/ojiepermana-angular-component-sheet.mjs +797 -347
  65. package/fesm2022/ojiepermana-angular-component-skeleton.mjs +62 -29
  66. package/fesm2022/ojiepermana-angular-component-slider.mjs +592 -376
  67. package/fesm2022/ojiepermana-angular-component-spinner.mjs +135 -38
  68. package/fesm2022/ojiepermana-angular-component-switch.mjs +315 -103
  69. package/fesm2022/ojiepermana-angular-component-table.mjs +440 -153
  70. package/fesm2022/ojiepermana-angular-component-tabs.mjs +590 -317
  71. package/fesm2022/ojiepermana-angular-component-textarea.mjs +85 -50
  72. package/fesm2022/ojiepermana-angular-component-timeline.mjs +609 -231
  73. package/fesm2022/ojiepermana-angular-component-toast.mjs +229 -243
  74. package/fesm2022/ojiepermana-angular-component-toggle-group.mjs +573 -288
  75. package/fesm2022/ojiepermana-angular-component-toggle.mjs +187 -78
  76. package/fesm2022/ojiepermana-angular-component-tooltip.mjs +798 -517
  77. package/fesm2022/ojiepermana-angular-component-utils-core.mjs +159 -292
  78. package/fesm2022/ojiepermana-angular-component-utils-overlay.mjs +46 -58
  79. package/fesm2022/ojiepermana-angular-component-utils-scale.mjs +76 -38
  80. package/fesm2022/ojiepermana-angular-component-utils.mjs +2 -8
  81. package/fesm2022/ojiepermana-angular-component.mjs +0 -10
  82. package/fesm2022/ojiepermana-angular-navigation-core.mjs +13 -23
  83. package/fesm2022/ojiepermana-angular-navigation-icon.mjs +35 -24
  84. package/fesm2022/ojiepermana-angular-navigation-navigation-badge-count.component-BKCeWzml.mjs +129 -0
  85. package/fesm2022/ojiepermana-angular-navigation-navigation-dockbar-menu.component-DFEJK2jD.mjs +811 -0
  86. package/fesm2022/{ojiepermana-angular-navigation-navigation-entry-grid.component-Cd-jh6tg.mjs → ojiepermana-angular-navigation-navigation-entry-grid.component-mpK9Ar08.mjs} +387 -183
  87. package/fesm2022/ojiepermana-angular-navigation-navigation-flyout-menu.component-BPgH7FJk.mjs +650 -0
  88. package/fesm2022/ojiepermana-angular-navigation-navigation-horizontal.component-DMpYcD9t.mjs +662 -0
  89. package/fesm2022/ojiepermana-angular-navigation-navigation-item.component-Basp5SIk.mjs +1228 -0
  90. package/fesm2022/ojiepermana-angular-navigation-navigation-list.component-YUzHI9Pj.mjs +311 -0
  91. package/fesm2022/ojiepermana-angular-navigation-service.mjs +542 -724
  92. package/fesm2022/ojiepermana-angular-navigation-types.mjs +27 -56
  93. package/fesm2022/ojiepermana-angular-navigation.mjs +3052 -4
  94. package/fesm2022/ojiepermana-angular-sdk.mjs +91 -201
  95. package/fesm2022/ojiepermana-angular-theme-component-settings.mjs +1115 -737
  96. package/fesm2022/ojiepermana-angular-theme-layout-services.mjs +245 -328
  97. package/fesm2022/ojiepermana-angular-theme-layout-types.mjs +35 -38
  98. package/fesm2022/ojiepermana-angular-theme-layout-wrapper.mjs +1719 -552
  99. package/fesm2022/ojiepermana-angular-theme-layout.mjs +847 -491
  100. package/fesm2022/ojiepermana-angular-theme-page-core.mjs +288 -358
  101. package/fesm2022/ojiepermana-angular-theme-page-filter.mjs +362 -224
  102. package/fesm2022/ojiepermana-angular-theme-page-overview.mjs +88 -0
  103. package/fesm2022/ojiepermana-angular-theme-page-root.mjs +576 -254
  104. package/fesm2022/ojiepermana-angular-theme-page-side.mjs +317 -177
  105. package/fesm2022/ojiepermana-angular-theme-page-slots.mjs +256 -112
  106. package/fesm2022/ojiepermana-angular-theme-page.mjs +7 -12
  107. package/fesm2022/ojiepermana-angular-theme-shell-services.mjs +215 -326
  108. package/fesm2022/ojiepermana-angular-theme-shell-types.mjs +68 -129
  109. package/fesm2022/ojiepermana-angular-theme-shell.mjs +907 -378
  110. package/fesm2022/ojiepermana-angular-theme-styles.mjs +521 -720
  111. package/fesm2022/ojiepermana-angular-theme.mjs +0 -10
  112. package/fesm2022/ojiepermana-angular.mjs +5 -24
  113. package/navigation/README.md +1 -1
  114. package/package.json +16 -12
  115. package/sdk/README.md +1 -1
  116. package/sdk/src/writer/index.js +2 -2
  117. package/theme/README.md +1 -1
  118. package/theme/layout/README.md +2 -4
  119. package/theme/page/README.md +50 -0
  120. package/theme/styles/README.md +10 -10
  121. package/theme/styles/css/base/prefers-dark.css +1 -1
  122. package/theme/styles/css/base/status.css +1 -1
  123. package/theme/styles/css/color/amber.css +1 -1
  124. package/theme/styles/css/color/blue.css +1 -1
  125. package/theme/styles/css/color/cyan.css +1 -1
  126. package/theme/styles/css/color/emerald.css +1 -1
  127. package/theme/styles/css/color/fuchsia.css +1 -1
  128. package/theme/styles/css/color/green.css +1 -1
  129. package/theme/styles/css/color/indigo.css +1 -1
  130. package/theme/styles/css/color/lime.css +1 -1
  131. package/theme/styles/css/color/orange.css +1 -1
  132. package/theme/styles/css/color/pink.css +1 -1
  133. package/theme/styles/css/color/purple.css +1 -1
  134. package/theme/styles/css/color/red.css +1 -1
  135. package/theme/styles/css/color/rose.css +1 -1
  136. package/theme/styles/css/color/sky.css +1 -1
  137. package/theme/styles/css/color/teal.css +1 -1
  138. package/theme/styles/css/color/violet.css +1 -1
  139. package/theme/styles/css/color/yellow.css +1 -1
  140. package/theme/styles/css/neutral/gray.css +1 -1
  141. package/theme/styles/css/neutral/mauve.css +1 -1
  142. package/theme/styles/css/neutral/mist.css +1 -1
  143. package/theme/styles/css/neutral/neutral.css +1 -1
  144. package/theme/styles/css/neutral/olive.css +1 -1
  145. package/theme/styles/css/neutral/slate.css +1 -1
  146. package/theme/styles/css/neutral/stone.css +1 -1
  147. package/theme/styles/css/neutral/taupe.css +1 -1
  148. package/theme/styles/css/neutral/zinc.css +1 -1
  149. package/types/ojiepermana-angular-chart-area.d.ts +126 -63
  150. package/types/ojiepermana-angular-chart-bar.d.ts +244 -154
  151. package/types/ojiepermana-angular-chart-core.d.ts +409 -398
  152. package/types/ojiepermana-angular-chart-line.d.ts +141 -68
  153. package/types/ojiepermana-angular-chart-pie.d.ts +192 -121
  154. package/types/ojiepermana-angular-chart-primitives.d.ts +283 -214
  155. package/types/ojiepermana-angular-chart-radar.d.ts +189 -108
  156. package/types/ojiepermana-angular-chart-radial.d.ts +177 -106
  157. package/types/ojiepermana-angular-chart-scatter.d.ts +166 -110
  158. package/types/ojiepermana-angular-chart.d.ts +3 -2
  159. package/types/ojiepermana-angular-component-accordion.d.ts +135 -81
  160. package/types/ojiepermana-angular-component-alert-dialog.d.ts +271 -123
  161. package/types/ojiepermana-angular-component-alert.d.ts +69 -39
  162. package/types/ojiepermana-angular-component-aspect-ratio.d.ts +20 -12
  163. package/types/ojiepermana-angular-component-avatar.d.ts +103 -49
  164. package/types/ojiepermana-angular-component-badge.d.ts +36 -24
  165. package/types/ojiepermana-angular-component-breadcrumb.d.ts +79 -40
  166. package/types/ojiepermana-angular-component-button-group.d.ts +48 -24
  167. package/types/ojiepermana-angular-component-button.d.ts +44 -27
  168. package/types/ojiepermana-angular-component-calendar.d.ts +145 -107
  169. package/types/ojiepermana-angular-component-card.d.ts +112 -63
  170. package/types/ojiepermana-angular-component-carousel.d.ts +150 -81
  171. package/types/ojiepermana-angular-component-checkbox.d.ts +96 -38
  172. package/types/ojiepermana-angular-component-collapsible.d.ts +65 -39
  173. package/types/ojiepermana-angular-component-combobox.d.ts +100 -55
  174. package/types/ojiepermana-angular-component-command.d.ts +206 -121
  175. package/types/ojiepermana-angular-component-composer.d.ts +184 -84
  176. package/types/ojiepermana-angular-component-context-menu.d.ts +51 -41
  177. package/types/ojiepermana-angular-component-date-picker.d.ts +199 -109
  178. package/types/ojiepermana-angular-component-dialog.d.ts +200 -105
  179. package/types/ojiepermana-angular-component-drawer.d.ts +2 -1
  180. package/types/ojiepermana-angular-component-dropdown-menu.d.ts +324 -202
  181. package/types/ojiepermana-angular-component-editor.d.ts +215 -117
  182. package/types/ojiepermana-angular-component-empty.d.ts +80 -45
  183. package/types/ojiepermana-angular-component-form.d.ts +185 -121
  184. package/types/ojiepermana-angular-component-hover-card.d.ts +130 -72
  185. package/types/ojiepermana-angular-component-icon.d.ts +87 -57
  186. package/types/ojiepermana-angular-component-input-group.d.ts +93 -46
  187. package/types/ojiepermana-angular-component-input-otp.d.ts +243 -150
  188. package/types/ojiepermana-angular-component-input.d.ts +27 -17
  189. package/types/ojiepermana-angular-component-item.d.ts +160 -84
  190. package/types/ojiepermana-angular-component-kanban.d.ts +157 -62
  191. package/types/ojiepermana-angular-component-kbd.d.ts +24 -15
  192. package/types/ojiepermana-angular-component-label.d.ts +19 -11
  193. package/types/ojiepermana-angular-component-menubar.d.ts +120 -90
  194. package/types/ojiepermana-angular-component-native-select.d.ts +37 -24
  195. package/types/ojiepermana-angular-component-navigation-menu.d.ts +157 -98
  196. package/types/ojiepermana-angular-component-pagination.d.ts +78 -28
  197. package/types/ojiepermana-angular-component-pillbox.d.ts +361 -204
  198. package/types/ojiepermana-angular-component-popover.d.ts +94 -64
  199. package/types/ojiepermana-angular-component-progress.d.ts +45 -17
  200. package/types/ojiepermana-angular-component-radio.d.ts +129 -53
  201. package/types/ojiepermana-angular-component-resizable.d.ts +160 -112
  202. package/types/ojiepermana-angular-component-scroll-area.d.ts +33 -15
  203. package/types/ojiepermana-angular-component-segmented-control.d.ts +94 -50
  204. package/types/ojiepermana-angular-component-select.d.ts +94 -77
  205. package/types/ojiepermana-angular-component-separator.d.ts +26 -14
  206. package/types/ojiepermana-angular-component-sheet.d.ts +226 -116
  207. package/types/ojiepermana-angular-component-skeleton.d.ts +13 -10
  208. package/types/ojiepermana-angular-component-slider.d.ts +140 -75
  209. package/types/ojiepermana-angular-component-spinner.d.ts +31 -13
  210. package/types/ojiepermana-angular-component-switch.d.ts +97 -40
  211. package/types/ojiepermana-angular-component-table.d.ts +102 -50
  212. package/types/ojiepermana-angular-component-tabs.d.ts +174 -115
  213. package/types/ojiepermana-angular-component-textarea.d.ts +27 -17
  214. package/types/ojiepermana-angular-component-timeline.d.ts +141 -59
  215. package/types/ojiepermana-angular-component-toast.d.ts +51 -55
  216. package/types/ojiepermana-angular-component-toggle-group.d.ts +159 -88
  217. package/types/ojiepermana-angular-component-toggle.d.ts +47 -25
  218. package/types/ojiepermana-angular-component-tooltip.d.ts +222 -132
  219. package/types/ojiepermana-angular-component-utils-core.d.ts +81 -90
  220. package/types/ojiepermana-angular-component-utils-overlay.d.ts +7 -11
  221. package/types/ojiepermana-angular-component-utils-scale.d.ts +20 -12
  222. package/types/ojiepermana-angular-component-utils.d.ts +2 -2
  223. package/types/ojiepermana-angular-component.d.ts +1 -2
  224. package/types/ojiepermana-angular-navigation-core.d.ts +46 -50
  225. package/types/ojiepermana-angular-navigation-icon.d.ts +9 -12
  226. package/types/ojiepermana-angular-navigation-service.d.ts +112 -115
  227. package/types/ojiepermana-angular-navigation-types.d.ts +121 -125
  228. package/types/ojiepermana-angular-navigation.d.ts +663 -374
  229. package/types/ojiepermana-angular-sdk.d.ts +69 -71
  230. package/types/ojiepermana-angular-theme-component-settings.d.ts +115 -83
  231. package/types/ojiepermana-angular-theme-layout-services.d.ts +119 -124
  232. package/types/ojiepermana-angular-theme-layout-types.d.ts +27 -31
  233. package/types/ojiepermana-angular-theme-layout-wrapper.d.ts +399 -187
  234. package/types/ojiepermana-angular-theme-layout.d.ts +201 -112
  235. package/types/ojiepermana-angular-theme-page-core.d.ts +136 -142
  236. package/types/ojiepermana-angular-theme-page-filter.d.ts +112 -62
  237. package/types/ojiepermana-angular-theme-page-overview.d.ts +28 -0
  238. package/types/ojiepermana-angular-theme-page-root.d.ts +172 -88
  239. package/types/ojiepermana-angular-theme-page-side.d.ts +89 -49
  240. package/types/ojiepermana-angular-theme-page-slots.d.ts +58 -37
  241. package/types/ojiepermana-angular-theme-page.d.ts +7 -5
  242. package/types/ojiepermana-angular-theme-shell-services.d.ts +119 -125
  243. package/types/ojiepermana-angular-theme-shell-types.d.ts +38 -41
  244. package/types/ojiepermana-angular-theme-shell.d.ts +139 -61
  245. package/types/ojiepermana-angular-theme-styles.d.ts +184 -196
  246. package/types/ojiepermana-angular-theme.d.ts +1 -2
  247. package/types/ojiepermana-angular.d.ts +5 -5
  248. package/fesm2022/ojiepermana-angular-navigation-navigation-badge-count.component-CDBxQ8rk.mjs +0 -91
  249. package/fesm2022/ojiepermana-angular-navigation-navigation-dockbar-menu.component-DBQHdvGa.mjs +0 -512
  250. package/fesm2022/ojiepermana-angular-navigation-navigation-flyout-menu.component-BCGvhoYj.mjs +0 -404
  251. package/fesm2022/ojiepermana-angular-navigation-navigation-horizontal.component-Dk_03e-6.mjs +0 -466
  252. package/fesm2022/ojiepermana-angular-navigation-ojiepermana-angular-navigation-DNKU6viC.mjs +0 -2642
@@ -1,515 +1,1000 @@
1
- import { DOCUMENT } from '@angular/common';
2
- import * as i0 from '@angular/core';
3
- import { InjectionToken, inject, SecurityContext, input, booleanAttribute, output, computed, Component, ElementRef, signal, forwardRef } from '@angular/core';
4
- import { NG_VALUE_ACCESSOR } from '@angular/forms';
5
- import { cn } from '@ojiepermana/angular/component/utils/core';
6
- import { DomSanitizer } from '@angular/platform-browser';
7
-
8
- /**
9
- * Override this token when an application needs a stricter allow-list than
10
- * Angular's platform HTML sanitizer.
11
- */
12
- const EDITOR_HTML_SANITIZER = new InjectionToken('EDITOR_HTML_SANITIZER', {
13
- providedIn: 'root',
14
- factory: () => {
15
- const sanitizer = inject(DomSanitizer);
16
- return (html) => sanitizer.sanitize(SecurityContext.HTML, html) ?? '';
17
- },
1
+ import { DOCUMENT } from "@angular/common";
2
+ import * as i0 from "@angular/core";
3
+ import { Component, ElementRef, InjectionToken, SecurityContext, booleanAttribute, computed, forwardRef, inject, input, output, signal } from "@angular/core";
4
+ import { NG_VALUE_ACCESSOR } from "@angular/forms";
5
+ import { cn } from "@ojiepermana/angular/component/utils/core";
6
+ import { DomSanitizer } from "@angular/platform-browser";
7
+ const EDITOR_HTML_SANITIZER = new InjectionToken("EDITOR_HTML_SANITIZER", {
8
+ providedIn: "root",
9
+ factory: () => {
10
+ const sanitizer = inject(DomSanitizer);
11
+ return (html) => sanitizer.sanitize(SecurityContext.HTML, html) ?? "";
12
+ }
18
13
  });
19
-
20
- const DEFAULT_EDITOR_TOOLBAR = 'heading | bold italic underline strike | bullet ordered blockquote link align ~ undo redo';
21
- const EDITOR_BASE = 'block w-full min-w-0 text-sm text-foreground';
14
+ const DEFAULT_EDITOR_TOOLBAR = "heading | bold italic underline strike | bullet ordered blockquote link align ~ undo redo";
15
+ const EDITOR_BASE = "block w-full min-w-0 text-sm text-foreground";
22
16
  const EDITOR_SHELL_BASE = [
23
- 'relative min-w-0 overflow-hidden rounded-md border border-input bg-background shadow-sm',
24
- 'transition-[border-color,box-shadow] focus-within:border-ring focus-within:ring-1 focus-within:ring-ring',
25
- 'aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-within:ring-destructive',
26
- 'data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50',
27
- ].join(' ');
28
- const EDITOR_TOOLBAR_BASE = [
29
- 'flex min-h-11 min-w-0 flex-wrap items-center gap-1 border-b border-[hsl(var(--border)/var(--opacity-70))] bg-[hsl(var(--muted)/var(--opacity-30))] px-2 py-1.5',
30
- 'data-[disabled=true]:pointer-events-none',
31
- ].join(' ');
17
+ "relative min-w-0 overflow-hidden rounded-md border border-input bg-background shadow-sm",
18
+ "transition-[border-color,box-shadow] focus-within:border-ring focus-within:ring-1 focus-within:ring-ring",
19
+ "aria-[invalid=true]:border-destructive aria-[invalid=true]:focus-within:ring-destructive",
20
+ "data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50"
21
+ ].join(" ");
22
+ const EDITOR_TOOLBAR_BASE = ["flex min-h-11 min-w-0 flex-wrap items-center gap-1 border-b border-[hsl(var(--border)/var(--opacity-70))] bg-[hsl(var(--muted)/var(--opacity-30))] px-2 py-1.5", "data-[disabled=true]:pointer-events-none"].join(" ");
32
23
  const EDITOR_TOOL_BUTTON_BASE = [
33
- 'inline-flex size-8 shrink-0 items-center justify-center rounded-md text-sm font-medium text-muted-foreground',
34
- 'transition-colors hover:bg-accent hover:text-accent-foreground',
35
- 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
36
- 'disabled:pointer-events-none disabled:opacity-50',
37
- 'aria-pressed:bg-accent aria-pressed:text-accent-foreground',
38
- ].join(' ');
24
+ "inline-flex size-8 shrink-0 items-center justify-center rounded-md text-sm font-medium text-muted-foreground",
25
+ "transition-colors hover:bg-accent hover:text-accent-foreground",
26
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
27
+ "disabled:pointer-events-none disabled:opacity-50",
28
+ "aria-pressed:bg-accent aria-pressed:text-accent-foreground"
29
+ ].join(" ");
39
30
  const EDITOR_SELECT_BASE = [
40
- 'h-8 rounded-md border border-transparent bg-transparent px-2 text-sm font-medium text-muted-foreground outline-none',
41
- 'transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:ring-2 focus-visible:ring-ring',
42
- 'disabled:pointer-events-none disabled:opacity-50',
43
- ].join(' ');
31
+ "h-8 rounded-md border border-transparent bg-transparent px-2 text-sm font-medium text-muted-foreground outline-none",
32
+ "transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:ring-2 focus-visible:ring-ring",
33
+ "disabled:pointer-events-none disabled:opacity-50"
34
+ ].join(" ");
44
35
  const EDITOR_CONTENT_BASE = [
45
- 'block min-h-50 max-h-125 w-full overflow-y-auto px-4 py-3 text-sm leading-6 outline-none',
46
- '[&_p]:my-2 [&_h1]:mb-2 [&_h1]:mt-4 [&_h1]:text-2xl [&_h1]:font-semibold [&_h2]:mb-2 [&_h2]:mt-4 [&_h2]:text-xl [&_h2]:font-semibold [&_h3]:mb-2 [&_h3]:mt-4 [&_h3]:text-lg [&_h3]:font-semibold',
47
- '[&_blockquote]:my-3 [&_blockquote]:border-l-2 [&_blockquote]:border-border [&_blockquote]:pl-3 [&_blockquote]:text-muted-foreground [&_ul]:my-2 [&_ul]:list-disc [&_ul]:pl-6 [&_ol]:my-2 [&_ol]:list-decimal [&_ol]:pl-6 [&_pre]:my-3 [&_pre]:overflow-x-auto [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-3 [&_pre]:font-mono [&_pre]:text-xs',
48
- 'data-[empty=true]:before:pointer-events-none data-[empty=true]:before:text-muted-foreground data-[empty=true]:before:content-[attr(data-placeholder)]',
49
- 'data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50',
50
- ].join(' ');
36
+ "block min-h-50 max-h-125 w-full overflow-y-auto px-4 py-3 text-sm leading-6 outline-none",
37
+ "[&_p]:my-2 [&_h1]:mb-2 [&_h1]:mt-4 [&_h1]:text-2xl [&_h1]:font-semibold [&_h2]:mb-2 [&_h2]:mt-4 [&_h2]:text-xl [&_h2]:font-semibold [&_h3]:mb-2 [&_h3]:mt-4 [&_h3]:text-lg [&_h3]:font-semibold",
38
+ "[&_blockquote]:my-3 [&_blockquote]:border-l-2 [&_blockquote]:border-border [&_blockquote]:pl-3 [&_blockquote]:text-muted-foreground [&_ul]:my-2 [&_ul]:list-disc [&_ul]:pl-6 [&_ol]:my-2 [&_ol]:list-decimal [&_ol]:pl-6 [&_pre]:my-3 [&_pre]:overflow-x-auto [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-3 [&_pre]:font-mono [&_pre]:text-xs",
39
+ "data-[empty=true]:before:pointer-events-none data-[empty=true]:before:text-muted-foreground data-[empty=true]:before:content-[attr(data-placeholder)]",
40
+ "data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50"
41
+ ].join(" ");
51
42
  const toolbarButtons = {
52
- bold: { label: 'B', ariaLabel: 'Bold' },
53
- italic: { label: 'I', ariaLabel: 'Italic' },
54
- underline: { label: 'U', ariaLabel: 'Underline' },
55
- strike: { label: 'S', ariaLabel: 'Strikethrough' },
56
- bullet: { label: 'UL', ariaLabel: 'Bulleted list' },
57
- ordered: { label: '1.', ariaLabel: 'Numbered list' },
58
- blockquote: { label: 'Q', ariaLabel: 'Block quote' },
59
- subscript: { label: 'Sub', ariaLabel: 'Subscript' },
60
- superscript: { label: 'Sup', ariaLabel: 'Superscript' },
61
- highlight: { label: 'H', ariaLabel: 'Highlight' },
62
- link: { label: 'Link', ariaLabel: 'Insert link' },
63
- code: { label: '</>', ariaLabel: 'Code block' },
64
- undo: { label: 'Undo', ariaLabel: 'Undo' },
65
- redo: { label: 'Redo', ariaLabel: 'Redo' },
43
+ bold: {
44
+ label: "B",
45
+ ariaLabel: "Bold"
46
+ },
47
+ italic: {
48
+ label: "I",
49
+ ariaLabel: "Italic"
50
+ },
51
+ underline: {
52
+ label: "U",
53
+ ariaLabel: "Underline"
54
+ },
55
+ strike: {
56
+ label: "S",
57
+ ariaLabel: "Strikethrough"
58
+ },
59
+ bullet: {
60
+ label: "UL",
61
+ ariaLabel: "Bulleted list"
62
+ },
63
+ ordered: {
64
+ label: "1.",
65
+ ariaLabel: "Numbered list"
66
+ },
67
+ blockquote: {
68
+ label: "Q",
69
+ ariaLabel: "Block quote"
70
+ },
71
+ subscript: {
72
+ label: "Sub",
73
+ ariaLabel: "Subscript"
74
+ },
75
+ superscript: {
76
+ label: "Sup",
77
+ ariaLabel: "Superscript"
78
+ },
79
+ highlight: {
80
+ label: "H",
81
+ ariaLabel: "Highlight"
82
+ },
83
+ link: {
84
+ label: "Link",
85
+ ariaLabel: "Insert link"
86
+ },
87
+ code: {
88
+ label: "</>",
89
+ ariaLabel: "Code block"
90
+ },
91
+ undo: {
92
+ label: "Undo",
93
+ ariaLabel: "Undo"
94
+ },
95
+ redo: {
96
+ label: "Redo",
97
+ ariaLabel: "Redo"
98
+ }
66
99
  };
67
- /** document.execCommand name (+ optional value) for each editor command. */
68
100
  const EDITOR_EXEC_COMMANDS = {
69
- paragraph: ['formatBlock', 'p'],
70
- 'heading-1': ['formatBlock', 'h1'],
71
- 'heading-2': ['formatBlock', 'h2'],
72
- 'heading-3': ['formatBlock', 'h3'],
73
- bold: ['bold'],
74
- italic: ['italic'],
75
- underline: ['underline'],
76
- strike: ['strikeThrough'],
77
- bullet: ['insertUnorderedList'],
78
- ordered: ['insertOrderedList'],
79
- blockquote: ['formatBlock', 'blockquote'],
80
- subscript: ['subscript'],
81
- superscript: ['superscript'],
82
- highlight: ['backColor'],
83
- link: ['createLink', '#'],
84
- code: ['formatBlock', 'pre'],
85
- 'align-left': ['justifyLeft'],
86
- 'align-center': ['justifyCenter'],
87
- 'align-right': ['justifyRight'],
88
- undo: ['undo'],
89
- redo: ['redo'],
101
+ paragraph: ["formatBlock", "p"],
102
+ "heading-1": ["formatBlock", "h1"],
103
+ "heading-2": ["formatBlock", "h2"],
104
+ "heading-3": ["formatBlock", "h3"],
105
+ bold: ["bold"],
106
+ italic: ["italic"],
107
+ underline: ["underline"],
108
+ strike: ["strikeThrough"],
109
+ bullet: ["insertUnorderedList"],
110
+ ordered: ["insertOrderedList"],
111
+ blockquote: ["formatBlock", "blockquote"],
112
+ subscript: ["subscript"],
113
+ superscript: ["superscript"],
114
+ highlight: ["backColor"],
115
+ link: ["createLink", "#"],
116
+ code: ["formatBlock", "pre"],
117
+ "align-left": ["justifyLeft"],
118
+ "align-center": ["justifyCenter"],
119
+ "align-right": ["justifyRight"],
120
+ undo: ["undo"],
121
+ redo: ["redo"]
90
122
  };
91
- /** Keeps the text selection alive while clicking toolbar controls. */
92
123
  const preserveEditorSelection = (event) => {
93
- event.preventDefault();
124
+ event.preventDefault();
94
125
  };
95
126
  const parseToolbarItems = (items) => {
96
- const tokens = items.split(/\s+/).filter(Boolean);
97
- return tokens.flatMap((token, index) => {
98
- if (token === '|') {
99
- return [{ type: 'separator', track: `separator-${index}` }];
100
- }
101
- if (token === '~') {
102
- return [{ type: 'spacer', track: `spacer-${index}` }];
103
- }
104
- if (token === 'heading') {
105
- return [{ type: 'heading', track: `heading-${index}` }];
106
- }
107
- if (token === 'align') {
108
- return [{ type: 'align', track: `align-${index}` }];
109
- }
110
- const command = token;
111
- const button = toolbarButtons[command];
112
- if (!button) {
113
- return [];
114
- }
115
- return [{ type: 'button', command, label: button.label, ariaLabel: button.ariaLabel }];
116
- });
127
+ return items.split(/\s+/).filter(Boolean).flatMap((token, index) => {
128
+ if (token === "|") return [{
129
+ type: "separator",
130
+ track: `separator-${index}`
131
+ }];
132
+ if (token === "~") return [{
133
+ type: "spacer",
134
+ track: `spacer-${index}`
135
+ }];
136
+ if (token === "heading") return [{
137
+ type: "heading",
138
+ track: `heading-${index}`
139
+ }];
140
+ if (token === "align") return [{
141
+ type: "align",
142
+ track: `align-${index}`
143
+ }];
144
+ const command = token;
145
+ const button = toolbarButtons[command];
146
+ if (!button) return [];
147
+ return [{
148
+ type: "button",
149
+ command,
150
+ label: button.label,
151
+ ariaLabel: button.ariaLabel
152
+ }];
153
+ });
117
154
  };
118
- class EditorComponent {
119
- disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
120
- invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
121
- class = input('', /* @ts-ignore */
122
- ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
123
- commandSelected = output();
124
- content = null;
125
- classes = computed(() => cn(EDITOR_BASE, this.class()), /* @ts-ignore */
126
- ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
127
- shellClasses = computed(() => cn(EDITOR_SHELL_BASE), /* @ts-ignore */
128
- ...(ngDevMode ? [{ debugName: "shellClasses" }] : /* istanbul ignore next */ []));
129
- execute(command, source = 'api', originalEvent) {
130
- if (this.disabled()) {
131
- return;
132
- }
133
- this.content?.execute(command);
134
- this.commandSelected.emit({ command, source, originalEvent });
135
- }
136
- registerContent(content) {
137
- this.content = content;
138
- }
139
- unregisterContent(content) {
140
- if (this.content === content) {
141
- this.content = null;
142
- }
143
- }
144
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: EditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
145
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.4", type: EditorComponent, isStandalone: true, selector: "Editor", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { commandSelected: "commandSelected" }, host: { properties: { "class": "classes()", "attr.data-slot": "\"editor\"", "attr.data-disabled": "disabled() ? \"true\" : null", "attr.aria-disabled": "disabled() ? \"true\" : null", "attr.aria-invalid": "invalid() ? \"true\" : null", "attr.inert": "disabled() ? \"\" : null" } }, ngImport: i0, template: "<div\n data-slot=\"editor-shell\"\n [class]=\"shellClasses()\"\n [attr.data-disabled]=\"disabled() ? 'true' : null\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n>\n <ng-content select=\"EditorToolbar\" />\n <ng-content select=\"EditorContent\" />\n</div>\n" });
146
- }
147
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: EditorComponent, decorators: [{
148
- type: Component,
149
- args: [{ selector: 'Editor', host: {
150
- '[class]': 'classes()',
151
- '[attr.data-slot]': '"editor"',
152
- '[attr.data-disabled]': 'disabled() ? "true" : null',
153
- '[attr.aria-disabled]': 'disabled() ? "true" : null',
154
- '[attr.aria-invalid]': 'invalid() ? "true" : null',
155
- '[attr.inert]': 'disabled() ? "" : null',
156
- }, template: "<div\n data-slot=\"editor-shell\"\n [class]=\"shellClasses()\"\n [attr.data-disabled]=\"disabled() ? 'true' : null\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n>\n <ng-content select=\"EditorToolbar\" />\n <ng-content select=\"EditorContent\" />\n</div>\n" }]
157
- }], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], commandSelected: [{ type: i0.Output, args: ["commandSelected"] }] } });
158
- class EditorToolbarComponent {
159
- editor = inject(EditorComponent, { optional: true });
160
- items = input(DEFAULT_EDITOR_TOOLBAR, /* @ts-ignore */
161
- ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
162
- disabledInput = input(false, { ...(ngDevMode ? { debugName: "disabledInput" } : /* istanbul ignore next */ {}), alias: 'disabled', transform: booleanAttribute });
163
- ariaLabel = input('Formatting', { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: 'aria-label' });
164
- class = input('', /* @ts-ignore */
165
- ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
166
- buttonClasses = EDITOR_TOOL_BUTTON_BASE;
167
- selectClasses = EDITOR_SELECT_BASE;
168
- disabled = computed(() => this.disabledInput() || this.editor?.disabled() === true, /* @ts-ignore */
169
- ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
170
- parts = computed(() => parseToolbarItems(this.items()), /* @ts-ignore */
171
- ...(ngDevMode ? [{ debugName: "parts" }] : /* istanbul ignore next */ []));
172
- classes = computed(() => cn(EDITOR_TOOLBAR_BASE, this.class()), /* @ts-ignore */
173
- ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
174
- execute(command, event) {
175
- this.editor?.execute(command, 'toolbar', event);
176
- }
177
- handleSelect(event) {
178
- const select = event.target;
179
- this.editor?.execute(select.value, 'toolbar', event);
180
- select.selectedIndex = 0;
181
- }
182
- preserveSelection = preserveEditorSelection;
183
- trackPart(part, index) {
184
- if (part.type === 'button') {
185
- return `${part.command}-${index}`;
186
- }
187
- return part.track;
188
- }
189
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: EditorToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
190
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: EditorToolbarComponent, isStandalone: true, selector: "EditorToolbar", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "toolbar" }, properties: { "class": "classes()", "attr.data-slot": "\"editor-toolbar\"", "attr.aria-label": "ariaLabel()", "attr.data-disabled": "disabled() ? \"true\" : null" } }, ngImport: i0, template: "@for (part of parts(); track trackPart(part, $index)) {\n @switch (part.type) {\n @case ('heading') {\n <select\n [class]=\"selectClasses\"\n [disabled]=\"disabled()\"\n aria-label=\"Text style\"\n (change)=\"handleSelect($event)\"\n >\n <option value=\"paragraph\">Text</option>\n <option value=\"heading-1\">Heading 1</option>\n <option value=\"heading-2\">Heading 2</option>\n <option value=\"heading-3\">Heading 3</option>\n </select>\n }\n @case ('align') {\n <select\n [class]=\"selectClasses\"\n [disabled]=\"disabled()\"\n aria-label=\"Text alignment\"\n (change)=\"handleSelect($event)\"\n >\n <option value=\"align-left\">Left</option>\n <option value=\"align-center\">Center</option>\n <option value=\"align-right\">Right</option>\n </select>\n }\n @case ('separator') {\n <span\n data-slot=\"editor-separator\"\n class=\"mx-1 h-6 w-px shrink-0 bg-border\"\n role=\"separator\"\n aria-orientation=\"vertical\"\n ></span>\n }\n @case ('spacer') {\n <span data-slot=\"editor-spacer\" class=\"min-w-2 flex-1\"></span>\n }\n @case ('button') {\n <button\n type=\"button\"\n data-slot=\"editor-button\"\n [class]=\"buttonClasses\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"part.ariaLabel\"\n [attr.title]=\"part.ariaLabel\"\n (mousedown)=\"preserveSelection($event)\"\n (click)=\"execute(part.command, $event)\"\n >\n @if (part.command === 'undo') {\n <svg\n aria-hidden=\"true\"\n class=\"size-4\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"M9 14 4 9l5-5\" />\n <path d=\"M4 9h10a6 6 0 0 1 0 12h-2\" />\n </svg>\n } @else if (part.command === 'redo') {\n <svg\n aria-hidden=\"true\"\n class=\"size-4\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"m15 14 5-5-5-5\" />\n <path d=\"M20 9H10a6 6 0 0 0 0 12h2\" />\n </svg>\n } @else {\n <span aria-hidden=\"true\">{{ part.label }}</span>\n }\n </button>\n }\n }\n}\n<ng-content />\n" });
191
- }
192
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: EditorToolbarComponent, decorators: [{
193
- type: Component,
194
- args: [{ selector: 'EditorToolbar', host: {
195
- '[class]': 'classes()',
196
- '[attr.data-slot]': '"editor-toolbar"',
197
- role: 'toolbar',
198
- '[attr.aria-label]': 'ariaLabel()',
199
- '[attr.data-disabled]': 'disabled() ? "true" : null',
200
- }, template: "@for (part of parts(); track trackPart(part, $index)) {\n @switch (part.type) {\n @case ('heading') {\n <select\n [class]=\"selectClasses\"\n [disabled]=\"disabled()\"\n aria-label=\"Text style\"\n (change)=\"handleSelect($event)\"\n >\n <option value=\"paragraph\">Text</option>\n <option value=\"heading-1\">Heading 1</option>\n <option value=\"heading-2\">Heading 2</option>\n <option value=\"heading-3\">Heading 3</option>\n </select>\n }\n @case ('align') {\n <select\n [class]=\"selectClasses\"\n [disabled]=\"disabled()\"\n aria-label=\"Text alignment\"\n (change)=\"handleSelect($event)\"\n >\n <option value=\"align-left\">Left</option>\n <option value=\"align-center\">Center</option>\n <option value=\"align-right\">Right</option>\n </select>\n }\n @case ('separator') {\n <span\n data-slot=\"editor-separator\"\n class=\"mx-1 h-6 w-px shrink-0 bg-border\"\n role=\"separator\"\n aria-orientation=\"vertical\"\n ></span>\n }\n @case ('spacer') {\n <span data-slot=\"editor-spacer\" class=\"min-w-2 flex-1\"></span>\n }\n @case ('button') {\n <button\n type=\"button\"\n data-slot=\"editor-button\"\n [class]=\"buttonClasses\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"part.ariaLabel\"\n [attr.title]=\"part.ariaLabel\"\n (mousedown)=\"preserveSelection($event)\"\n (click)=\"execute(part.command, $event)\"\n >\n @if (part.command === 'undo') {\n <svg\n aria-hidden=\"true\"\n class=\"size-4\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"M9 14 4 9l5-5\" />\n <path d=\"M4 9h10a6 6 0 0 1 0 12h-2\" />\n </svg>\n } @else if (part.command === 'redo') {\n <svg\n aria-hidden=\"true\"\n class=\"size-4\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"m15 14 5-5-5-5\" />\n <path d=\"M20 9H10a6 6 0 0 0 0 12h2\" />\n </svg>\n } @else {\n <span aria-hidden=\"true\">{{ part.label }}</span>\n }\n </button>\n }\n }\n}\n<ng-content />\n" }]
201
- }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
202
- class EditorButtonComponent {
203
- editor = inject(EditorComponent, { optional: true });
204
- command = input(null, /* @ts-ignore */
205
- ...(ngDevMode ? [{ debugName: "command" }] : /* istanbul ignore next */ []));
206
- pressed = input(null, /* @ts-ignore */
207
- ...(ngDevMode ? [{ debugName: "pressed" }] : /* istanbul ignore next */ []));
208
- disabledInput = input(false, { ...(ngDevMode ? { debugName: "disabledInput" } : /* istanbul ignore next */ {}), alias: 'disabled', transform: booleanAttribute });
209
- tooltip = input('', /* @ts-ignore */
210
- ...(ngDevMode ? [{ debugName: "tooltip" }] : /* istanbul ignore next */ []));
211
- class = input('', /* @ts-ignore */
212
- ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
213
- disabled = computed(() => this.disabledInput() || this.editor?.disabled() === true, /* @ts-ignore */
214
- ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
215
- classes = computed(() => cn(EDITOR_TOOL_BUTTON_BASE, this.class()), /* @ts-ignore */
216
- ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
217
- handleClick(event) {
218
- const command = this.command();
219
- if (!command) {
220
- return;
221
- }
222
- this.editor?.execute(command, 'toolbar', event);
223
- }
224
- preserveSelection = preserveEditorSelection;
225
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: EditorButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
226
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.4", type: EditorButtonComponent, isStandalone: true, selector: "button[EditorButton]", inputs: { command: { classPropertyName: "command", publicName: "command", isSignal: true, isRequired: false, transformFunction: null }, pressed: { classPropertyName: "pressed", publicName: "pressed", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, tooltip: { classPropertyName: "tooltip", publicName: "tooltip", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "type": "button" }, listeners: { "mousedown": "preserveSelection($event)", "click": "handleClick($event)" }, properties: { "class": "classes()", "attr.data-slot": "\"editor-button\"", "attr.title": "tooltip() || null", "attr.aria-pressed": "pressed() === null ? null : pressed()", "disabled": "disabled() || null" } }, ngImport: i0, template: `<ng-content />`, isInline: true });
227
- }
228
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: EditorButtonComponent, decorators: [{
229
- type: Component,
230
- args: [{
231
- selector: 'button[EditorButton]',
232
- host: {
233
- '[class]': 'classes()',
234
- '[attr.data-slot]': '"editor-button"',
235
- '[attr.title]': 'tooltip() || null',
236
- '[attr.aria-pressed]': 'pressed() === null ? null : pressed()',
237
- '[disabled]': 'disabled() || null',
238
- type: 'button',
239
- '(mousedown)': 'preserveSelection($event)',
240
- '(click)': 'handleClick($event)',
241
- },
242
- template: `<ng-content />`,
243
- }]
244
- }], propDecorators: { command: [{ type: i0.Input, args: [{ isSignal: true, alias: "command", required: false }] }], pressed: [{ type: i0.Input, args: [{ isSignal: true, alias: "pressed", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], tooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltip", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
245
- class EditorSeparatorComponent {
246
- class = input('', /* @ts-ignore */
247
- ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
248
- classes = computed(() => cn('mx-1 h-6 w-px shrink-0 bg-border', this.class()), /* @ts-ignore */
249
- ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
250
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: EditorSeparatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
251
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.4", type: EditorSeparatorComponent, isStandalone: true, selector: "EditorSeparator", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "separator", "aria-orientation": "vertical" }, properties: { "class": "classes()", "attr.data-slot": "\"editor-separator\"" } }, ngImport: i0, template: '', isInline: true });
252
- }
253
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: EditorSeparatorComponent, decorators: [{
254
- type: Component,
255
- args: [{
256
- selector: 'EditorSeparator',
257
- host: {
258
- '[class]': 'classes()',
259
- '[attr.data-slot]': '"editor-separator"',
260
- role: 'separator',
261
- 'aria-orientation': 'vertical',
262
- },
263
- template: '',
264
- }]
265
- }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
266
- class EditorSpacerComponent {
267
- class = input('', /* @ts-ignore */
268
- ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
269
- classes = computed(() => cn('min-w-2 flex-1', this.class()), /* @ts-ignore */
270
- ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
271
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: EditorSpacerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
272
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.4", type: EditorSpacerComponent, isStandalone: true, selector: "EditorSpacer", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.data-slot": "\"editor-spacer\"" } }, ngImport: i0, template: '', isInline: true });
273
- }
274
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: EditorSpacerComponent, decorators: [{
275
- type: Component,
276
- args: [{
277
- selector: 'EditorSpacer',
278
- host: {
279
- '[class]': 'classes()',
280
- '[attr.data-slot]': '"editor-spacer"',
281
- },
282
- template: '',
283
- }]
284
- }], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
285
- class EditorContentComponent {
286
- el = inject(ElementRef);
287
- editor = inject(EditorComponent, { optional: true });
288
- document = inject(DOCUMENT);
289
- sanitizeHtml = inject(EDITOR_HTML_SANITIZER);
290
- placeholder = input('Write something...', /* @ts-ignore */
291
- ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
292
- ariaLabel = input('Rich text editor', { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: 'aria-label' });
293
- disabledInput = input(false, { ...(ngDevMode ? { debugName: "disabledInput" } : /* istanbul ignore next */ {}), alias: 'disabled', transform: booleanAttribute });
294
- invalidInput = input(false, { ...(ngDevMode ? { debugName: "invalidInput" } : /* istanbul ignore next */ {}), alias: 'aria-invalid', transform: booleanAttribute });
295
- class = input('', /* @ts-ignore */
296
- ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
297
- disabledState = signal(false, /* @ts-ignore */
298
- ...(ngDevMode ? [{ debugName: "disabledState" }] : /* istanbul ignore next */ []));
299
- empty = signal(true, /* @ts-ignore */
300
- ...(ngDevMode ? [{ debugName: "empty" }] : /* istanbul ignore next */ []));
301
- disabled = computed(() => this.disabledInput() || this.disabledState() || this.editor?.disabled() === true, /* @ts-ignore */
302
- ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
303
- invalid = computed(() => this.invalidInput() || this.editor?.invalid() === true, /* @ts-ignore */
304
- ...(ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []));
305
- classes = computed(() => cn(EDITOR_CONTENT_BASE, this.class()), /* @ts-ignore */
306
- ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
307
- lastKnownValue = '';
308
- onChange = () => { };
309
- onTouched = () => { };
310
- ngAfterViewInit() {
311
- this.editor?.registerContent(this);
312
- this.setSanitizedValue(this.el.nativeElement.innerHTML);
313
- queueMicrotask(() => this.syncEmptyState());
314
- }
315
- ngOnDestroy() {
316
- this.editor?.unregisterContent(this);
317
- }
318
- writeValue(value) {
319
- this.setSanitizedValue(value ?? '');
320
- queueMicrotask(() => this.syncEmptyState());
321
- }
322
- registerOnChange(fn) {
323
- this.onChange = fn;
324
- }
325
- registerOnTouched(fn) {
326
- this.onTouched = fn;
327
- }
328
- setDisabledState(isDisabled) {
329
- this.disabledState.set(isDisabled);
330
- }
331
- execute(command) {
332
- if (this.disabled()) {
333
- return;
334
- }
335
- this.el.nativeElement.focus();
336
- const [name, value] = EDITOR_EXEC_COMMANDS[command];
337
- this.exec(name, command === 'highlight' ? this.highlightColor() : value);
338
- this.handleInput();
339
- }
340
- focus() {
341
- this.el.nativeElement.focus();
342
- }
343
- handleInput() {
344
- const element = this.el.nativeElement;
345
- const unsafeHtml = element.innerHTML;
346
- const safeHtml = this.sanitizeHtml(unsafeHtml);
347
- if (safeHtml !== unsafeHtml) {
348
- element.innerHTML = safeHtml;
349
- }
350
- // Read back after assignment: the browser normalizes markup, so the
351
- // DOM-normalized form is the canonical value emitted to consumers.
352
- const html = element.innerHTML;
353
- this.syncEmptyState();
354
- if (html === this.lastKnownValue) {
355
- return;
356
- }
357
- this.lastKnownValue = html;
358
- this.onChange(html);
359
- }
360
- setSanitizedValue(value) {
361
- this.el.nativeElement.innerHTML = this.sanitizeHtml(value);
362
- this.lastKnownValue = this.el.nativeElement.innerHTML;
363
- }
364
- handleBlur() {
365
- this.onTouched();
366
- }
367
- handleKeydown(event) {
368
- if (this.disabled()) {
369
- return;
370
- }
371
- const command = this.shortcutCommand(event);
372
- if (!command) {
373
- return;
374
- }
375
- event.preventDefault();
376
- if (this.editor) {
377
- this.editor.execute(command, 'shortcut', event);
378
- return;
379
- }
380
- this.execute(command);
381
- }
382
- exec(command, value) {
383
- if (typeof this.document.execCommand !== 'function') {
384
- return;
385
- }
386
- this.document.execCommand(command, false, value);
387
- }
388
- highlightColor() {
389
- const highlight = this.document.defaultView
390
- ?.getComputedStyle(this.document.documentElement)
391
- .getPropertyValue('--editor-highlight')
392
- .trim();
393
- return highlight ? `hsl(${highlight})` : 'hsl(48 96% 80%)';
394
- }
395
- syncEmptyState() {
396
- const element = this.el.nativeElement;
397
- const html = element.innerHTML
398
- .replace(/<br\s*\/?>/gi, '')
399
- .replace(/&nbsp;/g, '')
400
- .trim();
401
- const text = element.textContent?.replace(/\u00a0/g, '').trim() ?? '';
402
- this.empty.set(html.length === 0 && text.length === 0);
403
- }
404
- shortcutCommand(event) {
405
- const modifier = event.metaKey || event.ctrlKey;
406
- if (!modifier) {
407
- return null;
408
- }
409
- const key = event.key.toLowerCase();
410
- // The digit rows are matched on the PHYSICAL key. `event.key` carries the
411
- // shifted or option-modified character -- `&`/`*` on a US layout, `/`/`(`
412
- // on DE/FR, `¡`/`™` for Option+1/2 on macOS -- so it is never the digit.
413
- const code = event.code;
414
- if (event.altKey && !event.shiftKey) {
415
- if (code === 'Digit0') {
416
- return 'paragraph';
417
- }
418
- if (code === 'Digit1') {
419
- return 'heading-1';
420
- }
421
- if (code === 'Digit2') {
422
- return 'heading-2';
423
- }
424
- if (code === 'Digit3') {
425
- return 'heading-3';
426
- }
427
- }
428
- if (event.shiftKey && !event.altKey) {
429
- if (code === 'Digit7') {
430
- return 'ordered';
431
- }
432
- if (code === 'Digit8') {
433
- return 'bullet';
434
- }
435
- switch (key) {
436
- case 'x':
437
- return 'strike';
438
- case 'b':
439
- return 'blockquote';
440
- case 'h':
441
- return 'highlight';
442
- case 'l':
443
- return 'align-left';
444
- case 'e':
445
- return 'align-center';
446
- case 'r':
447
- return 'align-right';
448
- case 'z':
449
- return 'redo';
450
- }
451
- }
452
- if (event.altKey || event.shiftKey) {
453
- return null;
454
- }
455
- switch (key) {
456
- case 'b':
457
- return 'bold';
458
- case 'i':
459
- return 'italic';
460
- case 'u':
461
- return 'underline';
462
- case 'e':
463
- return 'code';
464
- case 'z':
465
- return 'undo';
466
- default:
467
- return null;
468
- }
469
- }
470
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: EditorContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
471
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.4", type: EditorContentComponent, isStandalone: true, selector: "EditorContent", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalidInput: { classPropertyName: "invalidInput", publicName: "aria-invalid", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "input": "handleInput()", "blur": "handleBlur()", "keydown": "handleKeydown($event)" }, properties: { "class": "classes()", "attr.data-slot": "\"editor-content\"", "attr.contenteditable": "disabled() ? \"false\" : \"true\"", "attr.role": "\"textbox\"", "attr.aria-multiline": "\"true\"", "attr.aria-label": "ariaLabel()", "attr.aria-disabled": "disabled() ? \"true\" : null", "attr.aria-invalid": "invalid() ? \"true\" : null", "attr.data-disabled": "disabled() ? \"true\" : null", "attr.data-empty": "empty() ? \"true\" : null", "attr.data-placeholder": "placeholder()", "attr.tabindex": "disabled() ? null : \"0\"" } }, providers: [
472
- {
473
- provide: NG_VALUE_ACCESSOR,
474
- useExisting: forwardRef(() => EditorContentComponent),
475
- multi: true,
476
- },
477
- ], ngImport: i0, template: `<ng-content />`, isInline: true });
478
- }
479
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: EditorContentComponent, decorators: [{
480
- type: Component,
481
- args: [{
482
- selector: 'EditorContent',
483
- providers: [
484
- {
485
- provide: NG_VALUE_ACCESSOR,
486
- useExisting: forwardRef(() => EditorContentComponent),
487
- multi: true,
488
- },
489
- ],
490
- host: {
491
- '[class]': 'classes()',
492
- '[attr.data-slot]': '"editor-content"',
493
- '[attr.contenteditable]': 'disabled() ? "false" : "true"',
494
- '[attr.role]': '"textbox"',
495
- '[attr.aria-multiline]': '"true"',
496
- '[attr.aria-label]': 'ariaLabel()',
497
- '[attr.aria-disabled]': 'disabled() ? "true" : null',
498
- '[attr.aria-invalid]': 'invalid() ? "true" : null',
499
- '[attr.data-disabled]': 'disabled() ? "true" : null',
500
- '[attr.data-empty]': 'empty() ? "true" : null',
501
- '[attr.data-placeholder]': 'placeholder()',
502
- '[attr.tabindex]': 'disabled() ? null : "0"',
503
- '(input)': 'handleInput()',
504
- '(blur)': 'handleBlur()',
505
- '(keydown)': 'handleKeydown($event)',
506
- },
507
- template: `<ng-content />`,
508
- }]
509
- }], propDecorators: { placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalidInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-invalid", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }] } });
510
-
511
- /**
512
- * Generated bundle index. Do not edit.
513
- */
514
-
515
- export { EDITOR_HTML_SANITIZER, EditorButtonComponent, EditorComponent, EditorContentComponent, EditorSeparatorComponent, EditorSpacerComponent, EditorToolbarComponent };
155
+ var EditorComponent = class EditorComponent {
156
+ disabled = input(false, {
157
+ ...ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {},
158
+ transform: booleanAttribute
159
+ });
160
+ invalid = input(false, {
161
+ ...ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {},
162
+ transform: booleanAttribute
163
+ });
164
+ class = input("", ...ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []);
165
+ commandSelected = output();
166
+ content = null;
167
+ classes = computed(() => cn(EDITOR_BASE, this.class()), ...ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []);
168
+ shellClasses = computed(() => cn(EDITOR_SHELL_BASE), ...ngDevMode ? [{ debugName: "shellClasses" }] : /* istanbul ignore next */ []);
169
+ execute(command, source = "api", originalEvent) {
170
+ if (this.disabled()) return;
171
+ this.content?.execute(command);
172
+ this.commandSelected.emit({
173
+ command,
174
+ source,
175
+ originalEvent
176
+ });
177
+ }
178
+ registerContent(content) {
179
+ this.content = content;
180
+ }
181
+ unregisterContent(content) {
182
+ if (this.content === content) this.content = null;
183
+ }
184
+ static ɵfac = i0.ɵɵngDeclareFactory({
185
+ minVersion: "12.0.0",
186
+ version: "22.2.0",
187
+ ngImport: i0,
188
+ type: EditorComponent,
189
+ deps: [],
190
+ target: i0.ɵɵFactoryTarget.Component
191
+ });
192
+ static ɵcmp = i0.ɵɵngDeclareComponent({
193
+ minVersion: "17.1.0",
194
+ version: "22.2.0",
195
+ type: EditorComponent,
196
+ isStandalone: true,
197
+ selector: "Editor",
198
+ inputs: {
199
+ disabled: {
200
+ classPropertyName: "disabled",
201
+ publicName: "disabled",
202
+ isSignal: true,
203
+ isRequired: false,
204
+ transformFunction: null
205
+ },
206
+ invalid: {
207
+ classPropertyName: "invalid",
208
+ publicName: "invalid",
209
+ isSignal: true,
210
+ isRequired: false,
211
+ transformFunction: null
212
+ },
213
+ class: {
214
+ classPropertyName: "class",
215
+ publicName: "class",
216
+ isSignal: true,
217
+ isRequired: false,
218
+ transformFunction: null
219
+ }
220
+ },
221
+ outputs: { commandSelected: "commandSelected" },
222
+ host: { properties: {
223
+ "class": "classes()",
224
+ "attr.data-slot": "\"editor\"",
225
+ "attr.data-disabled": "disabled() ? \"true\" : null",
226
+ "attr.aria-disabled": "disabled() ? \"true\" : null",
227
+ "attr.aria-invalid": "invalid() ? \"true\" : null",
228
+ "attr.inert": "disabled() ? \"\" : null"
229
+ } },
230
+ ngImport: i0,
231
+ template: "<div\n data-slot=\"editor-shell\"\n [class]=\"shellClasses()\"\n [attr.data-disabled]=\"disabled() ? 'true' : null\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n>\n <ng-content select=\"EditorToolbar\" />\n <ng-content select=\"EditorContent\" />\n</div>\n"
232
+ });
233
+ };
234
+ i0.ɵɵngDeclareClassMetadata({
235
+ minVersion: "12.0.0",
236
+ version: "22.2.0",
237
+ ngImport: i0,
238
+ type: EditorComponent,
239
+ decorators: [{
240
+ type: Component,
241
+ args: [{
242
+ selector: "Editor",
243
+ host: {
244
+ "[class]": "classes()",
245
+ "[attr.data-slot]": "\"editor\"",
246
+ "[attr.data-disabled]": "disabled() ? \"true\" : null",
247
+ "[attr.aria-disabled]": "disabled() ? \"true\" : null",
248
+ "[attr.aria-invalid]": "invalid() ? \"true\" : null",
249
+ "[attr.inert]": "disabled() ? \"\" : null"
250
+ },
251
+ template: "<div\n data-slot=\"editor-shell\"\n [class]=\"shellClasses()\"\n [attr.data-disabled]=\"disabled() ? 'true' : null\"\n [attr.aria-invalid]=\"invalid() ? 'true' : null\"\n>\n <ng-content select=\"EditorToolbar\" />\n <ng-content select=\"EditorContent\" />\n</div>\n"
252
+ }]
253
+ }],
254
+ propDecorators: {
255
+ disabled: [{
256
+ type: i0.Input,
257
+ args: [{
258
+ isSignal: true,
259
+ alias: "disabled",
260
+ required: false
261
+ }]
262
+ }],
263
+ invalid: [{
264
+ type: i0.Input,
265
+ args: [{
266
+ isSignal: true,
267
+ alias: "invalid",
268
+ required: false
269
+ }]
270
+ }],
271
+ class: [{
272
+ type: i0.Input,
273
+ args: [{
274
+ isSignal: true,
275
+ alias: "class",
276
+ required: false
277
+ }]
278
+ }],
279
+ commandSelected: [{
280
+ type: i0.Output,
281
+ args: ["commandSelected"]
282
+ }]
283
+ }
284
+ });
285
+ var EditorToolbarComponent = class EditorToolbarComponent {
286
+ editor = inject(EditorComponent, { optional: true });
287
+ items = input(DEFAULT_EDITOR_TOOLBAR, ...ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []);
288
+ disabledInput = input(false, {
289
+ ...ngDevMode ? { debugName: "disabledInput" } : /* istanbul ignore next */ {},
290
+ alias: "disabled",
291
+ transform: booleanAttribute
292
+ });
293
+ ariaLabel = input("Formatting", {
294
+ ...ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {},
295
+ alias: "aria-label"
296
+ });
297
+ class = input("", ...ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []);
298
+ buttonClasses = EDITOR_TOOL_BUTTON_BASE;
299
+ selectClasses = EDITOR_SELECT_BASE;
300
+ disabled = computed(() => this.disabledInput() || this.editor?.disabled() === true, ...ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []);
301
+ parts = computed(() => parseToolbarItems(this.items()), ...ngDevMode ? [{ debugName: "parts" }] : /* istanbul ignore next */ []);
302
+ classes = computed(() => cn(EDITOR_TOOLBAR_BASE, this.class()), ...ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []);
303
+ execute(command, event) {
304
+ this.editor?.execute(command, "toolbar", event);
305
+ }
306
+ handleSelect(event) {
307
+ const select = event.target;
308
+ this.editor?.execute(select.value, "toolbar", event);
309
+ select.selectedIndex = 0;
310
+ }
311
+ preserveSelection = preserveEditorSelection;
312
+ trackPart(part, index) {
313
+ if (part.type === "button") return `${part.command}-${index}`;
314
+ return part.track;
315
+ }
316
+ static ɵfac = i0.ɵɵngDeclareFactory({
317
+ minVersion: "12.0.0",
318
+ version: "22.2.0",
319
+ ngImport: i0,
320
+ type: EditorToolbarComponent,
321
+ deps: [],
322
+ target: i0.ɵɵFactoryTarget.Component
323
+ });
324
+ static ɵcmp = i0.ɵɵngDeclareComponent({
325
+ minVersion: "17.0.0",
326
+ version: "22.2.0",
327
+ type: EditorToolbarComponent,
328
+ isStandalone: true,
329
+ selector: "EditorToolbar",
330
+ inputs: {
331
+ items: {
332
+ classPropertyName: "items",
333
+ publicName: "items",
334
+ isSignal: true,
335
+ isRequired: false,
336
+ transformFunction: null
337
+ },
338
+ disabledInput: {
339
+ classPropertyName: "disabledInput",
340
+ publicName: "disabled",
341
+ isSignal: true,
342
+ isRequired: false,
343
+ transformFunction: null
344
+ },
345
+ ariaLabel: {
346
+ classPropertyName: "ariaLabel",
347
+ publicName: "aria-label",
348
+ isSignal: true,
349
+ isRequired: false,
350
+ transformFunction: null
351
+ },
352
+ class: {
353
+ classPropertyName: "class",
354
+ publicName: "class",
355
+ isSignal: true,
356
+ isRequired: false,
357
+ transformFunction: null
358
+ }
359
+ },
360
+ host: {
361
+ attributes: { "role": "toolbar" },
362
+ properties: {
363
+ "class": "classes()",
364
+ "attr.data-slot": "\"editor-toolbar\"",
365
+ "attr.aria-label": "ariaLabel()",
366
+ "attr.data-disabled": "disabled() ? \"true\" : null"
367
+ }
368
+ },
369
+ ngImport: i0,
370
+ template: "@for (part of parts(); track trackPart(part, $index)) {\n @switch (part.type) {\n @case ('heading') {\n <select\n [class]=\"selectClasses\"\n [disabled]=\"disabled()\"\n aria-label=\"Text style\"\n (change)=\"handleSelect($event)\"\n >\n <option value=\"paragraph\">Text</option>\n <option value=\"heading-1\">Heading 1</option>\n <option value=\"heading-2\">Heading 2</option>\n <option value=\"heading-3\">Heading 3</option>\n </select>\n }\n @case ('align') {\n <select\n [class]=\"selectClasses\"\n [disabled]=\"disabled()\"\n aria-label=\"Text alignment\"\n (change)=\"handleSelect($event)\"\n >\n <option value=\"align-left\">Left</option>\n <option value=\"align-center\">Center</option>\n <option value=\"align-right\">Right</option>\n </select>\n }\n @case ('separator') {\n <span\n data-slot=\"editor-separator\"\n class=\"mx-1 h-6 w-px shrink-0 bg-border\"\n role=\"separator\"\n aria-orientation=\"vertical\"\n ></span>\n }\n @case ('spacer') {\n <span data-slot=\"editor-spacer\" class=\"min-w-2 flex-1\"></span>\n }\n @case ('button') {\n <button\n type=\"button\"\n data-slot=\"editor-button\"\n [class]=\"buttonClasses\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"part.ariaLabel\"\n [attr.title]=\"part.ariaLabel\"\n (mousedown)=\"preserveSelection($event)\"\n (click)=\"execute(part.command, $event)\"\n >\n @if (part.command === 'undo') {\n <svg\n aria-hidden=\"true\"\n class=\"size-4\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"M9 14 4 9l5-5\" />\n <path d=\"M4 9h10a6 6 0 0 1 0 12h-2\" />\n </svg>\n } @else if (part.command === 'redo') {\n <svg\n aria-hidden=\"true\"\n class=\"size-4\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"m15 14 5-5-5-5\" />\n <path d=\"M20 9H10a6 6 0 0 0 0 12h2\" />\n </svg>\n } @else {\n <span aria-hidden=\"true\">{{ part.label }}</span>\n }\n </button>\n }\n }\n}\n<ng-content />\n"
371
+ });
372
+ };
373
+ i0.ɵɵngDeclareClassMetadata({
374
+ minVersion: "12.0.0",
375
+ version: "22.2.0",
376
+ ngImport: i0,
377
+ type: EditorToolbarComponent,
378
+ decorators: [{
379
+ type: Component,
380
+ args: [{
381
+ selector: "EditorToolbar",
382
+ host: {
383
+ "[class]": "classes()",
384
+ "[attr.data-slot]": "\"editor-toolbar\"",
385
+ role: "toolbar",
386
+ "[attr.aria-label]": "ariaLabel()",
387
+ "[attr.data-disabled]": "disabled() ? \"true\" : null"
388
+ },
389
+ template: "@for (part of parts(); track trackPart(part, $index)) {\n @switch (part.type) {\n @case ('heading') {\n <select\n [class]=\"selectClasses\"\n [disabled]=\"disabled()\"\n aria-label=\"Text style\"\n (change)=\"handleSelect($event)\"\n >\n <option value=\"paragraph\">Text</option>\n <option value=\"heading-1\">Heading 1</option>\n <option value=\"heading-2\">Heading 2</option>\n <option value=\"heading-3\">Heading 3</option>\n </select>\n }\n @case ('align') {\n <select\n [class]=\"selectClasses\"\n [disabled]=\"disabled()\"\n aria-label=\"Text alignment\"\n (change)=\"handleSelect($event)\"\n >\n <option value=\"align-left\">Left</option>\n <option value=\"align-center\">Center</option>\n <option value=\"align-right\">Right</option>\n </select>\n }\n @case ('separator') {\n <span\n data-slot=\"editor-separator\"\n class=\"mx-1 h-6 w-px shrink-0 bg-border\"\n role=\"separator\"\n aria-orientation=\"vertical\"\n ></span>\n }\n @case ('spacer') {\n <span data-slot=\"editor-spacer\" class=\"min-w-2 flex-1\"></span>\n }\n @case ('button') {\n <button\n type=\"button\"\n data-slot=\"editor-button\"\n [class]=\"buttonClasses\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"part.ariaLabel\"\n [attr.title]=\"part.ariaLabel\"\n (mousedown)=\"preserveSelection($event)\"\n (click)=\"execute(part.command, $event)\"\n >\n @if (part.command === 'undo') {\n <svg\n aria-hidden=\"true\"\n class=\"size-4\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"M9 14 4 9l5-5\" />\n <path d=\"M4 9h10a6 6 0 0 1 0 12h-2\" />\n </svg>\n } @else if (part.command === 'redo') {\n <svg\n aria-hidden=\"true\"\n class=\"size-4\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <path d=\"m15 14 5-5-5-5\" />\n <path d=\"M20 9H10a6 6 0 0 0 0 12h2\" />\n </svg>\n } @else {\n <span aria-hidden=\"true\">{{ part.label }}</span>\n }\n </button>\n }\n }\n}\n<ng-content />\n"
390
+ }]
391
+ }],
392
+ propDecorators: {
393
+ items: [{
394
+ type: i0.Input,
395
+ args: [{
396
+ isSignal: true,
397
+ alias: "items",
398
+ required: false
399
+ }]
400
+ }],
401
+ disabledInput: [{
402
+ type: i0.Input,
403
+ args: [{
404
+ isSignal: true,
405
+ alias: "disabled",
406
+ required: false
407
+ }]
408
+ }],
409
+ ariaLabel: [{
410
+ type: i0.Input,
411
+ args: [{
412
+ isSignal: true,
413
+ alias: "aria-label",
414
+ required: false
415
+ }]
416
+ }],
417
+ class: [{
418
+ type: i0.Input,
419
+ args: [{
420
+ isSignal: true,
421
+ alias: "class",
422
+ required: false
423
+ }]
424
+ }]
425
+ }
426
+ });
427
+ var EditorButtonComponent = class EditorButtonComponent {
428
+ editor = inject(EditorComponent, { optional: true });
429
+ command = input(null, ...ngDevMode ? [{ debugName: "command" }] : /* istanbul ignore next */ []);
430
+ pressed = input(null, ...ngDevMode ? [{ debugName: "pressed" }] : /* istanbul ignore next */ []);
431
+ disabledInput = input(false, {
432
+ ...ngDevMode ? { debugName: "disabledInput" } : /* istanbul ignore next */ {},
433
+ alias: "disabled",
434
+ transform: booleanAttribute
435
+ });
436
+ tooltip = input("", ...ngDevMode ? [{ debugName: "tooltip" }] : /* istanbul ignore next */ []);
437
+ class = input("", ...ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []);
438
+ disabled = computed(() => this.disabledInput() || this.editor?.disabled() === true, ...ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []);
439
+ classes = computed(() => cn(EDITOR_TOOL_BUTTON_BASE, this.class()), ...ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []);
440
+ handleClick(event) {
441
+ const command = this.command();
442
+ if (!command) return;
443
+ this.editor?.execute(command, "toolbar", event);
444
+ }
445
+ preserveSelection = preserveEditorSelection;
446
+ static ɵfac = i0.ɵɵngDeclareFactory({
447
+ minVersion: "12.0.0",
448
+ version: "22.2.0",
449
+ ngImport: i0,
450
+ type: EditorButtonComponent,
451
+ deps: [],
452
+ target: i0.ɵɵFactoryTarget.Component
453
+ });
454
+ static ɵcmp = i0.ɵɵngDeclareComponent({
455
+ minVersion: "17.1.0",
456
+ version: "22.2.0",
457
+ type: EditorButtonComponent,
458
+ isStandalone: true,
459
+ selector: "button[EditorButton]",
460
+ inputs: {
461
+ command: {
462
+ classPropertyName: "command",
463
+ publicName: "command",
464
+ isSignal: true,
465
+ isRequired: false,
466
+ transformFunction: null
467
+ },
468
+ pressed: {
469
+ classPropertyName: "pressed",
470
+ publicName: "pressed",
471
+ isSignal: true,
472
+ isRequired: false,
473
+ transformFunction: null
474
+ },
475
+ disabledInput: {
476
+ classPropertyName: "disabledInput",
477
+ publicName: "disabled",
478
+ isSignal: true,
479
+ isRequired: false,
480
+ transformFunction: null
481
+ },
482
+ tooltip: {
483
+ classPropertyName: "tooltip",
484
+ publicName: "tooltip",
485
+ isSignal: true,
486
+ isRequired: false,
487
+ transformFunction: null
488
+ },
489
+ class: {
490
+ classPropertyName: "class",
491
+ publicName: "class",
492
+ isSignal: true,
493
+ isRequired: false,
494
+ transformFunction: null
495
+ }
496
+ },
497
+ host: {
498
+ attributes: { "type": "button" },
499
+ listeners: {
500
+ "mousedown": "preserveSelection($event)",
501
+ "click": "handleClick($event)"
502
+ },
503
+ properties: {
504
+ "class": "classes()",
505
+ "attr.data-slot": "\"editor-button\"",
506
+ "attr.title": "tooltip() || null",
507
+ "attr.aria-pressed": "pressed() === null ? null : pressed()",
508
+ "disabled": "disabled() || null"
509
+ }
510
+ },
511
+ ngImport: i0,
512
+ template: `<ng-content />`,
513
+ isInline: true
514
+ });
515
+ };
516
+ i0.ɵɵngDeclareClassMetadata({
517
+ minVersion: "12.0.0",
518
+ version: "22.2.0",
519
+ ngImport: i0,
520
+ type: EditorButtonComponent,
521
+ decorators: [{
522
+ type: Component,
523
+ args: [{
524
+ selector: "button[EditorButton]",
525
+ host: {
526
+ "[class]": "classes()",
527
+ "[attr.data-slot]": "\"editor-button\"",
528
+ "[attr.title]": "tooltip() || null",
529
+ "[attr.aria-pressed]": "pressed() === null ? null : pressed()",
530
+ "[disabled]": "disabled() || null",
531
+ type: "button",
532
+ "(mousedown)": "preserveSelection($event)",
533
+ "(click)": "handleClick($event)"
534
+ },
535
+ template: `<ng-content />`
536
+ }]
537
+ }],
538
+ propDecorators: {
539
+ command: [{
540
+ type: i0.Input,
541
+ args: [{
542
+ isSignal: true,
543
+ alias: "command",
544
+ required: false
545
+ }]
546
+ }],
547
+ pressed: [{
548
+ type: i0.Input,
549
+ args: [{
550
+ isSignal: true,
551
+ alias: "pressed",
552
+ required: false
553
+ }]
554
+ }],
555
+ disabledInput: [{
556
+ type: i0.Input,
557
+ args: [{
558
+ isSignal: true,
559
+ alias: "disabled",
560
+ required: false
561
+ }]
562
+ }],
563
+ tooltip: [{
564
+ type: i0.Input,
565
+ args: [{
566
+ isSignal: true,
567
+ alias: "tooltip",
568
+ required: false
569
+ }]
570
+ }],
571
+ class: [{
572
+ type: i0.Input,
573
+ args: [{
574
+ isSignal: true,
575
+ alias: "class",
576
+ required: false
577
+ }]
578
+ }]
579
+ }
580
+ });
581
+ var EditorSeparatorComponent = class EditorSeparatorComponent {
582
+ class = input("", ...ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []);
583
+ classes = computed(() => cn("mx-1 h-6 w-px shrink-0 bg-border", this.class()), ...ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []);
584
+ static ɵfac = i0.ɵɵngDeclareFactory({
585
+ minVersion: "12.0.0",
586
+ version: "22.2.0",
587
+ ngImport: i0,
588
+ type: EditorSeparatorComponent,
589
+ deps: [],
590
+ target: i0.ɵɵFactoryTarget.Component
591
+ });
592
+ static ɵcmp = i0.ɵɵngDeclareComponent({
593
+ minVersion: "17.1.0",
594
+ version: "22.2.0",
595
+ type: EditorSeparatorComponent,
596
+ isStandalone: true,
597
+ selector: "EditorSeparator",
598
+ inputs: { class: {
599
+ classPropertyName: "class",
600
+ publicName: "class",
601
+ isSignal: true,
602
+ isRequired: false,
603
+ transformFunction: null
604
+ } },
605
+ host: {
606
+ attributes: {
607
+ "role": "separator",
608
+ "aria-orientation": "vertical"
609
+ },
610
+ properties: {
611
+ "class": "classes()",
612
+ "attr.data-slot": "\"editor-separator\""
613
+ }
614
+ },
615
+ ngImport: i0,
616
+ template: "",
617
+ isInline: true
618
+ });
619
+ };
620
+ i0.ɵɵngDeclareClassMetadata({
621
+ minVersion: "12.0.0",
622
+ version: "22.2.0",
623
+ ngImport: i0,
624
+ type: EditorSeparatorComponent,
625
+ decorators: [{
626
+ type: Component,
627
+ args: [{
628
+ selector: "EditorSeparator",
629
+ host: {
630
+ "[class]": "classes()",
631
+ "[attr.data-slot]": "\"editor-separator\"",
632
+ role: "separator",
633
+ "aria-orientation": "vertical"
634
+ },
635
+ template: ""
636
+ }]
637
+ }],
638
+ propDecorators: { class: [{
639
+ type: i0.Input,
640
+ args: [{
641
+ isSignal: true,
642
+ alias: "class",
643
+ required: false
644
+ }]
645
+ }] }
646
+ });
647
+ var EditorSpacerComponent = class EditorSpacerComponent {
648
+ class = input("", ...ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []);
649
+ classes = computed(() => cn("min-w-2 flex-1", this.class()), ...ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []);
650
+ static ɵfac = i0.ɵɵngDeclareFactory({
651
+ minVersion: "12.0.0",
652
+ version: "22.2.0",
653
+ ngImport: i0,
654
+ type: EditorSpacerComponent,
655
+ deps: [],
656
+ target: i0.ɵɵFactoryTarget.Component
657
+ });
658
+ static ɵcmp = i0.ɵɵngDeclareComponent({
659
+ minVersion: "17.1.0",
660
+ version: "22.2.0",
661
+ type: EditorSpacerComponent,
662
+ isStandalone: true,
663
+ selector: "EditorSpacer",
664
+ inputs: { class: {
665
+ classPropertyName: "class",
666
+ publicName: "class",
667
+ isSignal: true,
668
+ isRequired: false,
669
+ transformFunction: null
670
+ } },
671
+ host: { properties: {
672
+ "class": "classes()",
673
+ "attr.data-slot": "\"editor-spacer\""
674
+ } },
675
+ ngImport: i0,
676
+ template: "",
677
+ isInline: true
678
+ });
679
+ };
680
+ i0.ɵɵngDeclareClassMetadata({
681
+ minVersion: "12.0.0",
682
+ version: "22.2.0",
683
+ ngImport: i0,
684
+ type: EditorSpacerComponent,
685
+ decorators: [{
686
+ type: Component,
687
+ args: [{
688
+ selector: "EditorSpacer",
689
+ host: {
690
+ "[class]": "classes()",
691
+ "[attr.data-slot]": "\"editor-spacer\""
692
+ },
693
+ template: ""
694
+ }]
695
+ }],
696
+ propDecorators: { class: [{
697
+ type: i0.Input,
698
+ args: [{
699
+ isSignal: true,
700
+ alias: "class",
701
+ required: false
702
+ }]
703
+ }] }
704
+ });
705
+ var EditorContentComponent = class EditorContentComponent {
706
+ el = inject(ElementRef);
707
+ editor = inject(EditorComponent, { optional: true });
708
+ document = inject(DOCUMENT);
709
+ sanitizeHtml = inject(EDITOR_HTML_SANITIZER);
710
+ placeholder = input("Write something...", ...ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []);
711
+ ariaLabel = input("Rich text editor", {
712
+ ...ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {},
713
+ alias: "aria-label"
714
+ });
715
+ disabledInput = input(false, {
716
+ ...ngDevMode ? { debugName: "disabledInput" } : /* istanbul ignore next */ {},
717
+ alias: "disabled",
718
+ transform: booleanAttribute
719
+ });
720
+ invalidInput = input(false, {
721
+ ...ngDevMode ? { debugName: "invalidInput" } : /* istanbul ignore next */ {},
722
+ alias: "aria-invalid",
723
+ transform: booleanAttribute
724
+ });
725
+ class = input("", ...ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []);
726
+ disabledState = signal(false, ...ngDevMode ? [{ debugName: "disabledState" }] : /* istanbul ignore next */ []);
727
+ empty = signal(true, ...ngDevMode ? [{ debugName: "empty" }] : /* istanbul ignore next */ []);
728
+ disabled = computed(() => this.disabledInput() || this.disabledState() || this.editor?.disabled() === true, ...ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []);
729
+ invalid = computed(() => this.invalidInput() || this.editor?.invalid() === true, ...ngDevMode ? [{ debugName: "invalid" }] : /* istanbul ignore next */ []);
730
+ classes = computed(() => cn(EDITOR_CONTENT_BASE, this.class()), ...ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []);
731
+ lastKnownValue = "";
732
+ onChange = () => {};
733
+ onTouched = () => {};
734
+ ngAfterViewInit() {
735
+ this.editor?.registerContent(this);
736
+ this.setSanitizedValue(this.el.nativeElement.innerHTML);
737
+ queueMicrotask(() => this.syncEmptyState());
738
+ }
739
+ ngOnDestroy() {
740
+ this.editor?.unregisterContent(this);
741
+ }
742
+ writeValue(value) {
743
+ this.setSanitizedValue(value ?? "");
744
+ queueMicrotask(() => this.syncEmptyState());
745
+ }
746
+ registerOnChange(fn) {
747
+ this.onChange = fn;
748
+ }
749
+ registerOnTouched(fn) {
750
+ this.onTouched = fn;
751
+ }
752
+ setDisabledState(isDisabled) {
753
+ this.disabledState.set(isDisabled);
754
+ }
755
+ execute(command) {
756
+ if (this.disabled()) return;
757
+ this.el.nativeElement.focus();
758
+ const [name, value] = EDITOR_EXEC_COMMANDS[command];
759
+ this.exec(name, command === "highlight" ? this.highlightColor() : value);
760
+ this.handleInput();
761
+ }
762
+ focus() {
763
+ this.el.nativeElement.focus();
764
+ }
765
+ handleInput() {
766
+ const element = this.el.nativeElement;
767
+ const unsafeHtml = element.innerHTML;
768
+ const safeHtml = this.sanitizeHtml(unsafeHtml);
769
+ if (safeHtml !== unsafeHtml) element.innerHTML = safeHtml;
770
+ const html = element.innerHTML;
771
+ this.syncEmptyState();
772
+ if (html === this.lastKnownValue) return;
773
+ this.lastKnownValue = html;
774
+ this.onChange(html);
775
+ }
776
+ setSanitizedValue(value) {
777
+ this.el.nativeElement.innerHTML = this.sanitizeHtml(value);
778
+ this.lastKnownValue = this.el.nativeElement.innerHTML;
779
+ }
780
+ handleBlur() {
781
+ this.onTouched();
782
+ }
783
+ handleKeydown(event) {
784
+ if (this.disabled()) return;
785
+ const command = this.shortcutCommand(event);
786
+ if (!command) return;
787
+ event.preventDefault();
788
+ if (this.editor) {
789
+ this.editor.execute(command, "shortcut", event);
790
+ return;
791
+ }
792
+ this.execute(command);
793
+ }
794
+ exec(command, value) {
795
+ if (typeof this.document.execCommand !== "function") return;
796
+ this.document.execCommand(command, false, value);
797
+ }
798
+ highlightColor() {
799
+ const highlight = this.document.defaultView?.getComputedStyle(this.document.documentElement).getPropertyValue("--editor-highlight").trim();
800
+ return highlight ? `hsl(${highlight})` : "hsl(48 96% 80%)";
801
+ }
802
+ syncEmptyState() {
803
+ const element = this.el.nativeElement;
804
+ const html = element.innerHTML.replace(/<br\s*\/?>/gi, "").replace(/&nbsp;/g, "").trim();
805
+ const text = element.textContent?.replace(/\u00a0/g, "").trim() ?? "";
806
+ this.empty.set(html.length === 0 && text.length === 0);
807
+ }
808
+ shortcutCommand(event) {
809
+ if (!(event.metaKey || event.ctrlKey)) return null;
810
+ const key = event.key.toLowerCase();
811
+ const code = event.code;
812
+ if (event.altKey && !event.shiftKey) {
813
+ if (code === "Digit0") return "paragraph";
814
+ if (code === "Digit1") return "heading-1";
815
+ if (code === "Digit2") return "heading-2";
816
+ if (code === "Digit3") return "heading-3";
817
+ }
818
+ if (event.shiftKey && !event.altKey) {
819
+ if (code === "Digit7") return "ordered";
820
+ if (code === "Digit8") return "bullet";
821
+ switch (key) {
822
+ case "x": return "strike";
823
+ case "b": return "blockquote";
824
+ case "h": return "highlight";
825
+ case "l": return "align-left";
826
+ case "e": return "align-center";
827
+ case "r": return "align-right";
828
+ case "z": return "redo";
829
+ }
830
+ }
831
+ if (event.altKey || event.shiftKey) return null;
832
+ switch (key) {
833
+ case "b": return "bold";
834
+ case "i": return "italic";
835
+ case "u": return "underline";
836
+ case "e": return "code";
837
+ case "z": return "undo";
838
+ default: return null;
839
+ }
840
+ }
841
+ static ɵfac = i0.ɵɵngDeclareFactory({
842
+ minVersion: "12.0.0",
843
+ version: "22.2.0",
844
+ ngImport: i0,
845
+ type: EditorContentComponent,
846
+ deps: [],
847
+ target: i0.ɵɵFactoryTarget.Component
848
+ });
849
+ static ɵcmp = i0.ɵɵngDeclareComponent({
850
+ minVersion: "17.1.0",
851
+ version: "22.2.0",
852
+ type: EditorContentComponent,
853
+ isStandalone: true,
854
+ selector: "EditorContent",
855
+ inputs: {
856
+ placeholder: {
857
+ classPropertyName: "placeholder",
858
+ publicName: "placeholder",
859
+ isSignal: true,
860
+ isRequired: false,
861
+ transformFunction: null
862
+ },
863
+ ariaLabel: {
864
+ classPropertyName: "ariaLabel",
865
+ publicName: "aria-label",
866
+ isSignal: true,
867
+ isRequired: false,
868
+ transformFunction: null
869
+ },
870
+ disabledInput: {
871
+ classPropertyName: "disabledInput",
872
+ publicName: "disabled",
873
+ isSignal: true,
874
+ isRequired: false,
875
+ transformFunction: null
876
+ },
877
+ invalidInput: {
878
+ classPropertyName: "invalidInput",
879
+ publicName: "aria-invalid",
880
+ isSignal: true,
881
+ isRequired: false,
882
+ transformFunction: null
883
+ },
884
+ class: {
885
+ classPropertyName: "class",
886
+ publicName: "class",
887
+ isSignal: true,
888
+ isRequired: false,
889
+ transformFunction: null
890
+ }
891
+ },
892
+ host: {
893
+ listeners: {
894
+ "input": "handleInput()",
895
+ "blur": "handleBlur()",
896
+ "keydown": "handleKeydown($event)"
897
+ },
898
+ properties: {
899
+ "class": "classes()",
900
+ "attr.data-slot": "\"editor-content\"",
901
+ "attr.contenteditable": "disabled() ? \"false\" : \"true\"",
902
+ "attr.role": "\"textbox\"",
903
+ "attr.aria-multiline": "\"true\"",
904
+ "attr.aria-label": "ariaLabel()",
905
+ "attr.aria-disabled": "disabled() ? \"true\" : null",
906
+ "attr.aria-invalid": "invalid() ? \"true\" : null",
907
+ "attr.data-disabled": "disabled() ? \"true\" : null",
908
+ "attr.data-empty": "empty() ? \"true\" : null",
909
+ "attr.data-placeholder": "placeholder()",
910
+ "attr.tabindex": "disabled() ? null : \"0\""
911
+ }
912
+ },
913
+ providers: [{
914
+ provide: NG_VALUE_ACCESSOR,
915
+ useExisting: forwardRef(() => EditorContentComponent),
916
+ multi: true
917
+ }],
918
+ ngImport: i0,
919
+ template: `<ng-content />`,
920
+ isInline: true
921
+ });
922
+ };
923
+ i0.ɵɵngDeclareClassMetadata({
924
+ minVersion: "12.0.0",
925
+ version: "22.2.0",
926
+ ngImport: i0,
927
+ type: EditorContentComponent,
928
+ decorators: [{
929
+ type: Component,
930
+ args: [{
931
+ selector: "EditorContent",
932
+ providers: [{
933
+ provide: NG_VALUE_ACCESSOR,
934
+ useExisting: forwardRef(() => EditorContentComponent),
935
+ multi: true
936
+ }],
937
+ host: {
938
+ "[class]": "classes()",
939
+ "[attr.data-slot]": "\"editor-content\"",
940
+ "[attr.contenteditable]": "disabled() ? \"false\" : \"true\"",
941
+ "[attr.role]": "\"textbox\"",
942
+ "[attr.aria-multiline]": "\"true\"",
943
+ "[attr.aria-label]": "ariaLabel()",
944
+ "[attr.aria-disabled]": "disabled() ? \"true\" : null",
945
+ "[attr.aria-invalid]": "invalid() ? \"true\" : null",
946
+ "[attr.data-disabled]": "disabled() ? \"true\" : null",
947
+ "[attr.data-empty]": "empty() ? \"true\" : null",
948
+ "[attr.data-placeholder]": "placeholder()",
949
+ "[attr.tabindex]": "disabled() ? null : \"0\"",
950
+ "(input)": "handleInput()",
951
+ "(blur)": "handleBlur()",
952
+ "(keydown)": "handleKeydown($event)"
953
+ },
954
+ template: `<ng-content />`
955
+ }]
956
+ }],
957
+ propDecorators: {
958
+ placeholder: [{
959
+ type: i0.Input,
960
+ args: [{
961
+ isSignal: true,
962
+ alias: "placeholder",
963
+ required: false
964
+ }]
965
+ }],
966
+ ariaLabel: [{
967
+ type: i0.Input,
968
+ args: [{
969
+ isSignal: true,
970
+ alias: "aria-label",
971
+ required: false
972
+ }]
973
+ }],
974
+ disabledInput: [{
975
+ type: i0.Input,
976
+ args: [{
977
+ isSignal: true,
978
+ alias: "disabled",
979
+ required: false
980
+ }]
981
+ }],
982
+ invalidInput: [{
983
+ type: i0.Input,
984
+ args: [{
985
+ isSignal: true,
986
+ alias: "aria-invalid",
987
+ required: false
988
+ }]
989
+ }],
990
+ class: [{
991
+ type: i0.Input,
992
+ args: [{
993
+ isSignal: true,
994
+ alias: "class",
995
+ required: false
996
+ }]
997
+ }]
998
+ }
999
+ });
1000
+ export { EDITOR_HTML_SANITIZER, EditorButtonComponent, EditorComponent, EditorContentComponent, EditorSeparatorComponent, EditorSpacerComponent, EditorToolbarComponent };