@webround/editor 0.0.0-stage → 0.3.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 (227) hide show
  1. package/dist/blocks.d.ts +90 -0
  2. package/dist/blocks.js +119 -0
  3. package/dist/bridge.d.ts +96 -0
  4. package/dist/bridge.js +970 -0
  5. package/dist/check/aria.d.ts +19 -0
  6. package/dist/check/aria.js +106 -0
  7. package/dist/check/cli.d.ts +3 -0
  8. package/dist/check/cli.js +30 -0
  9. package/dist/check/css.d.ts +13 -0
  10. package/dist/check/css.js +63 -0
  11. package/dist/check/html.d.ts +8 -0
  12. package/dist/check/html.js +29 -0
  13. package/dist/check/index.d.ts +4 -0
  14. package/dist/check/index.js +5 -0
  15. package/dist/check/links.d.ts +7 -0
  16. package/dist/check/links.js +23 -0
  17. package/dist/check/orphans.d.ts +20 -0
  18. package/dist/check/orphans.js +57 -0
  19. package/dist/check/producer-code.d.ts +53 -0
  20. package/dist/check/producer-code.js +379 -0
  21. package/dist/check/producer-dom.d.ts +21 -0
  22. package/dist/check/producer-dom.js +52 -0
  23. package/dist/check/project.d.ts +20 -0
  24. package/dist/check/project.js +51 -0
  25. package/dist/check/rules.d.ts +7 -0
  26. package/dist/check/rules.js +517 -0
  27. package/dist/check/types.d.ts +160 -0
  28. package/dist/check/types.js +22 -0
  29. package/dist/components/WrAltcha.d.ts +5 -0
  30. package/dist/components/WrAltcha.js +8 -0
  31. package/dist/components/WrButton.d.ts +8 -0
  32. package/dist/components/WrButton.js +34 -0
  33. package/dist/components/WrForm.d.ts +6 -0
  34. package/dist/components/WrForm.js +29 -0
  35. package/dist/components/WrFormPrivacy.d.ts +4 -0
  36. package/dist/components/WrFormPrivacy.js +7 -0
  37. package/dist/components/WrFormSuccess.d.ts +4 -0
  38. package/dist/components/WrFormSuccess.js +12 -0
  39. package/dist/components/WrIframe.d.ts +12 -0
  40. package/dist/components/WrIframe.js +30 -0
  41. package/dist/components/WrImage.d.ts +9 -0
  42. package/dist/components/WrImage.js +28 -0
  43. package/dist/components/WrInput.d.ts +8 -0
  44. package/dist/components/WrInput.js +29 -0
  45. package/dist/components/WrLink.d.ts +10 -0
  46. package/dist/components/WrLink.js +38 -0
  47. package/dist/components/WrNav.d.ts +26 -0
  48. package/dist/components/WrNav.js +30 -0
  49. package/dist/components/WrSection.d.ts +11 -0
  50. package/dist/components/WrSection.js +5 -0
  51. package/dist/components/WrShared.d.ts +12 -0
  52. package/dist/components/WrShared.js +20 -0
  53. package/dist/components/WrText.d.ts +11 -0
  54. package/dist/components/WrText.js +41 -0
  55. package/dist/components/WrVideo.d.ts +9 -0
  56. package/dist/components/WrVideo.js +73 -0
  57. package/dist/components/text-editor/CodeThemeContext.d.ts +8 -0
  58. package/dist/components/text-editor/CodeThemeContext.js +10 -0
  59. package/dist/components/text-editor/ExampleTheme.d.ts +77 -0
  60. package/dist/components/text-editor/ExampleTheme.js +76 -0
  61. package/dist/components/text-editor/ToolbarContext.d.ts +17 -0
  62. package/dist/components/text-editor/ToolbarContext.js +32 -0
  63. package/dist/components/text-editor/WrTextEditor.d.ts +13 -0
  64. package/dist/components/text-editor/WrTextEditor.js +48 -0
  65. package/dist/components/text-editor/common/constants.d.ts +109 -0
  66. package/dist/components/text-editor/common/constants.js +58 -0
  67. package/dist/components/text-editor/common/surface.d.ts +3 -0
  68. package/dist/components/text-editor/common/surface.js +8 -0
  69. package/dist/components/text-editor/common/utils.d.ts +7 -0
  70. package/dist/components/text-editor/common/utils.js +78 -0
  71. package/dist/components/text-editor/hooks/useLexicalCommitOnBlur.d.ts +5 -0
  72. package/dist/components/text-editor/hooks/useLexicalCommitOnBlur.js +41 -0
  73. package/dist/components/text-editor/hooks/useLexicalMarkdown.d.ts +33 -0
  74. package/dist/components/text-editor/hooks/useLexicalMarkdown.js +284 -0
  75. package/dist/components/text-editor/nodes/CodeBlockNode.d.ts +23 -0
  76. package/dist/components/text-editor/nodes/CodeBlockNode.js +138 -0
  77. package/dist/components/text-editor/nodes/HorizontalRuleNode.d.ts +13 -0
  78. package/dist/components/text-editor/nodes/HorizontalRuleNode.js +22 -0
  79. package/dist/components/text-editor/plugins/CodeBlockPlugin.d.ts +2 -0
  80. package/dist/components/text-editor/plugins/CodeBlockPlugin.js +38 -0
  81. package/dist/components/text-editor/plugins/FontPlugin.d.ts +12 -0
  82. package/dist/components/text-editor/plugins/FontPlugin.js +114 -0
  83. package/dist/components/text-editor/plugins/FontSizePlugin.d.ts +7 -0
  84. package/dist/components/text-editor/plugins/FontSizePlugin.js +105 -0
  85. package/dist/components/text-editor/plugins/FontWeightPlugin.d.ts +6 -0
  86. package/dist/components/text-editor/plugins/FontWeightPlugin.js +103 -0
  87. package/dist/components/text-editor/plugins/HTMLTagPlugin.d.ts +7 -0
  88. package/dist/components/text-editor/plugins/HTMLTagPlugin.js +82 -0
  89. package/dist/components/text-editor/plugins/HorizontalRulePlugin.d.ts +2 -0
  90. package/dist/components/text-editor/plugins/HorizontalRulePlugin.js +35 -0
  91. package/dist/components/text-editor/plugins/LineSpacingPlugin.d.ts +7 -0
  92. package/dist/components/text-editor/plugins/LineSpacingPlugin.js +83 -0
  93. package/dist/components/text-editor/plugins/LinkPlugin.d.ts +8 -0
  94. package/dist/components/text-editor/plugins/LinkPlugin.js +183 -0
  95. package/dist/components/text-editor/plugins/ListToolbarPlugin.d.ts +7 -0
  96. package/dist/components/text-editor/plugins/ListToolbarPlugin.js +40 -0
  97. package/dist/components/text-editor/plugins/LoadContentPlugin.d.ts +4 -0
  98. package/dist/components/text-editor/plugins/LoadContentPlugin.js +63 -0
  99. package/dist/components/text-editor/plugins/MarkdownExportPlugin.d.ts +4 -0
  100. package/dist/components/text-editor/plugins/MarkdownExportPlugin.js +17 -0
  101. package/dist/components/text-editor/plugins/MarkdownPastePlugin.d.ts +2 -0
  102. package/dist/components/text-editor/plugins/MarkdownPastePlugin.js +45 -0
  103. package/dist/components/text-editor/plugins/SanitizePastePlugin.d.ts +3 -0
  104. package/dist/components/text-editor/plugins/SanitizePastePlugin.js +40 -0
  105. package/dist/components/text-editor/plugins/TextAlignPlugin.d.ts +7 -0
  106. package/dist/components/text-editor/plugins/TextAlignPlugin.js +65 -0
  107. package/dist/components/text-editor/plugins/TextColorPlugin.d.ts +7 -0
  108. package/dist/components/text-editor/plugins/TextColorPlugin.js +117 -0
  109. package/dist/components/text-editor/plugins/ToolbarPlugin.d.ts +10 -0
  110. package/dist/components/text-editor/plugins/ToolbarPlugin.js +73 -0
  111. package/dist/components/text-editor/theme-colors.d.ts +11 -0
  112. package/dist/components/text-editor/theme-colors.js +28 -0
  113. package/dist/context/WrAppContext.d.ts +35 -0
  114. package/dist/context/WrAppContext.js +113 -0
  115. package/dist/context/WrLayout.d.ts +15 -0
  116. package/dist/context/WrLayout.js +22 -0
  117. package/dist/context/WrPageContext.d.ts +28 -0
  118. package/dist/context/WrPageContext.js +282 -0
  119. package/dist/context/restoreValues.d.ts +2 -0
  120. package/dist/context/restoreValues.js +6 -0
  121. package/dist/contrast.d.ts +45 -0
  122. package/dist/contrast.js +122 -0
  123. package/dist/drop.d.ts +7 -0
  124. package/dist/drop.js +51 -0
  125. package/dist/gaps.d.ts +14 -0
  126. package/dist/gaps.js +50 -0
  127. package/dist/hooks/useWrMessage.d.ts +5 -0
  128. package/dist/hooks/useWrMessage.js +24 -0
  129. package/dist/hooks/useWrSave.d.ts +2 -0
  130. package/dist/hooks/useWrSave.js +11 -0
  131. package/dist/index.css +467 -0
  132. package/dist/index.d.ts +20 -0
  133. package/dist/index.js +20 -0
  134. package/dist/interactive.d.ts +8 -0
  135. package/dist/interactive.js +13 -0
  136. package/dist/measure-rules.d.ts +34 -0
  137. package/dist/measure-rules.js +54 -0
  138. package/dist/measure.d.ts +11 -0
  139. package/dist/measure.js +139 -0
  140. package/dist/messages.d.ts +860 -0
  141. package/dist/messages.js +2 -0
  142. package/dist/nav.d.ts +5 -0
  143. package/dist/nav.js +10 -0
  144. package/dist/operations/animations-store.d.ts +6 -0
  145. package/dist/operations/animations-store.js +63 -0
  146. package/dist/operations/cli.d.ts +3 -0
  147. package/dist/operations/cli.js +52 -0
  148. package/dist/operations/comments-store.d.ts +17 -0
  149. package/dist/operations/comments-store.js +62 -0
  150. package/dist/operations/context.d.ts +12 -0
  151. package/dist/operations/context.js +35 -0
  152. package/dist/operations/define.d.ts +81 -0
  153. package/dist/operations/define.js +86 -0
  154. package/dist/operations/index.d.ts +6 -0
  155. package/dist/operations/index.js +6 -0
  156. package/dist/operations/ops/check.d.ts +5 -0
  157. package/dist/operations/ops/check.js +53 -0
  158. package/dist/operations/ops/comments.d.ts +6 -0
  159. package/dist/operations/ops/comments.js +133 -0
  160. package/dist/operations/ops/content.d.ts +16 -0
  161. package/dist/operations/ops/content.js +73 -0
  162. package/dist/operations/ops/json.d.ts +4 -0
  163. package/dist/operations/ops/json.js +27 -0
  164. package/dist/operations/ops/langs.d.ts +4 -0
  165. package/dist/operations/ops/langs.js +32 -0
  166. package/dist/operations/ops/nodes.d.ts +8 -0
  167. package/dist/operations/ops/nodes.js +270 -0
  168. package/dist/operations/ops/pages.d.ts +8 -0
  169. package/dist/operations/ops/pages.js +154 -0
  170. package/dist/operations/ops/project.d.ts +36 -0
  171. package/dist/operations/ops/project.js +97 -0
  172. package/dist/operations/ops/seo.d.ts +17 -0
  173. package/dist/operations/ops/seo.js +358 -0
  174. package/dist/operations/ops/style.d.ts +76 -0
  175. package/dist/operations/ops/style.js +268 -0
  176. package/dist/operations/ops/stylesets.d.ts +9 -0
  177. package/dist/operations/ops/stylesets.js +145 -0
  178. package/dist/operations/ops/theme.d.ts +6 -0
  179. package/dist/operations/ops/theme.js +304 -0
  180. package/dist/operations/registry.d.ts +8 -0
  181. package/dist/operations/registry.js +19 -0
  182. package/dist/operations/stylesets-store.d.ts +50 -0
  183. package/dist/operations/stylesets-store.js +216 -0
  184. package/dist/registry.d.ts +5 -0
  185. package/dist/registry.js +24 -0
  186. package/dist/save.d.ts +65 -0
  187. package/dist/save.js +86 -0
  188. package/dist/schema.d.ts +69 -0
  189. package/dist/schema.js +110 -0
  190. package/dist/scope.d.ts +41 -0
  191. package/dist/scope.js +44 -0
  192. package/dist/vite-plugins/ast.d.ts +3 -0
  193. package/dist/vite-plugins/ast.js +238 -0
  194. package/dist/vite-plugins/core-swap.d.ts +3 -0
  195. package/dist/vite-plugins/core-swap.js +57 -0
  196. package/dist/vite-plugins/create-page.d.ts +4 -0
  197. package/dist/vite-plugins/create-page.js +59 -0
  198. package/dist/vite-plugins/guard.d.ts +15 -0
  199. package/dist/vite-plugins/guard.js +35 -0
  200. package/dist/vite-plugins/head.d.ts +13 -0
  201. package/dist/vite-plugins/head.js +53 -0
  202. package/dist/vite-plugins/index.d.ts +7 -0
  203. package/dist/vite-plugins/index.js +7 -0
  204. package/dist/vite-plugins/jsx-tree.d.ts +118 -0
  205. package/dist/vite-plugins/jsx-tree.js +686 -0
  206. package/dist/vite-plugins/langs.d.ts +3 -0
  207. package/dist/vite-plugins/langs.js +44 -0
  208. package/dist/vite-plugins/operations.d.ts +10 -0
  209. package/dist/vite-plugins/operations.js +66 -0
  210. package/dist/vite-plugins/pages-api.d.ts +3 -0
  211. package/dist/vite-plugins/pages-api.js +112 -0
  212. package/dist/vite-plugins/pages.d.ts +3 -0
  213. package/dist/vite-plugins/pages.js +64 -0
  214. package/dist/vite-plugins/read.d.ts +3 -0
  215. package/dist/vite-plugins/read.js +45 -0
  216. package/dist/vite-plugins/seo-files.d.ts +8 -0
  217. package/dist/vite-plugins/seo-files.js +42 -0
  218. package/dist/vite-plugins/theme.d.ts +3 -0
  219. package/dist/vite-plugins/theme.js +207 -0
  220. package/dist/vite-plugins/update.d.ts +3 -0
  221. package/dist/vite-plugins/update.js +46 -0
  222. package/dist/vite-plugins/wr-plugins.d.ts +15 -0
  223. package/dist/vite-plugins/wr-plugins.js +34 -0
  224. package/dist/vite-plugins.d.ts +11 -0
  225. package/dist/vite-plugins.js +518 -0
  226. package/package.json +96 -5
  227. package/README.md +0 -3
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ interface Props {
3
+ editorPathKey?: string;
4
+ }
5
+ export default function ListToolbarPlugin({ editorPathKey }: Props): React.JSX.Element;
6
+ export {};
7
+ //# sourceMappingURL=ListToolbarPlugin.d.ts.map
@@ -0,0 +1,40 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
3
+ import { $getSelection, $isRangeSelection } from 'lexical';
4
+ import { INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND } from '@lexical/list';
5
+ import { PiListBullets, PiListNumbers } from 'react-icons/pi';
6
+ export default function ListToolbarPlugin({ editorPathKey = '' }) {
7
+ const [editor] = useLexicalComposerContext();
8
+ const extractTextStyle = () => {
9
+ let style = '';
10
+ editor.getEditorState().read(() => {
11
+ const selection = $getSelection();
12
+ if ($isRangeSelection(selection)) {
13
+ style = selection.anchor.getNode().getStyle?.() || '';
14
+ }
15
+ });
16
+ return style;
17
+ };
18
+ const applyStyleToListElement = () => {
19
+ editor.update(() => {
20
+ const selection = $getSelection();
21
+ if (!$isRangeSelection(selection))
22
+ return;
23
+ let node = selection.anchor.getNode();
24
+ while (node && node.getType() !== 'list') {
25
+ node = node.getParent();
26
+ }
27
+ if (node?.getType() === 'list') {
28
+ const parent = node.getParent();
29
+ if (parent)
30
+ parent.setStyle(extractTextStyle());
31
+ }
32
+ });
33
+ };
34
+ const insertList = (listType) => {
35
+ editor.dispatchCommand(listType === 'ol' ? INSERT_ORDERED_LIST_COMMAND : INSERT_UNORDERED_LIST_COMMAND, undefined);
36
+ applyStyleToListElement();
37
+ };
38
+ return (_jsxs(_Fragment, { children: [_jsx("button", { className: `wr-toolbar-icon-btn path-${editorPathKey}`, onClick: () => insertList('ul'), title: "Lista puntata", children: _jsx(PiListBullets, {}) }), _jsx("button", { className: `wr-toolbar-icon-btn path-${editorPathKey}`, onClick: () => insertList('ol'), title: "Lista numerata", children: _jsx(PiListNumbers, {}) })] }));
39
+ }
40
+ //# sourceMappingURL=ListToolbarPlugin.js.map
@@ -0,0 +1,4 @@
1
+ export default function LoadContentPlugin({ html }: {
2
+ html: string;
3
+ }): null;
4
+ //# sourceMappingURL=LoadContentPlugin.d.ts.map
@@ -0,0 +1,63 @@
1
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
2
+ import { useEffect, useRef } from 'react';
3
+ import { $getRoot, $insertNodes } from 'lexical';
4
+ import { $generateNodesFromDOM } from '@lexical/html';
5
+ export default function LoadContentPlugin({ html }) {
6
+ const [editor] = useLexicalComposerContext();
7
+ const loadedRef = useRef(false);
8
+ useEffect(() => {
9
+ if (loadedRef.current)
10
+ return;
11
+ if (!html)
12
+ return;
13
+ loadedRef.current = true;
14
+ editor.update(() => {
15
+ const parser = new DOMParser();
16
+ const dom = parser.parseFromString(html, 'text/html');
17
+ // Inserisci i nodi dalla struttura HTML
18
+ const nodes = $generateNodesFromDOM(editor, dom);
19
+ $getRoot().clear();
20
+ $getRoot().select();
21
+ $insertNodes(nodes);
22
+ // $generateNodesFromDOM non preserva gli stili inline dei <span style="...">,
23
+ // perché Lexical non ha un converter registrato per span[style].
24
+ // Fix: camminiamo DOM e Lexical in parallelo per indice posizionale
25
+ // (più robusto del matching per textContent che si rompe con testi identici).
26
+ const domLeaves = getStyledLeaves(dom.body);
27
+ const lexNodes = $getRoot().getAllTextNodes();
28
+ domLeaves.forEach((leaf, i) => {
29
+ if (leaf.style && lexNodes[i]) {
30
+ lexNodes[i].setStyle(leaf.style);
31
+ }
32
+ });
33
+ });
34
+ // eslint-disable-next-line react-hooks/exhaustive-deps
35
+ }, []);
36
+ return null;
37
+ }
38
+ /**
39
+ * Raccoglie in ordine di documento tutte le foglie di testo del DOM
40
+ * con il loro stile inline (se presente sul parent diretto o antenato span).
41
+ * Restituisce un array parallelo ai TextNode di Lexical.
42
+ */
43
+ function getStyledLeaves(root) {
44
+ const results = [];
45
+ function walk(node, inheritedStyle) {
46
+ if (node.nodeType === Node.TEXT_NODE) {
47
+ const text = node.textContent ?? '';
48
+ if (text.trim())
49
+ results.push({ text, style: inheritedStyle });
50
+ return;
51
+ }
52
+ if (node.nodeType === Node.ELEMENT_NODE) {
53
+ const el = node;
54
+ const style = el.getAttribute('style') ?? inheritedStyle;
55
+ for (const child of Array.from(el.childNodes)) {
56
+ walk(child, style);
57
+ }
58
+ }
59
+ }
60
+ walk(root, '');
61
+ return results;
62
+ }
63
+ //# sourceMappingURL=LoadContentPlugin.js.map
@@ -0,0 +1,4 @@
1
+ export default function MarkdownExportPlugin({ editorPathKey }: {
2
+ editorPathKey: string;
3
+ }): import("react").JSX.Element;
4
+ //# sourceMappingURL=MarkdownExportPlugin.d.ts.map
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { PiMarkdownLogo } from "react-icons/pi";
4
+ import { FaCheck } from "react-icons/fa";
5
+ import { useLexicalMarkdown } from "../hooks/useLexicalMarkdown";
6
+ export default function MarkdownExportPlugin({ editorPathKey }) {
7
+ const { toMarkdown } = useLexicalMarkdown();
8
+ const [copied, setCopied] = useState(false);
9
+ const handleCopy = async () => {
10
+ const md = toMarkdown();
11
+ await navigator.clipboard.writeText(md);
12
+ setCopied(true);
13
+ setTimeout(() => setCopied(false), 1500);
14
+ };
15
+ return (_jsx("button", { className: `wr-toolbar-icon-btn path-${editorPathKey}`, onClick: handleCopy, title: "Copy as markdown", children: copied ? _jsx(FaCheck, { style: { color: '#22c55e' } }) : _jsx(PiMarkdownLogo, {}) }));
16
+ }
17
+ //# sourceMappingURL=MarkdownExportPlugin.js.map
@@ -0,0 +1,2 @@
1
+ export default function MarkdownPastePlugin(): null;
2
+ //# sourceMappingURL=MarkdownPastePlugin.d.ts.map
@@ -0,0 +1,45 @@
1
+ import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
2
+ import { PASTE_COMMAND, COMMAND_PRIORITY_HIGH, $getSelection, $isRangeSelection } from "lexical";
3
+ import { useEffect } from "react";
4
+ import { buildNodes, tokenizeInline, useLexicalMarkdown } from "../hooks/useLexicalMarkdown";
5
+ const MD_BLOCK_RE = /^(#{1,6} |\s*[-*] |\s*\d+\. )/m;
6
+ const isBlock = (text) => MD_BLOCK_RE.test(text) ||
7
+ /\*\*.+\*\*/s.test(text) ||
8
+ text.includes("\n");
9
+ const isInline = (text) => /\[.+?\]\(.+?\)/.test(text) ||
10
+ /\*.+?\*/.test(text) ||
11
+ /\*\*.+?\*\*/.test(text);
12
+ export default function MarkdownPastePlugin() {
13
+ const [editor] = useLexicalComposerContext();
14
+ const { fromMarkdown } = useLexicalMarkdown();
15
+ useEffect(() => {
16
+ return editor.registerCommand(PASTE_COMMAND, (event) => {
17
+ const clipboardEvent = event;
18
+ const data = clipboardEvent.clipboardData;
19
+ if (!data)
20
+ return false;
21
+ const raw = (data.getData("text/plain") || "")
22
+ .replace(/\r\n/g, "\n")
23
+ .replace(/\r/g, "\n");
24
+ if (isBlock(raw)) {
25
+ clipboardEvent.preventDefault();
26
+ fromMarkdown(raw);
27
+ return true;
28
+ }
29
+ if (isInline(raw)) {
30
+ clipboardEvent.preventDefault();
31
+ editor.update(() => {
32
+ const selection = $getSelection();
33
+ if (!$isRangeSelection(selection))
34
+ return;
35
+ const nodes = buildNodes(tokenizeInline(raw), "");
36
+ nodes.forEach((n) => selection.insertNodes([n]));
37
+ });
38
+ return true;
39
+ }
40
+ return false;
41
+ }, COMMAND_PRIORITY_HIGH);
42
+ }, [editor, fromMarkdown]);
43
+ return null;
44
+ }
45
+ //# sourceMappingURL=MarkdownPastePlugin.js.map
@@ -0,0 +1,3 @@
1
+ declare const SanitizePastePlugin: () => null;
2
+ export default SanitizePastePlugin;
3
+ //# sourceMappingURL=SanitizePastePlugin.d.ts.map
@@ -0,0 +1,40 @@
1
+ import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
2
+ import { PASTE_COMMAND, $createTextNode, $getSelection, $getRoot, $isRangeSelection, } from "lexical";
3
+ import { useEffect } from "react";
4
+ const SanitizePastePlugin = () => {
5
+ const [editor] = useLexicalComposerContext();
6
+ useEffect(() => {
7
+ return editor.registerCommand(PASTE_COMMAND, (event) => {
8
+ const clipboardEvent = event;
9
+ const data = clipboardEvent.clipboardData;
10
+ if (!data)
11
+ return false;
12
+ clipboardEvent.preventDefault();
13
+ const raw = data.getData("text/plain") || data.getData("text/html") || "";
14
+ const clean = raw
15
+ .replace(/<br\s*\/?>/gi, " ")
16
+ .replace(/<a[^>]*>(.*?)<\/a>/gi, "$1")
17
+ .replace(/<\/?[^>]+(>|$)/g, "")
18
+ .replace(/[\r\n\t]+/g, " ")
19
+ .replace(/\u00A0/g, " ")
20
+ .replace(/[^\S\r\n]+/g, " ")
21
+ .replace(/\s+/g, " ")
22
+ .trim();
23
+ editor.update(() => {
24
+ const selection = $getSelection();
25
+ if (selection && $isRangeSelection(selection)) {
26
+ selection.insertRawText(clean);
27
+ }
28
+ else {
29
+ const root = $getRoot();
30
+ const textNode = $createTextNode(clean);
31
+ root.append(textNode);
32
+ }
33
+ });
34
+ return true;
35
+ }, 1);
36
+ }, [editor]);
37
+ return null;
38
+ };
39
+ export default SanitizePastePlugin;
40
+ //# sourceMappingURL=SanitizePastePlugin.js.map
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ interface Props {
3
+ editorPathKey?: string;
4
+ }
5
+ declare function TextAlignPlugin({ editorPathKey }: Props): React.JSX.Element;
6
+ export default TextAlignPlugin;
7
+ //# sourceMappingURL=TextAlignPlugin.d.ts.map
@@ -0,0 +1,65 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useRef, useEffect, useState } from 'react';
3
+ import { createPortal } from 'react-dom';
4
+ import { PiTextAlignLeft, PiTextAlignCenter, PiTextAlignRight, PiTextAlignJustify } from 'react-icons/pi';
5
+ import { WR_SURFACE_STYLE } from '../common/surface';
6
+ import { requestTextAlign } from '../../../bridge';
7
+ const alignments = {
8
+ left: _jsx(PiTextAlignLeft, {}),
9
+ center: _jsx(PiTextAlignCenter, {}),
10
+ right: _jsx(PiTextAlignRight, {}),
11
+ justify: _jsx(PiTextAlignJustify, {}),
12
+ };
13
+ function TextAlignPlugin({ editorPathKey = '' }) {
14
+ const [isMenuOpen, setIsMenuOpen] = useState(false);
15
+ const [selectedAlignment, setSelectedAlignment] = useState('left');
16
+ const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 });
17
+ const buttonRef = useRef(null);
18
+ const menuRef = useRef(null);
19
+ const toggleMenu = (event) => {
20
+ event.stopPropagation();
21
+ setIsMenuOpen((prev) => !prev);
22
+ };
23
+ // The alignment is the text element's own (its class, at the breakpoint the editor's panel is on), not a mark in each paragraph: the editor writes it, and the text is drawn again
24
+ const applyAlignment = (alignment) => {
25
+ requestTextAlign(editorPathKey, alignment);
26
+ setSelectedAlignment(alignment);
27
+ setIsMenuOpen(false);
28
+ };
29
+ const calculateMenuPosition = () => {
30
+ if (buttonRef.current && menuRef.current) {
31
+ const buttonRect = buttonRef.current.getBoundingClientRect();
32
+ const menuRect = menuRef.current.getBoundingClientRect();
33
+ let top = buttonRect.bottom;
34
+ let left = buttonRect.left;
35
+ const pageWidth = document.body.clientWidth;
36
+ if (left + menuRect.width > pageWidth)
37
+ left = pageWidth - menuRect.width - 10;
38
+ if (left < 0)
39
+ left = 10;
40
+ setMenuPosition({ top, left });
41
+ }
42
+ };
43
+ useEffect(() => {
44
+ const handleClickOutside = (event) => {
45
+ if (menuRef.current &&
46
+ !menuRef.current.contains(event.target) &&
47
+ !buttonRef.current?.contains(event.target)) {
48
+ setIsMenuOpen(false);
49
+ }
50
+ };
51
+ if (isMenuOpen) {
52
+ document.addEventListener('click', handleClickOutside);
53
+ calculateMenuPosition();
54
+ }
55
+ return () => document.removeEventListener('click', handleClickOutside);
56
+ }, [isMenuOpen]);
57
+ // What the element shows now, wherever it comes from (its class at this width, or an alignment written in the text before)
58
+ useEffect(() => {
59
+ const shown = getComputedStyle(buttonRef.current?.closest('[data-wr-editing]') ?? document.body).textAlign;
60
+ setSelectedAlignment(shown === 'center' || shown === 'right' || shown === 'justify' ? shown : 'left');
61
+ });
62
+ return (_jsxs("div", { className: `path-${editorPathKey} toolbarClass`, style: { position: 'relative', display: 'inline-block', textAlign: 'left' }, onClick: (e) => e.stopPropagation(), children: [_jsx("button", { ref: buttonRef, type: "button", onClick: toggleMenu, className: "wr-toolbar-trigger", "aria-expanded": isMenuOpen, "aria-haspopup": "true", title: "Allineamento testo", children: alignments[selectedAlignment] }), isMenuOpen && createPortal(_jsx("div", { ref: menuRef, className: `toolbarClass path-${editorPathKey} wr-toolbar-menu`, style: { ...WR_SURFACE_STYLE, top: menuPosition.top, left: menuPosition.left, width: 160 }, children: _jsx("div", { style: { padding: '4px 0' }, role: "none", children: Object.keys(alignments).map((alignment) => (_jsxs("button", { onClick: () => applyAlignment(alignment), className: `wr-toolbar-item ${alignment === selectedAlignment ? 'wr-toolbar-item--active' : ''}`, style: { display: 'flex', alignItems: 'center', gap: 8 }, role: "menuitem", children: [alignments[alignment], _jsx("span", { style: { textTransform: 'capitalize' }, children: alignment })] }, alignment))) }) }), document.body)] }));
63
+ }
64
+ export default TextAlignPlugin;
65
+ //# sourceMappingURL=TextAlignPlugin.js.map
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ interface Props {
3
+ editorPathKey?: string;
4
+ }
5
+ declare function TextColorPlugin({ editorPathKey }: Props): React.JSX.Element;
6
+ export default TextColorPlugin;
7
+ //# sourceMappingURL=TextColorPlugin.d.ts.map
@@ -0,0 +1,117 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useRef, useEffect, useState, useCallback } from 'react';
3
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
4
+ import { $getSelection, $isRangeSelection } from 'lexical';
5
+ import { $patchStyleText } from '@lexical/selection';
6
+ import { createPortal } from 'react-dom';
7
+ import { wrGetTheme } from '../../../save';
8
+ import { WR_SURFACE_STYLE } from '../common/surface';
9
+ import { themeTextColors } from '../theme-colors';
10
+ const colorMap = {
11
+ white: '#ffffff', black: '#000000',
12
+ gray: '#9CA3AF', stone: '#A8A29E', slate: '#64748B',
13
+ yellow: '#FACC15', 'highlighter yellow': '#FFFF00',
14
+ amber: '#F59E0B', orange: '#FB923C', red: '#EF4444',
15
+ rose: '#F43F5E', brown: '#8B4513', fuchsia: '#D946EF',
16
+ pink: '#EC4899', purple: '#8B5CF6', indigo: '#6366F1',
17
+ blue: '#3B82F6', sky: '#38BDF8', cyan: '#06B6D4',
18
+ teal: '#14B8A6', emerald: '#10B981', green: '#22C55E', lime: '#84CC16',
19
+ };
20
+ const colorNames = Object.keys(colorMap);
21
+ function TextColorPlugin({ editorPathKey = '' }) {
22
+ const [editor] = useLexicalComposerContext();
23
+ const [isMenuOpen, setIsMenuOpen] = useState(false);
24
+ const [selectedColor, setSelectedColor] = useState(colorMap['black']);
25
+ const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 });
26
+ // The theme's colors a text can be (those that read on the page): taken from the theme each time the menu opens, so a color added in the Theme panel is there at once
27
+ const [themeColors, setThemeColors] = useState([]);
28
+ const buttonRef = useRef(null);
29
+ const menuRef = useRef(null);
30
+ const colorInputRef = useRef(null);
31
+ const savedSelectionRef = useRef(null);
32
+ const toggleMenu = (event) => {
33
+ event.stopPropagation();
34
+ if (!isMenuOpen)
35
+ wrGetTheme().then(({ items }) => setThemeColors(themeTextColors(items))).catch(() => setThemeColors([]));
36
+ setIsMenuOpen((prev) => !prev);
37
+ };
38
+ const applyTextColor = useCallback((colorValue) => {
39
+ editor.update(() => {
40
+ const selection = $getSelection();
41
+ if ($isRangeSelection(selection)) {
42
+ $patchStyleText(selection, { color: colorValue });
43
+ }
44
+ });
45
+ setSelectedColor(colorValue);
46
+ setIsMenuOpen(false);
47
+ }, [editor]);
48
+ const applyColorFromRef = useCallback((colorValue) => {
49
+ editor.update(() => {
50
+ const sel = savedSelectionRef.current;
51
+ if (sel) {
52
+ $patchStyleText(sel, { color: colorValue });
53
+ }
54
+ });
55
+ setSelectedColor(colorValue);
56
+ }, [editor]);
57
+ const openColorPicker = () => {
58
+ // Save current selection before menu closes / focus moves
59
+ editor.getEditorState().read(() => {
60
+ const sel = $getSelection();
61
+ if ($isRangeSelection(sel))
62
+ savedSelectionRef.current = sel.clone();
63
+ });
64
+ setIsMenuOpen(false);
65
+ setTimeout(() => colorInputRef.current?.click(), 0);
66
+ };
67
+ const calculateMenuPosition = () => {
68
+ if (buttonRef.current && menuRef.current) {
69
+ const buttonRect = buttonRef.current.getBoundingClientRect();
70
+ const menuRect = menuRef.current.getBoundingClientRect();
71
+ let top = buttonRect.bottom;
72
+ let left = buttonRect.left;
73
+ const pageWidth = document.body.clientWidth;
74
+ if (left + menuRect.width > pageWidth)
75
+ left = pageWidth - menuRect.width - 10;
76
+ if (left < 0)
77
+ left = 10;
78
+ setMenuPosition({ top, left });
79
+ }
80
+ };
81
+ useEffect(() => {
82
+ const handleClickOutside = (event) => {
83
+ if (menuRef.current &&
84
+ !menuRef.current.contains(event.target) &&
85
+ !buttonRef.current?.contains(event.target)) {
86
+ setIsMenuOpen(false);
87
+ }
88
+ };
89
+ if (isMenuOpen) {
90
+ document.addEventListener('click', handleClickOutside);
91
+ calculateMenuPosition();
92
+ }
93
+ return () => document.removeEventListener('click', handleClickOutside);
94
+ }, [isMenuOpen]);
95
+ useEffect(() => {
96
+ return editor.registerUpdateListener(() => {
97
+ editor.getEditorState().read(() => {
98
+ const selection = $getSelection();
99
+ if (!$isRangeSelection(selection))
100
+ return;
101
+ const anchorNode = selection.anchor.getNode();
102
+ if (!anchorNode)
103
+ return;
104
+ const styleString = anchorNode.getStyle();
105
+ const textContent = anchorNode.getTextContent().trim();
106
+ if (textContent === '' || !styleString)
107
+ return;
108
+ const colorMatch = styleString.match(/(?<!background-)color:\s*([^;]+)/i);
109
+ if (colorMatch)
110
+ setSelectedColor(colorMatch[1].trim());
111
+ });
112
+ });
113
+ }, [editor]);
114
+ return (_jsxs("div", { className: `path-${editorPathKey} toolbarClass`, style: { position: 'relative', display: 'inline-block', textAlign: 'left' }, onClick: (e) => e.stopPropagation(), children: [_jsx("input", { ref: colorInputRef, type: "color", value: selectedColor.startsWith('#') ? selectedColor : '#000000', onChange: (e) => applyColorFromRef(e.target.value), style: { position: 'absolute', opacity: 0, width: 0, height: 0, pointerEvents: 'none' }, tabIndex: -1 }), _jsxs("button", { ref: buttonRef, type: "button", onClick: toggleMenu, className: "wr-toolbar-trigger", "aria-expanded": isMenuOpen, "aria-haspopup": "true", children: [_jsx("div", { style: { display: 'flex', alignItems: 'center', gap: 8 }, children: _jsx("span", { className: "wr-color-dot", style: { backgroundColor: selectedColor } }) }), _jsx("svg", { className: `wr-toolbar-chevron ${isMenuOpen ? 'wr-toolbar-chevron--open' : ''}`, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", children: _jsx("path", { fillRule: "evenodd", d: "M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z", clipRule: "evenodd" }) })] }), isMenuOpen && createPortal(_jsx("div", { ref: menuRef, className: `toolbarClass path-${editorPathKey} wr-toolbar-menu`, role: "menu", "aria-orientation": "vertical", style: { ...WR_SURFACE_STYLE, top: menuPosition.top, left: menuPosition.left, width: 192 }, children: _jsxs("div", { style: { padding: '4px 0' }, role: "none", children: [_jsx("button", { onClick: openColorPicker, onPointerDown: (e) => e.preventDefault(), className: `toolbarClass path-${editorPathKey} wr-toolbar-item`, role: "menuitem", children: _jsxs("span", { className: "wr-menu-row", children: [_jsx("span", { className: "wr-color-dot", style: { backgroundColor: selectedColor } }), _jsx("span", { children: selectedColor })] }) }), themeColors.length > 0 && _jsx("div", { className: "wr-menu-heading", role: "presentation", children: "Theme" }), themeColors.map((color) => (_jsx("button", { onClick: () => applyTextColor(color.variable), className: `wr-toolbar-item ${color.variable === selectedColor ? 'wr-toolbar-item--active' : ''}`, role: "menuitem", "data-theme-color": color.name, children: _jsxs("span", { className: "wr-menu-row", children: [_jsx("span", { className: "wr-color-dot", style: { backgroundColor: color.variable } }), _jsx("span", { children: color.name })] }) }, color.variable))), themeColors.length > 0 && _jsx("div", { className: "wr-menu-heading", role: "presentation", children: "Other colors" }), colorNames.map((colorName) => (_jsx("button", { onClick: () => applyTextColor(colorMap[colorName]), className: `wr-toolbar-item ${colorMap[colorName] === selectedColor ? 'wr-toolbar-item--active' : ''}`, role: "menuitem", children: _jsxs("span", { className: "wr-menu-row", children: [_jsx("span", { className: "wr-color-dot", style: { backgroundColor: colorMap[colorName] } }), _jsx("span", { children: colorName })] }) }, colorName)))] }) }), document.body)] }));
115
+ }
116
+ export default TextColorPlugin;
117
+ //# sourceMappingURL=TextColorPlugin.js.map
@@ -0,0 +1,10 @@
1
+ interface Props {
2
+ editorRef: React.RefObject<HTMLDivElement | null>;
3
+ editorPathKey: string;
4
+ availablePages?: string[];
5
+ /** The person pressed or focused something that is not this text nor its toolbar (or left the page for the editor around it). */
6
+ onOutside: () => void;
7
+ }
8
+ export default function ToolbarPlugin({ editorRef, editorPathKey, availablePages, onOutside }: Props): import("react").ReactPortal | null;
9
+ export {};
10
+ //# sourceMappingURL=ToolbarPlugin.d.ts.map
@@ -0,0 +1,73 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useCallback, useEffect } from 'react';
3
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
4
+ import { mergeRegister } from '@lexical/utils';
5
+ import { $getSelection, $isRangeSelection, FORMAT_TEXT_COMMAND, SELECTION_CHANGE_COMMAND } from 'lexical';
6
+ import { PiTextItalic, PiTextStrikethrough, PiTextUnderline, } from 'react-icons/pi';
7
+ import { createPortal } from 'react-dom';
8
+ import { useToolbar } from '../ToolbarContext';
9
+ import FontPlugin from './FontPlugin';
10
+ import FontWeightPlugin from './FontWeightPlugin';
11
+ import TextColorPlugin from './TextColorPlugin';
12
+ import LineSpacingPlugin from './LineSpacingPlugin';
13
+ import FloatingLinkEditorPlugin from './LinkPlugin';
14
+ import ListToolbarPlugin from './ListToolbarPlugin';
15
+ import HTMLTagPlugin from './HTMLTagPlugin';
16
+ import FontSizePlugin from './FontSizePlugin';
17
+ import { WR_SURFACE_STYLE } from '../common/surface';
18
+ const LowPriority = 1;
19
+ function Divider() {
20
+ return _jsx("div", { className: "wr-divider" });
21
+ }
22
+ export default function ToolbarPlugin({ editorRef, editorPathKey, availablePages = [], onOutside }) {
23
+ const [editor] = useLexicalComposerContext();
24
+ const { toolbarVisible } = useToolbar();
25
+ const [isBold, setIsBold] = useState(false);
26
+ const [isItalic, setIsItalic] = useState(false);
27
+ const [isUnderline, setIsUnderline] = useState(false);
28
+ const [isStrikethrough, setIsStrikethrough] = useState(false);
29
+ const [visible, setVisible] = useState(false);
30
+ useEffect(() => {
31
+ function handleDocumentInteraction(event) {
32
+ const target = event.target;
33
+ const editorRoot = editorRef.current;
34
+ const toolbarEl = document.querySelector(`[data-editor-path="${editorPathKey}"]`);
35
+ const clickedInsideEditor = editorRoot?.contains(target);
36
+ const clickedInsideToolbar = toolbarEl?.contains(target);
37
+ const clickedInOwnToolbarClass = !!target.closest('.toolbarClass') && !!target.closest(`.path-${editorPathKey}`);
38
+ const clickedInsideColorPicker = !!target.closest('.color-picker');
39
+ const inside = !!(clickedInsideEditor || clickedInsideToolbar || clickedInOwnToolbarClass || clickedInsideColorPicker);
40
+ setVisible(inside);
41
+ // The same line that hides the toolbar ends the editing: what is outside the text and its toolbar is somewhere else
42
+ if (!inside)
43
+ onOutside();
44
+ }
45
+ document.addEventListener('pointerdown', handleDocumentInteraction, true);
46
+ document.addEventListener('focusin', handleDocumentInteraction, true);
47
+ // The panels of the editor are outside this page: pressing one is leaving the text too
48
+ window.addEventListener('blur', onOutside);
49
+ return () => {
50
+ window.removeEventListener('blur', onOutside);
51
+ document.removeEventListener('pointerdown', handleDocumentInteraction, true);
52
+ document.removeEventListener('focusin', handleDocumentInteraction, true);
53
+ };
54
+ }, [editorRef, editorPathKey, onOutside]);
55
+ const $updateToolbar = useCallback(() => {
56
+ const selection = $getSelection();
57
+ if ($isRangeSelection(selection)) {
58
+ setIsBold(selection.hasFormat('bold'));
59
+ setIsItalic(selection.hasFormat('italic'));
60
+ setIsUnderline(selection.hasFormat('underline'));
61
+ setIsStrikethrough(selection.hasFormat('strikethrough'));
62
+ }
63
+ }, []);
64
+ useEffect(() => {
65
+ return mergeRegister(editor.registerUpdateListener(({ editorState }) => {
66
+ editorState.read(() => { $updateToolbar(); });
67
+ }), editor.registerCommand(SELECTION_CHANGE_COMMAND, () => { $updateToolbar(); return false; }, LowPriority));
68
+ }, [editor, $updateToolbar]);
69
+ if (!visible)
70
+ return null;
71
+ return createPortal(_jsx("div", { className: "wr-floating-bar-wrap", "data-editor-path": editorPathKey, children: toolbarVisible && (_jsxs("div", { className: "wr-floating-bar", style: WR_SURFACE_STYLE, onPointerDown: (e) => e.preventDefault(), children: [_jsx(Divider, {}), _jsx(FontWeightPlugin, { editorPathKey: editorPathKey }), _jsx("button", { onClick: () => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'italic'), className: `wr-toolbar-icon-btn ${isItalic ? 'wr-toolbar-icon-btn--active' : ''} path-${editorPathKey}`, title: "Italic", children: _jsx(PiTextItalic, {}) }), _jsx("button", { onClick: () => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'underline'), className: `wr-toolbar-icon-btn ${isUnderline ? 'wr-toolbar-icon-btn--active' : ''} path-${editorPathKey}`, title: "Underline", children: _jsx(PiTextUnderline, {}) }), _jsx("button", { onClick: () => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'strikethrough'), className: `wr-toolbar-icon-btn ${isStrikethrough ? 'wr-toolbar-icon-btn--active' : ''} path-${editorPathKey}`, title: "Strikethrough", children: _jsx(PiTextStrikethrough, {}) }), _jsx(Divider, {}), _jsx(FloatingLinkEditorPlugin, { availablePages: availablePages, editorPathKey: editorPathKey }), _jsx(Divider, {}), _jsx(ListToolbarPlugin, { editorPathKey: editorPathKey }), _jsx(Divider, {}), _jsx(FontPlugin, { editorPathKey: editorPathKey }), _jsx(FontSizePlugin, { editorPathKey: editorPathKey }), _jsx(HTMLTagPlugin, { editorPathKey: editorPathKey }), _jsx(TextColorPlugin, { editorPathKey: editorPathKey }), _jsx(Divider, {}), _jsx(LineSpacingPlugin, { editorPathKey: editorPathKey })] })) }), document.body);
72
+ }
73
+ //# sourceMappingURL=ToolbarPlugin.js.map
@@ -0,0 +1,11 @@
1
+ import type { WrThemeItem } from '../../messages';
2
+ export interface ThemeTextColor {
3
+ /** `accent-text`. */
4
+ name: string;
5
+ /** What a text takes: `var(--wr-color-accent-text)`. */
6
+ variable: string;
7
+ /** How it looks now (the light value), to draw it. */
8
+ value: string;
9
+ }
10
+ export declare function themeTextColors(items: readonly WrThemeItem[]): ThemeTextColor[];
11
+ //# sourceMappingURL=theme-colors.d.ts.map
@@ -0,0 +1,28 @@
1
+ import { contrastRatio } from '../../contrast.js';
2
+ // The colors of the site's theme as a text can use them. A text takes `var(--wr-color-x)`, not its value, so it follows the theme (and its dark theme, when it has one). Which colors a text
3
+ // can be: the ones that can be READ on the page, by the WCAG rule (4.5:1 against the page's background, in each theme the site has): nothing marks them in the theme, the arithmetic does.
4
+ const PREFIX = '--wr-color-';
5
+ const BACKGROUND = `${PREFIX}background`;
6
+ const READABLE = 4.5;
7
+ function parseHex(value) {
8
+ const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(value.trim());
9
+ if (!m)
10
+ return null;
11
+ const hex = m[1].length === 3 ? m[1].split('').map(c => c + c).join('') : m[1];
12
+ return { r: parseInt(hex.slice(0, 2), 16), g: parseInt(hex.slice(2, 4), 16), b: parseInt(hex.slice(4, 6), 16) };
13
+ }
14
+ /** Whether a color reads on a background: true or false, and true when it cannot be known (a color that is not a hex: it is not judged by guess). */
15
+ const reads = (color, background) => {
16
+ const a = parseHex(color);
17
+ const b = background ? parseHex(background) : null;
18
+ return !a || !b || contrastRatio(a, b) >= READABLE;
19
+ };
20
+ export function themeTextColors(items) {
21
+ const properties = items.filter((i) => i.kind === 'property' && i.key.startsWith(PREFIX) && i.key.length > PREFIX.length);
22
+ const background = properties.find(p => p.key === BACKGROUND);
23
+ return properties
24
+ .filter(p => p.key !== BACKGROUND)
25
+ .filter(p => reads(p.value, background?.value) && (p.dark === undefined || reads(p.dark, background?.dark ?? background?.value)))
26
+ .map(p => ({ name: p.key.slice(PREFIX.length), variable: `var(${p.key})`, value: p.value }));
27
+ }
28
+ //# sourceMappingURL=theme-colors.js.map
@@ -0,0 +1,35 @@
1
+ import { type ComponentType, type ReactNode } from 'react';
2
+ import { wrBuildRegistry, wrBuildLazyRegistry, wrBuildPageConfigMap, type WrRoutesFile, type WrLangConfig, type WrSharedFile, type WrSharedScope } from '@webround/core/routing';
3
+ import type { LangCode } from '@webround/core/lang-codes';
4
+ import type { WrSeoSite } from '@webround/core/seo';
5
+ import { WrPageConfig } from '@webround/core/types';
6
+ export declare function useWrApp(): {
7
+ lang: "id" | "af" | "am" | "sq" | "ar" | "hy" | "az" | "eu" | "be" | "bn" | "bs" | "bg" | "ca" | "ceb" | "ny" | "zh" | "co" | "hr" | "cs" | "da" | "nl" | "sjn" | "en" | "eo" | "et" | "tl" | "fo" | "fj" | "fi" | "fr" | "fy" | "gl" | "ka" | "de" | "el" | "gu" | "haw" | "ht" | "ha" | "he" | "hi" | "hmn" | "hu" | "is" | "ig" | "iu" | "iku" | "ga" | "it" | "ja" | "jw" | "kk" | "kn" | "km" | "ko" | "kok" | "ky" | "ku" | "ckb" | "sdh" | "lo" | "lv" | "lt" | "lb" | "mk" | "mg" | "ms" | "ml" | "mt" | "mr" | "mn" | "mi" | "my" | "ne" | "no" | "pap" | "fa" | "pl" | "pt" | "pa" | "ps" | "otq" | "ro" | "ru" | "sm" | "gd" | "sr" | "sr-LA" | "sd" | "si" | "sk" | "sl" | "sn" | "st" | "so" | "es" | "su" | "sw" | "sv" | "ty" | "ta" | "tg" | "te" | "th" | "bo" | "to" | "tr" | "uk" | "ur" | "uz" | "vi" | "cy" | "xh" | "yi" | "yo" | "yua" | "yue" | "zu" | "default";
8
+ setLang: (lang: LangCode) => void;
9
+ };
10
+ export declare const WrPagesConfigContext: import("react").Context<Record<string, WrPageConfig>>;
11
+ export declare const useWrSharedScopes: () => readonly WrSharedScope[];
12
+ type EagerPageModules = Parameters<typeof wrBuildRegistry>[0];
13
+ type LazyPageModules = Parameters<typeof wrBuildLazyRegistry>[0];
14
+ type PageConfigModules = Parameters<typeof wrBuildPageConfigMap>[0];
15
+ export declare function WrAppProvider({ routesFile, eagerModules, lazyModules, configModules, langs, initialLang, lazyFallback, Header, Footer, seo, shared, children, }: {
16
+ routesFile: WrRoutesFile;
17
+ eagerModules: EagerPageModules;
18
+ lazyModules: LazyPageModules;
19
+ configModules: PageConfigModules;
20
+ /** Lingue del sito. Se omesso, niente routing multilingua, lang resta 'default'. */
21
+ langs?: WrLangConfig;
22
+ /** Fallback usato solo quando `langs` non è passato. */
23
+ initialLang?: LangCode;
24
+ lazyFallback?: ComponentType;
25
+ /** Header e footer del sito: su ogni pagina, salvo `header: false` / `footer: false` nella sua voce di routes.json. */
26
+ Header?: ComponentType;
27
+ Footer?: ComponentType;
28
+ /** What is the same for the whole site, for search engines (`config/seo.json`). */
29
+ seo?: WrSeoSite;
30
+ /** The shared components of the site (`config/shared.json`: name → file): the editor writes in the file of the one an element is in. */
31
+ shared?: WrSharedFile;
32
+ children?: ReactNode;
33
+ }): import("react").JSX.Element;
34
+ export {};
35
+ //# sourceMappingURL=WrAppContext.d.ts.map