@payloadcms/richtext-lexical 3.0.0-beta.1 → 3.0.0-beta.10

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 (66) hide show
  1. package/dist/field/features/converters/html/field/index.d.ts +8 -2
  2. package/dist/field/features/converters/html/field/index.d.ts.map +1 -1
  3. package/dist/field/features/converters/html/field/index.js +6 -3
  4. package/dist/field/features/converters/html/field/index.js.map +1 -1
  5. package/dist/field/features/horizontalrule/component/index.d.ts +10 -0
  6. package/dist/field/features/horizontalrule/component/index.d.ts.map +1 -0
  7. package/dist/field/features/horizontalrule/component/index.js +64 -0
  8. package/dist/field/features/horizontalrule/component/index.js.map +1 -0
  9. package/dist/field/features/horizontalrule/feature.client.d.ts +3 -0
  10. package/dist/field/features/horizontalrule/feature.client.d.ts.map +1 -0
  11. package/dist/field/features/horizontalrule/feature.client.js +53 -0
  12. package/dist/field/features/horizontalrule/feature.client.js.map +1 -0
  13. package/dist/field/features/horizontalrule/feature.server.d.ts +3 -0
  14. package/dist/field/features/horizontalrule/feature.server.d.ts.map +1 -0
  15. package/dist/field/features/horizontalrule/feature.server.js +36 -0
  16. package/dist/field/features/horizontalrule/feature.server.js.map +1 -0
  17. package/dist/field/features/horizontalrule/markdownTransformer.d.ts +3 -0
  18. package/dist/field/features/horizontalrule/markdownTransformer.d.ts.map +1 -0
  19. package/dist/field/features/horizontalrule/markdownTransformer.js +23 -0
  20. package/dist/field/features/horizontalrule/markdownTransformer.js.map +1 -0
  21. package/dist/field/features/horizontalrule/nodes/HorizontalRuleNode.d.ts +55 -0
  22. package/dist/field/features/horizontalrule/nodes/HorizontalRuleNode.d.ts.map +1 -0
  23. package/dist/field/features/horizontalrule/nodes/HorizontalRuleNode.js +89 -0
  24. package/dist/field/features/horizontalrule/nodes/HorizontalRuleNode.js.map +1 -0
  25. package/dist/field/features/horizontalrule/plugin/index.d.ts +6 -0
  26. package/dist/field/features/horizontalrule/plugin/index.d.ts.map +1 -0
  27. package/dist/field/features/horizontalrule/plugin/index.js +34 -0
  28. package/dist/field/features/horizontalrule/plugin/index.js.map +1 -0
  29. package/dist/field/features/horizontalrule/plugin/index.scss +20 -0
  30. package/dist/field/features/lists/htmlConverter.d.ts.map +1 -1
  31. package/dist/field/features/lists/htmlConverter.js +12 -4
  32. package/dist/field/features/lists/htmlConverter.js.map +1 -1
  33. package/dist/field/features/upload/validate.d.ts.map +1 -1
  34. package/dist/field/features/upload/validate.js +4 -6
  35. package/dist/field/features/upload/validate.js.map +1 -1
  36. package/dist/field/lexical/config/server/default.d.ts.map +1 -1
  37. package/dist/field/lexical/config/server/default.js +3 -1
  38. package/dist/field/lexical/config/server/default.js.map +1 -1
  39. package/dist/field/lexical/plugins/handles/AddBlockHandlePlugin/index.d.ts.map +1 -1
  40. package/dist/field/lexical/plugins/handles/AddBlockHandlePlugin/index.js +11 -6
  41. package/dist/field/lexical/plugins/handles/AddBlockHandlePlugin/index.js.map +1 -1
  42. package/dist/field/lexical/plugins/handles/DraggableBlockPlugin/index.d.ts.map +1 -1
  43. package/dist/field/lexical/plugins/handles/DraggableBlockPlugin/index.js +8 -3
  44. package/dist/field/lexical/plugins/handles/DraggableBlockPlugin/index.js.map +1 -1
  45. package/dist/field/lexical/plugins/handles/utils/doesLineHeightAffectElement.d.ts +9 -0
  46. package/dist/field/lexical/plugins/handles/utils/doesLineHeightAffectElement.d.ts.map +1 -0
  47. package/dist/field/lexical/plugins/handles/utils/doesLineHeightAffectElement.js +35 -0
  48. package/dist/field/lexical/plugins/handles/utils/doesLineHeightAffectElement.js.map +1 -0
  49. package/dist/field/lexical/plugins/handles/utils/setHandlePosition.d.ts +1 -1
  50. package/dist/field/lexical/plugins/handles/utils/setHandlePosition.d.ts.map +1 -1
  51. package/dist/field/lexical/plugins/handles/utils/setHandlePosition.js +17 -7
  52. package/dist/field/lexical/plugins/handles/utils/setHandlePosition.js.map +1 -1
  53. package/dist/field/lexical/theme/EditorTheme.scss +4 -0
  54. package/dist/field/lexical/ui/icons/HorizontalRule/index.d.ts +3 -0
  55. package/dist/field/lexical/ui/icons/HorizontalRule/index.d.ts.map +1 -0
  56. package/dist/field/lexical/ui/icons/HorizontalRule/index.js +19 -0
  57. package/dist/field/lexical/ui/icons/HorizontalRule/index.js.map +1 -0
  58. package/dist/generateComponentMap.d.ts.map +1 -1
  59. package/dist/generateComponentMap.js +4 -2
  60. package/dist/generateComponentMap.js.map +1 -1
  61. package/dist/scss/app.scss +2 -3
  62. package/dist/scss/vars.scss +0 -7
  63. package/package.json +14 -14
  64. package/components.d.ts +0 -6
  65. package/components.js +0 -7
  66. package/dist/scss/fonts.scss +0 -75
@@ -1,4 +1,5 @@
1
1
  import lexicalListImport from '@lexical/list';
2
+ import { v4 as uuidv4 } from 'uuid';
2
3
  const { ListItemNode, ListNode } = lexicalListImport;
3
4
  import { convertLexicalNodesToHTML } from '../converters/html/converter/index.js';
4
5
  export const ListHTMLConverter = {
@@ -12,7 +13,7 @@ export const ListHTMLConverter = {
12
13
  },
13
14
  payload
14
15
  });
15
- return `<${node?.tag} class="${node?.listType}">${childrenText}</${node?.tag}>`;
16
+ return `<${node?.tag} class="list-${node?.listType}">${childrenText}</${node?.tag}>`;
16
17
  },
