5htp-core 0.4.7 → 0.4.8

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 (38) hide show
  1. package/package.json +6 -1
  2. package/src/client/assets/css/text/titres.less +1 -1
  3. package/src/client/assets/css/utils/layouts.less +8 -2
  4. package/src/client/components/Dialog/Manager.tsx +65 -29
  5. package/src/client/components/Dialog/card.tsx +3 -1
  6. package/src/client/components/Dialog/index.less +1 -2
  7. package/src/client/components/Select/ChoiceSelector.tsx +7 -5
  8. package/src/client/components/Select/index.tsx +162 -130
  9. package/src/client/components/index.ts +2 -1
  10. package/src/client/components/inputv3/Rte/ExampleTheme.tsx +42 -0
  11. package/src/client/components/inputv3/Rte/ToolbarPlugin.tsx +167 -0
  12. package/src/client/components/inputv3/Rte/icons/LICENSE.md +5 -0
  13. package/src/client/components/inputv3/Rte/icons/arrow-clockwise.svg +4 -0
  14. package/src/client/components/inputv3/Rte/icons/arrow-counterclockwise.svg +4 -0
  15. package/src/client/components/inputv3/Rte/icons/journal-text.svg +5 -0
  16. package/src/client/components/inputv3/Rte/icons/justify.svg +3 -0
  17. package/src/client/components/inputv3/Rte/icons/text-center.svg +3 -0
  18. package/src/client/components/inputv3/Rte/icons/text-left.svg +3 -0
  19. package/src/client/components/inputv3/Rte/icons/text-paragraph.svg +3 -0
  20. package/src/client/components/inputv3/Rte/icons/text-right.svg +3 -0
  21. package/src/client/components/inputv3/Rte/icons/type-bold.svg +3 -0
  22. package/src/client/components/inputv3/Rte/icons/type-italic.svg +3 -0
  23. package/src/client/components/inputv3/Rte/icons/type-strikethrough.svg +3 -0
  24. package/src/client/components/inputv3/Rte/icons/type-underline.svg +3 -0
  25. package/src/client/components/inputv3/Rte/index.tsx +163 -0
  26. package/src/client/components/inputv3/Rte/style.less +428 -0
  27. package/src/client/components/inputv3/base.less +20 -33
  28. package/src/client/components/inputv3/base.tsx +36 -2
  29. package/src/client/components/inputv3/index.tsx +45 -44
  30. package/src/common/data/rte/index.ts +66 -0
  31. package/src/common/data/rte/nodes.ts +20 -0
  32. package/src/common/validation/validators.ts +46 -1
  33. package/src/server/services/auth/index.ts +0 -2
  34. package/src/server/services/database/index.ts +1 -1
  35. package/src/client/components/input/Rte/index.less +0 -13
  36. package/src/client/components/input/Rte/index.tsx +0 -143
  37. package/src/client/components/input/Rte/selection.ts +0 -34
  38. package/src/common/data/rte.tsx +0 -11
