@prenta/admin 0.92.0 → 0.94.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 (425) hide show
  1. package/CHANGELOG.md +663 -0
  2. package/design-system/tokens.css +173 -71
  3. package/design-system/tokens.json +244 -63
  4. package/design-system/tokens.scss +203 -98
  5. package/design-system/tokens.tailwind.cjs +93 -38
  6. package/dist/AdminRoot.d.ts +27 -6
  7. package/dist/AdminRoot.d.ts.map +1 -1
  8. package/dist/AdminRoot.js.map +1 -1
  9. package/dist/__tests__/components/breakpoint-controls.render.test.d.ts +2 -0
  10. package/dist/__tests__/components/breakpoint-controls.render.test.d.ts.map +1 -0
  11. package/dist/__tests__/components/breakpoint-controls.render.test.js +51 -0
  12. package/dist/__tests__/components/breakpoint-controls.render.test.js.map +1 -0
  13. package/dist/__tests__/components/canvas-edit-tip.render.test.d.ts +2 -0
  14. package/dist/__tests__/components/canvas-edit-tip.render.test.d.ts.map +1 -0
  15. package/dist/__tests__/components/canvas-edit-tip.render.test.js +37 -0
  16. package/dist/__tests__/components/canvas-edit-tip.render.test.js.map +1 -0
  17. package/dist/__tests__/components/editor-rail.render.test.d.ts +2 -0
  18. package/dist/__tests__/components/editor-rail.render.test.d.ts.map +1 -0
  19. package/dist/__tests__/components/editor-rail.render.test.js +138 -0
  20. package/dist/__tests__/components/editor-rail.render.test.js.map +1 -0
  21. package/dist/__tests__/components/media-block.render.test.d.ts +2 -0
  22. package/dist/__tests__/components/media-block.render.test.d.ts.map +1 -0
  23. package/dist/__tests__/components/media-block.render.test.js +108 -0
  24. package/dist/__tests__/components/media-block.render.test.js.map +1 -0
  25. package/dist/__tests__/components/page-audit-panel.render.test.d.ts +2 -0
  26. package/dist/__tests__/components/page-audit-panel.render.test.d.ts.map +1 -0
  27. package/dist/__tests__/components/page-audit-panel.render.test.js +59 -0
  28. package/dist/__tests__/components/page-audit-panel.render.test.js.map +1 -0
  29. package/dist/__tests__/components/reflow-meter.render.test.d.ts +2 -0
  30. package/dist/__tests__/components/reflow-meter.render.test.d.ts.map +1 -0
  31. package/dist/__tests__/components/reflow-meter.render.test.js +94 -0
  32. package/dist/__tests__/components/reflow-meter.render.test.js.map +1 -0
  33. package/dist/__tests__/components/seo-char-count.test.js +24 -6
  34. package/dist/__tests__/components/seo-char-count.test.js.map +1 -1
  35. package/dist/__tests__/components/serp-preview.render.test.d.ts +2 -0
  36. package/dist/__tests__/components/serp-preview.render.test.d.ts.map +1 -0
  37. package/dist/__tests__/components/serp-preview.render.test.js +25 -0
  38. package/dist/__tests__/components/serp-preview.render.test.js.map +1 -0
  39. package/dist/__tests__/lib/breakpoints.test.d.ts +2 -0
  40. package/dist/__tests__/lib/breakpoints.test.d.ts.map +1 -0
  41. package/dist/__tests__/lib/breakpoints.test.js +67 -0
  42. package/dist/__tests__/lib/breakpoints.test.js.map +1 -0
  43. package/dist/__tests__/lib/canvas-edit-chrome.test.d.ts +2 -0
  44. package/dist/__tests__/lib/canvas-edit-chrome.test.d.ts.map +1 -0
  45. package/dist/__tests__/lib/canvas-edit-chrome.test.js +44 -0
  46. package/dist/__tests__/lib/canvas-edit-chrome.test.js.map +1 -0
  47. package/dist/__tests__/lib/media-format.test.d.ts +2 -0
  48. package/dist/__tests__/lib/media-format.test.d.ts.map +1 -0
  49. package/dist/__tests__/lib/media-format.test.js +70 -0
  50. package/dist/__tests__/lib/media-format.test.js.map +1 -0
  51. package/dist/__tests__/lib/page-audit-input.test.d.ts +2 -0
  52. package/dist/__tests__/lib/page-audit-input.test.d.ts.map +1 -0
  53. package/dist/__tests__/lib/page-audit-input.test.js +122 -0
  54. package/dist/__tests__/lib/page-audit-input.test.js.map +1 -0
  55. package/dist/__tests__/lib/page-editor-service.test.js +2 -0
  56. package/dist/__tests__/lib/page-editor-service.test.js.map +1 -1
  57. package/dist/__tests__/lib/page-redirect.test.d.ts +2 -0
  58. package/dist/__tests__/lib/page-redirect.test.d.ts.map +1 -0
  59. package/dist/__tests__/lib/page-redirect.test.js +26 -0
  60. package/dist/__tests__/lib/page-redirect.test.js.map +1 -0
  61. package/dist/__tests__/lib/rail-width.test.d.ts +2 -0
  62. package/dist/__tests__/lib/rail-width.test.d.ts.map +1 -0
  63. package/dist/__tests__/lib/rail-width.test.js +69 -0
  64. package/dist/__tests__/lib/rail-width.test.js.map +1 -0
  65. package/dist/__tests__/lib/reflow-baseline.test.d.ts +2 -0
  66. package/dist/__tests__/lib/reflow-baseline.test.d.ts.map +1 -0
  67. package/dist/__tests__/lib/reflow-baseline.test.js +56 -0
  68. package/dist/__tests__/lib/reflow-baseline.test.js.map +1 -0
  69. package/dist/__tests__/lib/reflow-probe.test.d.ts +2 -0
  70. package/dist/__tests__/lib/reflow-probe.test.d.ts.map +1 -0
  71. package/dist/__tests__/lib/reflow-probe.test.js +73 -0
  72. package/dist/__tests__/lib/reflow-probe.test.js.map +1 -0
  73. package/dist/__tests__/lib/version-diff.test.d.ts +2 -0
  74. package/dist/__tests__/lib/version-diff.test.d.ts.map +1 -0
  75. package/dist/__tests__/lib/version-diff.test.js +230 -0
  76. package/dist/__tests__/lib/version-diff.test.js.map +1 -0
  77. package/dist/__tests__/lib/version-history.test.d.ts +2 -0
  78. package/dist/__tests__/lib/version-history.test.d.ts.map +1 -0
  79. package/dist/__tests__/lib/version-history.test.js +125 -0
  80. package/dist/__tests__/lib/version-history.test.js.map +1 -0
  81. package/dist/__tests__/styles/canvas-container-queries.test.d.ts +2 -0
  82. package/dist/__tests__/styles/canvas-container-queries.test.d.ts.map +1 -0
  83. package/dist/__tests__/styles/canvas-container-queries.test.js +87 -0
  84. package/dist/__tests__/styles/canvas-container-queries.test.js.map +1 -0
  85. package/dist/__tests__/styles/packaging.test.d.ts +2 -0
  86. package/dist/__tests__/styles/packaging.test.d.ts.map +1 -0
  87. package/dist/__tests__/styles/packaging.test.js +31 -0
  88. package/dist/__tests__/styles/packaging.test.js.map +1 -0
  89. package/dist/__tests__/styles/responsive-layer.test.d.ts +2 -0
  90. package/dist/__tests__/styles/responsive-layer.test.d.ts.map +1 -0
  91. package/dist/__tests__/styles/responsive-layer.test.js +127 -0
  92. package/dist/__tests__/styles/responsive-layer.test.js.map +1 -0
  93. package/dist/__tests__/styles/tokens-drift.test.d.ts +2 -0
  94. package/dist/__tests__/styles/tokens-drift.test.d.ts.map +1 -0
  95. package/dist/__tests__/styles/tokens-drift.test.js +92 -0
  96. package/dist/__tests__/styles/tokens-drift.test.js.map +1 -0
  97. package/dist/__tests__/views/admin-renderer-compat.test.d.ts +2 -0
  98. package/dist/__tests__/views/admin-renderer-compat.test.d.ts.map +1 -0
  99. package/dist/__tests__/views/admin-renderer-compat.test.js +43 -0
  100. package/dist/__tests__/views/admin-renderer-compat.test.js.map +1 -0
  101. package/dist/__tests__/views/admin-section-renderers.test.js +52 -4
  102. package/dist/__tests__/views/admin-section-renderers.test.js.map +1 -1
  103. package/dist/__tests__/views/canvas-review-mode.render.test.d.ts +2 -0
  104. package/dist/__tests__/views/canvas-review-mode.render.test.d.ts.map +1 -0
  105. package/dist/__tests__/views/canvas-review-mode.render.test.js +70 -0
  106. package/dist/__tests__/views/canvas-review-mode.render.test.js.map +1 -0
  107. package/dist/__tests__/views/editor-top-bar.render.test.js +30 -1
  108. package/dist/__tests__/views/editor-top-bar.render.test.js.map +1 -1
  109. package/dist/__tests__/views/page-tab.render.test.d.ts +2 -0
  110. package/dist/__tests__/views/page-tab.render.test.d.ts.map +1 -0
  111. package/dist/__tests__/views/page-tab.render.test.js +151 -0
  112. package/dist/__tests__/views/page-tab.render.test.js.map +1 -0
  113. package/dist/__tests__/views/section-class-parity.test.d.ts +2 -0
  114. package/dist/__tests__/views/section-class-parity.test.d.ts.map +1 -0
  115. package/dist/__tests__/views/section-class-parity.test.js +81 -0
  116. package/dist/__tests__/views/section-class-parity.test.js.map +1 -0
  117. package/dist/__tests__/views/sections-panel-design-owned.render.test.d.ts +2 -0
  118. package/dist/__tests__/views/sections-panel-design-owned.render.test.d.ts.map +1 -0
  119. package/dist/__tests__/views/sections-panel-design-owned.render.test.js +86 -0
  120. package/dist/__tests__/views/sections-panel-design-owned.render.test.js.map +1 -0
  121. package/dist/__tests__/views/version-history-panel.render.test.d.ts +2 -0
  122. package/dist/__tests__/views/version-history-panel.render.test.d.ts.map +1 -0
  123. package/dist/__tests__/views/version-history-panel.render.test.js +153 -0
  124. package/dist/__tests__/views/version-history-panel.render.test.js.map +1 -0
  125. package/dist/components/BreakpointPicker.d.ts +18 -0
  126. package/dist/components/BreakpointPicker.d.ts.map +1 -0
  127. package/dist/components/BreakpointPicker.js +31 -0
  128. package/dist/components/BreakpointPicker.js.map +1 -0
  129. package/dist/components/CanvasEditTip.d.ts +6 -0
  130. package/dist/components/CanvasEditTip.d.ts.map +1 -0
  131. package/dist/components/CanvasEditTip.js +22 -0
  132. package/dist/components/CanvasEditTip.js.map +1 -0
  133. package/dist/components/EditorRail.d.ts +36 -0
  134. package/dist/components/EditorRail.d.ts.map +1 -0
  135. package/dist/components/EditorRail.js +104 -0
  136. package/dist/components/EditorRail.js.map +1 -0
  137. package/dist/components/EditorRailTabs.d.ts +32 -0
  138. package/dist/components/EditorRailTabs.d.ts.map +1 -0
  139. package/dist/components/EditorRailTabs.js +45 -0
  140. package/dist/components/EditorRailTabs.js.map +1 -0
  141. package/dist/components/MediaBlock.d.ts +49 -0
  142. package/dist/components/MediaBlock.d.ts.map +1 -0
  143. package/dist/components/MediaBlock.js +50 -0
  144. package/dist/components/MediaBlock.js.map +1 -0
  145. package/dist/components/ReflowMeter.d.ts +28 -0
  146. package/dist/components/ReflowMeter.d.ts.map +1 -0
  147. package/dist/components/ReflowMeter.js +42 -0
  148. package/dist/components/ReflowMeter.js.map +1 -0
  149. package/dist/components/ZoomChip.d.ts +17 -0
  150. package/dist/components/ZoomChip.d.ts.map +1 -0
  151. package/dist/components/ZoomChip.js +17 -0
  152. package/dist/components/ZoomChip.js.map +1 -0
  153. package/dist/components/breakpoint-icons.d.ts +3 -0
  154. package/dist/components/breakpoint-icons.d.ts.map +1 -0
  155. package/dist/components/breakpoint-icons.js +16 -0
  156. package/dist/components/breakpoint-icons.js.map +1 -0
  157. package/dist/components/page-tab/AuthorPicker.d.ts +31 -0
  158. package/dist/components/page-tab/AuthorPicker.d.ts.map +1 -0
  159. package/dist/components/page-tab/AuthorPicker.js +95 -0
  160. package/dist/components/page-tab/AuthorPicker.js.map +1 -0
  161. package/dist/components/page-tab/DirectiveSwitch.d.ts +38 -0
  162. package/dist/components/page-tab/DirectiveSwitch.d.ts.map +1 -0
  163. package/dist/components/page-tab/DirectiveSwitch.js +33 -0
  164. package/dist/components/page-tab/DirectiveSwitch.js.map +1 -0
  165. package/dist/components/seo/EditorSeoScoreBadge.d.ts +8 -1
  166. package/dist/components/seo/EditorSeoScoreBadge.d.ts.map +1 -1
  167. package/dist/components/seo/EditorSeoScoreBadge.js +2 -2
  168. package/dist/components/seo/EditorSeoScoreBadge.js.map +1 -1
  169. package/dist/components/seo/PageAuditPanel.d.ts +14 -0
  170. package/dist/components/seo/PageAuditPanel.d.ts.map +1 -0
  171. package/dist/components/seo/PageAuditPanel.js +59 -0
  172. package/dist/components/seo/PageAuditPanel.js.map +1 -0
  173. package/dist/components/seo/SeoCharCount.d.ts +19 -7
  174. package/dist/components/seo/SeoCharCount.d.ts.map +1 -1
  175. package/dist/components/seo/SeoCharCount.js +30 -16
  176. package/dist/components/seo/SeoCharCount.js.map +1 -1
  177. package/dist/components/seo/SeoEditorPane.d.ts +15 -1
  178. package/dist/components/seo/SeoEditorPane.d.ts.map +1 -1
  179. package/dist/components/seo/SeoEditorPane.js +118 -21
  180. package/dist/components/seo/SeoEditorPane.js.map +1 -1
  181. package/dist/components/seo/SerpPreview.d.ts +20 -0
  182. package/dist/components/seo/SerpPreview.d.ts.map +1 -0
  183. package/dist/components/seo/SerpPreview.js +6 -0
  184. package/dist/components/seo/SerpPreview.js.map +1 -0
  185. package/dist/hooks/usePageAudit.d.ts +41 -0
  186. package/dist/hooks/usePageAudit.d.ts.map +1 -0
  187. package/dist/hooks/usePageAudit.js +68 -0
  188. package/dist/hooks/usePageAudit.js.map +1 -0
  189. package/dist/hooks/useReflowGuard.d.ts +47 -0
  190. package/dist/hooks/useReflowGuard.d.ts.map +1 -0
  191. package/dist/hooks/useReflowGuard.js +52 -0
  192. package/dist/hooks/useReflowGuard.js.map +1 -0
  193. package/dist/layout/primitives/AdminShell.d.ts.map +1 -1
  194. package/dist/layout/primitives/AdminShell.js +2 -2
  195. package/dist/layout/primitives/AdminShell.js.map +1 -1
  196. package/dist/lib/breakpoints.d.ts +51 -0
  197. package/dist/lib/breakpoints.d.ts.map +1 -0
  198. package/dist/lib/breakpoints.js +84 -0
  199. package/dist/lib/breakpoints.js.map +1 -0
  200. package/dist/lib/canvas-edit-chrome.d.ts +22 -0
  201. package/dist/lib/canvas-edit-chrome.d.ts.map +1 -0
  202. package/dist/lib/canvas-edit-chrome.js +81 -0
  203. package/dist/lib/canvas-edit-chrome.js.map +1 -0
  204. package/dist/lib/media-format.d.ts +55 -0
  205. package/dist/lib/media-format.d.ts.map +1 -0
  206. package/dist/lib/media-format.js +93 -0
  207. package/dist/lib/media-format.js.map +1 -0
  208. package/dist/lib/page-audit-input.d.ts +45 -0
  209. package/dist/lib/page-audit-input.d.ts.map +1 -0
  210. package/dist/lib/page-audit-input.js +53 -0
  211. package/dist/lib/page-audit-input.js.map +1 -0
  212. package/dist/lib/page-editor-service.d.ts +12 -0
  213. package/dist/lib/page-editor-service.d.ts.map +1 -1
  214. package/dist/lib/page-editor-service.js +6 -0
  215. package/dist/lib/page-editor-service.js.map +1 -1
  216. package/dist/lib/page-redirect.d.ts +39 -0
  217. package/dist/lib/page-redirect.d.ts.map +1 -0
  218. package/dist/lib/page-redirect.js +38 -0
  219. package/dist/lib/page-redirect.js.map +1 -0
  220. package/dist/lib/rail-width.d.ts +23 -0
  221. package/dist/lib/rail-width.d.ts.map +1 -0
  222. package/dist/lib/rail-width.js +59 -0
  223. package/dist/lib/rail-width.js.map +1 -0
  224. package/dist/lib/reflow-baseline.d.ts +45 -0
  225. package/dist/lib/reflow-baseline.d.ts.map +1 -0
  226. package/dist/lib/reflow-baseline.js +38 -0
  227. package/dist/lib/reflow-baseline.js.map +1 -0
  228. package/dist/lib/reflow-probe.d.ts +159 -0
  229. package/dist/lib/reflow-probe.d.ts.map +1 -0
  230. package/dist/lib/reflow-probe.js +228 -0
  231. package/dist/lib/reflow-probe.js.map +1 -0
  232. package/dist/lib/seo-service.d.ts +10 -0
  233. package/dist/lib/seo-service.d.ts.map +1 -1
  234. package/dist/lib/seo-service.js.map +1 -1
  235. package/dist/lib/version-diff.d.ts +50 -0
  236. package/dist/lib/version-diff.d.ts.map +1 -0
  237. package/dist/lib/version-diff.js +294 -0
  238. package/dist/lib/version-diff.js.map +1 -0
  239. package/dist/lib/version-history.d.ts +73 -0
  240. package/dist/lib/version-history.d.ts.map +1 -0
  241. package/dist/lib/version-history.js +126 -0
  242. package/dist/lib/version-history.js.map +1 -0
  243. package/dist/prenta-admin.css +1 -1
  244. package/dist/views/page-editor/CanvasMetaLine.d.ts +19 -0
  245. package/dist/views/page-editor/CanvasMetaLine.d.ts.map +1 -0
  246. package/dist/views/page-editor/CanvasMetaLine.js +23 -0
  247. package/dist/views/page-editor/CanvasMetaLine.js.map +1 -0
  248. package/dist/views/page-editor/EditorCanvas.d.ts +47 -8
  249. package/dist/views/page-editor/EditorCanvas.d.ts.map +1 -1
  250. package/dist/views/page-editor/EditorCanvas.js +68 -34
  251. package/dist/views/page-editor/EditorCanvas.js.map +1 -1
  252. package/dist/views/page-editor/EditorTopBar.d.ts +21 -2
  253. package/dist/views/page-editor/EditorTopBar.d.ts.map +1 -1
  254. package/dist/views/page-editor/EditorTopBar.js +13 -20
  255. package/dist/views/page-editor/EditorTopBar.js.map +1 -1
  256. package/dist/views/page-editor/PageSectionEditor.d.ts.map +1 -1
  257. package/dist/views/page-editor/PageSectionEditor.js +383 -78
  258. package/dist/views/page-editor/PageSectionEditor.js.map +1 -1
  259. package/dist/views/page-editor/PageTab.d.ts +36 -0
  260. package/dist/views/page-editor/PageTab.d.ts.map +1 -0
  261. package/dist/views/page-editor/PageTab.js +65 -0
  262. package/dist/views/page-editor/PageTab.js.map +1 -0
  263. package/dist/views/page-editor/ReviewBar.d.ts +21 -0
  264. package/dist/views/page-editor/ReviewBar.d.ts.map +1 -0
  265. package/dist/views/page-editor/ReviewBar.js +22 -0
  266. package/dist/views/page-editor/ReviewBar.js.map +1 -0
  267. package/dist/views/page-editor/SectionInspector.d.ts.map +1 -1
  268. package/dist/views/page-editor/SectionInspector.js +64 -20
  269. package/dist/views/page-editor/SectionInspector.js.map +1 -1
  270. package/dist/views/page-editor/SectionsPanel.d.ts +30 -5
  271. package/dist/views/page-editor/SectionsPanel.d.ts.map +1 -1
  272. package/dist/views/page-editor/SectionsPanel.js +38 -7
  273. package/dist/views/page-editor/SectionsPanel.js.map +1 -1
  274. package/dist/views/page-editor/SitePreviewFrame.d.ts.map +1 -1
  275. package/dist/views/page-editor/SitePreviewFrame.js +3 -0
  276. package/dist/views/page-editor/SitePreviewFrame.js.map +1 -1
  277. package/dist/views/page-editor/VersionHistoryPanel.d.ts +29 -0
  278. package/dist/views/page-editor/VersionHistoryPanel.d.ts.map +1 -0
  279. package/dist/views/page-editor/VersionHistoryPanel.js +81 -0
  280. package/dist/views/page-editor/VersionHistoryPanel.js.map +1 -0
  281. package/dist/views/page-editor/reflow-context.d.ts +28 -0
  282. package/dist/views/page-editor/reflow-context.d.ts.map +1 -0
  283. package/dist/views/page-editor/reflow-context.js +14 -0
  284. package/dist/views/page-editor/reflow-context.js.map +1 -0
  285. package/dist/views/page-editor/sections/ByTheNumbersSection.d.ts.map +1 -1
  286. package/dist/views/page-editor/sections/ByTheNumbersSection.js +1 -1
  287. package/dist/views/page-editor/sections/ByTheNumbersSection.js.map +1 -1
  288. package/dist/views/page-editor/sections/CtaBannerSection.d.ts.map +1 -1
  289. package/dist/views/page-editor/sections/CtaBannerSection.js +1 -1
  290. package/dist/views/page-editor/sections/CtaBannerSection.js.map +1 -1
  291. package/dist/views/page-editor/sections/FeatureHighlightSection.d.ts.map +1 -1
  292. package/dist/views/page-editor/sections/FeatureHighlightSection.js +2 -2
  293. package/dist/views/page-editor/sections/FeatureHighlightSection.js.map +1 -1
  294. package/dist/views/page-editor/sections/GallerySection.d.ts.map +1 -1
  295. package/dist/views/page-editor/sections/GallerySection.js +7 -3
  296. package/dist/views/page-editor/sections/GallerySection.js.map +1 -1
  297. package/dist/views/page-editor/sections/HeroBannerSection.js +1 -1
  298. package/dist/views/page-editor/sections/HeroBannerSection.js.map +1 -1
  299. package/dist/views/page-editor/sections/MissionSection.d.ts.map +1 -1
  300. package/dist/views/page-editor/sections/MissionSection.js +1 -1
  301. package/dist/views/page-editor/sections/MissionSection.js.map +1 -1
  302. package/dist/views/page-editor/sections/PullQuoteSection.d.ts.map +1 -1
  303. package/dist/views/page-editor/sections/PullQuoteSection.js +1 -1
  304. package/dist/views/page-editor/sections/PullQuoteSection.js.map +1 -1
  305. package/dist/views/page-editor/sections/RelatedPostsSection.d.ts.map +1 -1
  306. package/dist/views/page-editor/sections/RelatedPostsSection.js +1 -1
  307. package/dist/views/page-editor/sections/RelatedPostsSection.js.map +1 -1
  308. package/dist/views/page-editor/sections/SectionRenderer.d.ts +13 -1
  309. package/dist/views/page-editor/sections/SectionRenderer.d.ts.map +1 -1
  310. package/dist/views/page-editor/sections/SectionRenderer.js +66 -26
  311. package/dist/views/page-editor/sections/SectionRenderer.js.map +1 -1
  312. package/dist/views/page-editor/sections/admin-renderers.d.ts +47 -15
  313. package/dist/views/page-editor/sections/admin-renderers.d.ts.map +1 -1
  314. package/dist/views/page-editor/sections/admin-renderers.js +27 -15
  315. package/dist/views/page-editor/sections/admin-renderers.js.map +1 -1
  316. package/dist/views/page-editor/sections/parts.d.ts +0 -1
  317. package/dist/views/page-editor/sections/parts.d.ts.map +1 -1
  318. package/dist/views/page-editor/sections/parts.js +41 -16
  319. package/dist/views/page-editor/sections/parts.js.map +1 -1
  320. package/dist/views/page-editor/viewports.d.ts +7 -14
  321. package/dist/views/page-editor/viewports.d.ts.map +1 -1
  322. package/dist/views/page-editor/viewports.js +7 -12
  323. package/dist/views/page-editor/viewports.js.map +1 -1
  324. package/dist/views/post-editor/PostEditorCanvas.d.ts +2 -1
  325. package/dist/views/post-editor/PostEditorCanvas.d.ts.map +1 -1
  326. package/dist/views/post-editor/PostEditorCanvas.js +5 -2
  327. package/dist/views/post-editor/PostEditorCanvas.js.map +1 -1
  328. package/dist/views/post-editor/PostSectionEditor.d.ts.map +1 -1
  329. package/dist/views/post-editor/PostSectionEditor.js +2 -20
  330. package/dist/views/post-editor/PostSectionEditor.js.map +1 -1
  331. package/dist/views/post-editor/PostTemplateEditor.d.ts.map +1 -1
  332. package/dist/views/post-editor/PostTemplateEditor.js +4 -1
  333. package/dist/views/post-editor/PostTemplateEditor.js.map +1 -1
  334. package/package.json +5 -3
  335. package/src/AdminRoot.tsx +27 -6
  336. package/src/__tests__/components/breakpoint-controls.render.test.tsx +57 -0
  337. package/src/__tests__/components/canvas-edit-tip.render.test.tsx +41 -0
  338. package/src/__tests__/components/editor-rail.render.test.tsx +192 -0
  339. package/src/__tests__/components/media-block.render.test.tsx +126 -0
  340. package/src/__tests__/components/page-audit-panel.render.test.tsx +64 -0
  341. package/src/__tests__/components/reflow-meter.render.test.tsx +144 -0
  342. package/src/__tests__/components/seo-char-count.test.tsx +26 -6
  343. package/src/__tests__/components/serp-preview.render.test.tsx +32 -0
  344. package/src/__tests__/lib/breakpoints.test.ts +84 -0
  345. package/src/__tests__/lib/canvas-edit-chrome.test.ts +56 -0
  346. package/src/__tests__/lib/media-format.test.ts +89 -0
  347. package/src/__tests__/lib/page-audit-input.test.ts +144 -0
  348. package/src/__tests__/lib/page-editor-service.test.ts +2 -0
  349. package/src/__tests__/lib/page-redirect.test.ts +29 -0
  350. package/src/__tests__/lib/rail-width.test.ts +86 -0
  351. package/src/__tests__/lib/reflow-baseline.test.ts +64 -0
  352. package/src/__tests__/lib/reflow-probe.test.ts +95 -0
  353. package/src/__tests__/lib/version-diff.test.ts +278 -0
  354. package/src/__tests__/lib/version-history.test.ts +166 -0
  355. package/src/__tests__/styles/canvas-container-queries.test.ts +103 -0
  356. package/src/__tests__/styles/packaging.test.ts +38 -0
  357. package/src/__tests__/styles/responsive-layer.test.ts +152 -0
  358. package/src/__tests__/styles/tokens-drift.test.ts +110 -0
  359. package/src/__tests__/views/admin-renderer-compat.test.ts +48 -0
  360. package/src/__tests__/views/admin-section-renderers.test.tsx +70 -4
  361. package/src/__tests__/views/canvas-review-mode.render.test.tsx +94 -0
  362. package/src/__tests__/views/editor-top-bar.render.test.tsx +43 -1
  363. package/src/__tests__/views/page-tab.render.test.tsx +226 -0
  364. package/src/__tests__/views/section-class-parity.test.ts +98 -0
  365. package/src/__tests__/views/sections-panel-design-owned.render.test.tsx +104 -0
  366. package/src/__tests__/views/version-history-panel.render.test.tsx +195 -0
  367. package/src/components/BreakpointPicker.tsx +114 -0
  368. package/src/components/CanvasEditTip.tsx +46 -0
  369. package/src/components/EditorRail.tsx +219 -0
  370. package/src/components/EditorRailTabs.tsx +117 -0
  371. package/src/components/MediaBlock.tsx +223 -0
  372. package/src/components/ReflowMeter.tsx +125 -0
  373. package/src/components/ZoomChip.tsx +39 -0
  374. package/src/components/breakpoint-icons.ts +17 -0
  375. package/src/components/page-tab/AuthorPicker.tsx +240 -0
  376. package/src/components/page-tab/DirectiveSwitch.tsx +89 -0
  377. package/src/components/seo/EditorSeoScoreBadge.tsx +9 -1
  378. package/src/components/seo/PageAuditPanel.tsx +192 -0
  379. package/src/components/seo/SeoCharCount.tsx +55 -24
  380. package/src/components/seo/SeoEditorPane.tsx +213 -31
  381. package/src/components/seo/SerpPreview.tsx +41 -0
  382. package/src/hooks/usePageAudit.ts +98 -0
  383. package/src/hooks/useReflowGuard.ts +96 -0
  384. package/src/layout/primitives/AdminShell.tsx +13 -1
  385. package/src/lib/breakpoints.ts +107 -0
  386. package/src/lib/canvas-edit-chrome.ts +82 -0
  387. package/src/lib/media-format.ts +99 -0
  388. package/src/lib/page-audit-input.ts +104 -0
  389. package/src/lib/page-editor-service.ts +18 -0
  390. package/src/lib/page-redirect.ts +60 -0
  391. package/src/lib/rail-width.ts +58 -0
  392. package/src/lib/reflow-baseline.ts +70 -0
  393. package/src/lib/reflow-probe.ts +299 -0
  394. package/src/lib/seo-service.ts +10 -0
  395. package/src/lib/version-diff.ts +376 -0
  396. package/src/lib/version-history.ts +192 -0
  397. package/src/styles/prenta-tokens.css +120 -42
  398. package/src/styles/responsive.css +281 -0
  399. package/src/styles/theme.css +138 -0
  400. package/src/views/page-editor/CanvasMetaLine.tsx +50 -0
  401. package/src/views/page-editor/EditorCanvas.tsx +140 -54
  402. package/src/views/page-editor/EditorTopBar.tsx +55 -51
  403. package/src/views/page-editor/PageSectionEditor.tsx +575 -185
  404. package/src/views/page-editor/PageTab.tsx +433 -0
  405. package/src/views/page-editor/ReviewBar.tsx +76 -0
  406. package/src/views/page-editor/SectionInspector.tsx +84 -42
  407. package/src/views/page-editor/SectionsPanel.tsx +282 -141
  408. package/src/views/page-editor/SitePreviewFrame.tsx +3 -0
  409. package/src/views/page-editor/VersionHistoryPanel.tsx +302 -0
  410. package/src/views/page-editor/reflow-context.ts +43 -0
  411. package/src/views/page-editor/sections/ByTheNumbersSection.tsx +3 -2
  412. package/src/views/page-editor/sections/CtaBannerSection.tsx +3 -1
  413. package/src/views/page-editor/sections/FeatureHighlightSection.tsx +3 -2
  414. package/src/views/page-editor/sections/GallerySection.tsx +7 -3
  415. package/src/views/page-editor/sections/HeroBannerSection.tsx +2 -2
  416. package/src/views/page-editor/sections/MissionSection.tsx +4 -2
  417. package/src/views/page-editor/sections/PullQuoteSection.tsx +3 -1
  418. package/src/views/page-editor/sections/RelatedPostsSection.tsx +2 -1
  419. package/src/views/page-editor/sections/SectionRenderer.tsx +115 -34
  420. package/src/views/page-editor/sections/admin-renderers.tsx +54 -15
  421. package/src/views/page-editor/sections/parts.tsx +46 -18
  422. package/src/views/page-editor/viewports.ts +13 -26
  423. package/src/views/post-editor/PostEditorCanvas.tsx +18 -11
  424. package/src/views/post-editor/PostSectionEditor.tsx +1 -56
  425. package/src/views/post-editor/PostTemplateEditor.tsx +3 -0