17
18
  nodeTypes: [
18
19
  ListNode.getType()
@@ -20,6 +21,7 @@ export const ListHTMLConverter = {
20
21
  };
21
22
  export const ListItemHTMLConverter = {
22
23
  converter: async ({ converters, node, parent, payload })=>{
24
+ const hasSubLists = node.children.some((child)=>child.type === 'list');
23
25
  const childrenText = await convertLexicalNodesToHTML({
24
26
  converters,
25
27
  lexicalNodes: node.children,
@@ -30,15 +32,21 @@ export const ListItemHTMLConverter = {
30
32
  payload
31
33
  });
32
34
  if ('listType' in parent && parent?.listType === 'check') {
33
- return `<li aria-checked=${node.checked ? 'true' : 'false'} class="${'list-item-checkbox' + node.checked ? 'list-item-checkbox-checked' : 'list-item-checkbox-unchecked'}"
35
+ const uuid = uuidv4();
36
+ return `<li aria-checked=${node.checked ? 'true' : 'false'} class="${'list-item-checkbox' + (node.checked ? ' list-item-checkbox-checked' : ' list-item-checkbox-unchecked') + (hasSubLists ? ' nestedListItem' : '')}"
34
37
  role="checkbox"
35
38
  tabIndex=${-1}
36
39
  value=${node?.value}
37
40
  >
38
- ${childrenText}
41
+ ${hasSubLists ? childrenText : `
42
+ <input type="checkbox" id="${uuid}"${node.checked ? ' checked' : ''}>
43
+ <label for="${uuid}">${childrenText}</label><br>
44
+ `}
45
+
46
+
39
47
  </li>`;
40
48
  } else {
41
- return `<li value=${node?.value}>${childrenText}</li>`;
49
+ return `<li ${hasSubLists ? `class="nestedListItem" ` : ''}value=${node?.value}>${childrenText}</li>`;
42
50
  }
43
51
  },
44
52
  nodeTypes: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/field/features/lists/htmlConverter.ts"],"sourcesContent":["import type { SerializedListItemNode, SerializedListNode } from '@lexical/list'\n\nimport lexicalListImport from '@lexical/list'\nconst { ListItemNode, ListNode } = lexicalListImport\n\nimport type { HTMLConverter } from '../converters/html/converter/types.js'\n\nimport { convertLexicalNodesToHTML } from '../converters/html/converter/index.js'\n\nexport const ListHTMLConverter: HTMLConverter<SerializedListNode> = {\n converter: async ({ converters, node, parent, payload }) => {\n const childrenText = await convertLexicalNodesToHTML({\n converters,\n lexicalNodes: node.children,\n parent: {\n ...node,\n parent,\n },\n payload,\n })\n\n return `<${node?.tag} class=\"${node?.listType}\">${childrenText}</${node?.tag}>`\n },\n nodeTypes: [ListNode.getType()],\n}\n\nexport const ListItemHTMLConverter: HTMLConverter<SerializedListItemNode> = {\n converter: async ({ converters, node, parent, payload }) => {\n const childrenText = await convertLexicalNodesToHTML({\n converters,\n lexicalNodes: node.children,\n parent: {\n ...node,\n parent,\n },\n payload,\n })\n\n if ('listType' in parent && parent?.listType === 'check') {\n return `<li aria-checked=${node.checked ? 'true' : 'false'} class=\"${\n 'list-item-checkbox' + node.checked\n ? 'list-item-checkbox-checked'\n : 'list-item-checkbox-unchecked'\n }\"\n role=\"checkbox\"\n tabIndex=${-1}\n value=${node?.value}\n >\n ${childrenText}\n </li>`\n } else {\n return `<li value=${node?.value}>${childrenText}</li>`\n }\n },\n nodeTypes: [ListItemNode.getType()],\n}\n"],"names":["lexicalListImport","ListItemNode","ListNode","convertLexicalNodesToHTML","ListHTMLConverter","converter","converters","node","parent","payload","childrenText","lexicalNodes","children","tag","listType","nodeTypes","getType","ListItemHTMLConverter","checked","value"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAEA,OAAOA,uBAAuB,gBAAe;AAC7C,MAAM,EAAEC,YAAY,EAAEC,QAAQ,EAAE,GAAGF;AAInC,SAASG,yBAAyB,QAAQ,wCAAuC;AAEjF,OAAO,MAAMC,oBAAuD;IAClEC,WAAW,OAAO,EAAEC,UAAU,EAAEC,IAAI,EAAEC,MAAM,EAAEC,OAAO,EAAE;QACrD,MAAMC,eAAe,MAAMP,0BAA0B;YACnDG;YACAK,cAAcJ,KAAKK,QAAQ;YAC3BJ,QAAQ;gBACN,GAAGD,IAAI;gBACPC;YACF;YACAC;QACF;QAEA,OAAO,CAAC,CAAC,EAAEF,MAAMM,IAAI,QAAQ,EAAEN,MAAMO,SAAS,EAAE,EAAEJ,aAAa,EAAE,EAAEH,MAAMM,IAAI,CAAC,CAAC;IACjF;IACAE,WAAW;QAACb,SAASc,OAAO;KAAG;AACjC,EAAC;AAED,OAAO,MAAMC,wBAA+D;IAC1EZ,WAAW,OAAO,EAAEC,UAAU,EAAEC,IAAI,EAAEC,MAAM,EAAEC,OAAO,EAAE;QACrD,MAAMC,eAAe,MAAMP,0BAA0B;YACnDG;YACAK,cAAcJ,KAAKK,QAAQ;YAC3BJ,QAAQ;gBACN,GAAGD,IAAI;gBACPC;YACF;YACAC;QACF;QAEA,IAAI,cAAcD,UAAUA,QAAQM,aAAa,SAAS;YACxD,OAAO,CAAC,iBAAiB,EAAEP,KAAKW,OAAO,GAAG,SAAS,QAAQ,QAAQ,EACjE,uBAAuBX,KAAKW,OAAO,GAC/B,+BACA,+BACL;;mBAEY,EAAE,CAAC,EAAE;gBACR,EAAEX,MAAMY,MAAM;;UAEpB,EAAET,aAAa;eACV,CAAC;QACZ,OAAO;YACL,OAAO,CAAC,UAAU,EAAEH,MAAMY,MAAM,CAAC,EAAET,aAAa,KAAK,CAAC;QACxD;IACF;IACAK,WAAW;QAACd,aAAae,OAAO;KAAG;AACrC,EAAC"}
1
+ {"version":3,"sources":["../../../../src/field/features/lists/htmlConverter.ts"],"sourcesContent":["import type { SerializedListItemNode, SerializedListNode } from '@lexical/list'\n\nimport lexicalListImport from '@lexical/list'\nimport { v4 as uuidv4 } from 'uuid'\nconst { ListItemNode, ListNode } = lexicalListImport\n\nimport type { HTMLConverter } from '../converters/html/converter/types.js'\n\nimport { convertLexicalNodesToHTML } from '../converters/html/converter/index.js'\n\nexport const ListHTMLConverter: HTMLConverter<SerializedListNode> = {\n converter: async ({ converters, node, parent, payload }) => {\n const childrenText = await convertLexicalNodesToHTML({\n converters,\n lexicalNodes: node.children,\n parent: {\n ...node,\n parent,\n },\n payload,\n })\n\n return `<${node?.tag} class=\"list-${node?.listType}\">${childrenText}</${node?.tag}>`\n },\n nodeTypes: [ListNode.getType()],\n}\n\nexport const ListItemHTMLConverter: HTMLConverter<SerializedListItemNode> = {\n converter: async ({ converters, node, parent, payload }) => {\n const hasSubLists = node.children.some((child) => child.type === 'list')\n\n const childrenText = await convertLexicalNodesToHTML({\n converters,\n lexicalNodes: node.children,\n parent: {\n ...node,\n parent,\n },\n payload,\n })\n\n if ('listType' in parent && parent?.listType === 'check') {\n const uuid = uuidv4()\n\n return `<li aria-checked=${node.checked ? 'true' : 'false'} class=\"${\n 'list-item-checkbox' +\n (node.checked ? ' list-item-checkbox-checked' : ' list-item-checkbox-unchecked') +\n (hasSubLists ? ' nestedListItem' : '')\n }\"\n role=\"checkbox\"\n tabIndex=${-1}\n value=${node?.value}\n >\n ${\n hasSubLists\n ? childrenText\n : `\n <input type=\"checkbox\" id=\"${uuid}\"${node.checked ? ' checked' : ''}>\n <label for=\"${uuid}\">${childrenText}</label><br>\n `\n }\n\n\n </li>`\n } else {\n return `<li ${hasSubLists ? `class=\"nestedListItem\" ` : ''}value=${node?.value}>${childrenText}</li>`\n }\n },\n nodeTypes: [ListItemNode.getType()],\n}\n"],"names":["lexicalListImport","v4","uuidv4","ListItemNode","ListNode","convertLexicalNodesToHTML","ListHTMLConverter","converter","converters","node","parent","payload","childrenText","lexicalNodes","children","tag","listType","nodeTypes","getType","ListItemHTMLConverter","hasSubLists","some","child","type","uuid","checked","value"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAEA,OAAOA,uBAAuB,gBAAe;AAC7C,SAASC,MAAMC,MAAM,QAAQ,OAAM;AACnC,MAAM,EAAEC,YAAY,EAAEC,QAAQ,EAAE,GAAGJ;AAInC,SAASK,yBAAyB,QAAQ,wCAAuC;AAEjF,OAAO,MAAMC,oBAAuD;IAClEC,WAAW,OAAO,EAAEC,UAAU,EAAEC,IAAI,EAAEC,MAAM,EAAEC,OAAO,EAAE;QACrD,MAAMC,eAAe,MAAMP,0BAA0B;YACnDG;YACAK,cAAcJ,KAAKK,QAAQ;YAC3BJ,QAAQ;gBACN,GAAGD,IAAI;gBACPC;YACF;YACAC;QACF;QAEA,OAAO,CAAC,CAAC,EAAEF,MAAMM,IAAI,aAAa,EAAEN,MAAMO,SAAS,EAAE,EAAEJ,aAAa,EAAE,EAAEH,MAAMM,IAAI,CAAC,CAAC;IACtF;IACAE,WAAW;QAACb,SAASc,OAAO;KAAG;AACjC,EAAC;AAED,OAAO,MAAMC,wBAA+D;IAC1EZ,WAAW,OAAO,EAAEC,UAAU,EAAEC,IAAI,EAAEC,MAAM,EAAEC,OAAO,EAAE;QACrD,MAAMS,cAAcX,KAAKK,QAAQ,CAACO,IAAI,CAAC,CAACC,QAAUA,MAAMC,IAAI,KAAK;QAEjE,MAAMX,eAAe,MAAMP,0BAA0B;YACnDG;YACAK,cAAcJ,KAAKK,QAAQ;YAC3BJ,QAAQ;gBACN,GAAGD,IAAI;gBACPC;YACF;YACAC;QACF;QAEA,IAAI,cAAcD,UAAUA,QAAQM,aAAa,SAAS;YACxD,MAAMQ,OAAOtB;YAEb,OAAO,CAAC,iBAAiB,EAAEO,KAAKgB,OAAO,GAAG,SAAS,QAAQ,QAAQ,EACjE,uBACChB,CAAAA,KAAKgB,OAAO,GAAG,gCAAgC,+BAA8B,IAC7EL,CAAAA,cAAc,oBAAoB,EAAC,EACrC;;mBAEY,EAAE,CAAC,EAAE;gBACR,EAAEX,MAAMiB,MAAM;;MAExB,EACEN,cACIR,eACA,CAAC;mCACsB,EAAEY,KAAK,CAAC,EAAEf,KAAKgB,OAAO,GAAG,aAAa,GAAG;oBACxD,EAAED,KAAK,EAAE,EAAEZ,aAAa;MACtC,CAAC,CACA;;;eAGQ,CAAC;QACZ,OAAO;YACL,OAAO,CAAC,IAAI,EAAEQ,cAAc,CAAC,uBAAuB,CAAC,GAAG,GAAG,MAAM,EAAEX,MAAMiB,MAAM,CAAC,EAAEd,aAAa,KAAK,CAAC;QACvG;IACF;IACAK,WAAW;QAACd,aAAae,OAAO;KAAG;AACrC,EAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../../src/field/features/upload/validate.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAIjE,eAAO,MAAM,gBAAgB,QAAO,eAAe,oBAAoB,CA8BtE,CAAA"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../../src/field/features/upload/validate.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAIjE,eAAO,MAAM,gBAAgB,QAAO,eAAe,oBAAoB,CAuBtE,CAAA"}
@@ -1,12 +1,10 @@
1
- import { fieldAffectsData } from 'payload/types';
2
- import { getIDType, isValidID } from 'payload/utilities';
1
+ import { isValidID } from 'payload/utilities';
3
2
  import { CAN_USE_DOM } from '../../lexical/utils/canUseDOM.js';
4
3
  export const uploadValidation = ()=>{
5
- const uploadValidation = ({ node, validation: { options: { req: { payload: { config, db }, t } } } })=>{
4
+ const uploadValidation = ({ node, validation: { options: { req: { payload, t } } } })=>{
6
5
  if (!CAN_USE_DOM) {
7
- const idField = config.collections.find(({ slug })=>slug === node.relationTo).fields.find((field)=>fieldAffectsData(field) && field.name === 'id');
8
- const type = getIDType(idField, db?.defaultIDType);
9
- if (!isValidID(node.value?.id, type)) {
6
+ const idType = payload.collections[node.relationTo].customIDType || payload.db.defaultIDType;
7
+ if (!isValidID(node.value?.id, idType)) {
10
8
  return t('validation:validUploadID');
11
9
  }
12
10
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/field/features/upload/validate.ts"],"sourcesContent":["import { fieldAffectsData } from 'payload/types'\nimport { getIDType, isValidID } from 'payload/utilities'\n\nimport type { NodeValidation } from '../types.js'\nimport type { SerializedUploadNode } from './nodes/UploadNode.js'\n\nimport { CAN_USE_DOM } from '../../lexical/utils/canUseDOM.js'\n\nexport const uploadValidation = (): NodeValidation<SerializedUploadNode> => {\n const uploadValidation: NodeValidation<SerializedUploadNode> = ({\n node,\n validation: {\n options: {\n req: {\n payload: { config, db },\n t,\n },\n },\n },\n }) => {\n if (!CAN_USE_DOM) {\n const idField = config.collections\n .find(({ slug }) => slug === node.relationTo)\n .fields.find((field) => fieldAffectsData(field) && field.name === 'id')\n\n const type = getIDType(idField, db?.defaultIDType)\n\n if (!isValidID(node.value?.id, type)) {\n return t('validation:validUploadID')\n }\n }\n\n // TODO: validate upload collection fields\n\n return true\n }\n\n return uploadValidation\n}\n"],"names":["fieldAffectsData","getIDType","isValidID","CAN_USE_DOM","uploadValidation","node","validation","options","req","payload","config","db","t","idField","collections","find","slug","relationTo","fields","field","name","type","defaultIDType","value","id"],"rangeMappings":";;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,gBAAgB,QAAQ,gBAAe;AAChD,SAASC,SAAS,EAAEC,SAAS,QAAQ,oBAAmB;AAKxD,SAASC,WAAW,QAAQ,mCAAkC;AAE9D,OAAO,MAAMC,mBAAmB;IAC9B,MAAMA,mBAAyD,CAAC,EAC9DC,IAAI,EACJC,YAAY,EACVC,SAAS,EACPC,KAAK,EACHC,SAAS,EAAEC,MAAM,EAAEC,EAAE,EAAE,EACvBC,CAAC,EACF,EACF,EACF,EACF;QACC,IAAI,CAACT,aAAa;YAChB,MAAMU,UAAUH,OAAOI,WAAW,CAC/BC,IAAI,CAAC,CAAC,EAAEC,IAAI,EAAE,GAAKA,SAASX,KAAKY,UAAU,EAC3CC,MAAM,CAACH,IAAI,CAAC,CAACI,QAAUnB,iBAAiBmB,UAAUA,MAAMC,IAAI,KAAK;YAEpE,MAAMC,OAAOpB,UAAUY,SAASF,IAAIW;YAEpC,IAAI,CAACpB,UAAUG,KAAKkB,KAAK,EAAEC,IAAIH,OAAO;gBACpC,OAAOT,EAAE;YACX;QACF;QAEA,0CAA0C;QAE1C,OAAO;IACT;IAEA,OAAOR;AACT,EAAC"}
1
+ {"version":3,"sources":["../../../../src/field/features/upload/validate.ts"],"sourcesContent":["import { isValidID } from 'payload/utilities'\n\nimport type { NodeValidation } from '../types.js'\nimport type { SerializedUploadNode } from './nodes/UploadNode.js'\n\nimport { CAN_USE_DOM } from '../../lexical/utils/canUseDOM.js'\n\nexport const uploadValidation = (): NodeValidation<SerializedUploadNode> => {\n const uploadValidation: NodeValidation<SerializedUploadNode> = ({\n node,\n validation: {\n options: {\n req: { payload, t },\n },\n },\n }) => {\n if (!CAN_USE_DOM) {\n const idType = payload.collections[node.relationTo].customIDType || payload.db.defaultIDType\n\n if (!isValidID(node.value?.id, idType)) {\n return t('validation:validUploadID')\n }\n }\n\n // TODO: validate upload collection fields\n\n return true\n }\n\n return uploadValidation\n}\n"],"names":["isValidID","CAN_USE_DOM","uploadValidation","node","validation","options","req","payload","t","idType","collections","relationTo","customIDType","db","defaultIDType","value","id"],"rangeMappings":";;;;;;;;;;;;;;","mappings":"AAAA,SAASA,SAAS,QAAQ,oBAAmB;AAK7C,SAASC,WAAW,QAAQ,mCAAkC;AAE9D,OAAO,MAAMC,mBAAmB;IAC9B,MAAMA,mBAAyD,CAAC,EAC9DC,IAAI,EACJC,YAAY,EACVC,SAAS,EACPC,KAAK,EAAEC,OAAO,EAAEC,CAAC,EAAE,EACpB,EACF,EACF;QACC,IAAI,CAACP,aAAa;YAChB,MAAMQ,SAASF,QAAQG,WAAW,CAACP,KAAKQ,UAAU,CAAC,CAACC,YAAY,IAAIL,QAAQM,EAAE,CAACC,aAAa;YAE5F,IAAI,CAACd,UAAUG,KAAKY,KAAK,EAAEC,IAAIP,SAAS;gBACtC,OAAOD,EAAE;YACX;QACF;QAEA,0CAA0C;QAE1C,OAAO;IACT;IAEA,OAAON;AACT,EAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"default.d.ts","sourceRoot":"","sources":["../../../../../src/field/lexical/config/server/default.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,IAAI,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAEnF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AACvE,OAAO,KAAK,EAAE,2BAA2B,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAuBlF,eAAO,MAAM,0BAA0B,EAAE,mBAGxC,CAAA;AAED,eAAO,MAAM,qBAAqB,EAAE,qBAAqB,CAAC,OAAO,EAAE,OAAO,CAAC,EAmB1E,CAAA;AAED,eAAO,MAAM,mBAAmB,EAAE,kBAGjC,CAAA;AAED,eAAO,MAAM,kCAAkC,EAAE,2BACA,CAAA"}
1
+ {"version":3,"file":"default.d.ts","sourceRoot":"","sources":["../../../../../src/field/lexical/config/server/default.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,IAAI,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAEnF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AACvE,OAAO,KAAK,EAAE,2BAA2B,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAwBlF,eAAO,MAAM,0BAA0B,EAAE,mBAGxC,CAAA;AAED,eAAO,MAAM,qBAAqB,EAAE,qBAAqB,CAAC,OAAO,EAAE,OAAO,CAAC,EAoB1E,CAAA;AAED,eAAO,MAAM,mBAAmB,EAAE,kBAGjC,CAAA;AAED,eAAO,MAAM,kCAAkC,EAAE,2BACA,CAAA"}
@@ -8,6 +8,7 @@ import { SubscriptFeature } from '../../../features/format/subscript/feature.ser
8
8
  import { SuperscriptFeature } from '../../../features/format/superscript/feature.server.js';
9
9
  import { UnderlineFeature } from '../../../features/format/underline/feature.server.js';
10
10
  import { HeadingFeature } from '../../../features/heading/feature.server.js';
11
+ import { HorizontalRuleFeature } from '../../../features/horizontalrule/feature.server.js';
11
12
  import { IndentFeature } from '../../../features/indent/feature.server.js';
12
13
  import { LinkFeature } from '../../../features/link/feature.server.js';
13
14
  import { CheckListFeature } from '../../../features/lists/checklist/feature.server.js';
@@ -40,7 +41,8 @@ export const defaultEditorFeatures = [
40
41
  LinkFeature(),
41
42
  RelationshipFeature(),
42
43
  BlockQuoteFeature(),
43
- UploadFeature()
44
+ UploadFeature(),
45
+ HorizontalRuleFeature()
44
46
  ];
45
47
  export const defaultEditorConfig = {
46
48
  features: defaultEditorFeatures,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/field/lexical/config/server/default.ts"],"sourcesContent":["import type { EditorConfig as LexicalEditorConfig } from 'lexical/LexicalEditor.js'\n\nimport type { FeatureProviderServer } from '../../../features/types.js'\nimport type { SanitizedServerEditorConfig, ServerEditorConfig } from '../types.js'\n\nimport { AlignFeature } from '../../../features/align/feature.server.js'\nimport { BlockQuoteFeature } from '../../../features/blockquote/feature.server.js'\nimport { BoldFeature } from '../../../features/format/bold/feature.server.js'\nimport { InlineCodeFeature } from '../../../features/format/inlinecode/feature.server.js'\nimport { ItalicFeature } from '../../../features/format/italic/feature.server.js'\nimport { StrikethroughFeature } from '../../../features/format/strikethrough/feature.server.js'\nimport { SubscriptFeature } from '../../../features/format/subscript/feature.server.js'\nimport { SuperscriptFeature } from '../../../features/format/superscript/feature.server.js'\nimport { UnderlineFeature } from '../../../features/format/underline/feature.server.js'\nimport { HeadingFeature } from '../../../features/heading/feature.server.js'\nimport { IndentFeature } from '../../../features/indent/feature.server.js'\nimport { LinkFeature } from '../../../features/link/feature.server.js'\nimport { CheckListFeature } from '../../../features/lists/checklist/feature.server.js'\nimport { OrderedListFeature } from '../../../features/lists/orderedlist/feature.server.js'\nimport { UnorderedListFeature } from '../../../features/lists/unorderedlist/feature.server.js'\nimport { ParagraphFeature } from '../../../features/paragraph/feature.server.js'\nimport { RelationshipFeature } from '../../../features/relationship/feature.server.js'\nimport { UploadFeature } from '../../../features/upload/feature.server.js'\nimport { LexicalEditorTheme } from '../../theme/EditorTheme.js'\nimport { sanitizeServerEditorConfig } from './sanitize.js'\n\nexport const defaultEditorLexicalConfig: LexicalEditorConfig = {\n namespace: 'lexical',\n theme: LexicalEditorTheme,\n}\n\nexport const defaultEditorFeatures: FeatureProviderServer<unknown, unknown>[] = [\n BoldFeature(),\n ItalicFeature(),\n UnderlineFeature(),\n StrikethroughFeature(),\n SubscriptFeature(),\n SuperscriptFeature(),\n InlineCodeFeature(),\n ParagraphFeature(),\n HeadingFeature(),\n AlignFeature(),\n IndentFeature(),\n UnorderedListFeature(),\n OrderedListFeature(),\n CheckListFeature(),\n LinkFeature(),\n RelationshipFeature(),\n BlockQuoteFeature(),\n UploadFeature(),\n]\n\nexport const defaultEditorConfig: ServerEditorConfig = {\n features: defaultEditorFeatures,\n lexical: defaultEditorLexicalConfig,\n}\n\nexport const defaultSanitizedServerEditorConfig: SanitizedServerEditorConfig =\n sanitizeServerEditorConfig(defaultEditorConfig)\n"],"names":["AlignFeature","BlockQuoteFeature","BoldFeature","InlineCodeFeature","ItalicFeature","StrikethroughFeature","SubscriptFeature","SuperscriptFeature","UnderlineFeature","HeadingFeature","IndentFeature","LinkFeature","CheckListFeature","OrderedListFeature","UnorderedListFeature","ParagraphFeature","RelationshipFeature","UploadFeature","LexicalEditorTheme","sanitizeServerEditorConfig","defaultEditorLexicalConfig","namespace","theme","defaultEditorFeatures","defaultEditorConfig","features","lexical","defaultSanitizedServerEditorConfig"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAKA,SAASA,YAAY,QAAQ,4CAA2C;AACxE,SAASC,iBAAiB,QAAQ,iDAAgD;AAClF,SAASC,WAAW,QAAQ,kDAAiD;AAC7E,SAASC,iBAAiB,QAAQ,wDAAuD;AACzF,SAASC,aAAa,QAAQ,oDAAmD;AACjF,SAASC,oBAAoB,QAAQ,2DAA0D;AAC/F,SAASC,gBAAgB,QAAQ,uDAAsD;AACvF,SAASC,kBAAkB,QAAQ,yDAAwD;AAC3F,SAASC,gBAAgB,QAAQ,uDAAsD;AACvF,SAASC,cAAc,QAAQ,8CAA6C;AAC5E,SAASC,aAAa,QAAQ,6CAA4C;AAC1E,SAASC,WAAW,QAAQ,2CAA0C;AACtE,SAASC,gBAAgB,QAAQ,sDAAqD;AACtF,SAASC,kBAAkB,QAAQ,wDAAuD;AAC1F,SAASC,oBAAoB,QAAQ,0DAAyD;AAC9F,SAASC,gBAAgB,QAAQ,gDAA+C;AAChF,SAASC,mBAAmB,QAAQ,mDAAkD;AACtF,SAASC,aAAa,QAAQ,6CAA4C;AAC1E,SAASC,kBAAkB,QAAQ,6BAA4B;AAC/D,SAASC,0BAA0B,QAAQ,gBAAe;AAE1D,OAAO,MAAMC,6BAAkD;IAC7DC,WAAW;IACXC,OAAOJ;AACT,EAAC;AAED,OAAO,MAAMK,wBAAmE;IAC9ErB;IACAE;IACAI;IACAH;IACAC;IACAC;IACAJ;IACAY;IACAN;IACAT;IACAU;IACAI;IACAD;IACAD;IACAD;IACAK;IACAf;IACAgB;CACD,CAAA;AAED,OAAO,MAAMO,sBAA0C;IACrDC,UAAUF;IACVG,SAASN;AACX,EAAC;AAED,OAAO,MAAMO,qCACXR,2BAA2BK,qBAAoB"}
1
+ {"version":3,"sources":["../../../../../src/field/lexical/config/server/default.ts"],"sourcesContent":["import type { EditorConfig as LexicalEditorConfig } from 'lexical/LexicalEditor.js'\n\nimport type { FeatureProviderServer } from '../../../features/types.js'\nimport type { SanitizedServerEditorConfig, ServerEditorConfig } from '../types.js'\n\nimport { AlignFeature } from '../../../features/align/feature.server.js'\nimport { BlockQuoteFeature } from '../../../features/blockquote/feature.server.js'\nimport { BoldFeature } from '../../../features/format/bold/feature.server.js'\nimport { InlineCodeFeature } from '../../../features/format/inlinecode/feature.server.js'\nimport { ItalicFeature } from '../../../features/format/italic/feature.server.js'\nimport { StrikethroughFeature } from '../../../features/format/strikethrough/feature.server.js'\nimport { SubscriptFeature } from '../../../features/format/subscript/feature.server.js'\nimport { SuperscriptFeature } from '../../../features/format/superscript/feature.server.js'\nimport { UnderlineFeature } from '../../../features/format/underline/feature.server.js'\nimport { HeadingFeature } from '../../../features/heading/feature.server.js'\nimport { HorizontalRuleFeature } from '../../../features/horizontalrule/feature.server.js'\nimport { IndentFeature } from '../../../features/indent/feature.server.js'\nimport { LinkFeature } from '../../../features/link/feature.server.js'\nimport { CheckListFeature } from '../../../features/lists/checklist/feature.server.js'\nimport { OrderedListFeature } from '../../../features/lists/orderedlist/feature.server.js'\nimport { UnorderedListFeature } from '../../../features/lists/unorderedlist/feature.server.js'\nimport { ParagraphFeature } from '../../../features/paragraph/feature.server.js'\nimport { RelationshipFeature } from '../../../features/relationship/feature.server.js'\nimport { UploadFeature } from '../../../features/upload/feature.server.js'\nimport { LexicalEditorTheme } from '../../theme/EditorTheme.js'\nimport { sanitizeServerEditorConfig } from './sanitize.js'\n\nexport const defaultEditorLexicalConfig: LexicalEditorConfig = {\n namespace: 'lexical',\n theme: LexicalEditorTheme,\n}\n\nexport const defaultEditorFeatures: FeatureProviderServer<unknown, unknown>[] = [\n BoldFeature(),\n ItalicFeature(),\n UnderlineFeature(),\n StrikethroughFeature(),\n SubscriptFeature(),\n SuperscriptFeature(),\n InlineCodeFeature(),\n ParagraphFeature(),\n HeadingFeature(),\n AlignFeature(),\n IndentFeature(),\n UnorderedListFeature(),\n OrderedListFeature(),\n CheckListFeature(),\n LinkFeature(),\n RelationshipFeature(),\n BlockQuoteFeature(),\n UploadFeature(),\n HorizontalRuleFeature(),\n]\n\nexport const defaultEditorConfig: ServerEditorConfig = {\n features: defaultEditorFeatures,\n lexical: defaultEditorLexicalConfig,\n}\n\nexport const defaultSanitizedServerEditorConfig: SanitizedServerEditorConfig =\n sanitizeServerEditorConfig(defaultEditorConfig)\n"],"names":["AlignFeature","BlockQuoteFeature","BoldFeature","InlineCodeFeature","ItalicFeature","StrikethroughFeature","SubscriptFeature","SuperscriptFeature","UnderlineFeature","HeadingFeature","HorizontalRuleFeature","IndentFeature","LinkFeature","CheckListFeature","OrderedListFeature","UnorderedListFeature","ParagraphFeature","RelationshipFeature","UploadFeature","LexicalEditorTheme","sanitizeServerEditorConfig","defaultEditorLexicalConfig","namespace","theme","defaultEditorFeatures","defaultEditorConfig","features","lexical","defaultSanitizedServerEditorConfig"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAKA,SAASA,YAAY,QAAQ,4CAA2C;AACxE,SAASC,iBAAiB,QAAQ,iDAAgD;AAClF,SAASC,WAAW,QAAQ,kDAAiD;AAC7E,SAASC,iBAAiB,QAAQ,wDAAuD;AACzF,SAASC,aAAa,QAAQ,oDAAmD;AACjF,SAASC,oBAAoB,QAAQ,2DAA0D;AAC/F,SAASC,gBAAgB,QAAQ,uDAAsD;AACvF,SAASC,kBAAkB,QAAQ,yDAAwD;AAC3F,SAASC,gBAAgB,QAAQ,uDAAsD;AACvF,SAASC,cAAc,QAAQ,8CAA6C;AAC5E,SAASC,qBAAqB,QAAQ,qDAAoD;AAC1F,SAASC,aAAa,QAAQ,6CAA4C;AAC1E,SAASC,WAAW,QAAQ,2CAA0C;AACtE,SAASC,gBAAgB,QAAQ,sDAAqD;AACtF,SAASC,kBAAkB,QAAQ,wDAAuD;AAC1F,SAASC,oBAAoB,QAAQ,0DAAyD;AAC9F,SAASC,gBAAgB,QAAQ,gDAA+C;AAChF,SAASC,mBAAmB,QAAQ,mDAAkD;AACtF,SAASC,aAAa,QAAQ,6CAA4C;AAC1E,SAASC,kBAAkB,QAAQ,6BAA4B;AAC/D,SAASC,0BAA0B,QAAQ,gBAAe;AAE1D,OAAO,MAAMC,6BAAkD;IAC7DC,WAAW;IACXC,OAAOJ;AACT,EAAC;AAED,OAAO,MAAMK,wBAAmE;IAC9EtB;IACAE;IACAI;IACAH;IACAC;IACAC;IACAJ;IACAa;IACAP;IACAT;IACAW;IACAI;IACAD;IACAD;IACAD;IACAK;IACAhB;IACAiB;IACAR;CACD,CAAA;AAED,OAAO,MAAMe,sBAA0C;IACrDC,UAAUF;IACVG,SAASN;AACX,EAAC;AAED,OAAO,MAAMO,qCACXR,2BAA2BK,qBAAoB"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/field/lexical/plugins/handles/AddBlockHandlePlugin/index.tsx"],"names":[],"mappings":";AAoBA,OAAO,cAAc,CAAA;AAwSrB,wBAAgB,oBAAoB,CAAC,EACnC,UAA0B,GAC3B,EAAE;IACD,UAAU,CAAC,EAAE,WAAW,CAAA;CACzB,GAAG,GAAG,CAAC,OAAO,CAGd"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/field/lexical/plugins/handles/AddBlockHandlePlugin/index.tsx"],"names":[],"mappings":";AAoBA,OAAO,cAAc,CAAA;AA4SrB,wBAAgB,oBAAoB,CAAC,EACnC,UAA0B,GAC3B,EAAE;IACD,UAAU,CAAC,EAAE,WAAW,CAAA;CACzB,GAAG,GAAG,CAAC,OAAO,CAGd"}
@@ -122,7 +122,9 @@ function useAddBlockHandle(editor, anchorElem, isEditable) {
122
122
  const adjustedTop = top + window.scrollY;
123
123
  const adjustedBottom = bottom + window.scrollY;
124
124
  if (pageY < adjustedTop - verticalBuffer || pageY > adjustedBottom + verticalBuffer || pageX < left - horizontalBuffer || pageX > right + horizontalBuffer) {
125
- setHoveredElement(null);
125
+ if (hoveredElement !== null) {
126
+ setHoveredElement(null);
127
+ }
126
128
  return;
127
129
  }
128
130
  // This is used to allow the _emptyBlockElem to be found when the mouse is in the
@@ -138,10 +140,12 @@ function useAddBlockHandle(editor, anchorElem, isEditable) {
138
140
  if (!_emptyBlockElem) {
139
141
  return;
140
142
  }
141
- setHoveredElement({
142
- elem: _emptyBlockElem,
143
- node: blockNode
144
- });
143
+ if (hoveredElement?.node !== blockNode || hoveredElement?.elem !== _emptyBlockElem) {
144
+ setHoveredElement({
145
+ elem: _emptyBlockElem,
146
+ node: blockNode
147
+ });
148
+ }
145
149
  }
146
150
  // Since the draggableBlockElem is outside the actual editor, we need to listen to the document
147
151
  // to be able to detect when the mouse is outside the editor and respect a buffer around
@@ -153,7 +157,8 @@ function useAddBlockHandle(editor, anchorElem, isEditable) {
153
157
  }, [
154
158
  scrollerElem,
155
159
  anchorElem,
156
- editor
160
+ editor,
161
+ hoveredElement
157
162
  ]);
158
163
  useEffect(()=>{
159
164
  if (menuRef.current && hoveredElement?.node) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../src/field/lexical/plugins/handles/AddBlockHandlePlugin/index.tsx"],"sourcesContent":["'use client'\nimport type { LexicalEditor, LexicalNode, ParagraphNode } from 'lexical'\n\nimport lexicalComposerContextImport from '@lexical/react/LexicalComposerContext.js'\nconst { useLexicalComposerContext } = lexicalComposerContextImport\nimport lexicalImport from 'lexical'\nconst { $createParagraphNode, $getNodeByKey } = lexicalImport\n\nimport * as React from 'react'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { isHTMLElement } from '../../../utils/guard.js'\nimport { Point } from '../../../utils/point.js'\nimport { Rect } from '../../../utils/rect.js'\nimport { ENABLE_SLASH_MENU_COMMAND } from '../../SlashMenu/LexicalTypeaheadMenuPlugin/index.js'\nimport { getCollapsedMargins } from '../utils/getCollapsedMargins.js'\nimport { getTopLevelNodeKeys } from '../utils/getTopLevelNodeKeys.js'\nimport { isOnHandleElement } from '../utils/isOnHandleElement.js'\nimport { setHandlePosition } from '../utils/setHandlePosition.js'\nimport './index.scss'\n\nconst SPACE = -24\nconst ADD_BLOCK_MENU_CLASSNAME = 'add-block-menu'\n\nconst Downward = 1\nconst Upward = -1\nconst Indeterminate = 0\n\nlet prevIndex = Infinity\n\nfunction getCurrentIndex(keysLength: number): number {\n if (keysLength === 0) {\n return Infinity\n }\n if (prevIndex >= 0 && prevIndex < keysLength) {\n return prevIndex\n }\n\n return Math.floor(keysLength / 2)\n}\n\nfunction getBlockElement(\n anchorElem: HTMLElement,\n editor: LexicalEditor,\n event: MouseEvent,\n useEdgeAsDefault = false,\n horizontalOffset = 0,\n): {\n blockElem: HTMLElement | null\n blockNode: LexicalNode | null\n} {\n const anchorElementRect = anchorElem.getBoundingClientRect()\n const topLevelNodeKeys = getTopLevelNodeKeys(editor)\n\n let blockElem: HTMLElement | null = null\n let blockNode: LexicalNode | null = null\n\n // Return null if matching block element is the first or last node\n editor.getEditorState().read(() => {\n if (useEdgeAsDefault) {\n const [firstNode, lastNode] = [\n editor.getElementByKey(topLevelNodeKeys[0]),\n editor.getElementByKey(topLevelNodeKeys[topLevelNodeKeys.length - 1]),\n ]\n\n const [firstNodeRect, lastNodeRect] = [\n firstNode?.getBoundingClientRect(),\n lastNode?.getBoundingClientRect(),\n ]\n\n if (firstNodeRect && lastNodeRect) {\n if (event.y < firstNodeRect.top) {\n blockElem = firstNode\n } else if (event.y > lastNodeRect.bottom) {\n blockElem = lastNode\n }\n\n if (blockElem) {\n return {\n blockElem: null,\n }\n }\n }\n }\n\n // Find matching block element\n let index = getCurrentIndex(topLevelNodeKeys.length)\n let direction = Indeterminate\n\n while (index >= 0 && index < topLevelNodeKeys.length) {\n const key = topLevelNodeKeys[index]\n const elem = editor.getElementByKey(key)\n if (elem === null) {\n break\n }\n const point = new Point(event.x + horizontalOffset, event.y)\n const domRect = Rect.fromDOM(elem)\n const { marginBottom, marginTop } = getCollapsedMargins(elem)\n\n const rect = domRect.generateNewRect({\n bottom: domRect.bottom + marginBottom,\n left: anchorElementRect.left,\n right: anchorElementRect.right,\n top: domRect.top - marginTop,\n })\n\n const {\n reason: { isOnBottomSide, isOnTopSide },\n result,\n } = rect.contains(point)\n\n if (result) {\n blockElem = elem\n blockNode = $getNodeByKey(key)\n prevIndex = index\n break\n }\n\n if (direction === Indeterminate) {\n if (isOnTopSide) {\n direction = Upward\n } else if (isOnBottomSide) {\n direction = Downward\n } else {\n // stop search block element\n direction = Infinity\n }\n }\n\n index += direction\n }\n })\n\n return {\n blockElem,\n blockNode,\n }\n}\n\nfunction useAddBlockHandle(\n editor: LexicalEditor,\n anchorElem: HTMLElement,\n isEditable: boolean,\n): JSX.Element {\n const scrollerElem = anchorElem.parentElement\n\n const menuRef = useRef<HTMLButtonElement>(null)\n const [hoveredElement, setHoveredElement] = useState<{\n elem: HTMLElement\n node: LexicalNode\n } | null>(null)\n\n useEffect(() => {\n function onDocumentMouseMove(event: MouseEvent) {\n const target = event.target\n if (!isHTMLElement(target)) {\n return\n }\n\n let distanceFromScrollerElem = 0\n // Calculate distance between scrollerElem and target if target is not in scrollerElem\n if (scrollerElem && !scrollerElem.contains(target)) {\n const { bottom, left, right, top } = scrollerElem.getBoundingClientRect()\n const { pageX, pageY } = event\n const horizontalBuffer = 50\n const verticalBuffer = 25\n const adjustedTop = top + window.scrollY\n const adjustedBottom = bottom + window.scrollY\n\n if (\n pageY < adjustedTop - verticalBuffer ||\n pageY > adjustedBottom + verticalBuffer ||\n pageX < left - horizontalBuffer ||\n pageX > right + horizontalBuffer\n ) {\n setHoveredElement(null)\n return\n }\n\n // This is used to allow the _emptyBlockElem to be found when the mouse is in the\n // buffer zone around the scrollerElem.\n if (pageX < left || pageX > right) {\n distanceFromScrollerElem = pageX < left ? pageX - left : pageX - right\n }\n }\n\n if (isOnHandleElement(target, ADD_BLOCK_MENU_CLASSNAME)) {\n return\n }\n const { blockElem: _emptyBlockElem, blockNode } = getBlockElement(\n anchorElem,\n editor,\n event,\n false,\n -distanceFromScrollerElem,\n )\n if (!_emptyBlockElem) {\n return\n }\n setHoveredElement({\n elem: _emptyBlockElem,\n node: blockNode,\n })\n }\n\n // Since the draggableBlockElem is outside the actual editor, we need to listen to the document\n // to be able to detect when the mouse is outside the editor and respect a buffer around\n // the scrollerElem to avoid the draggableBlockElem disappearing too early.\n document?.addEventListener('mousemove', onDocumentMouseMove)\n\n return () => {\n document?.removeEventListener('mousemove', onDocumentMouseMove)\n }\n }, [scrollerElem, anchorElem, editor])\n\n useEffect(() => {\n if (menuRef.current && hoveredElement?.node) {\n editor.getEditorState().read(() => {\n // Check if blockNode is an empty text node\n let isEmptyParagraph = true\n if (\n hoveredElement.node.getType() !== 'paragraph' ||\n hoveredElement.node.getTextContent() !== ''\n ) {\n isEmptyParagraph = false\n }\n\n setHandlePosition(\n hoveredElement?.elem,\n menuRef.current,\n anchorElem,\n isEmptyParagraph ? SPACE : SPACE - 20,\n )\n })\n }\n }, [anchorElem, hoveredElement, editor])\n\n const handleAddClick = useCallback(\n (event) => {\n let hoveredElementToUse = hoveredElement\n if (!hoveredElementToUse?.node) {\n return\n }\n\n // 1. Update hoveredElement.node to a new paragraph node if the hoveredElement.node is not a paragraph node\n editor.update(() => {\n // Check if blockNode is an empty text node\n let isEmptyParagraph = true\n if (\n hoveredElementToUse.node.getType() !== 'paragraph' ||\n hoveredElementToUse.node.getTextContent() !== ''\n ) {\n isEmptyParagraph = false\n }\n\n if (!isEmptyParagraph) {\n const newParagraph = $createParagraphNode()\n hoveredElementToUse.node.insertAfter(newParagraph)\n\n setTimeout(() => {\n hoveredElementToUse = {\n elem: editor.getElementByKey(newParagraph.getKey()),\n node: newParagraph,\n }\n setHoveredElement(hoveredElementToUse)\n }, 0)\n }\n })\n\n // 2. Focus on the new paragraph node\n setTimeout(() => {\n editor.update(() => {\n editor.focus()\n\n if (\n hoveredElementToUse.node &&\n 'select' in hoveredElementToUse.node &&\n typeof hoveredElementToUse.node.select === 'function'\n ) {\n hoveredElementToUse.node.select()\n }\n })\n }, 1)\n\n // Make sure this is called AFTER the focusing has been processed by the browser\n // Otherwise, this won't work\n setTimeout(() => {\n editor.dispatchCommand(ENABLE_SLASH_MENU_COMMAND, {\n node: hoveredElementToUse.node as ParagraphNode,\n })\n }, 2)\n\n event.stopPropagation()\n event.preventDefault()\n },\n [editor, hoveredElement],\n )\n\n return createPortal(\n <React.Fragment>\n <button\n className=\"icon add-block-menu\"\n onClick={(event) => {\n handleAddClick(event)\n }}\n ref={menuRef}\n type=\"button\"\n >\n <div className={isEditable ? 'icon' : ''} />\n </button>\n </React.Fragment>,\n anchorElem,\n )\n}\n\nexport function AddBlockHandlePlugin({\n anchorElem = document.body,\n}: {\n anchorElem?: HTMLElement\n}): JSX.Element {\n const [editor] = useLexicalComposerContext()\n return useAddBlockHandle(editor, anchorElem, editor._editable)\n}\n"],"names":["lexicalComposerContextImport","useLexicalComposerContext","lexicalImport","$createParagraphNode","$getNodeByKey","React","useCallback","useEffect","useRef","useState","createPortal","isHTMLElement","Point","Rect","ENABLE_SLASH_MENU_COMMAND","getCollapsedMargins","getTopLevelNodeKeys","isOnHandleElement","setHandlePosition","SPACE","ADD_BLOCK_MENU_CLASSNAME","Downward","Upward","Indeterminate","prevIndex","Infinity","getCurrentIndex","keysLength","Math","floor","getBlockElement","anchorElem","editor","event","useEdgeAsDefault","horizontalOffset","anchorElementRect","getBoundingClientRect","topLevelNodeKeys","blockElem","blockNode","getEditorState","read","firstNode","lastNode","getElementByKey","length","firstNodeRect","lastNodeRect","y","top","bottom","index","direction","key","elem","point","x","domRect","fromDOM","marginBottom","marginTop","rect","generateNewRect","left","right","reason","isOnBottomSide","isOnTopSide","result","contains","useAddBlockHandle","isEditable","scrollerElem","parentElement","menuRef","hoveredElement","setHoveredElement","onDocumentMouseMove","target","distanceFromScrollerElem","pageX","pageY","horizontalBuffer","verticalBuffer","adjustedTop","window","scrollY","adjustedBottom","_emptyBlockElem","node","document","addEventListener","removeEventListener","current","isEmptyParagraph","getType","getTextContent","handleAddClick","hoveredElementToUse","update","newParagraph","insertAfter","setTimeout","getKey","focus","select","dispatchCommand","stopPropagation","preventDefault","Fragment","button","className","onClick","ref","type","div","AddBlockHandlePlugin","body","_editable"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../src/field/lexical/plugins/handles/AddBlockHandlePlugin/index.tsx"],"sourcesContent":["'use client'\nimport type { LexicalEditor, LexicalNode, ParagraphNode } from 'lexical'\n\nimport lexicalComposerContextImport from '@lexical/react/LexicalComposerContext.js'\nconst { useLexicalComposerContext } = lexicalComposerContextImport\nimport lexicalImport from 'lexical'\nconst { $createParagraphNode, $getNodeByKey } = lexicalImport\n\nimport * as React from 'react'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { isHTMLElement } from '../../../utils/guard.js'\nimport { Point } from '../../../utils/point.js'\nimport { Rect } from '../../../utils/rect.js'\nimport { ENABLE_SLASH_MENU_COMMAND } from '../../SlashMenu/LexicalTypeaheadMenuPlugin/index.js'\nimport { getCollapsedMargins } from '../utils/getCollapsedMargins.js'\nimport { getTopLevelNodeKeys } from '../utils/getTopLevelNodeKeys.js'\nimport { isOnHandleElement } from '../utils/isOnHandleElement.js'\nimport { setHandlePosition } from '../utils/setHandlePosition.js'\nimport './index.scss'\n\nconst SPACE = -24\nconst ADD_BLOCK_MENU_CLASSNAME = 'add-block-menu'\n\nconst Downward = 1\nconst Upward = -1\nconst Indeterminate = 0\n\nlet prevIndex = Infinity\n\nfunction getCurrentIndex(keysLength: number): number {\n if (keysLength === 0) {\n return Infinity\n }\n if (prevIndex >= 0 && prevIndex < keysLength) {\n return prevIndex\n }\n\n return Math.floor(keysLength / 2)\n}\n\nfunction getBlockElement(\n anchorElem: HTMLElement,\n editor: LexicalEditor,\n event: MouseEvent,\n useEdgeAsDefault = false,\n horizontalOffset = 0,\n): {\n blockElem: HTMLElement | null\n blockNode: LexicalNode | null\n} {\n const anchorElementRect = anchorElem.getBoundingClientRect()\n const topLevelNodeKeys = getTopLevelNodeKeys(editor)\n\n let blockElem: HTMLElement | null = null\n let blockNode: LexicalNode | null = null\n\n // Return null if matching block element is the first or last node\n editor.getEditorState().read(() => {\n if (useEdgeAsDefault) {\n const [firstNode, lastNode] = [\n editor.getElementByKey(topLevelNodeKeys[0]),\n editor.getElementByKey(topLevelNodeKeys[topLevelNodeKeys.length - 1]),\n ]\n\n const [firstNodeRect, lastNodeRect] = [\n firstNode?.getBoundingClientRect(),\n lastNode?.getBoundingClientRect(),\n ]\n\n if (firstNodeRect && lastNodeRect) {\n if (event.y < firstNodeRect.top) {\n blockElem = firstNode\n } else if (event.y > lastNodeRect.bottom) {\n blockElem = lastNode\n }\n\n if (blockElem) {\n return {\n blockElem: null,\n }\n }\n }\n }\n\n // Find matching block element\n let index = getCurrentIndex(topLevelNodeKeys.length)\n let direction = Indeterminate\n\n while (index >= 0 && index < topLevelNodeKeys.length) {\n const key = topLevelNodeKeys[index]\n const elem = editor.getElementByKey(key)\n if (elem === null) {\n break\n }\n const point = new Point(event.x + horizontalOffset, event.y)\n const domRect = Rect.fromDOM(elem)\n const { marginBottom, marginTop } = getCollapsedMargins(elem)\n\n const rect = domRect.generateNewRect({\n bottom: domRect.bottom + marginBottom,\n left: anchorElementRect.left,\n right: anchorElementRect.right,\n top: domRect.top - marginTop,\n })\n\n const {\n reason: { isOnBottomSide, isOnTopSide },\n result,\n } = rect.contains(point)\n\n if (result) {\n blockElem = elem\n blockNode = $getNodeByKey(key)\n prevIndex = index\n break\n }\n\n if (direction === Indeterminate) {\n if (isOnTopSide) {\n direction = Upward\n } else if (isOnBottomSide) {\n direction = Downward\n } else {\n // stop search block element\n direction = Infinity\n }\n }\n\n index += direction\n }\n })\n\n return {\n blockElem,\n blockNode,\n }\n}\n\nfunction useAddBlockHandle(\n editor: LexicalEditor,\n anchorElem: HTMLElement,\n isEditable: boolean,\n): JSX.Element {\n const scrollerElem = anchorElem.parentElement\n\n const menuRef = useRef<HTMLButtonElement>(null)\n const [hoveredElement, setHoveredElement] = useState<{\n elem: HTMLElement\n node: LexicalNode\n } | null>(null)\n\n useEffect(() => {\n function onDocumentMouseMove(event: MouseEvent) {\n const target = event.target\n if (!isHTMLElement(target)) {\n return\n }\n\n let distanceFromScrollerElem = 0\n // Calculate distance between scrollerElem and target if target is not in scrollerElem\n if (scrollerElem && !scrollerElem.contains(target)) {\n const { bottom, left, right, top } = scrollerElem.getBoundingClientRect()\n const { pageX, pageY } = event\n const horizontalBuffer = 50\n const verticalBuffer = 25\n const adjustedTop = top + window.scrollY\n const adjustedBottom = bottom + window.scrollY\n\n if (\n pageY < adjustedTop - verticalBuffer ||\n pageY > adjustedBottom + verticalBuffer ||\n pageX < left - horizontalBuffer ||\n pageX > right + horizontalBuffer\n ) {\n if (hoveredElement !== null) {\n setHoveredElement(null)\n }\n return\n }\n\n // This is used to allow the _emptyBlockElem to be found when the mouse is in the\n // buffer zone around the scrollerElem.\n if (pageX < left || pageX > right) {\n distanceFromScrollerElem = pageX < left ? pageX - left : pageX - right\n }\n }\n\n if (isOnHandleElement(target, ADD_BLOCK_MENU_CLASSNAME)) {\n return\n }\n const { blockElem: _emptyBlockElem, blockNode } = getBlockElement(\n anchorElem,\n editor,\n event,\n false,\n -distanceFromScrollerElem,\n )\n if (!_emptyBlockElem) {\n return\n }\n if (hoveredElement?.node !== blockNode || hoveredElement?.elem !== _emptyBlockElem) {\n setHoveredElement({\n elem: _emptyBlockElem,\n node: blockNode,\n })\n }\n }\n\n // Since the draggableBlockElem is outside the actual editor, we need to listen to the document\n // to be able to detect when the mouse is outside the editor and respect a buffer around\n // the scrollerElem to avoid the draggableBlockElem disappearing too early.\n document?.addEventListener('mousemove', onDocumentMouseMove)\n\n return () => {\n document?.removeEventListener('mousemove', onDocumentMouseMove)\n }\n }, [scrollerElem, anchorElem, editor, hoveredElement])\n\n useEffect(() => {\n if (menuRef.current && hoveredElement?.node) {\n editor.getEditorState().read(() => {\n // Check if blockNode is an empty text node\n let isEmptyParagraph = true\n if (\n hoveredElement.node.getType() !== 'paragraph' ||\n hoveredElement.node.getTextContent() !== ''\n ) {\n isEmptyParagraph = false\n }\n\n setHandlePosition(\n hoveredElement?.elem,\n menuRef.current,\n anchorElem,\n isEmptyParagraph ? SPACE : SPACE - 20,\n )\n })\n }\n }, [anchorElem, hoveredElement, editor])\n\n const handleAddClick = useCallback(\n (event) => {\n let hoveredElementToUse = hoveredElement\n if (!hoveredElementToUse?.node) {\n return\n }\n\n // 1. Update hoveredElement.node to a new paragraph node if the hoveredElement.node is not a paragraph node\n editor.update(() => {\n // Check if blockNode is an empty text node\n let isEmptyParagraph = true\n if (\n hoveredElementToUse.node.getType() !== 'paragraph' ||\n hoveredElementToUse.node.getTextContent() !== ''\n ) {\n isEmptyParagraph = false\n }\n\n if (!isEmptyParagraph) {\n const newParagraph = $createParagraphNode()\n hoveredElementToUse.node.insertAfter(newParagraph)\n\n setTimeout(() => {\n hoveredElementToUse = {\n elem: editor.getElementByKey(newParagraph.getKey()),\n node: newParagraph,\n }\n setHoveredElement(hoveredElementToUse)\n }, 0)\n }\n })\n\n // 2. Focus on the new paragraph node\n setTimeout(() => {\n editor.update(() => {\n editor.focus()\n\n if (\n hoveredElementToUse.node &&\n 'select' in hoveredElementToUse.node &&\n typeof hoveredElementToUse.node.select === 'function'\n ) {\n hoveredElementToUse.node.select()\n }\n })\n }, 1)\n\n // Make sure this is called AFTER the focusing has been processed by the browser\n // Otherwise, this won't work\n setTimeout(() => {\n editor.dispatchCommand(ENABLE_SLASH_MENU_COMMAND, {\n node: hoveredElementToUse.node as ParagraphNode,\n })\n }, 2)\n\n event.stopPropagation()\n event.preventDefault()\n },\n [editor, hoveredElement],\n )\n\n return createPortal(\n <React.Fragment>\n <button\n className=\"icon add-block-menu\"\n onClick={(event) => {\n handleAddClick(event)\n }}\n ref={menuRef}\n type=\"button\"\n >\n <div className={isEditable ? 'icon' : ''} />\n </button>\n </React.Fragment>,\n anchorElem,\n )\n}\n\nexport function AddBlockHandlePlugin({\n anchorElem = document.body,\n}: {\n anchorElem?: HTMLElement\n}): JSX.Element {\n const [editor] = useLexicalComposerContext()\n return useAddBlockHandle(editor, anchorElem, editor._editable)\n}\n"],"names":["lexicalComposerContextImport","useLexicalComposerContext","lexicalImport","$createParagraphNode","$getNodeByKey","React","useCallback","useEffect","useRef","useState","createPortal","isHTMLElement","Point","Rect","ENABLE_SLASH_MENU_COMMAND","getCollapsedMargins","getTopLevelNodeKeys","isOnHandleElement","setHandlePosition","SPACE","ADD_BLOCK_MENU_CLASSNAME","Downward","Upward","Indeterminate","prevIndex","Infinity","getCurrentIndex","keysLength","Math","floor","getBlockElement","anchorElem","editor","event","useEdgeAsDefault","horizontalOffset","anchorElementRect","getBoundingClientRect","topLevelNodeKeys","blockElem","blockNode","getEditorState","read","firstNode","lastNode","getElementByKey","length","firstNodeRect","lastNodeRect","y","top","bottom","index","direction","key","elem","point","x","domRect","fromDOM","marginBottom","marginTop","rect","generateNewRect","left","right","reason","isOnBottomSide","isOnTopSide","result","contains","useAddBlockHandle","isEditable","scrollerElem","parentElement","menuRef","hoveredElement","setHoveredElement","onDocumentMouseMove","target","distanceFromScrollerElem","pageX","pageY","horizontalBuffer","verticalBuffer","adjustedTop","window","scrollY","adjustedBottom","_emptyBlockElem","node","document","addEventListener","removeEventListener","current","isEmptyParagraph","getType","getTextContent","handleAddClick","hoveredElementToUse","update","newParagraph","insertAfter","setTimeout","getKey","focus","select","dispatchCommand","stopPropagation","preventDefault","Fragment","button","className","onClick","ref","type","div","AddBlockHandlePlugin","body","_editable"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/field/lexical/plugins/handles/DraggableBlockPlugin/index.tsx"],"names":[],"mappings":";AAqBA,OAAO,cAAc,CAAA;AAgXrB,wBAAgB,oBAAoB,CAAC,EACnC,UAA0B,GAC3B,EAAE;IACD,UAAU,CAAC,EAAE,WAAW,CAAA;CACzB,GAAG,GAAG,CAAC,OAAO,CAGd"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/field/lexical/plugins/handles/DraggableBlockPlugin/index.tsx"],"names":[],"mappings":";AAqBA,OAAO,cAAc,CAAA;AAoXrB,wBAAgB,oBAAoB,CAAC,EACnC,UAA0B,GAC3B,EAAE;IACD,UAAU,CAAC,EAAE,WAAW,CAAA;CACzB,GAAG,GAAG,CAAC,OAAO,CAGd"}
@@ -106,7 +106,9 @@ function useDraggableBlockMenu(editor, anchorElem, isEditable) {
106
106
  if (!_draggableBlockElem && !isFoundNodeEmptyParagraph) {
107
107
  return;
108
108
  }
109
- setDraggableBlockElem(_draggableBlockElem);
109
+ if (draggableBlockElem !== _draggableBlockElem) {
110
+ setDraggableBlockElem(_draggableBlockElem);
111
+ }
110
112
  }
111
113
  // Since the draggableBlockElem is outside the actual editor, we need to listen to the document
112
114
  // to be able to detect when the mouse is outside the editor and respect a buffer around the
@@ -119,7 +121,8 @@ function useDraggableBlockMenu(editor, anchorElem, isEditable) {
119
121
  scrollerElem,
120
122
  anchorElem,
121
123
  editor,
122
- calculateDistanceFromScrollerElem
124
+ calculateDistanceFromScrollerElem,
125
+ draggableBlockElem
123
126
  ]);
124
127
  useEffect(()=>{
125
128
  if (menuRef.current) {
@@ -230,7 +233,9 @@ function useDraggableBlockMenu(editor, anchorElem, isEditable) {
230
233
  targetNode.insertAfter(draggedNode)
231
234
  } else {
232
235
  targetNode.insertBefore(draggedNode)
233
- }*/ setDraggableBlockElem(null);
236
+ }*/ if (draggableBlockElem !== null) {
237
+ setDraggableBlockElem(null);
238
+ }
234
239
  });
235
240
  return true;
236
241
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../src/field/lexical/plugins/handles/DraggableBlockPlugin/index.tsx"],"sourcesContent":["'use client'\nimport type { LexicalEditor } from 'lexical'\nimport type { DragEvent as ReactDragEvent } from 'react'\n\nimport lexicalComposerContextImport from '@lexical/react/LexicalComposerContext.js'\nconst { useLexicalComposerContext } = lexicalComposerContextImport\n\nimport { eventFiles } from '@lexical/rich-text'\nimport lexicalImport from 'lexical'\nconst { $getNearestNodeFromDOMNode, $getNodeByKey } = lexicalImport\nimport * as React from 'react'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { isHTMLElement } from '../../../utils/guard.js'\nimport { Point } from '../../../utils/point.js'\nimport { getTopLevelNodeKeys } from '../utils/getTopLevelNodeKeys.js'\nimport { isOnHandleElement } from '../utils/isOnHandleElement.js'\nimport { setHandlePosition } from '../utils/setHandlePosition.js'\nimport { getBoundingClientRectWithoutTransform } from './getBoundingRectWithoutTransform.js'\nimport { getNodeCloseToPoint } from './getNodeCloseToPoint.js'\nimport './index.scss'\nimport { setTargetLine } from './setTargetLine.js'\n\nconst SPACE = -24\nconst DRAGGABLE_BLOCK_MENU_CLASSNAME = 'draggable-block-menu'\nconst DRAG_DATA_FORMAT = 'application/x-lexical-drag-block'\n\nlet prevIndex = Infinity\n\nfunction getCurrentIndex(keysLength: number): number {\n if (keysLength === 0) {\n return Infinity\n }\n if (prevIndex >= 0 && prevIndex < keysLength) {\n return prevIndex\n }\n\n return Math.floor(keysLength / 2)\n}\n\nfunction setDragImage(dataTransfer: DataTransfer, draggableBlockElem: HTMLElement) {\n const { transform } = draggableBlockElem.style\n\n // Remove dragImage borders\n dataTransfer.setDragImage(draggableBlockElem, 0, 0)\n\n setTimeout(() => {\n draggableBlockElem.style.transform = transform\n })\n}\n\nfunction hideTargetLine(\n targetLineElem: HTMLElement | null,\n lastTargetBlockElem: HTMLElement | null,\n) {\n if (targetLineElem) {\n targetLineElem.style.opacity = '0'\n }\n if (lastTargetBlockElem) {\n lastTargetBlockElem.style.opacity = '1'\n lastTargetBlockElem.style.transform = 'translate(0, 0)'\n //lastTargetBlockElem.style.border = 'none'\n }\n}\n\nfunction useDraggableBlockMenu(\n editor: LexicalEditor,\n anchorElem: HTMLElement,\n isEditable: boolean,\n): JSX.Element {\n const scrollerElem = anchorElem.parentElement\n\n const menuRef = useRef<HTMLDivElement>(null)\n const targetLineRef = useRef<HTMLDivElement>(null)\n const debugHighlightRef = useRef<HTMLDivElement>(null)\n const isDraggingBlockRef = useRef<boolean>(false)\n const [draggableBlockElem, setDraggableBlockElem] = useState<HTMLElement | null>(null)\n const [lastTargetBlockElem, setLastTargetBlockElem] = useState<HTMLElement | null>(null)\n\n const calculateDistanceFromScrollerElem = useCallback(\n (\n pageX: number,\n pageY: number,\n target: HTMLElement,\n horizontalBuffer: number = 50,\n verticalBuffer: number = 25,\n ): number => {\n let distanceFromScrollerElem = 0\n // Calculate distance between scrollerElem and target if target is not in scrollerElem\n if (scrollerElem && !scrollerElem.contains(target)) {\n const { bottom, left, right, top } = scrollerElem.getBoundingClientRect()\n\n const adjustedTop = top + window.scrollY\n const adjustedBottom = bottom + window.scrollY\n\n if (\n pageY < adjustedTop - verticalBuffer ||\n pageY > adjustedBottom + verticalBuffer ||\n pageX < left - horizontalBuffer ||\n pageX > right + horizontalBuffer\n ) {\n setDraggableBlockElem(null)\n return distanceFromScrollerElem\n }\n\n // This is used to allow the _draggableBlockElem to be found when the mouse is in the\n // buffer zone around the scrollerElem.\n if (pageX < left || pageX > right) {\n distanceFromScrollerElem = pageX < left ? pageX - left : pageX - right\n }\n }\n return distanceFromScrollerElem\n },\n [scrollerElem],\n )\n\n useEffect(() => {\n /**\n * Handles positioning of the drag handle\n */\n function onDocumentMouseMove(event: MouseEvent) {\n const target = event.target\n if (!isHTMLElement(target)) {\n return\n }\n\n const distanceFromScrollerElem = calculateDistanceFromScrollerElem(\n event.pageX,\n event.pageY,\n target,\n )\n\n if (isOnHandleElement(target, DRAGGABLE_BLOCK_MENU_CLASSNAME)) {\n return\n }\n\n const topLevelNodeKeys = getTopLevelNodeKeys(editor)\n const {\n blockElem: _draggableBlockElem,\n foundAtIndex,\n isFoundNodeEmptyParagraph,\n } = getNodeCloseToPoint({\n anchorElem,\n cache_treshold: 0,\n editor,\n horizontalOffset: -distanceFromScrollerElem,\n point: new Point(event.x, event.y),\n startIndex: getCurrentIndex(topLevelNodeKeys.length),\n useEdgeAsDefault: false,\n })\n //if (DEBUG && _draggableBlockElem) {\n //targetBlockElem.style.border = '3px solid red'\n // highlightElemOriginalPosition(debugHighlightRef, _draggableBlockElem, anchorElem)\n //}\n prevIndex = foundAtIndex\n\n if (!_draggableBlockElem && !isFoundNodeEmptyParagraph) {\n return\n }\n\n setDraggableBlockElem(_draggableBlockElem)\n }\n\n // Since the draggableBlockElem is outside the actual editor, we need to listen to the document\n // to be able to detect when the mouse is outside the editor and respect a buffer around the\n // the scrollerElem to avoid the draggableBlockElem disappearing too early.\n document?.addEventListener('mousemove', onDocumentMouseMove)\n\n return () => {\n document?.removeEventListener('mousemove', onDocumentMouseMove)\n }\n }, [scrollerElem, anchorElem, editor, calculateDistanceFromScrollerElem])\n\n useEffect(() => {\n if (menuRef.current) {\n setHandlePosition(draggableBlockElem, menuRef.current, anchorElem, SPACE)\n }\n }, [anchorElem, draggableBlockElem])\n\n useEffect(() => {\n function onDragover(event: DragEvent): boolean {\n if (!isDraggingBlockRef.current) {\n return false\n }\n const [isFileTransfer] = eventFiles(event)\n if (isFileTransfer) {\n return false\n }\n\n const { pageY, target } = event\n if (!isHTMLElement(target)) {\n return false\n }\n\n const distanceFromScrollerElem = calculateDistanceFromScrollerElem(\n event.pageX,\n event.pageY,\n target,\n 100,\n 50,\n )\n\n const topLevelNodeKeys = getTopLevelNodeKeys(editor)\n\n const {\n blockElem: targetBlockElem,\n foundAtIndex,\n isFoundNodeEmptyParagraph,\n } = getNodeCloseToPoint({\n anchorElem,\n editor,\n fuzzy: true,\n horizontalOffset: -distanceFromScrollerElem,\n point: new Point(event.x, event.y),\n startIndex: getCurrentIndex(topLevelNodeKeys.length),\n useEdgeAsDefault: true,\n verbose: true,\n })\n prevIndex = foundAtIndex\n\n const targetLineElem = targetLineRef.current\n // targetBlockElem === null shouldn't happen\n if (targetBlockElem === null || targetLineElem === null) {\n return false\n }\n\n if (draggableBlockElem !== targetBlockElem) {\n setTargetLine(\n SPACE,\n targetLineElem,\n targetBlockElem,\n lastTargetBlockElem,\n pageY,\n anchorElem,\n event,\n debugHighlightRef,\n isFoundNodeEmptyParagraph,\n )\n\n // Prevent default event to be able to trigger onDrop events\n // Calling preventDefault() adds the green plus icon to the cursor,\n // indicating that the drop is allowed.\n event.preventDefault()\n } else {\n hideTargetLine(targetLineElem, lastTargetBlockElem)\n }\n\n setLastTargetBlockElem(targetBlockElem)\n\n return true\n }\n\n function onDrop(event: DragEvent): boolean {\n if (!isDraggingBlockRef.current) {\n return false\n }\n const [isFileTransfer] = eventFiles(event)\n if (isFileTransfer) {\n return false\n }\n const { dataTransfer, pageY, target } = event\n const dragData = dataTransfer?.getData(DRAG_DATA_FORMAT) || ''\n\n editor.update(() => {\n const draggedNode = $getNodeByKey(dragData)\n if (!draggedNode) {\n return false\n }\n if (!isHTMLElement(target)) {\n return false\n }\n const distanceFromScrollerElem = calculateDistanceFromScrollerElem(\n event.pageX,\n event.pageY,\n target,\n 100,\n 50,\n )\n\n const { blockElem: targetBlockElem, isFoundNodeEmptyParagraph } = getNodeCloseToPoint({\n anchorElem,\n editor,\n fuzzy: true,\n horizontalOffset: -distanceFromScrollerElem,\n point: new Point(event.x, event.y),\n useEdgeAsDefault: true,\n })\n\n if (!targetBlockElem) {\n return false\n }\n const targetNode = $getNearestNodeFromDOMNode(targetBlockElem)\n if (!targetNode) {\n return false\n }\n if (targetNode === draggedNode) {\n return true\n }\n\n const { height: targetBlockElemHeight, top: targetBlockElemTop } =\n getBoundingClientRectWithoutTransform(targetBlockElem)\n\n const mouseY = pageY\n const isBelow = mouseY >= targetBlockElemTop + targetBlockElemHeight / 2 + window.scrollY\n\n if (!isFoundNodeEmptyParagraph) {\n if (isBelow) {\n // below targetBlockElem\n targetNode.insertAfter(draggedNode)\n } else {\n // above targetBlockElem\n targetNode.insertBefore(draggedNode)\n }\n } else {\n //\n targetNode.insertBefore(draggedNode)\n targetNode.remove()\n }\n\n /*\n if (pageY >= targetBlockElemTop + targetBlockElemHeight / 2) {\n targetNode.insertAfter(draggedNode)\n } else {\n targetNode.insertBefore(draggedNode)\n }*/\n setDraggableBlockElem(null)\n })\n\n return true\n }\n\n // register onDragover event listeners:\n document.addEventListener('dragover', onDragover)\n // register onDrop event listeners:\n document.addEventListener('drop', onDrop)\n\n return () => {\n document.removeEventListener('dragover', onDragover)\n document.removeEventListener('drop', onDrop)\n }\n }, [\n anchorElem,\n editor,\n lastTargetBlockElem,\n calculateDistanceFromScrollerElem,\n draggableBlockElem,\n ])\n\n function onDragStart(event: ReactDragEvent<HTMLDivElement>): void {\n const dataTransfer = event.dataTransfer\n if (!dataTransfer || !draggableBlockElem) {\n return\n }\n setDragImage(dataTransfer, draggableBlockElem)\n let nodeKey = ''\n editor.update(() => {\n const node = $getNearestNodeFromDOMNode(draggableBlockElem)\n if (node) {\n nodeKey = node.getKey()\n }\n })\n isDraggingBlockRef.current = true\n dataTransfer.setData(DRAG_DATA_FORMAT, nodeKey)\n }\n\n function onDragEnd(): void {\n isDraggingBlockRef.current = false\n hideTargetLine(targetLineRef.current, lastTargetBlockElem)\n }\n\n return createPortal(\n <React.Fragment>\n <div\n className=\"icon draggable-block-menu\"\n draggable\n onDragEnd={onDragEnd}\n onDragStart={onDragStart}\n ref={menuRef}\n >\n <div className={isEditable ? 'icon' : ''} />\n </div>\n <div className=\"draggable-block-target-line\" ref={targetLineRef} />\n <div className=\"debug-highlight\" ref={debugHighlightRef} />\n </React.Fragment>,\n anchorElem,\n )\n}\n\nexport function DraggableBlockPlugin({\n anchorElem = document.body,\n}: {\n anchorElem?: HTMLElement\n}): JSX.Element {\n const [editor] = useLexicalComposerContext()\n return useDraggableBlockMenu(editor, anchorElem, editor._editable)\n}\n"],"names":["lexicalComposerContextImport","useLexicalComposerContext","eventFiles","lexicalImport","$getNearestNodeFromDOMNode","$getNodeByKey","React","useCallback","useEffect","useRef","useState","createPortal","isHTMLElement","Point","getTopLevelNodeKeys","isOnHandleElement","setHandlePosition","getBoundingClientRectWithoutTransform","getNodeCloseToPoint","setTargetLine","SPACE","DRAGGABLE_BLOCK_MENU_CLASSNAME","DRAG_DATA_FORMAT","prevIndex","Infinity","getCurrentIndex","keysLength","Math","floor","setDragImage","dataTransfer","draggableBlockElem","transform","style","setTimeout","hideTargetLine","targetLineElem","lastTargetBlockElem","opacity","useDraggableBlockMenu","editor","anchorElem","isEditable","scrollerElem","parentElement","menuRef","targetLineRef","debugHighlightRef","isDraggingBlockRef","setDraggableBlockElem","setLastTargetBlockElem","calculateDistanceFromScrollerElem","pageX","pageY","target","horizontalBuffer","verticalBuffer","distanceFromScrollerElem","contains","bottom","left","right","top","getBoundingClientRect","adjustedTop","window","scrollY","adjustedBottom","onDocumentMouseMove","event","topLevelNodeKeys","blockElem","_draggableBlockElem","foundAtIndex","isFoundNodeEmptyParagraph","cache_treshold","horizontalOffset","point","x","y","startIndex","length","useEdgeAsDefault","document","addEventListener","removeEventListener","current","onDragover","isFileTransfer","targetBlockElem","fuzzy","verbose","preventDefault","onDrop","dragData","getData","update","draggedNode","targetNode","height","targetBlockElemHeight","targetBlockElemTop","mouseY","isBelow","insertAfter","insertBefore","remove","onDragStart","nodeKey","node","getKey","setData","onDragEnd","Fragment","div","className","draggable","ref","DraggableBlockPlugin","body","_editable"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../src/field/lexical/plugins/handles/DraggableBlockPlugin/index.tsx"],"sourcesContent":["'use client'\nimport type { LexicalEditor } from 'lexical'\nimport type { DragEvent as ReactDragEvent } from 'react'\n\nimport lexicalComposerContextImport from '@lexical/react/LexicalComposerContext.js'\nconst { useLexicalComposerContext } = lexicalComposerContextImport\n\nimport { eventFiles } from '@lexical/rich-text'\nimport lexicalImport from 'lexical'\nconst { $getNearestNodeFromDOMNode, $getNodeByKey } = lexicalImport\nimport * as React from 'react'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { isHTMLElement } from '../../../utils/guard.js'\nimport { Point } from '../../../utils/point.js'\nimport { getTopLevelNodeKeys } from '../utils/getTopLevelNodeKeys.js'\nimport { isOnHandleElement } from '../utils/isOnHandleElement.js'\nimport { setHandlePosition } from '../utils/setHandlePosition.js'\nimport { getBoundingClientRectWithoutTransform } from './getBoundingRectWithoutTransform.js'\nimport { getNodeCloseToPoint } from './getNodeCloseToPoint.js'\nimport './index.scss'\nimport { setTargetLine } from './setTargetLine.js'\n\nconst SPACE = -24\nconst DRAGGABLE_BLOCK_MENU_CLASSNAME = 'draggable-block-menu'\nconst DRAG_DATA_FORMAT = 'application/x-lexical-drag-block'\n\nlet prevIndex = Infinity\n\nfunction getCurrentIndex(keysLength: number): number {\n if (keysLength === 0) {\n return Infinity\n }\n if (prevIndex >= 0 && prevIndex < keysLength) {\n return prevIndex\n }\n\n return Math.floor(keysLength / 2)\n}\n\nfunction setDragImage(dataTransfer: DataTransfer, draggableBlockElem: HTMLElement) {\n const { transform } = draggableBlockElem.style\n\n // Remove dragImage borders\n dataTransfer.setDragImage(draggableBlockElem, 0, 0)\n\n setTimeout(() => {\n draggableBlockElem.style.transform = transform\n })\n}\n\nfunction hideTargetLine(\n targetLineElem: HTMLElement | null,\n lastTargetBlockElem: HTMLElement | null,\n) {\n if (targetLineElem) {\n targetLineElem.style.opacity = '0'\n }\n if (lastTargetBlockElem) {\n lastTargetBlockElem.style.opacity = '1'\n lastTargetBlockElem.style.transform = 'translate(0, 0)'\n //lastTargetBlockElem.style.border = 'none'\n }\n}\n\nfunction useDraggableBlockMenu(\n editor: LexicalEditor,\n anchorElem: HTMLElement,\n isEditable: boolean,\n): JSX.Element {\n const scrollerElem = anchorElem.parentElement\n\n const menuRef = useRef<HTMLDivElement>(null)\n const targetLineRef = useRef<HTMLDivElement>(null)\n const debugHighlightRef = useRef<HTMLDivElement>(null)\n const isDraggingBlockRef = useRef<boolean>(false)\n const [draggableBlockElem, setDraggableBlockElem] = useState<HTMLElement | null>(null)\n const [lastTargetBlockElem, setLastTargetBlockElem] = useState<HTMLElement | null>(null)\n\n const calculateDistanceFromScrollerElem = useCallback(\n (\n pageX: number,\n pageY: number,\n target: HTMLElement,\n horizontalBuffer: number = 50,\n verticalBuffer: number = 25,\n ): number => {\n let distanceFromScrollerElem = 0\n // Calculate distance between scrollerElem and target if target is not in scrollerElem\n if (scrollerElem && !scrollerElem.contains(target)) {\n const { bottom, left, right, top } = scrollerElem.getBoundingClientRect()\n\n const adjustedTop = top + window.scrollY\n const adjustedBottom = bottom + window.scrollY\n\n if (\n pageY < adjustedTop - verticalBuffer ||\n pageY > adjustedBottom + verticalBuffer ||\n pageX < left - horizontalBuffer ||\n pageX > right + horizontalBuffer\n ) {\n setDraggableBlockElem(null)\n return distanceFromScrollerElem\n }\n\n // This is used to allow the _draggableBlockElem to be found when the mouse is in the\n // buffer zone around the scrollerElem.\n if (pageX < left || pageX > right) {\n distanceFromScrollerElem = pageX < left ? pageX - left : pageX - right\n }\n }\n return distanceFromScrollerElem\n },\n [scrollerElem],\n )\n\n useEffect(() => {\n /**\n * Handles positioning of the drag handle\n */\n function onDocumentMouseMove(event: MouseEvent) {\n const target = event.target\n if (!isHTMLElement(target)) {\n return\n }\n\n const distanceFromScrollerElem = calculateDistanceFromScrollerElem(\n event.pageX,\n event.pageY,\n target,\n )\n\n if (isOnHandleElement(target, DRAGGABLE_BLOCK_MENU_CLASSNAME)) {\n return\n }\n\n const topLevelNodeKeys = getTopLevelNodeKeys(editor)\n const {\n blockElem: _draggableBlockElem,\n foundAtIndex,\n isFoundNodeEmptyParagraph,\n } = getNodeCloseToPoint({\n anchorElem,\n cache_treshold: 0,\n editor,\n horizontalOffset: -distanceFromScrollerElem,\n point: new Point(event.x, event.y),\n startIndex: getCurrentIndex(topLevelNodeKeys.length),\n useEdgeAsDefault: false,\n })\n //if (DEBUG && _draggableBlockElem) {\n //targetBlockElem.style.border = '3px solid red'\n // highlightElemOriginalPosition(debugHighlightRef, _draggableBlockElem, anchorElem)\n //}\n prevIndex = foundAtIndex\n\n if (!_draggableBlockElem && !isFoundNodeEmptyParagraph) {\n return\n }\n\n if (draggableBlockElem !== _draggableBlockElem) {\n setDraggableBlockElem(_draggableBlockElem)\n }\n }\n\n // Since the draggableBlockElem is outside the actual editor, we need to listen to the document\n // to be able to detect when the mouse is outside the editor and respect a buffer around the\n // the scrollerElem to avoid the draggableBlockElem disappearing too early.\n document?.addEventListener('mousemove', onDocumentMouseMove)\n\n return () => {\n document?.removeEventListener('mousemove', onDocumentMouseMove)\n }\n }, [scrollerElem, anchorElem, editor, calculateDistanceFromScrollerElem, draggableBlockElem])\n\n useEffect(() => {\n if (menuRef.current) {\n setHandlePosition(draggableBlockElem, menuRef.current, anchorElem, SPACE)\n }\n }, [anchorElem, draggableBlockElem])\n\n useEffect(() => {\n function onDragover(event: DragEvent): boolean {\n if (!isDraggingBlockRef.current) {\n return false\n }\n const [isFileTransfer] = eventFiles(event)\n if (isFileTransfer) {\n return false\n }\n\n const { pageY, target } = event\n if (!isHTMLElement(target)) {\n return false\n }\n\n const distanceFromScrollerElem = calculateDistanceFromScrollerElem(\n event.pageX,\n event.pageY,\n target,\n 100,\n 50,\n )\n\n const topLevelNodeKeys = getTopLevelNodeKeys(editor)\n\n const {\n blockElem: targetBlockElem,\n foundAtIndex,\n isFoundNodeEmptyParagraph,\n } = getNodeCloseToPoint({\n anchorElem,\n editor,\n fuzzy: true,\n horizontalOffset: -distanceFromScrollerElem,\n point: new Point(event.x, event.y),\n startIndex: getCurrentIndex(topLevelNodeKeys.length),\n useEdgeAsDefault: true,\n verbose: true,\n })\n prevIndex = foundAtIndex\n\n const targetLineElem = targetLineRef.current\n // targetBlockElem === null shouldn't happen\n if (targetBlockElem === null || targetLineElem === null) {\n return false\n }\n\n if (draggableBlockElem !== targetBlockElem) {\n setTargetLine(\n SPACE,\n targetLineElem,\n targetBlockElem,\n lastTargetBlockElem,\n pageY,\n anchorElem,\n event,\n debugHighlightRef,\n isFoundNodeEmptyParagraph,\n )\n\n // Prevent default event to be able to trigger onDrop events\n // Calling preventDefault() adds the green plus icon to the cursor,\n // indicating that the drop is allowed.\n event.preventDefault()\n } else {\n hideTargetLine(targetLineElem, lastTargetBlockElem)\n }\n\n setLastTargetBlockElem(targetBlockElem)\n\n return true\n }\n\n function onDrop(event: DragEvent): boolean {\n if (!isDraggingBlockRef.current) {\n return false\n }\n const [isFileTransfer] = eventFiles(event)\n if (isFileTransfer) {\n return false\n }\n const { dataTransfer, pageY, target } = event\n const dragData = dataTransfer?.getData(DRAG_DATA_FORMAT) || ''\n\n editor.update(() => {\n const draggedNode = $getNodeByKey(dragData)\n if (!draggedNode) {\n return false\n }\n if (!isHTMLElement(target)) {\n return false\n }\n const distanceFromScrollerElem = calculateDistanceFromScrollerElem(\n event.pageX,\n event.pageY,\n target,\n 100,\n 50,\n )\n\n const { blockElem: targetBlockElem, isFoundNodeEmptyParagraph } = getNodeCloseToPoint({\n anchorElem,\n editor,\n fuzzy: true,\n horizontalOffset: -distanceFromScrollerElem,\n point: new Point(event.x, event.y),\n useEdgeAsDefault: true,\n })\n\n if (!targetBlockElem) {\n return false\n }\n const targetNode = $getNearestNodeFromDOMNode(targetBlockElem)\n if (!targetNode) {\n return false\n }\n if (targetNode === draggedNode) {\n return true\n }\n\n const { height: targetBlockElemHeight, top: targetBlockElemTop } =\n getBoundingClientRectWithoutTransform(targetBlockElem)\n\n const mouseY = pageY\n const isBelow = mouseY >= targetBlockElemTop + targetBlockElemHeight / 2 + window.scrollY\n\n if (!isFoundNodeEmptyParagraph) {\n if (isBelow) {\n // below targetBlockElem\n targetNode.insertAfter(draggedNode)\n } else {\n // above targetBlockElem\n targetNode.insertBefore(draggedNode)\n }\n } else {\n //\n targetNode.insertBefore(draggedNode)\n targetNode.remove()\n }\n\n /*\n if (pageY >= targetBlockElemTop + targetBlockElemHeight / 2) {\n targetNode.insertAfter(draggedNode)\n } else {\n targetNode.insertBefore(draggedNode)\n }*/\n if (draggableBlockElem !== null) {\n setDraggableBlockElem(null)\n }\n })\n\n return true\n }\n\n // register onDragover event listeners:\n document.addEventListener('dragover', onDragover)\n // register onDrop event listeners:\n document.addEventListener('drop', onDrop)\n\n return () => {\n document.removeEventListener('dragover', onDragover)\n document.removeEventListener('drop', onDrop)\n }\n }, [\n anchorElem,\n editor,\n lastTargetBlockElem,\n calculateDistanceFromScrollerElem,\n draggableBlockElem,\n ])\n\n function onDragStart(event: ReactDragEvent<HTMLDivElement>): void {\n const dataTransfer = event.dataTransfer\n if (!dataTransfer || !draggableBlockElem) {\n return\n }\n setDragImage(dataTransfer, draggableBlockElem)\n let nodeKey = ''\n editor.update(() => {\n const node = $getNearestNodeFromDOMNode(draggableBlockElem)\n if (node) {\n nodeKey = node.getKey()\n }\n })\n isDraggingBlockRef.current = true\n dataTransfer.setData(DRAG_DATA_FORMAT, nodeKey)\n }\n\n function onDragEnd(): void {\n isDraggingBlockRef.current = false\n hideTargetLine(targetLineRef.current, lastTargetBlockElem)\n }\n\n return createPortal(\n <React.Fragment>\n <div\n className=\"icon draggable-block-menu\"\n draggable\n onDragEnd={onDragEnd}\n onDragStart={onDragStart}\n ref={menuRef}\n >\n <div className={isEditable ? 'icon' : ''} />\n </div>\n <div className=\"draggable-block-target-line\" ref={targetLineRef} />\n <div className=\"debug-highlight\" ref={debugHighlightRef} />\n </React.Fragment>,\n anchorElem,\n )\n}\n\nexport function DraggableBlockPlugin({\n anchorElem = document.body,\n}: {\n anchorElem?: HTMLElement\n}): JSX.Element {\n const [editor] = useLexicalComposerContext()\n return useDraggableBlockMenu(editor, anchorElem, editor._editable)\n}\n"],"names":["lexicalComposerContextImport","useLexicalComposerContext","eventFiles","lexicalImport","$getNearestNodeFromDOMNode","$getNodeByKey","React","useCallback","useEffect","useRef","useState","createPortal","isHTMLElement","Point","getTopLevelNodeKeys","isOnHandleElement","setHandlePosition","getBoundingClientRectWithoutTransform","getNodeCloseToPoint","setTargetLine","SPACE","DRAGGABLE_BLOCK_MENU_CLASSNAME","DRAG_DATA_FORMAT","prevIndex","Infinity","getCurrentIndex","keysLength","Math","floor","setDragImage","dataTransfer","draggableBlockElem","transform","style","setTimeout","hideTargetLine","targetLineElem","lastTargetBlockElem","opacity","useDraggableBlockMenu","editor","anchorElem","isEditable","scrollerElem","parentElement","menuRef","targetLineRef","debugHighlightRef","isDraggingBlockRef","setDraggableBlockElem","setLastTargetBlockElem","calculateDistanceFromScrollerElem","pageX","pageY","target","horizontalBuffer","verticalBuffer","distanceFromScrollerElem","contains","bottom","left","right","top","getBoundingClientRect","adjustedTop","window","scrollY","adjustedBottom","onDocumentMouseMove","event","topLevelNodeKeys","blockElem","_draggableBlockElem","foundAtIndex","isFoundNodeEmptyParagraph","cache_treshold","horizontalOffset","point","x","y","startIndex","length","useEdgeAsDefault","document","addEventListener","removeEventListener","current","onDragover","isFileTransfer","targetBlockElem","fuzzy","verbose","preventDefault","onDrop","dragData","getData","update","draggedNode","targetNode","height","targetBlockElemHeight","targetBlockElemTop","mouseY","isBelow","insertAfter","insertBefore","remove","onDragStart","nodeKey","node","getKey","setData","onDragEnd","Fragment","div","className","draggable","ref","DraggableBlockPlugin","body","_editable"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * From ChatGPT, only that verified it works for HR elements.
3
+ *
4
+ * HTML Elements can have CSS lineHeight applied to them, but it doesn't always affect the visual layout.
5
+ * This function checks if the line-height property has an effect on the element's layout.
6
+ * @param htmlElem
7
+ */
8
+ export declare function doesLineHeightAffectElement(htmlElem: HTMLElement): boolean;
9
+ //# sourceMappingURL=doesLineHeightAffectElement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doesLineHeightAffectElement.d.ts","sourceRoot":"","sources":["../../../../../../src/field/lexical/plugins/handles/utils/doesLineHeightAffectElement.ts"],"names":[],"mappings":"AAaA;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,WAAW,WA2BhE"}
@@ -0,0 +1,35 @@
1
+ const replacedElements = [
2
+ 'IMG',
3
+ 'INPUT',
4
+ 'TEXTAREA',
5
+ 'SELECT',
6
+ 'BUTTON',
7
+ 'VIDEO',
8
+ 'OBJECT',
9
+ 'EMBED',
10
+ 'IFRAME',
11
+ 'HR'
12
+ ];
13
+ /**
14
+ * From ChatGPT, only that verified it works for HR elements.
15
+ *
16
+ * HTML Elements can have CSS lineHeight applied to them, but it doesn't always affect the visual layout.
17
+ * This function checks if the line-height property has an effect on the element's layout.
18
+ * @param htmlElem
19
+ */ export function doesLineHeightAffectElement(htmlElem) {
20
+ if (!htmlElem) return false;
21
+ // Check for replaced elements, elements that typically don't support line-height adjustments,
22
+ // and elements without visible content
23
+ if (replacedElements.includes(htmlElem.tagName) || htmlElem.offsetHeight === 0 || htmlElem.offsetWidth === 0) {
24
+ return false;
25
+ }
26
+ // Check for specific CSS properties that negate line-height's visual effects
27
+ const style = window.getComputedStyle(htmlElem);
28
+ if (style.display === 'table-cell' || style.position === 'absolute' || style.visibility === 'hidden' || style.opacity === '0') {
29
+ return false;
30
+ }
31
+ // This is a basic check, and there can be more complex scenarios where line-height doesn't have an effect.
32
+ return true;
33
+ }
34
+
35
+ //# sourceMappingURL=doesLineHeightAffectElement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../src/field/lexical/plugins/handles/utils/doesLineHeightAffectElement.ts"],"sourcesContent":["const replacedElements = [\n 'IMG',\n 'INPUT',\n 'TEXTAREA',\n 'SELECT',\n 'BUTTON',\n 'VIDEO',\n 'OBJECT',\n 'EMBED',\n 'IFRAME',\n 'HR',\n]\n\n/**\n * From ChatGPT, only that verified it works for HR elements.\n *\n * HTML Elements can have CSS lineHeight applied to them, but it doesn't always affect the visual layout.\n * This function checks if the line-height property has an effect on the element's layout.\n * @param htmlElem\n */\nexport function doesLineHeightAffectElement(htmlElem: HTMLElement) {\n if (!htmlElem) return false\n\n // Check for replaced elements, elements that typically don't support line-height adjustments,\n // and elements without visible content\n\n if (\n replacedElements.includes(htmlElem.tagName) ||\n htmlElem.offsetHeight === 0 ||\n htmlElem.offsetWidth === 0\n ) {\n return false\n }\n\n // Check for specific CSS properties that negate line-height's visual effects\n const style = window.getComputedStyle(htmlElem)\n if (\n style.display === 'table-cell' ||\n style.position === 'absolute' ||\n style.visibility === 'hidden' ||\n style.opacity === '0'\n ) {\n return false\n }\n\n // This is a basic check, and there can be more complex scenarios where line-height doesn't have an effect.\n return true\n}\n"],"names":["replacedElements","doesLineHeightAffectElement","htmlElem","includes","tagName","offsetHeight","offsetWidth","style","window","getComputedStyle","display","position","visibility","opacity"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,MAAMA,mBAAmB;IACvB;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD;AAED;;;;;;CAMC,GACD,OAAO,SAASC,4BAA4BC,QAAqB;IAC/D,IAAI,CAACA,UAAU,OAAO;IAEtB,8FAA8F;IAC9F,uCAAuC;IAEvC,IACEF,iBAAiBG,QAAQ,CAACD,SAASE,OAAO,KAC1CF,SAASG,YAAY,KAAK,KAC1BH,SAASI,WAAW,KAAK,GACzB;QACA,OAAO;IACT;IAEA,6EAA6E;IAC7E,MAAMC,QAAQC,OAAOC,gBAAgB,CAACP;IACtC,IACEK,MAAMG,OAAO,KAAK,gBAClBH,MAAMI,QAAQ,KAAK,cACnBJ,MAAMK,UAAU,KAAK,YACrBL,MAAMM,OAAO,KAAK,KAClB;QACA,OAAO;IACT;IAEA,2GAA2G;IAC3G,OAAO;AACT"}
@@ -1,2 +1,2 @@
1
- export declare function setHandlePosition(targetElem: HTMLElement | null, floatingElem: HTMLElement, anchorElem: HTMLElement, leftOffset?: number): void;
1
+ export declare function setHandlePosition(targetElem: HTMLElement | null, handleElem: HTMLElement, anchorElem: HTMLElement, leftOffset?: number): void;
2
2
  //# sourceMappingURL=setHandlePosition.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"setHandlePosition.d.ts","sourceRoot":"","sources":["../../../../../../src/field/lexical/plugins/handles/utils/setHandlePosition.ts"],"names":[],"mappings":"AAAA,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,WAAW,GAAG,IAAI,EAC9B,YAAY,EAAE,WAAW,EACzB,UAAU,EAAE,WAAW,EACvB,UAAU,GAAE,MAAU,QAsBvB"}
1
+ {"version":3,"file":"setHandlePosition.d.ts","sourceRoot":"","sources":["../../../../../../src/field/lexical/plugins/handles/utils/setHandlePosition.ts"],"names":[],"mappings":"AAEA,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,WAAW,GAAG,IAAI,EAC9B,UAAU,EAAE,WAAW,EACvB,UAAU,EAAE,WAAW,EACvB,UAAU,GAAE,MAAU,QAkCvB"}
@@ -1,17 +1,27 @@
1
- export function setHandlePosition(targetElem, floatingElem, anchorElem, leftOffset = 0) {
1
+ import { doesLineHeightAffectElement } from './doesLineHeightAffectElement.js';
2
+ export function setHandlePosition(targetElem, handleElem, anchorElem, leftOffset = 0) {
2
3
  if (!targetElem) {
3
- floatingElem.style.opacity = '0';
4
- floatingElem.style.transform = 'translate(-10000px, -10000px)';
4
+ handleElem.style.opacity = '0';
5
+ handleElem.style.transform = 'translate(-10000px, -10000px)';
5
6
  return;
6
7
  }
7
8
  const targetRect = targetElem.getBoundingClientRect();
8
9
  const targetStyle = window.getComputedStyle(targetElem);
9
- const floatingElemRect = floatingElem.getBoundingClientRect();
10
+ const floatingElemRect = handleElem.getBoundingClientRect();
10
11
  const anchorElementRect = anchorElem.getBoundingClientRect();
11
- const top = targetRect.top + (parseInt(targetStyle.lineHeight, 10) - floatingElemRect.height) / 2 - anchorElementRect.top;
12
+ let top;
13
+ const shouldDisplayHandleInCenter = targetRect.height < 60;
14
+ if (!shouldDisplayHandleInCenter) {
15
+ // No need to let line height affect the re-positioning of the floating element if line height has no
16
+ // visual effect on the element. Otherwise, the floating element will be positioned incorrectly.
17
+ const actualLineHeight = doesLineHeightAffectElement(targetElem) ? parseInt(targetStyle.lineHeight, 10) : 0;
18
+ top = targetRect.top + (actualLineHeight - floatingElemRect.height) / 2 - anchorElementRect.top;
19
+ } else {
20
+ top = targetRect.top - floatingElemRect.height / 2 - anchorElementRect.top + targetRect.height / 2;
21
+ }
12
22
  const left = leftOffset;
13
- floatingElem.style.opacity = '1';
14
- floatingElem.style.transform = `translate(${left}px, ${top}px)`;
23
+ handleElem.style.opacity = '1';
24
+ handleElem.style.transform = `translate(${left}px, ${top}px)`;
15
25
  }
16
26
 
17
27
  //# sourceMappingURL=setHandlePosition.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../src/field/lexical/plugins/handles/utils/setHandlePosition.ts"],"sourcesContent":["export function setHandlePosition(\n targetElem: HTMLElement | null,\n floatingElem: HTMLElement,\n anchorElem: HTMLElement,\n leftOffset: number = 0, // SPACE\n) {\n if (!targetElem) {\n floatingElem.style.opacity = '0'\n floatingElem.style.transform = 'translate(-10000px, -10000px)'\n return\n }\n\n const targetRect = targetElem.getBoundingClientRect()\n const targetStyle = window.getComputedStyle(targetElem)\n const floatingElemRect = floatingElem.getBoundingClientRect()\n const anchorElementRect = anchorElem.getBoundingClientRect()\n\n const top =\n targetRect.top +\n (parseInt(targetStyle.lineHeight, 10) - floatingElemRect.height) / 2 -\n anchorElementRect.top\n\n const left = leftOffset\n\n floatingElem.style.opacity = '1'\n floatingElem.style.transform = `translate(${left}px, ${top}px)`\n}\n"],"names":["setHandlePosition","targetElem","floatingElem","anchorElem","leftOffset","style","opacity","transform","targetRect","getBoundingClientRect","targetStyle","window","getComputedStyle","floatingElemRect","anchorElementRect","top","parseInt","lineHeight","height","left"],"rangeMappings":";;;;;;;;;;;;;;","mappings":"AAAA,OAAO,SAASA,kBACdC,UAA8B,EAC9BC,YAAyB,EACzBC,UAAuB,EACvBC,aAAqB,CAAC;IAEtB,IAAI,CAACH,YAAY;QACfC,aAAaG,KAAK,CAACC,OAAO,GAAG;QAC7BJ,aAAaG,KAAK,CAACE,SAAS,GAAG;QAC/B;IACF;IAEA,MAAMC,aAAaP,WAAWQ,qBAAqB;IACnD,MAAMC,cAAcC,OAAOC,gBAAgB,CAACX;IAC5C,MAAMY,mBAAmBX,aAAaO,qBAAqB;IAC3D,MAAMK,oBAAoBX,WAAWM,qBAAqB;IAE1D,MAAMM,MACJP,WAAWO,GAAG,GACd,AAACC,CAAAA,SAASN,YAAYO,UAAU,EAAE,MAAMJ,iBAAiBK,MAAM,AAAD,IAAK,IACnEJ,kBAAkBC,GAAG;IAEvB,MAAMI,OAAOf;IAEbF,aAAaG,KAAK,CAACC,OAAO,GAAG;IAC7BJ,aAAaG,KAAK,CAACE,SAAS,GAAG,CAAC,UAAU,EAAEY,KAAK,IAAI,EAAEJ,IAAI,GAAG,CAAC;AACjE"}
1
+ {"version":3,"sources":["../../../../../../src/field/lexical/plugins/handles/utils/setHandlePosition.ts"],"sourcesContent":["import { doesLineHeightAffectElement } from './doesLineHeightAffectElement.js'\n\nexport function setHandlePosition(\n targetElem: HTMLElement | null,\n handleElem: HTMLElement,\n anchorElem: HTMLElement,\n leftOffset: number = 0, // SPACE\n) {\n if (!targetElem) {\n handleElem.style.opacity = '0'\n handleElem.style.transform = 'translate(-10000px, -10000px)'\n return\n }\n\n const targetRect = targetElem.getBoundingClientRect()\n const targetStyle = window.getComputedStyle(targetElem)\n const floatingElemRect = handleElem.getBoundingClientRect()\n const anchorElementRect = anchorElem.getBoundingClientRect()\n\n let top: number\n\n const shouldDisplayHandleInCenter = targetRect.height < 60\n\n if (!shouldDisplayHandleInCenter) {\n // No need to let line height affect the re-positioning of the floating element if line height has no\n // visual effect on the element. Otherwise, the floating element will be positioned incorrectly.\n const actualLineHeight = doesLineHeightAffectElement(targetElem)\n ? parseInt(targetStyle.lineHeight, 10)\n : 0\n\n top = targetRect.top + (actualLineHeight - floatingElemRect.height) / 2 - anchorElementRect.top\n } else {\n top =\n targetRect.top - floatingElemRect.height / 2 - anchorElementRect.top + targetRect.height / 2\n }\n\n const left = leftOffset\n\n handleElem.style.opacity = '1'\n handleElem.style.transform = `translate(${left}px, ${top}px)`\n}\n"],"names":["doesLineHeightAffectElement","setHandlePosition","targetElem","handleElem","anchorElem","leftOffset","style","opacity","transform","targetRect","getBoundingClientRect","targetStyle","window","getComputedStyle","floatingElemRect","anchorElementRect","top","shouldDisplayHandleInCenter","height","actualLineHeight","parseInt","lineHeight","left"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,SAASA,2BAA2B,QAAQ,mCAAkC;AAE9E,OAAO,SAASC,kBACdC,UAA8B,EAC9BC,UAAuB,EACvBC,UAAuB,EACvBC,aAAqB,CAAC;IAEtB,IAAI,CAACH,YAAY;QACfC,WAAWG,KAAK,CAACC,OAAO,GAAG;QAC3BJ,WAAWG,KAAK,CAACE,SAAS,GAAG;QAC7B;IACF;IAEA,MAAMC,aAAaP,WAAWQ,qBAAqB;IACnD,MAAMC,cAAcC,OAAOC,gBAAgB,CAACX;IAC5C,MAAMY,mBAAmBX,WAAWO,qBAAqB;IACzD,MAAMK,oBAAoBX,WAAWM,qBAAqB;IAE1D,IAAIM;IAEJ,MAAMC,8BAA8BR,WAAWS,MAAM,GAAG;IAExD,IAAI,CAACD,6BAA6B;QAChC,qGAAqG;QACrG,gGAAgG;QAChG,MAAME,mBAAmBnB,4BAA4BE,cACjDkB,SAAST,YAAYU,UAAU,EAAE,MACjC;QAEJL,MAAMP,WAAWO,GAAG,GAAG,AAACG,CAAAA,mBAAmBL,iBAAiBI,MAAM,AAAD,IAAK,IAAIH,kBAAkBC,GAAG;IACjG,OAAO;QACLA,MACEP,WAAWO,GAAG,GAAGF,iBAAiBI,MAAM,GAAG,IAAIH,kBAAkBC,GAAG,GAAGP,WAAWS,MAAM,GAAG;IAC/F;IAEA,MAAMI,OAAOjB;IAEbF,WAAWG,KAAK,CAACC,OAAO,GAAG;IAC3BJ,WAAWG,KAAK,CAACE,SAAS,GAAG,CAAC,UAAU,EAAEc,KAAK,IAAI,EAAEN,IAAI,GAAG,CAAC;AAC/D"}
@@ -331,6 +331,10 @@
331
331
  list-style-position: inside;
332
332
  }
333
333
 
334
+ &__ul ul {
335
+ margin: 0;
336
+ }
337
+
334
338
  &__listItem {
335
339
  margin: 0 0px 0.4em 16px;
336
340
  }
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ export declare const HorizontalRuleIcon: React.FC;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/field/lexical/ui/icons/HorizontalRule/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAatC,CAAA"}