@payloadcms/richtext-lexical 3.64.0-internal.23abf20 → 3.64.0-internal.9a6b44a

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 (96) hide show
  1. package/dist/exports/client/Field-B7GNSKZ4.js +2 -0
  2. package/dist/exports/client/Field-B7GNSKZ4.js.map +7 -0
  3. package/dist/exports/client/bundled.css +1 -1
  4. package/dist/exports/client/chunk-6NIGQP6A.js +12 -0
  5. package/dist/exports/client/chunk-6NIGQP6A.js.map +7 -0
  6. package/dist/exports/client/index.d.ts +1 -0
  7. package/dist/exports/client/index.d.ts.map +1 -1
  8. package/dist/exports/client/index.js +20 -20
  9. package/dist/exports/client/index.js.map +3 -3
  10. package/dist/exports/react/index.d.ts +1 -1
  11. package/dist/exports/react/index.d.ts.map +1 -1
  12. package/dist/exports/react/index.js.map +1 -1
  13. package/dist/exports/server/ast/mdx.d.ts.map +1 -1
  14. package/dist/exports/server/ast/mdx.js +1 -0
  15. package/dist/exports/server/ast/mdx.js.map +1 -1
  16. package/dist/features/converters/lexicalToJSX/Component/index.d.ts +2 -14
  17. package/dist/features/converters/lexicalToJSX/Component/index.d.ts.map +1 -1
  18. package/dist/features/converters/lexicalToJSX/Component/index.js +4 -2
  19. package/dist/features/converters/lexicalToJSX/Component/index.js.map +1 -1
  20. package/dist/features/converters/lexicalToJSX/converter/index.d.ts +16 -1
  21. package/dist/features/converters/lexicalToJSX/converter/index.d.ts.map +1 -1
  22. package/dist/features/converters/lexicalToJSX/converter/index.js +76 -4
  23. package/dist/features/converters/lexicalToJSX/converter/index.js.map +1 -1
  24. package/dist/features/converters/lexicalToJSX/converter/types.d.ts +14 -10
  25. package/dist/features/converters/lexicalToJSX/converter/types.d.ts.map +1 -1
  26. package/dist/features/converters/lexicalToJSX/converter/types.js.map +1 -1
  27. package/dist/features/debug/jsxConverter/client/plugin/index.js +1 -1
  28. package/dist/features/debug/jsxConverter/client/plugin/index.js.map +1 -1
  29. package/dist/field/Field.d.ts.map +1 -1
  30. package/dist/field/Field.js +11 -6
  31. package/dist/field/Field.js.map +1 -1
  32. package/dist/field/RichTextViewProvider.d.ts +83 -0
  33. package/dist/field/RichTextViewProvider.d.ts.map +1 -0
  34. package/dist/field/RichTextViewProvider.js +87 -0
  35. package/dist/field/RichTextViewProvider.js.map +1 -0
  36. package/dist/field/ViewSelector.d.ts +4 -0
  37. package/dist/field/ViewSelector.d.ts.map +1 -0
  38. package/dist/field/ViewSelector.js +89 -0
  39. package/dist/field/ViewSelector.js.map +1 -0
  40. package/dist/field/bundled.css +1 -1
  41. package/dist/field/index.d.ts +1 -0
  42. package/dist/field/index.d.ts.map +1 -1
  43. package/dist/field/index.js +47 -29
  44. package/dist/field/index.js.map +1 -1
  45. package/dist/field/rscEntry.d.ts +1 -1
  46. package/dist/field/rscEntry.d.ts.map +1 -1
  47. package/dist/field/rscEntry.js +12 -0
  48. package/dist/field/rscEntry.js.map +1 -1
  49. package/dist/index.d.ts +1 -1
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +3 -1
  52. package/dist/index.js.map +1 -1
  53. package/dist/lexical/LexicalEditor.d.ts.map +1 -1
  54. package/dist/lexical/LexicalEditor.js +2 -1
  55. package/dist/lexical/LexicalEditor.js.map +1 -1
  56. package/dist/lexical/LexicalProvider.d.ts.map +1 -1
  57. package/dist/lexical/LexicalProvider.js +12 -3
  58. package/dist/lexical/LexicalProvider.js.map +1 -1
  59. package/dist/lexical/config/client/sanitize.d.ts +1 -1
  60. package/dist/lexical/config/client/sanitize.d.ts.map +1 -1
  61. package/dist/lexical/config/client/sanitize.js +3 -2
  62. package/dist/lexical/config/client/sanitize.js.map +1 -1
  63. package/dist/lexical/config/types.d.ts +4 -0
  64. package/dist/lexical/config/types.d.ts.map +1 -1
  65. package/dist/lexical/config/types.js.map +1 -1
  66. package/dist/lexical/nodes/index.d.ts +12 -2
  67. package/dist/lexical/nodes/index.d.ts.map +1 -1
  68. package/dist/lexical/nodes/index.js +195 -2
  69. package/dist/lexical/nodes/index.js.map +1 -1
  70. package/dist/lexical/plugins/NodeViewOverridePlugin/index.d.ts +2 -0
  71. package/dist/lexical/plugins/NodeViewOverridePlugin/index.d.ts.map +1 -0
  72. package/dist/lexical/plugins/NodeViewOverridePlugin/index.js +48 -0
  73. package/dist/lexical/plugins/NodeViewOverridePlugin/index.js.map +1 -0
  74. package/dist/lexical/utils/url.d.ts +2 -0
  75. package/dist/lexical/utils/url.d.ts.map +1 -1
  76. package/dist/lexical/utils/url.js +18 -2
  77. package/dist/lexical/utils/url.js.map +1 -1
  78. package/dist/lexical/utils/url.spec.js +85 -4
  79. package/dist/lexical/utils/url.spec.js.map +1 -1
  80. package/dist/packages/@lexical/markdown/MarkdownImport.js +1 -0
  81. package/dist/packages/@lexical/markdown/MarkdownImport.js.map +1 -1
  82. package/dist/types.d.ts +138 -2
  83. package/dist/types.d.ts.map +1 -1
  84. package/dist/types.js.map +1 -1
  85. package/dist/utilities/generateImportMap.d.ts.map +1 -1
  86. package/dist/utilities/generateImportMap.js +1 -0
  87. package/dist/utilities/generateImportMap.js.map +1 -1
  88. package/dist/validate/hasText.d.ts +6 -1
  89. package/dist/validate/hasText.d.ts.map +1 -1
  90. package/dist/validate/hasText.js +10 -4
  91. package/dist/validate/hasText.js.map +1 -1
  92. package/package.json +8 -8
  93. package/dist/exports/client/Field-5MPJSBMW.js +0 -2
  94. package/dist/exports/client/Field-5MPJSBMW.js.map +0 -7
  95. package/dist/exports/client/chunk-EZX4YW7S.js +0 -12
  96. package/dist/exports/client/chunk-EZX4YW7S.js.map +0 -7