@@ -0,0 +1,89 @@
1
+ 'use client'
2
+
3
+ import * as Switch from '@radix-ui/react-switch'
4
+
5
+ export interface DirectiveSwitchProps {
6
+ id: string
7
+ /** Human label, e.g. "Show in search results". */
8
+ label: string
9
+ /** One line on what turning it off actually costs. */
10
+ hint?: string
11
+ /** `true` = permissive. */
12
+ checked: boolean
13
+ onChange: (next: boolean) => void
14
+ /** Directive token when permitted, e.g. `index`. */
15
+ permissiveToken: string
16
+ /** Directive token when restricted, e.g. `noindex`. */
17
+ restrictiveToken: string
18
+ disabled?: boolean
19
+ }
20
+
21
+ /**
22
+ * A robots-directive switch.
23
+ *
24
+ * ── Why this is not the ordinary Toggle ───────────────────────────────────
25
+ *
26
+ * The admin's `Toggle` turns brand purple when on, because "on" is the state
27
+ * the product is nudging you towards. That reading is wrong here. These
28
+ * switches are not on/off, they are permissive/restrictive — and the meaningful
29
+ * distinction is not "did I enable something" but "is this page still allowed
30
+ * to be found". Purple would say "enabled" about a switch whose enabled state
31
+ * is simply the default, and say nothing about the one state worth noticing.
32
+ *
33
+ * So: green when permitted, red when restricted. And the literal directive
34
+ * token sits beside it, because the failure this UI has to prevent is an editor
35
+ * flipping something whose consequence they could not name. `noindex` next to
36
+ * the switch turns an abstract toggle into the thing it actually writes into
37
+ * the page's head.
38
+ *
39
+ * Colour never carries it alone — the token chip is text, and the switch's
40
+ * accessible name states the label and the token it will produce.
41
+ */
42
+ export function DirectiveSwitch({
43
+ id,
44
+ label,
45
+ hint,
46
+ checked,
47
+ onChange,
48
+ permissiveToken,
49
+ restrictiveToken,
50
+ disabled = false,
51
+ }: DirectiveSwitchProps) {
52
+ const token = checked ? permissiveToken : restrictiveToken
53
+
54
+ return (
55
+ <div className="flex items-start justify-between gap-3 py-1.5">
56
+ <div className="min-w-0">
57
+ <label htmlFor={id} className="text-foreground block text-[12.5px] font-medium">
58
+ {label}
59
+ </label>
60
+ {hint && <p className="text-muted-foreground mt-0.5 text-[11px] leading-snug">{hint}</p>}
61
+ </div>
62
+
63
+ <div className="flex shrink-0 items-center gap-2">
64
+ <code
65
+ className={`rounded px-1.5 py-0.5 font-mono text-[9.5px] font-bold ${
66
+ checked ? 'bg-success/12 text-success' : 'bg-destructive/12 text-destructive'
67
+ }`}
68
+ >
69
+ {token}
70
+ </code>
71
+ <Switch.Root
72
+ id={id}
73
+ checked={checked}
74
+ onCheckedChange={onChange}
75
+ disabled={disabled}
76
+ aria-label={`${label} — currently ${token}`}
77
+ // `prenta-touch-hit`, not `prenta-touch-target`: growing the track to
78
+ // 44px would strand the thumb, which is positioned against it. The
79
+ // hit area grows; the switch keeps its measured 34×19.
80
+ className={`prenta-touch-hit focus-visible:ring-ring relative h-[19px] w-[34px] shrink-0 rounded-full transition-colors duration-(--mo-base) focus-visible:ring-2 focus-visible:outline-none disabled:opacity-50 ${
81
+ checked ? 'bg-success' : 'bg-destructive/55'
82
+ }`}
83
+ >
84
+ <Switch.Thumb className="block h-3.5 w-3.5 translate-x-[2.5px] rounded-full bg-white shadow-[0_1px_3px_rgba(0,0,0,0.25)] transition-transform duration-(--mo-base) data-[state=checked]:translate-x-[18px]" />
85
+ </Switch.Root>
86
+ </div>
87
+ </div>
88
+ )
89
+ }
@@ -5,13 +5,21 @@ import { gradeFromScore, gradeMeta } from './primitives.js'
5
5
  /** Compact color-coded score for the page/post editor toolbar (`77/100` left of "SEO"). */