@@ -0,0 +1,66 @@
1
+ import { createHeadlessEditor } from '@lexical/headless';
2
+ import { $generateNodesFromDOM, $generateHtmlFromNodes } from '@lexical/html';
3
+ import { $getRoot } from 'lexical';
4
+
5
+ import { JSDOM } from 'jsdom';
6
+
7
+ import editorNodes from './nodes';
8
+
9
+ export const htmlToJson = async (htmlString: string) => {
10
+
11
+ const editor = createHeadlessEditor({
12
+ nodes: editorNodes
13
+ });
14
+
15
+ await editor.update(() => {
16
+
17
+ const root = $getRoot();
18
+
19
+ // In a headless environment you can use a package such as JSDom to parse the HTML string.
20
+ const dom = new JSDOM(htmlString);
21
+
22
+ // Once you have the DOM instance it's easy to generate LexicalNodes.
23
+ const lexicalNodes = $generateNodesFromDOM(editor, dom.window.document);
24
+
25
+ lexicalNodes.forEach((node) => root.append(node));
26
+ });
27
+
28
+ const state = editor.getEditorState();
29
+ return state.toJSON();
30
+ };
31
+
32
+ export const jsonToHtml = async (jsonString: string) => {
33
+
34
+
35
+ const dom = new JSDOM(`<!DOCTYPE html><body></body>`);
36
+ global.window = dom.window;
37
+ global.document = dom.window.document;
38
+ global.DOMParser = dom.window.DOMParser;
39
+ global.MutationObserver = dom.window.MutationObserver;
40
+
41
+ // Create a headless Lexical editor instance
42
+ const editor = createHeadlessEditor({
43
+ namespace: 'headless',
44
+ editable: false,
45
+ });
46
+
47
+ // Set the editor state from JSON
48
+ const state = editor.parseEditorState(jsonString);
49
+ if (state.isEmpty())
50
+ return null;
51
+
52
+ editor.setEditorState( state );
53
+
54
+ // Generate HTML from the Lexical nodes
55
+ const html = await editor.getEditorState().read(() => {
56
+ return $generateHtmlFromNodes(editor);
57
+ });
58
+
59
+ // Clean up global variables set for JSDOM to avoid memory leaks
60
+ delete global.window;
61
+ delete global.document;
62
+ delete global.DOMParser;
63
+ delete global.MutationObserver;
64
+
65
+ return html;
66
+ }
@@ -0,0 +1,20 @@
1
+
2
+ import { HeadingNode, QuoteNode } from "@lexical/rich-text";
3
+ import { TableCellNode, TableNode, TableRowNode } from "@lexical/table";
4
+ import { ListItemNode, ListNode } from "@lexical/list";
5
+ import { CodeHighlightNode, CodeNode } from "@lexical/code";
6
+ import { AutoLinkNode, LinkNode } from "@lexical/link";
7
+
8
+ export default [
9
+ HeadingNode,
10
+ ListNode,
11
+ ListItemNode,
12
+ QuoteNode,
13
+ CodeNode,
14
+ CodeHighlightNode,
15
+ TableNode,
16
+ TableCellNode,
17
+ TableRowNode,
18
+ AutoLinkNode,
19
+ LinkNode
20
+ ]
@@ -139,7 +139,7 @@ export default class SchemaValidators {
139
139
  return undefined;
140
140
 
141
141
  // Normalize for verifications
142
- const choicesValues = choices?.map(v => v.value)
142
+ const choicesValues = choices?.map(v => typeof v === 'object' ? v.value : v)
143
143
 
144
144
  const checkChoice = ( choice: any ) => {
145
145
 
@@ -350,6 +350,51 @@ export default class SchemaValidators {
350
350
  ...opts,
351
351
  })
352
352
 
353
+ public richText = (opts: TValidator<string> & {
354
+
355
+ } = {}) => new Validator<string>('richText', (val, options, path) => {
356
+
357
+ // Check that the root exists and has a valid type
358
+ if (!val || typeof val !== 'object' || typeof val.root !== 'object' || val.root.type !== 'root')
359
+ throw new InputError("Invalid rich text value (1).");
360
+
361
+ // Check if root has children array
362
+ if (!Array.isArray(val.root.children))
363
+ throw new InputError("Invalid rich text value (2).");
364
+
365
+ // Recursive function to validate each node
366
+ function validateNode(node) {
367
+ // Each node should be an object with a `type` property
368
+ if (typeof node !== 'object' || !node.type || typeof node.type !== 'string')
369
+ throw new InputError("Invalid rich text value (3).");
370
+
371
+ // Validate text nodes
372
+ if (node.type === 'text') {
373
+ if (typeof node.text !== 'string')
374
+ throw new InputError("Invalid rich text value (4).");
375
+ }
376
+
377
+ // Validate paragraph, heading, or other structural nodes that may contain children
378
+ if (['paragraph', 'heading', 'list', 'listitem'].includes(node.type))
379
+ if (!Array.isArray(node.children) || !node.children.every(validateNode)) {
380
+ throw new InputError("Invalid rich text value (5).");
381
+ }
382
+
383
+ return true;
384
+ }
385
+
386
+ // Validate each child node in root
387
+ for (const child of val.root.children) {
388
+ validateNode(child);
389
+ }
390
+
391
+ return val;
392
+
393
+ }, {
394
+ //defaut: new Date,
395
+ ...opts,
396
+ })
397
+
353
398
  /*----------------------------------
354
399
  - FICHIER
355
400
  ----------------------------------*/
@@ -225,8 +225,6 @@ export default abstract class AuthService<
225
225
 
226
226
  this.config.debug && console.warn(LogPrefix, `Check auth, role = ${role}. Current user =`, user?.name);
227
227
 
228
- console.log({ entity, role, motivation });
229
-
230
228
  if (user === undefined) {
231
229
 
232
230
  throw new Error(`request.user has not been decoded.`);
@@ -256,7 +256,7 @@ export default class SQL extends Service<Config, Hooks, Application, Services> {
256
256
  }
257
257
 
258
258
  public equalities = (data: TObjetDonnees, keys = Object.keys(data)) =>
259
- keys.map(k => '' + k + ' = ' + mysql.escape( data[k] ))
259
+ keys.map(k => '' + k + ' = ' + this.esc( data[k] ))
260
260
 
261
261
  /*----------------------------------
262
262
  - OPERATIONS: LOW LEVELf
@@ -1,13 +0,0 @@
1
- .contChamp.rte {
2
- .corpsChamp {
3
- height: auto !important;
4
- line-height: auto !important;
5
- }
6
-
7
- #toolbar {
8
- position: absolute;
9
- background: red;
10
- height: 30px;
11
- width: 15rem;
12
- }
13
- }
@@ -1,143 +0,0 @@
1
-
2
- // INSPIRATION:
3
- // https://github.com/sstur/react-rte
4
- // https://drupalgutenberg.org/demo
5
-
6
- /*----------------------------------
7
- - DEPENDANCES
8
- ----------------------------------*/
9
-
10
- // Npm
11
- import React from 'react';
12
- import {
13
-
14
- Editor,
15
- EditorState,
16
-
17
- SelectionState,
18
-
19
- convertToRaw,
20
- KeyBindingUtil,
21
- RawDraftContentState,
22
-
23
- ContentBlock,
24
- EditorBlock
25
- } from 'draft-js';
26
-
27
- // Libs
28
- import Champ from '../Base';
29
- import { getSelection, getSelectionRect } from './selection';
30
-
31
- /*----------------------------------
32
- - TYPES
33
- ----------------------------------*/
34
- type TValeur = EditorState
35
- const valeurDefaut = '' as string;
36
- type TValeurDefaut = EditorState;
37
- type TValeurOut = string;
38
-
39
- export type Props = {
40
- valeur: TValeur,
41
- }
42
-
43
- /*----------------------------------
44
- - COMPOSANT
45
- ----------------------------------*/
46
- import './index.less';
47
- export default Champ<Props, TValeurDefaut, TValeurOut>('rte', {
48
- valeurDefaut,
49
- saisieManuelle: true
50
- }, ({
51
- // Spread TOUTES les props dont on a besoin pour éviter les problèmes de référence avec props
52
- placeholder, attrsChamp
53
- }, { valeur, state, setState, commitCurrentValue }, rendre) => {
54
-
55
- /*----------------------------------
56
- - CONSTRUCTION CHAMP
57
- ----------------------------------*/
58
-
59
- const refEditeur = React.useRef<Editor>(null);
60
-
61
- // Init state
62
- if (!valeur)
63
- valeur = EditorState.createEmpty();
64
-
65
- /*const updateToolbar = (selection: SelectionState) => {
66
-
67
- if (selection.isCollapsed()) {
68
- return;
69
- }
70
- // eslint-disable-next-line no-undef
71
- const nativeSelection = getSelection(window);
72
- if (!nativeSelection.rangeCount) {
73
- return;
74
- }
75
- const selectionBoundary = getSelectionRect(nativeSelection);
76
-
77
- console.log('selectionBoundary', selectionBoundary);
78
-
79
- const toolbarNode = document.getElementById('toolbar');
80
- if (!toolbarNode) return;
81
- const toolbarBoundary = toolbarNode.getBoundingClientRect();
82
-
83
- // parent = conteneur éditeur draft
84
- const parent = document.getElementById('toolbar');
85
- if (!parent) return;
86
- const parentBoundary = parent.getBoundingClientRect();
87
-
88
- toolbarNode.style.top =
89
- `${(selectionBoundary.top - parentBoundary.top - toolbarBoundary.height - 5)}px`;
90
- toolbarNode.style.width = `${toolbarBoundary.width}px`;
91
-
92
- // The left side of the tooltip should be:
93
- // center of selection relative to parent - half width of toolbar
94
- const selectionCenter = (selectionBoundary.left + (selectionBoundary.width / 2)) - parentBoundary.left;
95
- let left = selectionCenter - (toolbarBoundary.width / 2);
96
- const screenLeft = parentBoundary.left + left;
97
- if (screenLeft < 0) {
98
- // If the toolbar would be off-screen
99
- // move it as far left as it can without going off-screen
100
- left = -parentBoundary.left;
101
- }
102
- toolbarNode.style.left = `${left}px`;
103
-
104
-
105
- }*/
106
-
107
- const onChange = (state: EditorState) => {
108
-
109
- /*const selection = state.getSelection();
110
- updateToolbar(selection);*/
111
-
112
- // Détection changement de contenu
113
- /*const currentContentState = valeur.getCurrentContent()
114
- const newContentState = state.getCurrentContent()
115
- if (currentContentState === newContentState)*/
116
-
117
- setState({ valeur: state });
118
-
119
- }
120
-
121
- /*----------------------------------
122
- - RENDU DU CHAMP
123
- ----------------------------------*/
124
- return rendre((
125
- <div className="champ typographie" onClick={() => refEditeur.current?.focus()}>
126
- <Editor
127
- ref={refEditeur}
128
- editorState={valeur}
129
-
130
- onChange={onChange}
131
- onBlur={() => commitCurrentValue()}
132
-
133
- placeholder={placeholder}
134
- textAlignment="left"
135
- textDirectionality="LTR"
136
-
137
- />
138
-
139
- {/* <div id="toolbar">coucou</div> */}
140
- </div>
141
- // Les propétés modifiées sont passées ici
142
- ), { });
143
- })
@@ -1,34 +0,0 @@
1
- // https://github.com/brijeshb42/medium-draft/blob/c5350bb76489fd4f2f90f1dc69db92224138d20a/src/util/index.js
2
-
3
- /*
4
- Returns the `boundingClientRect` of the passed selection.
5
- */
6
- export const getSelectionRect = (selected): DOMRect => {
7
- const _rect = selected.getRangeAt(0).getBoundingClientRect();
8
- // selected.getRangeAt(0).getBoundingClientRect()
9
- let rect = _rect && _rect.top ? _rect : selected.getRangeAt(0).getClientRects()[0];
10
- if (!rect) {
11
- if (selected.anchorNode && selected.anchorNode.getBoundingClientRect) {
12
- rect = selected.anchorNode.getBoundingClientRect();
13
- rect.isEmptyline = true;
14
- } else {
15
- return null;
16
- }
17
- }
18
- return rect;
19
- };
20
-
21
- /*
22
- Returns the native selection node.
23
- */
24
- export const getSelection = (root) => {
25
- let t = null;
26
- if (root.getSelection) {
27
- t = root.getSelection();
28
- } else if (root.document.getSelection) {
29
- t = root.document.getSelection();
30
- } else if (root.document.selection) {
31
- t = root.document.selection.createRange().text;
32
- }
33
- return t;
34
- };
@@ -1,11 +0,0 @@
1
- import mediumDraftExporter from '@client/components/Rte/exporter';
2
- import { convertFromRaw } from 'draft-js';
3
- export { convertFromRaw } from 'draft-js';
4
-
5
- export const convertir = (
6
- state: any,
7
- amp?: boolean
8
- ) => mediumDraftExporter(convertFromRaw( state ), amp);
9
-
10
- export const versHtml = (state: any): string => convertir(state);
11
- export const versAmp = (state: any): string => convertir(state, true);