@@ -1 +1 @@
1
- {"version":3,"file":"sanitize.js","names":["deepMerge","sanitizeClientFeatures","features","sanitized","enabledFeatures","enabledFormats","markdownTransformers","nodes","plugins","providers","slashMenu","dynamicGroups","groups","toolbarFixed","toolbarInline","customGroups","forEach","feature","key","sanitizedClientFeatureProps","size","length","concat","enableFormats","push","node","plugin","i","clientProps","Component","position","group","foundGroup","find","sanitizedGroup","items","filter","optionGroup","transformer","allNodes","allTransformers","Object","keys","map","customConfig","sort","a","b","order","sanitizeClientEditorConfig","resolvedClientFeatureMap","lexical","admin","resolvedFeatureMap"],"sources":["../../../../src/lexical/config/client/sanitize.ts"],"sourcesContent":["'use client'\n\nimport type { EditorConfig as LexicalEditorConfig } from 'lexical'\n\nimport { deepMerge } from 'payload/shared'\n\nimport type { ToolbarGroup } from '../../../features/toolbars/types.js'\nimport type {\n ResolvedClientFeatureMap,\n SanitizedClientFeatures,\n} from '../../../features/typesClient.js'\nimport type { LexicalFieldAdminClientProps } from '../../../types.js'\nimport type { SanitizedClientEditorConfig } from '../types.js'\n\nexport const sanitizeClientFeatures = (\n features: ResolvedClientFeatureMap,\n): SanitizedClientFeatures => {\n const sanitized: SanitizedClientFeatures = {\n enabledFeatures: [],\n enabledFormats: [],\n markdownTransformers: [],\n nodes: [],\n plugins: [],\n providers: [],\n slashMenu: {\n dynamicGroups: [],\n groups: [],\n },\n toolbarFixed: {\n groups: [],\n },\n toolbarInline: {\n groups: [],\n },\n }\n\n // Allow customization of groups for toolbarFixed\n let customGroups: Record<string, Partial<ToolbarGroup>> = {}\n features.forEach((feature) => {\n if (feature.key === 'toolbarFixed' && feature.sanitizedClientFeatureProps?.customGroups) {\n customGroups = {\n ...customGroups,\n ...feature.sanitizedClientFeatureProps.customGroups,\n }\n }\n })\n\n if (!features?.size) {\n return sanitized\n }\n\n features.forEach((feature) => {\n if (feature.providers?.length) {\n sanitized.providers = sanitized.providers.concat(feature.providers)\n }\n\n if (feature.enableFormats?.length) {\n sanitized.enabledFormats.push(...feature.enableFormats)\n }\n\n if (feature.nodes?.length) {\n // Important: do not use concat\n for (const node of feature.nodes) {\n sanitized.nodes.push(node)\n }\n }\n if (feature.plugins?.length) {\n feature.plugins.forEach((plugin, i) => {\n sanitized.plugins?.push({\n clientProps: feature.sanitizedClientFeatureProps,\n Component: plugin.Component as any, // Appeases strict: true\n key: feature.key + i,\n position: plugin.position,\n })\n })\n }\n\n if (feature.toolbarInline?.groups?.length) {\n for (const group of feature.toolbarInline.groups) {\n // 1. find the group with the same key or create new one\n let foundGroup = sanitized.toolbarInline.groups.find(\n (sanitizedGroup) => sanitizedGroup.key === group.key,\n )\n if (!foundGroup) {\n foundGroup = {\n ...group,\n items: [],\n }\n } else {\n sanitized.toolbarInline.groups = sanitized.toolbarInline.groups.filter(\n (sanitizedGroup) => sanitizedGroup.key !== group.key,\n )\n }\n\n // 2. Add options to group options array and add to sanitized.slashMenu.groupsWithOptions\n if (group?.items?.length) {\n foundGroup.items = foundGroup.items.concat(group.items)\n }\n sanitized.toolbarInline?.groups.push(foundGroup)\n }\n }\n\n if (feature.toolbarFixed?.groups?.length) {\n for (const group of feature.toolbarFixed.groups) {\n // 1. find the group with the same key or create new one\n let foundGroup = sanitized.toolbarFixed.groups.find(\n (sanitizedGroup) => sanitizedGroup.key === group.key,\n )\n if (!foundGroup) {\n foundGroup = {\n ...group,\n items: [],\n }\n } else {\n sanitized.toolbarFixed.groups = sanitized.toolbarFixed.groups.filter(\n (sanitizedGroup) => sanitizedGroup.key !== group.key,\n )\n }\n\n // 2. Add options to group options array and add to sanitized.slashMenu.groupsWithOptions\n if (group?.items?.length) {\n foundGroup.items = foundGroup.items.concat(group.items)\n }\n sanitized.toolbarFixed?.groups.push(foundGroup)\n }\n }\n\n if (feature.slashMenu?.groups) {\n if (feature.slashMenu.dynamicGroups?.length) {\n sanitized.slashMenu.dynamicGroups = sanitized.slashMenu.dynamicGroups.concat(\n feature.slashMenu.dynamicGroups,\n )\n }\n\n for (const optionGroup of feature.slashMenu.groups) {\n // 1. find the group with the same name or create new one\n let group = sanitized.slashMenu.groups.find((group) => group.key === optionGroup.key)\n if (!group) {\n group = {\n ...optionGroup,\n items: [],\n }\n } else {\n sanitized.slashMenu.groups = sanitized.slashMenu.groups.filter(\n (group) => group.key !== optionGroup.key,\n )\n }\n\n // 2. Add options to group options array and add to sanitized.slashMenu.groupsWithOptions\n if (optionGroup?.items?.length) {\n group.items = group.items.concat(optionGroup.items)\n }\n sanitized.slashMenu.groups.push(group)\n }\n }\n\n if (feature.markdownTransformers?.length) {\n // Important: do not use concat\n for (const transformer of feature.markdownTransformers) {\n if (typeof transformer === 'function') {\n sanitized.markdownTransformers.push(\n transformer({\n allNodes: sanitized.nodes,\n allTransformers: sanitized.markdownTransformers,\n }),\n )\n } else {\n sanitized.markdownTransformers.push(transformer)\n }\n }\n }\n sanitized.enabledFeatures.push(feature.key)\n })\n\n // Apply custom group configurations to toolbarFixed groups\n if (Object.keys(customGroups).length > 0) {\n sanitized.toolbarFixed.groups = sanitized.toolbarFixed.groups.map((group) => {\n const customConfig = customGroups[group.key]\n if (customConfig) {\n return deepMerge(group, customConfig)\n }\n return group\n })\n }\n\n // Sort sanitized.toolbarInline.groups by order property\n sanitized.toolbarInline.groups.sort((a, b) => {\n if (a.order && b.order) {\n return a.order - b.order\n } else if (a.order) {\n return -1\n } else if (b.order) {\n return 1\n } else {\n return 0\n }\n })\n // Sort sanitized.toolbarFixed.groups by order property\n sanitized.toolbarFixed.groups.sort((a, b) => {\n if (a.order && b.order) {\n return a.order - b.order\n } else if (a.order) {\n return -1\n } else if (b.order) {\n return 1\n } else {\n return 0\n }\n })\n\n // Sort sanitized.toolbarInline.groups.[group].entries by order property\n for (const group of sanitized.toolbarInline.groups) {\n group.items.sort((a, b) => {\n if (a.order && b.order) {\n return a.order - b.order\n } else if (a.order) {\n return -1\n } else if (b.order) {\n return 1\n } else {\n return 0\n }\n })\n }\n\n // Sort sanitized.toolbarFixed.groups.[group].entries by order property\n for (const group of sanitized.toolbarFixed.groups) {\n group.items.sort((a, b) => {\n if (a.order && b.order) {\n return a.order - b.order\n } else if (a.order) {\n return -1\n } else if (b.order) {\n return 1\n } else {\n return 0\n }\n })\n }\n\n return sanitized\n}\n\nexport function sanitizeClientEditorConfig(\n resolvedClientFeatureMap: ResolvedClientFeatureMap,\n lexical?: LexicalEditorConfig,\n admin?: LexicalFieldAdminClientProps,\n): SanitizedClientEditorConfig {\n return {\n admin,\n features: sanitizeClientFeatures(resolvedClientFeatureMap),\n lexical: lexical!,\n resolvedFeatureMap: resolvedClientFeatureMap,\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"sanitize.js","names":["deepMerge","sanitizeClientFeatures","features","sanitized","enabledFeatures","enabledFormats","markdownTransformers","nodes","plugins","providers","slashMenu","dynamicGroups","groups","toolbarFixed","toolbarInline","customGroups","forEach","feature","key","sanitizedClientFeatureProps","size","length","concat","enableFormats","push","node","plugin","i","clientProps","Component","position","group","foundGroup","find","sanitizedGroup","items","filter","optionGroup","transformer","allNodes","allTransformers","Object","keys","map","customConfig","sort","a","b","order","sanitizeClientEditorConfig","resolvedClientFeatureMap","lexical","admin","view","resolvedFeatureMap"],"sources":["../../../../src/lexical/config/client/sanitize.ts"],"sourcesContent":["'use client'\n\nimport type { EditorConfig as LexicalEditorConfig } from 'lexical'\n\nimport { deepMerge } from 'payload/shared'\n\nimport type { ToolbarGroup } from '../../../features/toolbars/types.js'\nimport type {\n ResolvedClientFeatureMap,\n SanitizedClientFeatures,\n} from '../../../features/typesClient.js'\nimport type { LexicalFieldAdminClientProps } from '../../../types.js'\nimport type { SanitizedClientEditorConfig } from '../types.js'\n\nexport const sanitizeClientFeatures = (\n features: ResolvedClientFeatureMap,\n): SanitizedClientFeatures => {\n const sanitized: SanitizedClientFeatures = {\n enabledFeatures: [],\n enabledFormats: [],\n markdownTransformers: [],\n nodes: [],\n plugins: [],\n providers: [],\n slashMenu: {\n dynamicGroups: [],\n groups: [],\n },\n toolbarFixed: {\n groups: [],\n },\n toolbarInline: {\n groups: [],\n },\n }\n\n // Allow customization of groups for toolbarFixed\n let customGroups: Record<string, Partial<ToolbarGroup>> = {}\n features.forEach((feature) => {\n if (feature.key === 'toolbarFixed' && feature.sanitizedClientFeatureProps?.customGroups) {\n customGroups = {\n ...customGroups,\n ...feature.sanitizedClientFeatureProps.customGroups,\n }\n }\n })\n\n if (!features?.size) {\n return sanitized\n }\n\n features.forEach((feature) => {\n if (feature.providers?.length) {\n sanitized.providers = sanitized.providers.concat(feature.providers)\n }\n\n if (feature.enableFormats?.length) {\n sanitized.enabledFormats.push(...feature.enableFormats)\n }\n\n if (feature.nodes?.length) {\n // Important: do not use concat\n for (const node of feature.nodes) {\n sanitized.nodes.push(node)\n }\n }\n if (feature.plugins?.length) {\n feature.plugins.forEach((plugin, i) => {\n sanitized.plugins?.push({\n clientProps: feature.sanitizedClientFeatureProps,\n Component: plugin.Component as any, // Appeases strict: true\n key: feature.key + i,\n position: plugin.position,\n })\n })\n }\n\n if (feature.toolbarInline?.groups?.length) {\n for (const group of feature.toolbarInline.groups) {\n // 1. find the group with the same key or create new one\n let foundGroup = sanitized.toolbarInline.groups.find(\n (sanitizedGroup) => sanitizedGroup.key === group.key,\n )\n if (!foundGroup) {\n foundGroup = {\n ...group,\n items: [],\n }\n } else {\n sanitized.toolbarInline.groups = sanitized.toolbarInline.groups.filter(\n (sanitizedGroup) => sanitizedGroup.key !== group.key,\n )\n }\n\n // 2. Add options to group options array and add to sanitized.slashMenu.groupsWithOptions\n if (group?.items?.length) {\n foundGroup.items = foundGroup.items.concat(group.items)\n }\n sanitized.toolbarInline?.groups.push(foundGroup)\n }\n }\n\n if (feature.toolbarFixed?.groups?.length) {\n for (const group of feature.toolbarFixed.groups) {\n // 1. find the group with the same key or create new one\n let foundGroup = sanitized.toolbarFixed.groups.find(\n (sanitizedGroup) => sanitizedGroup.key === group.key,\n )\n if (!foundGroup) {\n foundGroup = {\n ...group,\n items: [],\n }\n } else {\n sanitized.toolbarFixed.groups = sanitized.toolbarFixed.groups.filter(\n (sanitizedGroup) => sanitizedGroup.key !== group.key,\n )\n }\n\n // 2. Add options to group options array and add to sanitized.slashMenu.groupsWithOptions\n if (group?.items?.length) {\n foundGroup.items = foundGroup.items.concat(group.items)\n }\n sanitized.toolbarFixed?.groups.push(foundGroup)\n }\n }\n\n if (feature.slashMenu?.groups) {\n if (feature.slashMenu.dynamicGroups?.length) {\n sanitized.slashMenu.dynamicGroups = sanitized.slashMenu.dynamicGroups.concat(\n feature.slashMenu.dynamicGroups,\n )\n }\n\n for (const optionGroup of feature.slashMenu.groups) {\n // 1. find the group with the same name or create new one\n let group = sanitized.slashMenu.groups.find((group) => group.key === optionGroup.key)\n if (!group) {\n group = {\n ...optionGroup,\n items: [],\n }\n } else {\n sanitized.slashMenu.groups = sanitized.slashMenu.groups.filter(\n (group) => group.key !== optionGroup.key,\n )\n }\n\n // 2. Add options to group options array and add to sanitized.slashMenu.groupsWithOptions\n if (optionGroup?.items?.length) {\n group.items = group.items.concat(optionGroup.items)\n }\n sanitized.slashMenu.groups.push(group)\n }\n }\n\n if (feature.markdownTransformers?.length) {\n // Important: do not use concat\n for (const transformer of feature.markdownTransformers) {\n if (typeof transformer === 'function') {\n sanitized.markdownTransformers.push(\n transformer({\n allNodes: sanitized.nodes,\n allTransformers: sanitized.markdownTransformers,\n }),\n )\n } else {\n sanitized.markdownTransformers.push(transformer)\n }\n }\n }\n sanitized.enabledFeatures.push(feature.key)\n })\n\n // Apply custom group configurations to toolbarFixed groups\n if (Object.keys(customGroups).length > 0) {\n sanitized.toolbarFixed.groups = sanitized.toolbarFixed.groups.map((group) => {\n const customConfig = customGroups[group.key]\n if (customConfig) {\n return deepMerge(group, customConfig)\n }\n return group\n })\n }\n\n // Sort sanitized.toolbarInline.groups by order property\n sanitized.toolbarInline.groups.sort((a, b) => {\n if (a.order && b.order) {\n return a.order - b.order\n } else if (a.order) {\n return -1\n } else if (b.order) {\n return 1\n } else {\n return 0\n }\n })\n // Sort sanitized.toolbarFixed.groups by order property\n sanitized.toolbarFixed.groups.sort((a, b) => {\n if (a.order && b.order) {\n return a.order - b.order\n } else if (a.order) {\n return -1\n } else if (b.order) {\n return 1\n } else {\n return 0\n }\n })\n\n // Sort sanitized.toolbarInline.groups.[group].entries by order property\n for (const group of sanitized.toolbarInline.groups) {\n group.items.sort((a, b) => {\n if (a.order && b.order) {\n return a.order - b.order\n } else if (a.order) {\n return -1\n } else if (b.order) {\n return 1\n } else {\n return 0\n }\n })\n }\n\n // Sort sanitized.toolbarFixed.groups.[group].entries by order property\n for (const group of sanitized.toolbarFixed.groups) {\n group.items.sort((a, b) => {\n if (a.order && b.order) {\n return a.order - b.order\n } else if (a.order) {\n return -1\n } else if (b.order) {\n return 1\n } else {\n return 0\n }\n })\n }\n\n return sanitized\n}\n\nexport function sanitizeClientEditorConfig(\n resolvedClientFeatureMap: ResolvedClientFeatureMap,\n lexical?: LexicalEditorConfig,\n admin?: LexicalFieldAdminClientProps,\n view?: string,\n): SanitizedClientEditorConfig {\n return {\n admin,\n features: sanitizeClientFeatures(resolvedClientFeatureMap),\n lexical: lexical!,\n resolvedFeatureMap: resolvedClientFeatureMap,\n view,\n }\n}\n"],"mappings":"AAAA;;AAIA,SAASA,SAAS,QAAQ;AAU1B,OAAO,MAAMC,sBAAA,GACXC,QAAA;EAEA,MAAMC,SAAA,GAAqC;IACzCC,eAAA,EAAiB,EAAE;IACnBC,cAAA,EAAgB,EAAE;IAClBC,oBAAA,EAAsB,EAAE;IACxBC,KAAA,EAAO,EAAE;IACTC,OAAA,EAAS,EAAE;IACXC,SAAA,EAAW,EAAE;IACbC,SAAA,EAAW;MACTC,aAAA,EAAe,EAAE;MACjBC,MAAA,EAAQ;IACV;IACAC,YAAA,EAAc;MACZD,MAAA,EAAQ;IACV;IACAE,aAAA,EAAe;MACbF,MAAA,EAAQ;IACV;EACF;EAEA;EACA,IAAIG,YAAA,GAAsD,CAAC;EAC3Db,QAAA,CAASc,OAAO,CAAEC,OAAA;IAChB,IAAIA,OAAA,CAAQC,GAAG,KAAK,kBAAkBD,OAAA,CAAQE,2BAA2B,EAAEJ,YAAA,EAAc;MACvFA,YAAA,GAAe;QACb,GAAGA,YAAY;QACf,GAAGE,OAAA,CAAQE,2BAA2B,CAACJ;MACzC;IACF;EACF;EAEA,IAAI,CAACb,QAAA,EAAUkB,IAAA,EAAM;IACnB,OAAOjB,SAAA;EACT;EAEAD,QAAA,CAASc,OAAO,CAAEC,OAAA;IAChB,IAAIA,OAAA,CAAQR,SAAS,EAAEY,MAAA,EAAQ;MAC7BlB,SAAA,CAAUM,SAAS,GAAGN,SAAA,CAAUM,SAAS,CAACa,MAAM,CAACL,OAAA,CAAQR,SAAS;IACpE;IAEA,IAAIQ,OAAA,CAAQM,aAAa,EAAEF,MAAA,EAAQ;MACjClB,SAAA,CAAUE,cAAc,CAACmB,IAAI,IAAIP,OAAA,CAAQM,aAAa;IACxD;IAEA,IAAIN,OAAA,CAAQV,KAAK,EAAEc,MAAA,EAAQ;MACzB;MACA,KAAK,MAAMI,IAAA,IAAQR,OAAA,CAAQV,KAAK,EAAE;QAChCJ,SAAA,CAAUI,KAAK,CAACiB,IAAI,CAACC,IAAA;MACvB;IACF;IACA,IAAIR,OAAA,CAAQT,OAAO,EAAEa,MAAA,EAAQ;MAC3BJ,OAAA,CAAQT,OAAO,CAACQ,OAAO,CAAC,CAACU,MAAA,EAAQC,CAAA;QAC/BxB,SAAA,CAAUK,OAAO,EAAEgB,IAAA,CAAK;UACtBI,WAAA,EAAaX,OAAA,CAAQE,2BAA2B;UAChDU,SAAA,EAAWH,MAAA,CAAOG,SAAS;UAC3BX,GAAA,EAAKD,OAAA,CAAQC,GAAG,GAAGS,CAAA;UACnBG,QAAA,EAAUJ,MAAA,CAAOI;QACnB;MACF;IACF;IAEA,IAAIb,OAAA,CAAQH,aAAa,EAAEF,MAAA,EAAQS,MAAA,EAAQ;MACzC,KAAK,MAAMU,KAAA,IAASd,OAAA,CAAQH,aAAa,CAACF,MAAM,EAAE;QAChD;QACA,IAAIoB,UAAA,GAAa7B,SAAA,CAAUW,aAAa,CAACF,MAAM,CAACqB,IAAI,CACjDC,cAAA,IAAmBA,cAAA,CAAehB,GAAG,KAAKa,KAAA,CAAMb,GAAG;QAEtD,IAAI,CAACc,UAAA,EAAY;UACfA,UAAA,GAAa;YACX,GAAGD,KAAK;YACRI,KAAA,EAAO;UACT;QACF,OAAO;UACLhC,SAAA,CAAUW,aAAa,CAACF,MAAM,GAAGT,SAAA,CAAUW,aAAa,CAACF,MAAM,CAACwB,MAAM,CACnEF,cAAA,IAAmBA,cAAA,CAAehB,GAAG,KAAKa,KAAA,CAAMb,GAAG;QAExD;QAEA;QACA,IAAIa,KAAA,EAAOI,KAAA,EAAOd,MAAA,EAAQ;UACxBW,UAAA,CAAWG,KAAK,GAAGH,UAAA,CAAWG,KAAK,CAACb,MAAM,CAACS,KAAA,CAAMI,KAAK;QACxD;QACAhC,SAAA,CAAUW,aAAa,EAAEF,MAAA,CAAOY,IAAA,CAAKQ,UAAA;MACvC;IACF;IAEA,IAAIf,OAAA,CAAQJ,YAAY,EAAED,MAAA,EAAQS,MAAA,EAAQ;MACxC,KAAK,MAAMU,KAAA,IAASd,OAAA,CAAQJ,YAAY,CAACD,MAAM,EAAE;QAC/C;QACA,IAAIoB,UAAA,GAAa7B,SAAA,CAAUU,YAAY,CAACD,MAAM,CAACqB,IAAI,CAChDC,cAAA,IAAmBA,cAAA,CAAehB,GAAG,KAAKa,KAAA,CAAMb,GAAG;QAEtD,IAAI,CAACc,UAAA,EAAY;UACfA,UAAA,GAAa;YACX,GAAGD,KAAK;YACRI,KAAA,EAAO;UACT;QACF,OAAO;UACLhC,SAAA,CAAUU,YAAY,CAACD,MAAM,GAAGT,SAAA,CAAUU,YAAY,CAACD,MAAM,CAACwB,MAAM,CACjEF,cAAA,IAAmBA,cAAA,CAAehB,GAAG,KAAKa,KAAA,CAAMb,GAAG;QAExD;QAEA;QACA,IAAIa,KAAA,EAAOI,KAAA,EAAOd,MAAA,EAAQ;UACxBW,UAAA,CAAWG,KAAK,GAAGH,UAAA,CAAWG,KAAK,CAACb,MAAM,CAACS,KAAA,CAAMI,KAAK;QACxD;QACAhC,SAAA,CAAUU,YAAY,EAAED,MAAA,CAAOY,IAAA,CAAKQ,UAAA;MACtC;IACF;IAEA,IAAIf,OAAA,CAAQP,SAAS,EAAEE,MAAA,EAAQ;MAC7B,IAAIK,OAAA,CAAQP,SAAS,CAACC,aAAa,EAAEU,MAAA,EAAQ;QAC3ClB,SAAA,CAAUO,SAAS,CAACC,aAAa,GAAGR,SAAA,CAAUO,SAAS,CAACC,aAAa,CAACW,MAAM,CAC1EL,OAAA,CAAQP,SAAS,CAACC,aAAa;MAEnC;MAEA,KAAK,MAAM0B,WAAA,IAAepB,OAAA,CAAQP,SAAS,CAACE,MAAM,EAAE;QAClD;QACA,IAAImB,KAAA,GAAQ5B,SAAA,CAAUO,SAAS,CAACE,MAAM,CAACqB,IAAI,CAAEF,KAAA,IAAUA,KAAA,CAAMb,GAAG,KAAKmB,WAAA,CAAYnB,GAAG;QACpF,IAAI,CAACa,KAAA,EAAO;UACVA,KAAA,GAAQ;YACN,GAAGM,WAAW;YACdF,KAAA,EAAO;UACT;QACF,OAAO;UACLhC,SAAA,CAAUO,SAAS,CAACE,MAAM,GAAGT,SAAA,CAAUO,SAAS,CAACE,MAAM,CAACwB,MAAM,CAC3DL,KAAA,IAAUA,KAAA,CAAMb,GAAG,KAAKmB,WAAA,CAAYnB,GAAG;QAE5C;QAEA;QACA,IAAImB,WAAA,EAAaF,KAAA,EAAOd,MAAA,EAAQ;UAC9BU,KAAA,CAAMI,KAAK,GAAGJ,KAAA,CAAMI,KAAK,CAACb,MAAM,CAACe,WAAA,CAAYF,KAAK;QACpD;QACAhC,SAAA,CAAUO,SAAS,CAACE,MAAM,CAACY,IAAI,CAACO,KAAA;MAClC;IACF;IAEA,IAAId,OAAA,CAAQX,oBAAoB,EAAEe,MAAA,EAAQ;MACxC;MACA,KAAK,MAAMiB,WAAA,IAAerB,OAAA,CAAQX,oBAAoB,EAAE;QACtD,IAAI,OAAOgC,WAAA,KAAgB,YAAY;UACrCnC,SAAA,CAAUG,oBAAoB,CAACkB,IAAI,CACjCc,WAAA,CAAY;YACVC,QAAA,EAAUpC,SAAA,CAAUI,KAAK;YACzBiC,eAAA,EAAiBrC,SAAA,CAAUG;UAC7B;QAEJ,OAAO;UACLH,SAAA,CAAUG,oBAAoB,CAACkB,IAAI,CAACc,WAAA;QACtC;MACF;IACF;IACAnC,SAAA,CAAUC,eAAe,CAACoB,IAAI,CAACP,OAAA,CAAQC,GAAG;EAC5C;EAEA;EACA,IAAIuB,MAAA,CAAOC,IAAI,CAAC3B,YAAA,EAAcM,MAAM,GAAG,GAAG;IACxClB,SAAA,CAAUU,YAAY,CAACD,MAAM,GAAGT,SAAA,CAAUU,YAAY,CAACD,MAAM,CAAC+B,GAAG,CAAEZ,KAAA;MACjE,MAAMa,YAAA,GAAe7B,YAAY,CAACgB,KAAA,CAAMb,GAAG,CAAC;MAC5C,IAAI0B,YAAA,EAAc;QAChB,OAAO5C,SAAA,CAAU+B,KAAA,EAAOa,YAAA;MAC1B;MACA,OAAOb,KAAA;IACT;EACF;EAEA;EACA5B,SAAA,CAAUW,aAAa,CAACF,MAAM,CAACiC,IAAI,CAAC,CAACC,CAAA,EAAGC,CAAA;IACtC,IAAID,CAAA,CAAEE,KAAK,IAAID,CAAA,CAAEC,KAAK,EAAE;MACtB,OAAOF,CAAA,CAAEE,KAAK,GAAGD,CAAA,CAAEC,KAAK;IAC1B,OAAO,IAAIF,CAAA,CAAEE,KAAK,EAAE;MAClB,OAAO,CAAC;IACV,OAAO,IAAID,CAAA,CAAEC,KAAK,EAAE;MAClB,OAAO;IACT,OAAO;MACL,OAAO;IACT;EACF;EACA;EACA7C,SAAA,CAAUU,YAAY,CAACD,MAAM,CAACiC,IAAI,CAAC,CAACC,CAAA,EAAGC,CAAA;IACrC,IAAID,CAAA,CAAEE,KAAK,IAAID,CAAA,CAAEC,KAAK,EAAE;MACtB,OAAOF,CAAA,CAAEE,KAAK,GAAGD,CAAA,CAAEC,KAAK;IAC1B,OAAO,IAAIF,CAAA,CAAEE,KAAK,EAAE;MAClB,OAAO,CAAC;IACV,OAAO,IAAID,CAAA,CAAEC,KAAK,EAAE;MAClB,OAAO;IACT,OAAO;MACL,OAAO;IACT;EACF;EAEA;EACA,KAAK,MAAMjB,KAAA,IAAS5B,SAAA,CAAUW,aAAa,CAACF,MAAM,EAAE;IAClDmB,KAAA,CAAMI,KAAK,CAACU,IAAI,CAAC,CAACC,CAAA,EAAGC,CAAA;MACnB,IAAID,CAAA,CAAEE,KAAK,IAAID,CAAA,CAAEC,KAAK,EAAE;QACtB,OAAOF,CAAA,CAAEE,KAAK,GAAGD,CAAA,CAAEC,KAAK;MAC1B,OAAO,IAAIF,CAAA,CAAEE,KAAK,EAAE;QAClB,OAAO,CAAC;MACV,OAAO,IAAID,CAAA,CAAEC,KAAK,EAAE;QAClB,OAAO;MACT,OAAO;QACL,OAAO;MACT;IACF;EACF;EAEA;EACA,KAAK,MAAMjB,KAAA,IAAS5B,SAAA,CAAUU,YAAY,CAACD,MAAM,EAAE;IACjDmB,KAAA,CAAMI,KAAK,CAACU,IAAI,CAAC,CAACC,CAAA,EAAGC,CAAA;MACnB,IAAID,CAAA,CAAEE,KAAK,IAAID,CAAA,CAAEC,KAAK,EAAE;QACtB,OAAOF,CAAA,CAAEE,KAAK,GAAGD,CAAA,CAAEC,KAAK;MAC1B,OAAO,IAAIF,CAAA,CAAEE,KAAK,EAAE;QAClB,OAAO,CAAC;MACV,OAAO,IAAID,CAAA,CAAEC,KAAK,EAAE;QAClB,OAAO;MACT,OAAO;QACL,OAAO;MACT;IACF;EACF;EAEA,OAAO7C,SAAA;AACT;AAEA,OAAO,SAAS8C,2BACdC,wBAAkD,EAClDC,OAA6B,EAC7BC,KAAoC,EACpCC,IAAa;EAEb,OAAO;IACLD,KAAA;IACAlD,QAAA,EAAUD,sBAAA,CAAuBiD,wBAAA;IACjCC,OAAA,EAASA,OAAA;IACTG,kBAAA,EAAoBJ,wBAAA;IACpBG;EACF;AACF","ignoreList":[]}
@@ -20,5 +20,9 @@ export type SanitizedClientEditorConfig = {
20
20
  features: SanitizedClientFeatures;
21
21
  lexical: LexicalEditorConfig;
22
22
  resolvedFeatureMap: ResolvedClientFeatureMap;
23
+ /**
24
+ * To identify what view this editor config was created for.
25
+ */
26
+ view?: string;
23
27
  };
24
28
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lexical/config/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,IAAI,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAElE,OAAO,KAAK,EACV,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,+BAA+B,CAAA;AACtC,OAAO,KAAK,EACV,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,+BAA+B,CAAA;AACtC,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,gBAAgB,CAAA;AAElE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,qBAAqB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,CAAA;IAChD,OAAO,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAA;CAC1C,CAAA;AAED,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,EAAE,uBAAuB,CAAA;IACjC,OAAO,EAAE,mBAAmB,GAAG,SAAS,CAAA;IACxC,kBAAkB,EAAE,wBAAwB,CAAA;CAC7C,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,qBAAqB,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAA;IAC3C,OAAO,CAAC,EAAE,mBAAmB,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,2BAA2B,GAAG;IACxC,KAAK,CAAC,EAAE,4BAA4B,CAAA;IACpC,QAAQ,EAAE,uBAAuB,CAAA;IACjC,OAAO,EAAE,mBAAmB,CAAA;IAC5B,kBAAkB,EAAE,wBAAwB,CAAA;CAC7C,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lexical/config/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,IAAI,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAElE,OAAO,KAAK,EACV,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,+BAA+B,CAAA;AACtC,OAAO,KAAK,EACV,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,+BAA+B,CAAA;AACtC,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,gBAAgB,CAAA;AAElE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,qBAAqB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,CAAA;IAChD,OAAO,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAA;CAC1C,CAAA;AAED,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,EAAE,uBAAuB,CAAA;IACjC,OAAO,EAAE,mBAAmB,GAAG,SAAS,CAAA;IACxC,kBAAkB,EAAE,wBAAwB,CAAA;CAC7C,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,qBAAqB,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAA;IAC3C,OAAO,CAAC,EAAE,mBAAmB,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,2BAA2B,GAAG;IACxC,KAAK,CAAC,EAAE,4BAA4B,CAAA;IACpC,QAAQ,EAAE,uBAAuB,CAAA;IACjC,OAAO,EAAE,mBAAmB,CAAA;IAC5B,kBAAkB,EAAE,wBAAwB,CAAA;IAC5C;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":[],"sources":["../../../src/lexical/config/types.ts"],"sourcesContent":["import type { EditorConfig as LexicalEditorConfig } from 'lexical'\n\nimport type {\n FeatureProviderClient,\n ResolvedClientFeatureMap,\n SanitizedClientFeatures,\n} from '../../features/typesClient.js'\nimport type {\n FeatureProviderServer,\n ResolvedServerFeatureMap,\n SanitizedServerFeatures,\n} from '../../features/typesServer.js'\nimport type { LexicalFieldAdminClientProps } from '../../types.js'\n\nexport type ServerEditorConfig = {\n features: FeatureProviderServer<any, any, any>[]\n lexical?: LexicalEditorConfig | undefined // If undefined, the default lexical editor config will be used. This can be undefined so that we do not send the default lexical editor config to the client.\n}\n\nexport type SanitizedServerEditorConfig = {\n features: SanitizedServerFeatures\n lexical: LexicalEditorConfig | undefined // If undefined, the default lexical editor config will be used. This can be undefined so that we do not send the default lexical editor config to the client.\n resolvedFeatureMap: ResolvedServerFeatureMap\n}\n\nexport type ClientEditorConfig = {\n features: FeatureProviderClient<any, any>[]\n lexical?: LexicalEditorConfig\n}\n\nexport type SanitizedClientEditorConfig = {\n admin?: LexicalFieldAdminClientProps\n features: SanitizedClientFeatures\n lexical: LexicalEditorConfig\n resolvedFeatureMap: ResolvedClientFeatureMap\n}\n"],"mappings":"AA8BA","ignoreList":[]}
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../../src/lexical/config/types.ts"],"sourcesContent":["import type { EditorConfig as LexicalEditorConfig } from 'lexical'\n\nimport type {\n FeatureProviderClient,\n ResolvedClientFeatureMap,\n SanitizedClientFeatures,\n} from '../../features/typesClient.js'\nimport type {\n FeatureProviderServer,\n ResolvedServerFeatureMap,\n SanitizedServerFeatures,\n} from '../../features/typesServer.js'\nimport type { LexicalFieldAdminClientProps } from '../../types.js'\n\nexport type ServerEditorConfig = {\n features: FeatureProviderServer<any, any, any>[]\n lexical?: LexicalEditorConfig | undefined // If undefined, the default lexical editor config will be used. This can be undefined so that we do not send the default lexical editor config to the client.\n}\n\nexport type SanitizedServerEditorConfig = {\n features: SanitizedServerFeatures\n lexical: LexicalEditorConfig | undefined // If undefined, the default lexical editor config will be used. This can be undefined so that we do not send the default lexical editor config to the client.\n resolvedFeatureMap: ResolvedServerFeatureMap\n}\n\nexport type ClientEditorConfig = {\n features: FeatureProviderClient<any, any>[]\n lexical?: LexicalEditorConfig\n}\n\nexport type SanitizedClientEditorConfig = {\n admin?: LexicalFieldAdminClientProps\n features: SanitizedClientFeatures\n lexical: LexicalEditorConfig\n resolvedFeatureMap: ResolvedClientFeatureMap\n /**\n * To identify what view this editor config was created for.\n */\n view?: string\n}\n"],"mappings":"AA8BA","ignoreList":[]}
@@ -1,8 +1,18 @@
1
- import type { Klass, LexicalNode, LexicalNodeReplacement } from 'lexical';
1
+ import type { Klass, LexicalEditor, LexicalNode, LexicalNodeReplacement } from 'lexical';
2
2
  import type { NodeWithHooks } from '../../features/typesServer.js';
3
+ import type { LexicalEditorNodeMap } from '../../types.js';
3
4
  import type { SanitizedClientEditorConfig, SanitizedServerEditorConfig } from '../config/types.js';
4
- export declare function getEnabledNodes({ editorConfig, }: {
5
+ /**
6
+ * Register view definitions for an editor
7
+ */
8
+ export declare function registerEditorNodeViews(editor: LexicalEditor, nodeViews: LexicalEditorNodeMap): void;
9
+ /**
10
+ * Clear all view overrides for an editor (restores default rendering)
11
+ */
12
+ export declare function clearEditorNodeViews(editor: LexicalEditor): void;
13
+ export declare function getEnabledNodes({ editorConfig, nodeViews, }: {
5
14
  editorConfig: SanitizedClientEditorConfig | SanitizedServerEditorConfig;
15
+ nodeViews?: LexicalEditorNodeMap;
6
16
  }): Array<Klass<LexicalNode> | LexicalNodeReplacement>;
7
17
  export declare function getEnabledNodesFromServerNodes({ nodes, }: {
8
18
  nodes: Array<Klass<LexicalNode> | LexicalNodeReplacement> | Array<NodeWithHooks>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lexical/nodes/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAA;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AAClE,OAAO,KAAK,EAAE,2BAA2B,EAAE,2BAA2B,EAAE,MAAM,oBAAoB,CAAA;AAElG,wBAAgB,eAAe,CAAC,EAC9B,YAAY,GACb,EAAE;IACD,YAAY,EAAE,2BAA2B,GAAG,2BAA2B,CAAA;CACxE,GAAG,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,sBAAsB,CAAC,CAIrD;AAED,wBAAgB,8BAA8B,CAAC,EAC7C,KAAK,GACN,EAAE;IACD,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,sBAAsB,CAAC,GAAG,KAAK,CAAC,aAAa,CAAC,CAAA;CACjF,GAAG,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,sBAAsB,CAAC,CAOrD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lexical/nodes/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,KAAK,EACL,aAAa,EACb,WAAW,EACX,sBAAsB,EACvB,MAAM,SAAS,CAAA;AAIhB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AAClE,OAAO,KAAK,EAAE,oBAAoB,EAAgB,MAAM,gBAAgB,CAAA;AACxE,OAAO,KAAK,EAAE,2BAA2B,EAAE,2BAA2B,EAAE,MAAM,oBAAoB,CAAA;AAMlG;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,oBAAoB,GAC9B,IAAI,CAsCN;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAEhE;AAoID,wBAAgB,eAAe,CAAC,EAC9B,YAAY,EACZ,SAAS,GACV,EAAE;IACD,YAAY,EAAE,2BAA2B,GAAG,2BAA2B,CAAA;IACvE,SAAS,CAAC,EAAE,oBAAoB,CAAA;CACjC,GAAG,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,sBAAsB,CAAC,CAyCrD;AAED,wBAAgB,8BAA8B,CAAC,EAC7C,KAAK,GACN,EAAE;IACD,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,sBAAsB,CAAC,GAAG,KAAK,CAAC,aAAa,CAAC,CAAA;CACjF,GAAG,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,sBAAsB,CAAC,CAOrD"}
@@ -1,9 +1,202 @@
1
+ import React from 'react';
2
+ // Store view definitions for each editor and node type
3
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
+ const editorNodeViews = new WeakMap();
5
+ /**
6
+ * Register view definitions for an editor
7
+ */
8
+ export function registerEditorNodeViews(editor, nodeViews) {
9
+ if (!editorNodeViews.has(editor)) {
10
+ editorNodeViews.set(editor, new Map());
11
+ }
12
+ const editorViews = editorNodeViews.get(editor);
13
+ // Register each node type's view
14
+ for (const [nodeType, value] of Object.entries(nodeViews)) {
15
+ if (!value || typeof value !== 'object') {
16
+ continue;
17
+ }
18
+ // Handle blocks specially - store each block type with key 'block:blockType'
19
+ if (nodeType === 'blocks') {
20
+ for (const [blockType, viewDef] of Object.entries(
21
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
+ value)) {
23
+ editorViews.set(`block:${blockType}`, viewDef);
24
+ }
25
+ continue;
26
+ }
27
+ // Handle inlineBlocks specially - store each block type with key 'inlineBlock:blockType'
28
+ if (nodeType === 'inlineBlocks') {
29
+ for (const [blockType, viewDef] of Object.entries(
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
+ value)) {
32
+ editorViews.set(`inlineBlock:${blockType}`, viewDef);
33
+ }
34
+ continue;
35
+ }
36
+ // Regular node types
37
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
+ editorViews.set(nodeType, value);
39
+ }
40
+ }
41
+ /**
42
+ * Clear all view overrides for an editor (restores default rendering)
43
+ */
44
+ export function clearEditorNodeViews(editor) {
45
+ editorNodeViews.delete(editor);
46
+ }
47
+ /**
48
+ * Get the view definition for a specific editor and node
49
+ */
50
+ function getEditorNodeView(editor, nodeType,
51
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
52
+ node) {
53
+ const editorViews = editorNodeViews.get(editor);
54
+ // For block nodes, look up by blockType
55
+ if (nodeType === 'block' && node?.['__fields']?.blockType) {
56
+ const blockType = node['__fields'].blockType;
57
+ return editorViews?.get(`block:${blockType}`);
58
+ }
59
+ // For inlineBlock nodes, look up by blockType
60
+ if (nodeType === 'inlineBlock' && node?.['__fields']?.blockType) {
61
+ const blockType = node['__fields'].blockType;
62
+ return editorViews?.get(`inlineBlock:${blockType}`);
63
+ }
64
+ // Regular node types
65
+ return editorViews?.get(nodeType);
66
+ }
67
+ /**
68
+ * Apply view overrides to a specific node type by modifying its prototype
69
+ * Uses WeakMap to check per-editor at runtime
70
+ */
71
+ function applyNodeOverride({
72
+ node,
73
+ nodeType
74
+ }) {
75
+ if (!('getType' in node) || node.getType() !== nodeType) {
76
+ return;
77
+ }
78
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
79
+ const NodeClass = node;
80
+ // Store original methods if not already stored
81
+ if (!NodeClass.prototype._originalDecorate) {
82
+ NodeClass.prototype._originalDecorate = NodeClass.prototype.decorate;
83
+ }
84
+ if (!NodeClass.prototype._originalCreateDOM) {
85
+ NodeClass.prototype._originalCreateDOM = NodeClass.prototype.createDOM;
86
+ }
87
+ // Override decorate method (for DecoratorNodes)
88
+ if (NodeClass.prototype.decorate && !NodeClass.prototype._decorateOverridden) {
89
+ NodeClass.prototype._decorateOverridden = true;
90
+ const hasCreateDOM = !!NodeClass.prototype.createDOM;
91
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
92
+ NodeClass.prototype.decorate = function (editor, config) {
93
+ const viewDef = getEditorNodeView(editor, nodeType, this);
94
+ if (viewDef) {
95
+ // Priority 1: If Component is provided, use it
96
+ if (viewDef.Component) {
97
+ return viewDef.Component({
98
+ config,
99
+ editor,
100
+ isEditor: true,
101
+ isJSXConverter: false,
102
+ node: this
103
+ });
104
+ }
105
+ // Priority 2: If custom createDOM is provided, use html in decorate
106
+ if (viewDef.createDOM && viewDef.html) {
107
+ const htmlContent = typeof viewDef.html === 'function' ? viewDef.html({
108
+ config,
109
+ editor,
110
+ isEditor: true,
111
+ isJSXConverter: false,
112
+ node: this
113
+ }) : viewDef.html;
114
+ return React.createElement('span', {
115
+ dangerouslySetInnerHTML: {
116
+ __html: htmlContent
117
+ }
118
+ });
119
+ }
120
+ // Priority 3: If only html is provided (no custom createDOM),
121
+ // createDOM will handle it, so decorate returns empty fragment
122
+ if (viewDef.html && hasCreateDOM && !viewDef.createDOM) {
123
+ return React.createElement(React.Fragment);
124
+ }
125
+ }
126
+ // Otherwise use original
127
+ return NodeClass.prototype._originalDecorate.call(this, editor, config);
128
+ };
129
+ }
130
+ // Override createDOM method (for ElementNodes)
131
+ if (NodeClass.prototype.createDOM && !NodeClass.prototype._createDOMOverridden) {
132
+ NodeClass.prototype._createDOMOverridden = true;
133
+ NodeClass.prototype.createDOM = function (config, editor) {
134
+ const viewDef = getEditorNodeView(editor, nodeType, this);
135
+ if (viewDef) {
136
+ // If createDOM is provided, use it
137
+ if (viewDef.createDOM) {
138
+ return viewDef.createDOM({
139
+ config,
140
+ editor,
141
+ node: this
142
+ });
143
+ }
144
+ // If html is provided (as a function or string), create element from it
145
+ if (viewDef.html) {
146
+ const htmlContent = typeof viewDef.html === 'function' ? viewDef.html({
147
+ config,
148
+ editor,
149
+ isEditor: true,
150
+ isJSXConverter: false,
151
+ node: this
152
+ }) : viewDef.html;
153
+ const tempDiv = document.createElement('div');
154
+ tempDiv.innerHTML = htmlContent;
155
+ return tempDiv.firstElementChild || tempDiv;
156
+ }
157
+ }
158
+ // Otherwise use original
159
+ return NodeClass.prototype._originalCreateDOM.call(this, config, editor);
160
+ };
161
+ }
162
+ }
1
163
  export function getEnabledNodes({
2
- editorConfig
164
+ editorConfig,
165
+ nodeViews
3
166
  }) {
4
- return getEnabledNodesFromServerNodes({
167
+ const nodes = getEnabledNodesFromServerNodes({
5
168
  nodes: editorConfig.features.nodes
6
169
  });
170
+ if (nodeViews) {
171
+ // Apply node overrides by modifying prototypes (once globally)
172
+ // The overrides check per-editor at runtime using WeakMap
173
+ const nodeTypesToOverride = new Set();
174
+ for (const [key, value] of Object.entries(nodeViews)) {
175
+ if (!value || typeof value !== 'object') {
176
+ continue;
177
+ }
178
+ // If 'blocks' key exists with content, we need to override 'block' nodes
179
+ if (key === 'blocks' && Object.keys(value).length > 0) {
180
+ nodeTypesToOverride.add('block');
181
+ } else if (key === 'inlineBlocks' && Object.keys(value).length > 0) {
182
+ nodeTypesToOverride.add('inlineBlock');
183
+ } else {
184
+ nodeTypesToOverride.add(key);
185
+ }
186
+ }
187
+ for (const node of nodes) {
188
+ if ('getType' in node) {
189
+ const nodeType = node.getType();
190
+ if (nodeTypesToOverride.has(nodeType)) {
191
+ applyNodeOverride({
192
+ node,
193
+ nodeType
194
+ });
195
+ }
196
+ }
197
+ }
198
+ }
199
+ return nodes;
7
200
  }
8
201
  export function getEnabledNodesFromServerNodes({
9
202
  nodes
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["getEnabledNodes","editorConfig","getEnabledNodesFromServerNodes","nodes","features","map","node"],"sources":["../../../src/lexical/nodes/index.ts"],"sourcesContent":["import type { Klass, LexicalNode, LexicalNodeReplacement } from 'lexical'\n\nimport type { NodeWithHooks } from '../../features/typesServer.js'\nimport type { SanitizedClientEditorConfig, SanitizedServerEditorConfig } from '../config/types.js'\n\nexport function getEnabledNodes({\n editorConfig,\n}: {\n editorConfig: SanitizedClientEditorConfig | SanitizedServerEditorConfig\n}): Array<Klass<LexicalNode> | LexicalNodeReplacement> {\n return getEnabledNodesFromServerNodes({\n nodes: editorConfig.features.nodes,\n })\n}\n\nexport function getEnabledNodesFromServerNodes({\n nodes,\n}: {\n nodes: Array<Klass<LexicalNode> | LexicalNodeReplacement> | Array<NodeWithHooks>\n}): Array<Klass<LexicalNode> | LexicalNodeReplacement> {\n return nodes.map((node) => {\n if ('node' in node) {\n return node.node\n }\n return node\n })\n}\n"],"mappings":"AAKA,OAAO,SAASA,gBAAgB;EAC9BC;AAAY,CAGb;EACC,OAAOC,8BAAA,CAA+B;IACpCC,KAAA,EAAOF,YAAA,CAAaG,QAAQ,CAACD;EAC/B;AACF;AAEA,OAAO,SAASD,+BAA+B;EAC7CC;AAAK,CAGN;EACC,OAAOA,KAAA,CAAME,GAAG,CAAEC,IAAA;IAChB,IAAI,UAAUA,IAAA,EAAM;MAClB,OAAOA,IAAA,CAAKA,IAAI;IAClB;IACA,OAAOA,IAAA;EACT;AACF","ignoreList":[]}
1
+ {"version":3,"file":"index.js","names":["React","editorNodeViews","WeakMap","registerEditorNodeViews","editor","nodeViews","has","set","Map","editorViews","get","nodeType","value","Object","entries","blockType","viewDef","clearEditorNodeViews","delete","getEditorNodeView","node","applyNodeOverride","getType","NodeClass","prototype","_originalDecorate","decorate","_originalCreateDOM","createDOM","_decorateOverridden","hasCreateDOM","config","Component","isEditor","isJSXConverter","html","htmlContent","createElement","dangerouslySetInnerHTML","__html","Fragment","call","_createDOMOverridden","tempDiv","document","innerHTML","firstElementChild","getEnabledNodes","editorConfig","nodes","getEnabledNodesFromServerNodes","features","nodeTypesToOverride","Set","key","keys","length","add","map"],"sources":["../../../src/lexical/nodes/index.ts"],"sourcesContent":["import type {\n EditorConfig,\n Klass,\n LexicalEditor,\n LexicalNode,\n LexicalNodeReplacement,\n} from 'lexical'\n\nimport React from 'react'\n\nimport type { NodeWithHooks } from '../../features/typesServer.js'\nimport type { LexicalEditorNodeMap, NodeMapValue } from '../../types.js'\nimport type { SanitizedClientEditorConfig, SanitizedServerEditorConfig } from '../config/types.js'\n\n// Store view definitions for each editor and node type\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst editorNodeViews = new WeakMap<LexicalEditor, Map<string, NodeMapValue<any>>>()\n\n/**\n * Register view definitions for an editor\n */\nexport function registerEditorNodeViews(\n editor: LexicalEditor,\n nodeViews: LexicalEditorNodeMap,\n): void {\n if (!editorNodeViews.has(editor)) {\n editorNodeViews.set(editor, new Map())\n }\n const editorViews = editorNodeViews.get(editor)!\n\n // Register each node type's view\n for (const [nodeType, value] of Object.entries(nodeViews)) {\n if (!value || typeof value !== 'object') {\n continue\n }\n\n // Handle blocks specially - store each block type with key 'block:blockType'\n if (nodeType === 'blocks') {\n for (const [blockType, viewDef] of Object.entries(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n value as Record<string, NodeMapValue<any>>,\n )) {\n editorViews.set(`block:${blockType}`, viewDef)\n }\n continue\n }\n\n // Handle inlineBlocks specially - store each block type with key 'inlineBlock:blockType'\n if (nodeType === 'inlineBlocks') {\n for (const [blockType, viewDef] of Object.entries(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n value as Record<string, NodeMapValue<any>>,\n )) {\n editorViews.set(`inlineBlock:${blockType}`, viewDef)\n }\n continue\n }\n\n // Regular node types\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n editorViews.set(nodeType, value as NodeMapValue<any>)\n }\n}\n\n/**\n * Clear all view overrides for an editor (restores default rendering)\n */\nexport function clearEditorNodeViews(editor: LexicalEditor): void {\n editorNodeViews.delete(editor)\n}\n\n/**\n * Get the view definition for a specific editor and node\n */\nfunction getEditorNodeView(\n editor: LexicalEditor,\n nodeType: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n node?: any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): NodeMapValue<any> | undefined {\n const editorViews = editorNodeViews.get(editor)\n\n // For block nodes, look up by blockType\n if (nodeType === 'block' && node?.['__fields']?.blockType) {\n const blockType = node['__fields'].blockType\n return editorViews?.get(`block:${blockType}`)\n }\n\n // For inlineBlock nodes, look up by blockType\n if (nodeType === 'inlineBlock' && node?.['__fields']?.blockType) {\n const blockType = node['__fields'].blockType\n return editorViews?.get(`inlineBlock:${blockType}`)\n }\n\n // Regular node types\n return editorViews?.get(nodeType)\n}\n\n/**\n * Apply view overrides to a specific node type by modifying its prototype\n * Uses WeakMap to check per-editor at runtime\n */\nfunction applyNodeOverride({\n node,\n nodeType,\n}: {\n node: Klass<LexicalNode>\n nodeType: string\n}): void {\n if (!('getType' in node) || node.getType() !== nodeType) {\n return\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const NodeClass = node as any\n\n // Store original methods if not already stored\n if (!NodeClass.prototype._originalDecorate) {\n NodeClass.prototype._originalDecorate = NodeClass.prototype.decorate\n }\n if (!NodeClass.prototype._originalCreateDOM) {\n NodeClass.prototype._originalCreateDOM = NodeClass.prototype.createDOM\n }\n\n // Override decorate method (for DecoratorNodes)\n if (NodeClass.prototype.decorate && !NodeClass.prototype._decorateOverridden) {\n NodeClass.prototype._decorateOverridden = true\n const hasCreateDOM = !!NodeClass.prototype.createDOM\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n NodeClass.prototype.decorate = function (editor: LexicalEditor, config: EditorConfig): any {\n const viewDef = getEditorNodeView(editor, nodeType, this)\n\n if (viewDef) {\n // Priority 1: If Component is provided, use it\n if (viewDef.Component) {\n return viewDef.Component({\n config,\n editor,\n isEditor: true,\n isJSXConverter: false,\n node: this,\n })\n }\n\n // Priority 2: If custom createDOM is provided, use html in decorate\n if (viewDef.createDOM && viewDef.html) {\n const htmlContent =\n typeof viewDef.html === 'function'\n ? viewDef.html({ config, editor, isEditor: true, isJSXConverter: false, node: this })\n : viewDef.html\n return React.createElement('span', {\n dangerouslySetInnerHTML: { __html: htmlContent },\n })\n }\n\n // Priority 3: If only html is provided (no custom createDOM),\n // createDOM will handle it, so decorate returns empty fragment\n if (viewDef.html && hasCreateDOM && !viewDef.createDOM) {\n return React.createElement(React.Fragment)\n }\n }\n\n // Otherwise use original\n return NodeClass.prototype._originalDecorate.call(this, editor, config)\n }\n }\n\n // Override createDOM method (for ElementNodes)\n if (NodeClass.prototype.createDOM && !NodeClass.prototype._createDOMOverridden) {\n NodeClass.prototype._createDOMOverridden = true\n NodeClass.prototype.createDOM = function (\n config: EditorConfig,\n editor: LexicalEditor,\n ): HTMLElement {\n const viewDef = getEditorNodeView(editor, nodeType, this)\n\n if (viewDef) {\n // If createDOM is provided, use it\n if (viewDef.createDOM) {\n return viewDef.createDOM({ config, editor, node: this })\n }\n\n // If html is provided (as a function or string), create element from it\n if (viewDef.html) {\n const htmlContent =\n typeof viewDef.html === 'function'\n ? viewDef.html({ config, editor, isEditor: true, isJSXConverter: false, node: this })\n : viewDef.html\n const tempDiv = document.createElement('div')\n tempDiv.innerHTML = htmlContent\n return (tempDiv.firstElementChild as HTMLElement) || tempDiv\n }\n }\n\n // Otherwise use original\n return NodeClass.prototype._originalCreateDOM.call(this, config, editor)\n }\n }\n}\n\nexport function getEnabledNodes({\n editorConfig,\n nodeViews,\n}: {\n editorConfig: SanitizedClientEditorConfig | SanitizedServerEditorConfig\n nodeViews?: LexicalEditorNodeMap\n}): Array<Klass<LexicalNode> | LexicalNodeReplacement> {\n const nodes = getEnabledNodesFromServerNodes({\n nodes: editorConfig.features.nodes,\n })\n\n if (nodeViews) {\n // Apply node overrides by modifying prototypes (once globally)\n // The overrides check per-editor at runtime using WeakMap\n const nodeTypesToOverride = new Set<string>()\n\n for (const [key, value] of Object.entries(nodeViews)) {\n if (!value || typeof value !== 'object') {\n continue\n }\n\n // If 'blocks' key exists with content, we need to override 'block' nodes\n if (key === 'blocks' && Object.keys(value).length > 0) {\n nodeTypesToOverride.add('block')\n }\n // If 'inlineBlocks' key exists with content, we need to override 'inlineBlock' nodes\n else if (key === 'inlineBlocks' && Object.keys(value).length > 0) {\n nodeTypesToOverride.add('inlineBlock')\n }\n // Regular node types\n else {\n nodeTypesToOverride.add(key)\n }\n }\n\n for (const node of nodes) {\n if ('getType' in node) {\n const nodeType = node.getType()\n\n if (nodeTypesToOverride.has(nodeType)) {\n applyNodeOverride({ node, nodeType })\n }\n }\n }\n }\n\n return nodes\n}\n\nexport function getEnabledNodesFromServerNodes({\n nodes,\n}: {\n nodes: Array<Klass<LexicalNode> | LexicalNodeReplacement> | Array<NodeWithHooks>\n}): Array<Klass<LexicalNode> | LexicalNodeReplacement> {\n return nodes.map((node) => {\n if ('node' in node) {\n return node.node\n }\n return node\n })\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+ export declare function NodeViewOverridePlugin(): null;
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lexical/plugins/NodeViewOverridePlugin/index.tsx"],"names":[],"mappings":"AAOA,wBAAgB,sBAAsB,IAAI,IAAI,CAsB7C"}
@@ -0,0 +1,48 @@
1
+ 'use client';
2
+
3
+ import { c as _c } from "react/compiler-runtime";
4
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext.js';
5
+ import { useEffect } from 'react';
6
+ import { useRichTextView } from '../../../field/RichTextViewProvider.js';
7
+ import { clearEditorNodeViews, registerEditorNodeViews } from '../../nodes/index.js';
8
+ export function NodeViewOverridePlugin() {
9
+ const $ = _c(5);
10
+ const [editor] = useLexicalComposerContext();
11
+ const {
12
+ currentView,
13
+ views
14
+ } = useRichTextView();
15
+ let t0;
16
+ let t1;
17
+ if ($[0] !== currentView || $[1] !== editor || $[2] !== views) {
18
+ t0 = () => {
19
+ if (!views) {
20
+ return;
21
+ }
22
+ if (currentView === "default") {
23
+ if (views.default) {
24
+ registerEditorNodeViews(editor, views.default?.nodes);
25
+ } else {
26
+ clearEditorNodeViews(editor);
27
+ }
28
+ } else {
29
+ if (views[currentView]) {
30
+ clearEditorNodeViews(editor);
31
+ registerEditorNodeViews(editor, views[currentView]?.nodes);
32
+ }
33
+ }
34
+ };
35
+ t1 = [editor, views, currentView];
36
+ $[0] = currentView;
37
+ $[1] = editor;
38
+ $[2] = views;
39
+ $[3] = t0;
40
+ $[4] = t1;
41
+ } else {
42
+ t0 = $[3];
43
+ t1 = $[4];
44
+ }
45
+ useEffect(t0, t1);
46
+ return null;
47
+ }
48
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["c","_c","useLexicalComposerContext","useEffect","useRichTextView","clearEditorNodeViews","registerEditorNodeViews","NodeViewOverridePlugin","$","editor","currentView","views","t0","t1","default","nodes"],"sources":["../../../../src/lexical/plugins/NodeViewOverridePlugin/index.tsx"],"sourcesContent":["'use client'\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext.js'\nimport { useEffect } from 'react'\n\nimport { useRichTextView } from '../../../field/RichTextViewProvider.js'\nimport { clearEditorNodeViews, registerEditorNodeViews } from '../../nodes/index.js'\n\nexport function NodeViewOverridePlugin(): null {\n const [editor] = useLexicalComposerContext()\n const { currentView, views } = useRichTextView()\n\n useEffect(() => {\n if (!views) {\n return\n }\n\n if (currentView === 'default') {\n if (views.default) {\n registerEditorNodeViews(editor, views.default?.nodes)\n } else {\n clearEditorNodeViews(editor)\n }\n } else if (views[currentView]) {\n clearEditorNodeViews(editor)\n registerEditorNodeViews(editor, views[currentView]?.nodes)\n }\n }, [editor, views, currentView])\n\n return null\n}\n"],"mappings":"AAAA;;AAAA,SAAAA,CAAA,IAAAC,EAAA;AACA,SAASC,yBAAyB,QAAQ;AAC1C,SAASC,SAAS,QAAQ;AAE1B,SAASC,eAAe,QAAQ;AAChC,SAASC,oBAAoB,EAAEC,uBAAuB,QAAQ;AAE9D,OAAO,SAAAC,uBAAA;EAAA,MAAAC,CAAA,GAAAP,EAAA;EACL,OAAAQ,MAAA,IAAiBP,yBAAA;EACjB;IAAAQ,WAAA;IAAAC;EAAA,IAA+BP,eAAA;EAAA,IAAAQ,EAAA;EAAA,IAAAC,EAAA;EAAA,IAAAL,CAAA,QAAAE,WAAA,IAAAF,CAAA,QAAAC,MAAA,IAAAD,CAAA,QAAAG,KAAA;IAErBC,EAAA,GAAAA,CAAA;MAAA,KACHD,KAAA;QAAA;MAAA;MAAA,IAIDD,WAAA,KAAgB;QAAA,IACdC,KAAA,CAAAG,OAAA;UACFR,uBAAA,CAAwBG,MAAA,EAAQE,KAAA,CAAAG,OAAA,EAAAC,KAAe;QAAA;UAE/CV,oBAAA,CAAqBI,MAAA;QAAA;MAAA;QAAA,IAEdE,KAAK,CAACD,WAAA;UACfL,oBAAA,CAAqBI,MAAA;UACrBH,uBAAA,CAAwBG,MAAA,EAAQE,KAAK,CAACD,WAAA,GAAAK,KAAc;QAAA;MAAA;IAAA;IAErDF,EAAA,IAACJ,MAAA,EAAQE,KAAA,EAAOD,WAAA;IAAYF,CAAA,MAAAE,WAAA;IAAAF,CAAA,MAAAC,MAAA;IAAAD,CAAA,MAAAG,KAAA;IAAAH,CAAA,MAAAI,EAAA;IAAAJ,CAAA,MAAAK,EAAA;EAAA;IAAAD,EAAA,GAAAJ,CAAA;IAAAK,EAAA,GAAAL,CAAA;EAAA;EAf/BL,SAAA,CAAUS,EAeV,EAAGC,EAA4B;EAAA;AAAA","ignoreList":[]}
@@ -17,6 +17,8 @@ export declare const absoluteRegExp: RegExp;
17
17
  * - /privacy-policy
18
18
  * - /privacy-policy#primary-terms
19
19
  * - #primary-terms
20
+ * - /page?id=123
21
+ * - /page?id=123#section
20
22
  * */
21
23
  export declare const relativeOrAnchorRegExp: RegExp;
22
24
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../../../src/lexical/utils/url.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAe/C;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,QACqK,CAAA;AAEhM;;;;;MAKM;AACN,eAAO,MAAM,sBAAsB,QAA6C,CAAA;AAEhF;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAMvD;AAID,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CA+BhD"}
1
+ {"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../../../src/lexical/utils/url.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAe/C;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,QACqK,CAAA;AAEhM;;;;;;;MAOM;AACN,eAAO,MAAM,sBAAsB,QAA4D,CAAA;AAE/F;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAMvD;AAID,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CA8ChD"}
@@ -26,8 +26,10 @@ export const absoluteRegExp = /^(?:[a-zA-Z][a-zA-Z\d+.-]*:(?:\/\/)?(?:[-;:&=+$,\
26
26
  * - /privacy-policy
27
27
  * - /privacy-policy#primary-terms
28
28
  * - #primary-terms
29
+ * - /page?id=123
30
+ * - /page?id=123#section
29
31
  * */
30
- export const relativeOrAnchorRegExp = /^(?:\/[\w\-./]*(?:#\w[\w-]*)?|#[\w\-]+)$/;
32
+ export const relativeOrAnchorRegExp = /^(?:\/[\w\-./]*(?:\?[-;&=%\w]*)?(?:#[\w-]+)?|#[\w\-]+)$/;
31
33
  /**
32
34
  * Prevents unreasonable URLs from being inserted into the editor.
33
35
  * @param url
@@ -46,6 +48,14 @@ export function validateUrl(url) {
46
48
  if (!url) {
47
49
  return false;
48
50
  }
51
+ // Reject URLs with spaces
52
+ if (url.includes(' ')) {
53
+ return false;
54
+ }
55
+ // Reject malformed protocol URLs (e.g., http:/example.com instead of http://example.com)
56
+ if (/^[a-z][a-z\d+.-]*:\/[^/]/i.test(url)) {
57
+ return false;
58
+ }
49
59
  if (url === 'https://') {
50
60
  return true;
51
61
  }
@@ -59,7 +69,13 @@ export function validateUrl(url) {
59
69
  }
60
70
  // While this doesn't allow URLs starting with www (which is why we use the regex above), it does properly handle tel: URLs
61
71
  try {
62
- new URL(url);
72
+ const urlObj = new URL(url);
73
+ // For http/https/ftp protocols, require a proper domain with at least one dot (for TLD)
74
+ if (['ftp:', 'http:', 'https:'].includes(urlObj.protocol)) {
75
+ if (!urlObj.hostname.includes('.')) {
76
+ return false;
77
+ }
78
+ }
63
79
  return true;
64
80
  } catch {
65
81
  /* empty */}
@@ -1 +1 @@
1
- {"version":3,"file":"url.js","names":["sanitizeUrl","url","SAFE_URL_PATTERN","DATA_URL_PATTERN","String","trim","match","absoluteRegExp","relativeOrAnchorRegExp","validateUrlMinimal","includes","validateUrl","test","URL"],"sources":["../../../src/lexical/utils/url.ts"],"sourcesContent":["export function sanitizeUrl(url: string): string {\n /** A pattern that matches safe URLs. */\n const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^&:/?#]*(?:[/?#]|$))/gi\n\n /** A pattern that matches safe data URLs. */\n const DATA_URL_PATTERN =\n /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,[a-z\\d+/]+=*$/i\n\n url = String(url).trim()\n\n if (url.match(SAFE_URL_PATTERN) != null || url.match(DATA_URL_PATTERN) != null) {\n return url\n }\n\n return 'https://'\n}\n\n/**\n * This regex checks for absolute URLs in a string. Tested for the following use cases:\n * - http://example.com\n * - https://example.com\n * - ftp://files.example.com\n * - http://example.com/resource\n * - https://example.com/resource?key=value\n * - http://example.com/resource#anchor\n * - http://www.example.com\n * - https://sub.example.com/path/file\n * - mailto:\n */\nexport const absoluteRegExp =\n /^(?:[a-zA-Z][a-zA-Z\\d+.-]*:(?:\\/\\/)?(?:[-;:&=+$,\\w]+@)?[A-Za-z\\d]+(?:\\.[A-Za-z\\d]+)+|www\\.[A-Za-z\\d]+(?:\\.[A-Za-z\\d]+)+|(?:tel|mailto):[\\w+.-]+)(?:\\/[+~%/\\w-]*)?(?:\\?[-;&=%\\w]*)?(?:#\\w+)?$/\n\n/**\n * This regex checks for relative URLs starting with / or anchor links starting with # in a string. Tested for the following use cases:\n * - /privacy-policy\n * - /privacy-policy#primary-terms\n * - #primary-terms\n * */\nexport const relativeOrAnchorRegExp = /^(?:\\/[\\w\\-./]*(?:#\\w[\\w-]*)?|#[\\w\\-]+)$/\n\n/**\n * Prevents unreasonable URLs from being inserted into the editor.\n * @param url\n */\nexport function validateUrlMinimal(url: string): boolean {\n if (!url) {\n return false\n }\n\n return !url.includes(' ')\n}\n\n// Do not keep validateUrl function too loose. This is run when pasting in text, to determine if links are in that text and if it should create AutoLinkNodes.\n// This is why we do not allow stuff like anchors here, as we don't want copied anchors to be turned into AutoLinkNodes.\nexport function validateUrl(url: string): boolean {\n // TODO Fix UI for link insertion; it should never default to an invalid URL such as https://.\n // Maybe show a dialog where they user can type the URL before inserting it.\n\n if (!url) {\n return false\n }\n\n if (url === 'https://') {\n return true\n }\n\n // This makes sure URLs starting with www. instead of https are valid too\n if (absoluteRegExp.test(url)) {\n return true\n }\n\n // Check relative or anchor links\n if (relativeOrAnchorRegExp.test(url)) {\n return true\n }\n\n // While this doesn't allow URLs starting with www (which is why we use the regex above), it does properly handle tel: URLs\n try {\n new URL(url)\n return true\n } catch {\n /* empty */\n }\n\n return false\n}\n"],"mappings":"AAAA,OAAO,SAASA,YAAYC,GAAW;EACrC,yCACA,MAAMC,gBAAA,GAAmB;EAEzB;EACA,MAAMC,gBAAA,GACJ;EAEFF,GAAA,GAAMG,MAAA,CAAOH,GAAA,EAAKI,IAAI;EAEtB,IAAIJ,GAAA,CAAIK,KAAK,CAACJ,gBAAA,KAAqB,QAAQD,GAAA,CAAIK,KAAK,CAACH,gBAAA,KAAqB,MAAM;IAC9E,OAAOF,GAAA;EACT;EAEA,OAAO;AACT;AAEA;;;;;;;;;;;;AAYA,OAAO,MAAMM,cAAA,GACX;AAEF;;;;;;AAMA,OAAO,MAAMC,sBAAA,GAAyB;AAEtC;;;;AAIA,OAAO,SAASC,mBAAmBR,GAAW;EAC5C,IAAI,CAACA,GAAA,EAAK;IACR,OAAO;EACT;EAEA,OAAO,CAACA,GAAA,CAAIS,QAAQ,CAAC;AACvB;AAEA;AACA;AACA,OAAO,SAASC,YAAYV,GAAW;EACrC;EACA;EAEA,IAAI,CAACA,GAAA,EAAK;IACR,OAAO;EACT;EAEA,IAAIA,GAAA,KAAQ,YAAY;IACtB,OAAO;EACT;EAEA;EACA,IAAIM,cAAA,CAAeK,IAAI,CAACX,GAAA,GAAM;IAC5B,OAAO;EACT;EAEA;EACA,IAAIO,sBAAA,CAAuBI,IAAI,CAACX,GAAA,GAAM;IACpC,OAAO;EACT;EAEA;EACA,IAAI;IACF,IAAIY,GAAA,CAAIZ,GAAA;IACR,OAAO;EACT,EAAE,MAAM;IACN;EAGF,OAAO;AACT","ignoreList":[]}
1
+ {"version":3,"file":"url.js","names":["sanitizeUrl","url","SAFE_URL_PATTERN","DATA_URL_PATTERN","String","trim","match","absoluteRegExp","relativeOrAnchorRegExp","validateUrlMinimal","includes","validateUrl","test","urlObj","URL","protocol","hostname"],"sources":["../../../src/lexical/utils/url.ts"],"sourcesContent":["export function sanitizeUrl(url: string): string {\n /** A pattern that matches safe URLs. */\n const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^&:/?#]*(?:[/?#]|$))/gi\n\n /** A pattern that matches safe data URLs. */\n const DATA_URL_PATTERN =\n /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,[a-z\\d+/]+=*$/i\n\n url = String(url).trim()\n\n if (url.match(SAFE_URL_PATTERN) != null || url.match(DATA_URL_PATTERN) != null) {\n return url\n }\n\n return 'https://'\n}\n\n/**\n * This regex checks for absolute URLs in a string. Tested for the following use cases:\n * - http://example.com\n * - https://example.com\n * - ftp://files.example.com\n * - http://example.com/resource\n * - https://example.com/resource?key=value\n * - http://example.com/resource#anchor\n * - http://www.example.com\n * - https://sub.example.com/path/file\n * - mailto:\n */\nexport const absoluteRegExp =\n /^(?:[a-zA-Z][a-zA-Z\\d+.-]*:(?:\\/\\/)?(?:[-;:&=+$,\\w]+@)?[A-Za-z\\d]+(?:\\.[A-Za-z\\d]+)+|www\\.[A-Za-z\\d]+(?:\\.[A-Za-z\\d]+)+|(?:tel|mailto):[\\w+.-]+)(?:\\/[+~%/\\w-]*)?(?:\\?[-;&=%\\w]*)?(?:#\\w+)?$/\n\n/**\n * This regex checks for relative URLs starting with / or anchor links starting with # in a string. Tested for the following use cases:\n * - /privacy-policy\n * - /privacy-policy#primary-terms\n * - #primary-terms\n * - /page?id=123\n * - /page?id=123#section\n * */\nexport const relativeOrAnchorRegExp = /^(?:\\/[\\w\\-./]*(?:\\?[-;&=%\\w]*)?(?:#[\\w-]+)?|#[\\w\\-]+)$/\n\n/**\n * Prevents unreasonable URLs from being inserted into the editor.\n * @param url\n */\nexport function validateUrlMinimal(url: string): boolean {\n if (!url) {\n return false\n }\n\n return !url.includes(' ')\n}\n\n// Do not keep validateUrl function too loose. This is run when pasting in text, to determine if links are in that text and if it should create AutoLinkNodes.\n// This is why we do not allow stuff like anchors here, as we don't want copied anchors to be turned into AutoLinkNodes.\nexport function validateUrl(url: string): boolean {\n // TODO Fix UI for link insertion; it should never default to an invalid URL such as https://.\n // Maybe show a dialog where they user can type the URL before inserting it.\n if (!url) {\n return false\n }\n\n // Reject URLs with spaces\n if (url.includes(' ')) {\n return false\n }\n\n // Reject malformed protocol URLs (e.g., http:/example.com instead of http://example.com)\n if (/^[a-z][a-z\\d+.-]*:\\/[^/]/i.test(url)) {\n return false\n }\n\n if (url === 'https://') {\n return true\n }\n\n // This makes sure URLs starting with www. instead of https are valid too\n if (absoluteRegExp.test(url)) {\n return true\n }\n\n // Check relative or anchor links\n if (relativeOrAnchorRegExp.test(url)) {\n return true\n }\n\n // While this doesn't allow URLs starting with www (which is why we use the regex above), it does properly handle tel: URLs\n try {\n const urlObj = new URL(url)\n // For http/https/ftp protocols, require a proper domain with at least one dot (for TLD)\n if (['ftp:', 'http:', 'https:'].includes(urlObj.protocol)) {\n if (!urlObj.hostname.includes('.')) {\n return false\n }\n }\n return true\n } catch {\n /* empty */\n }\n\n return false\n}\n"],"mappings":"AAAA,OAAO,SAASA,YAAYC,GAAW;EACrC,yCACA,MAAMC,gBAAA,GAAmB;EAEzB;EACA,MAAMC,gBAAA,GACJ;EAEFF,GAAA,GAAMG,MAAA,CAAOH,GAAA,EAAKI,IAAI;EAEtB,IAAIJ,GAAA,CAAIK,KAAK,CAACJ,gBAAA,KAAqB,QAAQD,GAAA,CAAIK,KAAK,CAACH,gBAAA,KAAqB,MAAM;IAC9E,OAAOF,GAAA;EACT;EAEA,OAAO;AACT;AAEA;;;;;;;;;;;;AAYA,OAAO,MAAMM,cAAA,GACX;AAEF;;;;;;;;AAQA,OAAO,MAAMC,sBAAA,GAAyB;AAEtC;;;;AAIA,OAAO,SAASC,mBAAmBR,GAAW;EAC5C,IAAI,CAACA,GAAA,EAAK;IACR,OAAO;EACT;EAEA,OAAO,CAACA,GAAA,CAAIS,QAAQ,CAAC;AACvB;AAEA;AACA;AACA,OAAO,SAASC,YAAYV,GAAW;EACrC;EACA;EACA,IAAI,CAACA,GAAA,EAAK;IACR,OAAO;EACT;EAEA;EACA,IAAIA,GAAA,CAAIS,QAAQ,CAAC,MAAM;IACrB,OAAO;EACT;EAEA;EACA,IAAI,4BAA4BE,IAAI,CAACX,GAAA,GAAM;IACzC,OAAO;EACT;EAEA,IAAIA,GAAA,KAAQ,YAAY;IACtB,OAAO;EACT;EAEA;EACA,IAAIM,cAAA,CAAeK,IAAI,CAACX,GAAA,GAAM;IAC5B,OAAO;EACT;EAEA;EACA,IAAIO,sBAAA,CAAuBI,IAAI,CAACX,GAAA,GAAM;IACpC,OAAO;EACT;EAEA;EACA,IAAI;IACF,MAAMY,MAAA,GAAS,IAAIC,GAAA,CAAIb,GAAA;IACvB;IACA,IAAI,CAAC,QAAQ,SAAS,SAAS,CAACS,QAAQ,CAACG,MAAA,CAAOE,QAAQ,GAAG;MACzD,IAAI,CAACF,MAAA,CAAOG,QAAQ,CAACN,QAAQ,CAAC,MAAM;QAClC,OAAO;MACT;IACF;IACA,OAAO;EACT,EAAE,MAAM;IACN;EAGF,OAAO;AACT","ignoreList":[]}
@@ -1,8 +1,8 @@
1
- import { absoluteRegExp, relativeOrAnchorRegExp } from './url.js';
1
+ import { absoluteRegExp, relativeOrAnchorRegExp, validateUrl } from './url.js';
2
2
  describe('Lexical URL Regex Matchers', () => {
3
- describe('relative URLs', () => {
3
+ describe('relativeOrAnchorRegExp', () => {
4
4
  it('validation for links it should match', async () => {
5
- const shouldMatch = ['/path/to/resource', '/file-name.html', '/', '/dir/', '/path.with.dots/', '#anchor', '#section-title', '/path#fragment'];
5
+ const shouldMatch = ['/path/to/resource', '/file-name.html', '/', '/dir/', '/path.with.dots/', '#anchor', '#section-title', '/path#fragment', '/page?id=123', '/page?id=123#section', '/search?q=test', '/?global=true'];
6
6
  shouldMatch.forEach(testCase => {
7
7
  expect(relativeOrAnchorRegExp.test(testCase)).toBe(true);
8
8
  });
@@ -14,7 +14,7 @@ describe('Lexical URL Regex Matchers', () => {
14
14
  });
15
15
  });
16
16
  });
17
- describe('absolute URLs', () => {
17
+ describe('absoluteRegExp', () => {
18
18
  it('validation for links it should match', async () => {
19
19
  const shouldMatch = ['http://example.com', 'https://example.com', 'ftp://files.example.com', 'http://example.com/resource', 'https://example.com/resource?key=value', 'http://example.com/resource#anchor', 'http://www.example.com', 'https://sub.example.com/path/file', 'mailto:email@example.com', 'tel:+1234567890', 'http://user:pass@example.com', 'www.example.com', 'www.example.com/resource', 'www.example.com/resource?query=1', 'www.example.com#fragment'];
20
20
  shouldMatch.forEach(testCase => {
@@ -28,5 +28,86 @@ describe('Lexical URL Regex Matchers', () => {
28
28
  });
29
29
  });
30
30
  });
31
+ describe('validateUrl', () => {
32
+ describe('absolute URLs', () => {
33
+ it('should validate http and https URLs', () => {
34
+ const validUrls = ['http://example.com', 'https://example.com', 'http://www.example.com', 'https://sub.example.com/path/file', 'http://example.com/resource', 'https://example.com/resource?key=value', 'http://example.com/resource#anchor'];
35
+ validUrls.forEach(url => {
36
+ expect(validateUrl(url)).toBe(true);
37
+ });
38
+ });
39
+ it('should validate other protocol URLs', () => {
40
+ const validUrls = ['ftp://files.example.com', 'mailto:email@example.com', 'tel:+1234567890'];
41
+ validUrls.forEach(url => {
42
+ expect(validateUrl(url)).toBe(true);
43
+ });
44
+ });
45
+ it('should validate www URLs without protocol', () => {
46
+ const validUrls = ['www.example.com', 'www.example.com/resource', 'www.example.com/resource?query=1', 'www.example.com#fragment'];
47
+ validUrls.forEach(url => {
48
+ expect(validateUrl(url)).toBe(true);
49
+ });
50
+ });
51
+ });
52
+ describe('relative URLs', () => {
53
+ it('should validate relative paths', () => {
54
+ const validUrls = ['/path/to/resource', '/file-name.html', '/', '/dir/', '/path.with.dots/', '/path#fragment'];
55
+ validUrls.forEach(url => {
56
+ expect(validateUrl(url)).toBe(true);
57
+ });
58
+ });
59
+ });
60
+ describe('anchor links', () => {
61
+ it('should validate anchor links', () => {
62
+ const validUrls = ['#anchor', '#section-title'];
63
+ validUrls.forEach(url => {
64
+ expect(validateUrl(url)).toBe(true);
65
+ });
66
+ });
67
+ });
68
+ describe('with query params', () => {
69
+ it('should validate relative URLs with query parameters', () => {
70
+ const validUrls = ['/page?id=123', '/search?q=test', '/products?category=electronics&sort=price', '/path?key=value&another=param', '/page?id=123&filter=active', '/?global=true'];
71
+ validUrls.forEach(url => {
72
+ expect(validateUrl(url)).toBe(true);
73
+ });
74
+ });
75
+ it('should validate absolute URLs with query parameters', () => {
76
+ const validUrls = ['https://example.com?id=123', 'http://example.com/page?key=value', 'www.example.com?search=query', 'https://example.com/path?a=1&b=2&c=3'];
77
+ validUrls.forEach(url => {
78
+ expect(validateUrl(url)).toBe(true);
79
+ });
80
+ });
81
+ it('should validate URLs with query parameters and anchors', () => {
82
+ const validUrls = ['/page?id=123#section', 'https://example.com?key=value#anchor', '/search?q=test#results'];
83
+ validUrls.forEach(url => {
84
+ expect(validateUrl(url)).toBe(true);
85
+ });
86
+ });
87
+ });
88
+ describe('edge cases', () => {
89
+ it('should handle the default https:// case', () => {
90
+ expect(validateUrl('https://')).toBe(true);
91
+ });
92
+ it('should return false for empty or invalid URLs', () => {
93
+ const invalidUrls = ['', 'not-a-url', 'example.com', 'relative/path', 'file.html', 'some#fragment', 'http://', 'http:/example.com', 'http//example.com'];
94
+ invalidUrls.forEach(url => {
95
+ expect(validateUrl(url)).toBe(false);
96
+ });
97
+ });
98
+ it('should return false for URLs with spaces', () => {
99
+ const invalidUrls = ['/path/with spaces', 'http://example.com/ spaces', 'https://example.com/path with spaces'];
100
+ invalidUrls.forEach(url => {
101
+ expect(validateUrl(url)).toBe(false);
102
+ });
103
+ });
104
+ it('should return false for malformed URLs', () => {
105
+ const invalidUrls = ['://missing.scheme', 'ftp://example .com', 'http://example', '#', '/#'];
106
+ invalidUrls.forEach(url => {
107
+ expect(validateUrl(url)).toBe(false);
108
+ });
109
+ });
110
+ });
111
+ });
31
112
  });
32
113
  //# sourceMappingURL=url.spec.js.map