6
6
  export function EditorSeoScoreBadge({
7
7
  score,
8
+ band,
8
9
  inverted = false,
9
10
  }: {
10
11
  score: number
12
+ /**
13
+ * Band for the colour. Supplied by the caller because different scores use
14
+ * different scales: the page audit bands at 80/55, `analyzeContent` at
15
+ * 80/60/1. Deriving it here would colour one model's number with another
16
+ * model's thresholds — they disagree between 55 and 59.
17
+ */
18
+ band?: 'good' | 'fair' | 'poor'
11
19
  /** When the SEO toggle uses `bg-primary`, render score in primary-foreground. */
12
20
  inverted?: boolean
13
21
  }) {
14
- const meta = gradeMeta(gradeFromScore(score))
22
+ const meta = gradeMeta(band ?? gradeFromScore(score))
15
23
  return (
16
24
  <span
17
25
  className={`inline-flex items-baseline gap-0.5 text-xs font-medium tabular-nums ${
@@ -0,0 +1,192 @@
1
+ 'use client'
2
+
3
+ import { useState } from 'react'
4
+ import { ChevronDown, Search, Sparkles } from 'lucide-react'
5
+ import {
6
+ scoreBand,
7
+ type AuditCheck,
8
+ type AuditGroupResult,
9
+ type PageAuditResult,
10
+ } from '@prenta/core/seo/page-audit'
11
+
12
+ const BAND_TEXT = { good: 'text-success', fair: 'text-warning', poor: 'text-destructive' } as const
13
+ const BAND_STROKE = {
14
+ good: 'stroke-success',
15
+ fair: 'stroke-warning',
16
+ poor: 'stroke-destructive',
17
+ } as const
18
+
19
+ /**
20
+ * A 52px score ring.
21
+ *
22
+ * `null` is a real state, not an error: a page held back from search has no
23
+ * search performance to rate. It renders as a dash on a neutral track rather
24
+ * than an alarming zero.
25
+ */
26
+ function ScoreRing({ score, label }: { score: number | null; label: string }) {
27
+ const R = 21
28
+ const CIRCUMFERENCE = 2 * Math.PI * R
29
+ const band = score === null ? null : scoreBand(score)
30
+ const dash = score === null ? 0 : (score / 100) * CIRCUMFERENCE
31
+
32
+ return (
33
+ <svg
34
+ width="52"
35
+ height="52"
36
+ viewBox="0 0 52 52"
37
+ role="img"
38
+ aria-label={score === null ? `${label}: not rated` : `${label} score: ${score} of 100`}
39
+ >
40
+ <circle cx="26" cy="26" r={R} className="stroke-border" strokeWidth="5" fill="none" />
41
+ {score !== null && (
42
+ <circle
43
+ cx="26"
44
+ cy="26"
45
+ r={R}
46
+ className={`${BAND_STROKE[band!]} motion-safe:transition-[stroke-dasharray,stroke] motion-safe:duration-350`}
47
+ strokeWidth="5"
48
+ fill="none"
49
+ strokeLinecap="round"
50
+ strokeDasharray={`${dash} ${CIRCUMFERENCE - dash}`}
51
+ // Start the arc at twelve o'clock instead of three.
52
+ transform="rotate(-90 26 26)"
53
+ />
54
+ )}
55
+ <text
56
+ x="26"
57
+ y="26"
58
+ textAnchor="middle"
59
+ dominantBaseline="central"
60
+ className={`fill-current text-[15px] font-bold tabular-nums ${
61
+ band ? BAND_TEXT[band] : 'text-muted-foreground'
62
+ }`}
63
+ >
64
+ {score === null ? '—' : score}
65
+ </text>
66
+ </svg>
67
+ )
68
+ }
69
+
70
+ function CheckRow({ check }: { check: AuditCheck }) {
71
+ const na = check.outcome === 'not-applicable'
72
+ const pass = check.outcome === 'pass'
73
+
74
+ return (
75
+ <li className="border-border flex gap-2 border-b py-[7px] last:border-b-0">
76
+ <span
77
+ aria-hidden
78
+ className={`mt-0.5 h-4 w-4 shrink-0 rounded ${
79
+ na ? 'bg-muted' : pass ? 'bg-success/15 text-success' : 'bg-warning/15 text-warning'
80
+ }`}
81
+ />
82
+ <div className="min-w-0">
83
+ <p className={`text-xs font-medium ${na ? 'text-muted-foreground' : 'text-foreground'}`}>
84
+ {check.label}
85
+ {/* The outcome must not rest on the colour of the square alone. */}
86
+ <span className="sr-only">
87
+ {na ? ' — not applicable' : pass ? ' — passing' : ' — needs attention'}
88
+ </span>
89
+ </p>
90
+ {/* A not-applicable check explains itself; a failing one says what to do.
91
+ A passing one needs neither. */}
92
+ {na ? (
93
+ <p className="text-muted-foreground text-[10.5px]">{check.naReason}</p>
94
+ ) : pass ? null : (
95
+ <p className="text-muted-foreground text-[10.5px]">{check.hint}</p>
96
+ )}
97
+ </div>
98
+ </li>
99
+ )
100
+ }
101
+
102
+ function CheckGroup({ result, title }: { result: AuditGroupResult; title: string }) {
103
+ const [open, setOpen] = useState(true)
104
+ const band = result.score === null ? null : scoreBand(result.score)
105
+
106
+ return (
107
+ <section className="border-border border-b">
108
+ <button
109
+ type="button"
110
+ onClick={() => setOpen((o) => !o)}
111
+ aria-expanded={open}
112
+ className="hover:bg-accent flex w-full items-center justify-between px-3.5 py-2.5 transition-colors"
113
+ >
114
+ <span className="text-muted-foreground text-[10px] font-bold tracking-[0.7px] uppercase">
115
+ {title}
116
+ </span>
117
+ <span className="flex items-center gap-1.5">
118
+ {/* The pill counts SCORED checks. Gates and not-applicable checks are
119
+ listed below but excluded, so the denominator matches the score. */}
120
+ <span
121
+ className={`rounded-full px-1.5 text-[10px] font-bold tabular-nums ${
122
+ band === 'good'
123
+ ? 'bg-success/15 text-success'
124
+ : band === 'fair'
125
+ ? 'bg-warning/15 text-warning'
126
+ : band === 'poor'
127
+ ? 'bg-destructive/15 text-destructive'
128
+ : 'bg-muted text-muted-foreground'
129
+ }`}
130
+ >
131
+ {result.score === null ? 'n/a' : `${result.passed}/${result.applicable}`}
132
+ </span>
133
+ <ChevronDown
134
+ className={`text-muted-foreground h-3.5 w-3.5 transition-transform ${open ? 'rotate-180' : ''}`}
135
+ aria-hidden
136
+ />
137
+ </span>
138
+ </button>
139
+ {open && (
140
+ <ul className="px-3.5 pb-3.5">
141
+ {result.checks.map((c) => (
142
+ <CheckRow key={c.id} check={c} />
143
+ ))}
144
+ </ul>
145
+ )}
146
+ </section>
147
+ )
148
+ }
149
+
150
+ export interface PageAuditPanelProps {
151
+ audit: PageAuditResult
152
+ }
153
+
154
+ /**
155
+ * Twin score rings over the SEO and GEO check lists.
156
+ *
157
+ * Both scores are reported the same way and neither is folded into a single
158
+ * headline: classic search and AI answer visibility fail for different reasons
159
+ * and are fixed by different edits, so averaging them would hide whichever is
160
+ * worse.
161
+ */
162
+ export function PageAuditPanel({ audit }: PageAuditPanelProps) {
163
+ const { seo, geo } = audit
164
+
165
+ return (
166
+ <div className="border-border border-b">
167
+ <div className="flex items-start justify-around gap-3 px-3.5 py-4">
168
+ {[
169
+ { r: seo, icon: Search, label: 'SEO', sub: 'Classic search & crawlability' },
170
+ { r: geo, icon: Sparkles, label: 'GEO', sub: 'AI answer visibility' },
171
+ ].map(({ r, icon: Icon, label, sub }) => (
172
+ <div key={label} className="flex min-w-0 flex-col items-center gap-1.5 text-center">
173
+ <ScoreRing score={r.score} label={label} />
174
+ <span className="text-foreground flex items-center gap-1 text-xs font-bold">
175
+ <Icon className="h-3 w-3" aria-hidden />
176
+ {label}
177
+ </span>
178
+ <span className="text-muted-foreground text-[10.5px] leading-tight">{sub}</span>
179
+ {/* Names the denominator, so a score that moves because the set of
180
+ applicable checks changed is explainable rather than mysterious. */}
181
+ <span className="text-muted-foreground text-[10px] tabular-nums">
182
+ {r.score === null ? 'not rated' : `${r.applicable} of ${r.total} apply`}
183
+ </span>
184
+ </div>
185
+ ))}
186
+ </div>
187
+
188
+ <CheckGroup result={seo} title="SEO checks" />
189
+ <CheckGroup result={geo} title="GEO checks" />
190
+ </div>
191
+ )
192
+ }
@@ -1,44 +1,75 @@
1
1
  'use client'
2
2
 
3
- import { Check, AlertTriangle } from 'lucide-react'
3
+ import { AlertTriangle, Check } from 'lucide-react'
4
4
 
5
5
  export interface SeoCharCountProps {
6
6
  value: string
7
- /** Recommended minimum length (inclusive). */
8
- min: number
7
+ /**
8
+ * Recommended minimum length (inclusive). Omit for cap-only fields, where
9
+ * short is not a fault — there is then no "too short" state and no "good",
10
+ * because there is no target to hit, only a ceiling not to cross.
11
+ */
12
+ min?: number
9
13
  /** Recommended/hard maximum length (inclusive). */
10
14
  max: number
15
+ /** Hide the meter bar where vertical space is tight. */
16
+ bar?: boolean
11
17
  }
12
18
 
13
19
  /**
14
- * A length counter with an accessible quality band for SEO fields. Color is
15
- * always paired with an icon + label so meaning is never conveyed by color
16
- * alone (WCAG). "Good" = within [min, max]; "long" (over max) is the only
17
- * destructive state; below min is a neutral hint.
20
+ * Length readout for an SEO field: a meter bar plus a stated count.
21
+ *
22
+ * Under and over are different problems and are named as such. "Too short"
23
+ * means search engines have less to match on; "will be truncated" means the
24
+ * tail is written but nobody will read it. The previous wording collapsed the
25
+ * short case into "aim for 30–60", which describes the target without saying
26
+ * which way to edit.
27
+ *
28
+ * Colour never carries meaning alone — the band is always spelled out in text,
29
+ * with an icon at the two decisive states.
18
30
  */
19
- export function SeoCharCount({ value, min, max }: SeoCharCountProps) {
31
+ export function SeoCharCount({ value, min, max, bar = true }: SeoCharCountProps) {
20
32
  const len = value.trim().length
21
33
  const empty = len === 0
22
- const long = len > max
23
- const good = !empty && len >= min && len <= max
34
+ const over = len > max
35
+ const under = min !== undefined && !empty && len < min
36
+ const good = min !== undefined && !empty && !over && !under
24
37
 
25
- const tone = long ? 'text-destructive' : 'text-muted-foreground'
26
- const label = empty
27
- ? `0/${max}`
28
- : long
29
- ? `${len}/${max} · too long`
38
+ const tone = over
39
+ ? 'text-destructive'
40
+ : under
41
+ ? 'text-warning'
30
42
  : good
31
- ? `${len}/${max} · good`
32
- : `${len}/${max} · aim for ${min}–${max}`
43
+ ? 'text-success'
44
+ : 'text-muted-foreground'
45
+
46
+ const fill = over ? 'bg-destructive' : under ? 'bg-warning' : good ? 'bg-success' : 'bg-border'
47
+
48
+ // Derived from `good`, not from "everything else": a cap-only field has no
49
+ // good state, and an unconditional else branch was labelling five characters
50
+ // in a 200-character field as "good".
51
+ const suffix = over ? ' · will be truncated' : under ? ' · too short' : good ? ' · good' : ''
33
52
 
34
53
  return (
35
- <span className={`inline-flex items-center gap-1 text-xs ${tone}`}>
36
- {long ? (
37
- <AlertTriangle size={12} aria-hidden="true" />
38
- ) : good ? (
39
- <Check size={12} aria-hidden="true" />
40
- ) : null}
41
- {label}
54
+ <span className="inline-flex min-w-0 flex-col items-end gap-1">
55
+ {bar && (
56
+ <span className="bg-border h-0.75 w-20 overflow-hidden rounded-full" aria-hidden>
57
+ <span
58
+ className={`block h-full rounded-full transition-[width] ${fill}`}
59
+ // Past the maximum the bar stays full and the overflow is reported
60
+ // in words. A bar that kept growing would imply more is better.
61
+ style={{ width: `${Math.min(100, (len / max) * 100)}%` }}
62
+ />
63
+ </span>
64
+ )}
65
+ <span className={`inline-flex items-center gap-1 text-[11px] whitespace-nowrap ${tone}`}>
66
+ {over ? (
67
+ <AlertTriangle size={11} aria-hidden />
68
+ ) : good ? (
69
+ <Check size={11} aria-hidden />
70
+ ) : null}
71
+ {len} / {max} characters{suffix}
72
+ </span>
42
73
  </span>
43
74
  )
44
75
  }