draftjs_exporter 5.2.0__tar.gz → 6.0.0__tar.gz

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 (53) hide show
  1. draftjs_exporter-6.0.0/PKG-INFO +75 -0
  2. draftjs_exporter-6.0.0/README.md +38 -0
  3. draftjs_exporter-6.0.0/draftjs_exporter/__init__.py +98 -0
  4. draftjs_exporter-6.0.0/draftjs_exporter/command.py +69 -0
  5. draftjs_exporter-6.0.0/draftjs_exporter/composite_decorators.py +137 -0
  6. {draftjs_exporter-5.2.0 → draftjs_exporter-6.0.0}/draftjs_exporter/constants.py +29 -0
  7. {draftjs_exporter-5.2.0 → draftjs_exporter-6.0.0}/draftjs_exporter/defaults.py +14 -7
  8. draftjs_exporter-6.0.0/draftjs_exporter/dom.py +183 -0
  9. draftjs_exporter-6.0.0/draftjs_exporter/engines/__init__.py +1 -0
  10. draftjs_exporter-6.0.0/draftjs_exporter/engines/base.py +79 -0
  11. draftjs_exporter-6.0.0/draftjs_exporter/engines/html5lib.py +89 -0
  12. draftjs_exporter-6.0.0/draftjs_exporter/engines/lxml.py +108 -0
  13. draftjs_exporter-6.0.0/draftjs_exporter/engines/markdown.py +172 -0
  14. draftjs_exporter-6.0.0/draftjs_exporter/engines/string.py +188 -0
  15. {draftjs_exporter-5.2.0 → draftjs_exporter-6.0.0}/draftjs_exporter/engines/string_compat.py +38 -7
  16. draftjs_exporter-6.0.0/draftjs_exporter/entity_state.py +155 -0
  17. draftjs_exporter-6.0.0/draftjs_exporter/error.py +9 -0
  18. draftjs_exporter-6.0.0/draftjs_exporter/html.py +263 -0
  19. draftjs_exporter-6.0.0/draftjs_exporter/markdown/__init__.py +222 -0
  20. draftjs_exporter-6.0.0/draftjs_exporter/markdown/blocks.py +62 -0
  21. draftjs_exporter-6.0.0/draftjs_exporter/markdown/code.py +42 -0
  22. draftjs_exporter-6.0.0/draftjs_exporter/markdown/entities.py +43 -0
  23. draftjs_exporter-6.0.0/draftjs_exporter/markdown/fallbacks.py +50 -0
  24. draftjs_exporter-6.0.0/draftjs_exporter/markdown/helpers.py +28 -0
  25. draftjs_exporter-6.0.0/draftjs_exporter/markdown/lists.py +106 -0
  26. draftjs_exporter-6.0.0/draftjs_exporter/markdown/styles.py +16 -0
  27. draftjs_exporter-6.0.0/draftjs_exporter/options.py +185 -0
  28. draftjs_exporter-6.0.0/draftjs_exporter/style_state.py +143 -0
  29. draftjs_exporter-6.0.0/draftjs_exporter/types.py +111 -0
  30. draftjs_exporter-6.0.0/draftjs_exporter/utils/__init__.py +1 -0
  31. {draftjs_exporter-5.2.0 → draftjs_exporter-6.0.0}/draftjs_exporter/utils/module_loading.py +16 -7
  32. {draftjs_exporter-5.2.0 → draftjs_exporter-6.0.0}/draftjs_exporter/wrapper_state.py +115 -30
  33. {draftjs_exporter-5.2.0 → draftjs_exporter-6.0.0}/pyproject.toml +56 -16
  34. draftjs_exporter-5.2.0/LICENSE +0 -9
  35. draftjs_exporter-5.2.0/PKG-INFO +0 -376
  36. draftjs_exporter-5.2.0/README.md +0 -330
  37. draftjs_exporter-5.2.0/draftjs_exporter/__init__.py +0 -5
  38. draftjs_exporter-5.2.0/draftjs_exporter/command.py +0 -56
  39. draftjs_exporter-5.2.0/draftjs_exporter/composite_decorators.py +0 -93
  40. draftjs_exporter-5.2.0/draftjs_exporter/dom.py +0 -129
  41. draftjs_exporter-5.2.0/draftjs_exporter/engines/__init__.py +0 -0
  42. draftjs_exporter-5.2.0/draftjs_exporter/engines/base.py +0 -50
  43. draftjs_exporter-5.2.0/draftjs_exporter/engines/html5lib.py +0 -45
  44. draftjs_exporter-5.2.0/draftjs_exporter/engines/lxml.py +0 -49
  45. draftjs_exporter-5.2.0/draftjs_exporter/engines/string.py +0 -116
  46. draftjs_exporter-5.2.0/draftjs_exporter/entity_state.py +0 -108
  47. draftjs_exporter-5.2.0/draftjs_exporter/error.py +0 -6
  48. draftjs_exporter-5.2.0/draftjs_exporter/html.py +0 -180
  49. draftjs_exporter-5.2.0/draftjs_exporter/options.py +0 -105
  50. draftjs_exporter-5.2.0/draftjs_exporter/style_state.py +0 -49
  51. draftjs_exporter-5.2.0/draftjs_exporter/types.py +0 -35
  52. draftjs_exporter-5.2.0/draftjs_exporter/utils/__init__.py +0 -0
  53. {draftjs_exporter-5.2.0 → draftjs_exporter-6.0.0}/draftjs_exporter/py.typed +0 -0
@@ -0,0 +1,75 @@
1
+ Metadata-Version: 2.4
2
+ Name: draftjs_exporter
3
+ Version: 6.0.0
4
+ Summary: Library to convert rich text from Draft.js raw ContentState to HTML
5
+ License-Expression: MIT
6
+ Classifier: Environment :: Web Environment
7
+ Classifier: Intended Audience :: Developers
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Programming Language :: Python
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Programming Language :: Python :: 3.15
18
+ Classifier: Topic :: Internet :: WWW/HTTP
19
+ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
20
+ Classifier: Topic :: Internet :: WWW/HTTP :: Site Management
21
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Classifier: Topic :: Text Editors :: Word Processors
24
+ Classifier: Typing :: Typed
25
+ Requires-Dist: beautifulsoup4>=4.4.1,<5 ; extra == 'html5lib'
26
+ Requires-Dist: html5lib>=0.999,<2 ; extra == 'html5lib'
27
+ Requires-Dist: lxml>=4.6.5,<7 ; extra == 'lxml'
28
+ Requires-Python: >=3.10
29
+ Project-URL: Documentation, https://wagtail.github.io/draftjs_exporter/
30
+ Project-URL: Source, https://github.com/wagtail/draftjs_exporter
31
+ Project-URL: Tracker, https://github.com/wagtail/draftjs_exporter/issues
32
+ Project-URL: Changelog, https://github.com/wagtail/draftjs_exporter/blob/main/CHANGELOG.md
33
+ Project-URL: llms.txt, https://wagtail.github.io/draftjs_exporter/llms.txt
34
+ Provides-Extra: html5lib
35
+ Provides-Extra: lxml
36
+ Description-Content-Type: text/markdown
37
+
38
+ # [Draft.js exporter](https://pypi.org/project/draftjs_exporter/)
39
+
40
+ > Library to convert rich text from Draft.js raw ContentState to HTML.
41
+
42
+ ## Features
43
+
44
+ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html), and [measures performance](https://thib.me/python-memory-profiling-for-the-draft-js-exporter) and [code coverage](https://coveralls.io/github/wagtail/draftjs_exporter). Code is checked with [mypy](https://mypy.readthedocs.io/en/latest/index.html).
45
+
46
+ - Extensive configuration of the generated HTML.
47
+ - Default, extensible block & inline style maps for common HTML elements.
48
+ - Convert line breaks to `<br>` elements with decorators.
49
+ - Define any attribute in the block map – custom class names for elements.
50
+ - React-like API to create custom components.
51
+ - Automatic conversion of entity data to HTML attributes (int & boolean to string, style object to style string).
52
+ - Nested lists (`<li>` elements go inside `<ul>` or `<ol>`, with multiple levels).
53
+ - Output inline styles as inline elements (`<em>`, `<strong>`, pick and choose, with any attribute).
54
+ - Overlapping inline style and entity ranges.
55
+ - Static type annotations.
56
+
57
+ It is developed alongside the [Draftail](https://www.draftail.org/) rich text editor, for [Wagtail](https://github.com/wagtail/wagtail). Check out the [online demo](http://playground.draftail.org/), and our [introductory blog post](https://www.draftail.org/blog/2018/03/13/rethinking-rich-text-pipelines-with-draft-js).
58
+
59
+ ## When to use the exporter
60
+
61
+ [Draft.js](https://draftjs.org/) is a rich text editor framework for [React](https://reactjs.org/). Its approach is different from most rich text editors because it does not store data as HTML, but rather in its own representation called ContentState. This exporter is useful when the ContentState to HTML conversion has to be done in a Python ecosystem.
62
+
63
+ The initial use case was to gain more control over the content managed by rich text editors in a Wagtail/Django site. If you want to read the full story, have a look at our blog post: [Rethinking rich text pipelines with Draft.js](https://www.draftail.org/blog/2018/03/13/rethinking-rich-text-pipelines-with-draft-js).
64
+
65
+ ## Documentation
66
+
67
+ The full documentation is available at [on the docs website](https://wagtail.github.io/draftjs_exporter/). For LLM-assisted tooling, there is also a concise [`llms.txt`](https://wagtail.github.io/draftjs_exporter/llms.txt) and a complete [`llms-full.txt`](https://wagtail.github.io/draftjs_exporter/llms-full.txt).
68
+
69
+ ## Contributing
70
+
71
+ See anything you like in here? Anything missing? We welcome all support, whether on bug reports, feature requests, code, design, reviews, tests, documentation, and more. Please have a look at our [contribution guidelines](docs/CONTRIBUTING.md).
72
+
73
+ ## Credits
74
+
75
+ Draftail was created by [Springload](https://github.com/springload/), and is now maintained by Wagtail contributors. View the full list of [contributors](https://github.com/wagtail/draftjs_exporter/graphs/contributors). MIT licensed.
@@ -0,0 +1,38 @@
1
+ # [Draft.js exporter](https://pypi.org/project/draftjs_exporter/)
2
+
3
+ > Library to convert rich text from Draft.js raw ContentState to HTML.
4
+
5
+ ## Features
6
+
7
+ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html), and [measures performance](https://thib.me/python-memory-profiling-for-the-draft-js-exporter) and [code coverage](https://coveralls.io/github/wagtail/draftjs_exporter). Code is checked with [mypy](https://mypy.readthedocs.io/en/latest/index.html).
8
+
9
+ - Extensive configuration of the generated HTML.
10
+ - Default, extensible block & inline style maps for common HTML elements.
11
+ - Convert line breaks to `<br>` elements with decorators.
12
+ - Define any attribute in the block map – custom class names for elements.
13
+ - React-like API to create custom components.
14
+ - Automatic conversion of entity data to HTML attributes (int & boolean to string, style object to style string).
15
+ - Nested lists (`<li>` elements go inside `<ul>` or `<ol>`, with multiple levels).
16
+ - Output inline styles as inline elements (`<em>`, `<strong>`, pick and choose, with any attribute).
17
+ - Overlapping inline style and entity ranges.
18
+ - Static type annotations.
19
+
20
+ It is developed alongside the [Draftail](https://www.draftail.org/) rich text editor, for [Wagtail](https://github.com/wagtail/wagtail). Check out the [online demo](http://playground.draftail.org/), and our [introductory blog post](https://www.draftail.org/blog/2018/03/13/rethinking-rich-text-pipelines-with-draft-js).
21
+
22
+ ## When to use the exporter
23
+
24
+ [Draft.js](https://draftjs.org/) is a rich text editor framework for [React](https://reactjs.org/). Its approach is different from most rich text editors because it does not store data as HTML, but rather in its own representation called ContentState. This exporter is useful when the ContentState to HTML conversion has to be done in a Python ecosystem.
25
+
26
+ The initial use case was to gain more control over the content managed by rich text editors in a Wagtail/Django site. If you want to read the full story, have a look at our blog post: [Rethinking rich text pipelines with Draft.js](https://www.draftail.org/blog/2018/03/13/rethinking-rich-text-pipelines-with-draft-js).
27
+
28
+ ## Documentation
29
+
30
+ The full documentation is available at [on the docs website](https://wagtail.github.io/draftjs_exporter/). For LLM-assisted tooling, there is also a concise [`llms.txt`](https://wagtail.github.io/draftjs_exporter/llms.txt) and a complete [`llms-full.txt`](https://wagtail.github.io/draftjs_exporter/llms-full.txt).
31
+
32
+ ## Contributing
33
+
34
+ See anything you like in here? Anything missing? We welcome all support, whether on bug reports, feature requests, code, design, reviews, tests, documentation, and more. Please have a look at our [contribution guidelines](docs/CONTRIBUTING.md).
35
+
36
+ ## Credits
37
+
38
+ Draftail was created by [Springload](https://github.com/springload/), and is now maintained by Wagtail contributors. View the full list of [contributors](https://github.com/wagtail/draftjs_exporter/graphs/contributors). MIT licensed.
@@ -0,0 +1,98 @@
1
+ """Public API and metadata of draftjs_exporter.
2
+
3
+ This module gathers metadata, core classes, default configuration maps,
4
+ type aliases, and helpers so callers can import everything from
5
+ ``draftjs_exporter`` directly.
6
+ """
7
+
8
+ __title__ = "draftjs_exporter"
9
+ __version__ = "6.0.0"
10
+ __uri__ = "https://wagtail.github.io/draftjs_exporter/"
11
+ __author__ = "Springload and Contributors"
12
+ __license__ = "MIT"
13
+ __copyright__ = "Copyright 2016-present Springload and Contributors"
14
+
15
+ from draftjs_exporter.constants import BLOCK_TYPES as BLOCK_TYPES
16
+ from draftjs_exporter.constants import ENTITY_TYPES as ENTITY_TYPES
17
+ from draftjs_exporter.constants import INLINE_STYLES as INLINE_STYLES
18
+ from draftjs_exporter.defaults import BLOCK_MAP as BLOCK_MAP
19
+ from draftjs_exporter.defaults import STYLE_MAP as STYLE_MAP
20
+ from draftjs_exporter.dom import DOM as DOM
21
+ from draftjs_exporter.html import HTML as HTML
22
+ from draftjs_exporter.html import ExporterConfig as ExporterConfig
23
+ from draftjs_exporter.markdown import CONFIG as MARKDOWN_CONFIG
24
+ from draftjs_exporter.markdown import MarkdownOptions as MarkdownOptions
25
+ from draftjs_exporter.markdown import build_markdown_config as build_markdown_config
26
+ from draftjs_exporter.types import Block as Block
27
+ from draftjs_exporter.types import Component as Component
28
+ from draftjs_exporter.types import CompositeDecorators as CompositeDecorators
29
+ from draftjs_exporter.types import ConfigMap as ConfigMap
30
+ from draftjs_exporter.types import ContentState as ContentState
31
+ from draftjs_exporter.types import Decorator as Decorator
32
+ from draftjs_exporter.types import Element as Element
33
+ from draftjs_exporter.types import Entity as Entity
34
+ from draftjs_exporter.types import EntityKey as EntityKey
35
+ from draftjs_exporter.types import EntityMap as EntityMap
36
+ from draftjs_exporter.types import EntityRange as EntityRange
37
+ from draftjs_exporter.types import InlineStyleRange as InlineStyleRange
38
+ from draftjs_exporter.types import Mutability as Mutability
39
+ from draftjs_exporter.types import Props as Props
40
+ from draftjs_exporter.types import RenderableConfig as RenderableConfig
41
+ from draftjs_exporter.types import RenderableType as RenderableType
42
+ from draftjs_exporter.types import Tag as Tag
43
+
44
+ __all__ = [
45
+ # Metadata
46
+ "__title__",
47
+ "__version__",
48
+ "__uri__",
49
+ "__author__",
50
+ "__license__",
51
+ "__copyright__",
52
+ # Core
53
+ "Exporter",
54
+ "HTML",
55
+ "ExporterConfig",
56
+ "ContentState",
57
+ "DOM",
58
+ # Configs
59
+ "HTML_CONFIG",
60
+ "MARKDOWN_CONFIG",
61
+ "MarkdownOptions",
62
+ "build_markdown_config",
63
+ # Constants
64
+ "BLOCK_TYPES",
65
+ "ENTITY_TYPES",
66
+ "INLINE_STYLES",
67
+ # Default maps
68
+ "BLOCK_MAP",
69
+ "STYLE_MAP",
70
+ # Types
71
+ "Block",
72
+ "Component",
73
+ "CompositeDecorators",
74
+ "ConfigMap",
75
+ "ContentState",
76
+ "Decorator",
77
+ "Element",
78
+ "Entity",
79
+ "EntityKey",
80
+ "EntityMap",
81
+ "EntityRange",
82
+ "InlineStyleRange",
83
+ "Mutability",
84
+ "Props",
85
+ "RenderableConfig",
86
+ "RenderableType",
87
+ "Tag",
88
+ ]
89
+
90
+ Exporter = HTML
91
+ """Compatibility alias for the HTML exporter."""
92
+
93
+ HTML_CONFIG: ExporterConfig = {
94
+ "block_map": BLOCK_MAP,
95
+ "style_map": STYLE_MAP,
96
+ "engine": DOM.STRING,
97
+ }
98
+ """Default exporter configuration using the built-in maps and string engine."""
@@ -0,0 +1,69 @@
1
+ """Represent and build rendering commands derived from Draft.js ranges."""
2
+
3
+ from draftjs_exporter.types import Block
4
+
5
+
6
+ class Command:
7
+ """Represent an operation applied while converting a block to HTML nodes."""
8
+
9
+ __slots__ = ("name", "index", "data")
10
+
11
+ def __init__(self, name: str, index: int, data: str = "") -> None:
12
+ """Initialize a command.
13
+
14
+ Parameters:
15
+ name: The operation name, such as ``start_entity`` or ``stop_inline_style``.
16
+ index: The character offset at which the command applies.
17
+ data: The payload for the command, such as an entity key or style name.
18
+ """
19
+ self.name = name
20
+ self.index = index
21
+ self.data = data
22
+
23
+ def __str__(self) -> str:
24
+ """Return a human-readable representation of the command."""
25
+ return f"<Command {self.name} {self.index} {self.data}>"
26
+
27
+ def __repr__(self) -> str:
28
+ """Return the same representation as ``__str__`` for debugging."""
29
+ return str(self)
30
+
31
+ @staticmethod
32
+ def from_entity_ranges(block: Block) -> list["Command"]:
33
+ """Create start and stop commands from a block's entity ranges.
34
+
35
+ Parameters:
36
+ block: The block containing ``entityRanges``.
37
+
38
+ Returns:
39
+ A list of start_entity and stop_entity commands.
40
+ """
41
+ commands: list["Command"] = []
42
+ for r in block.get("entityRanges", []):
43
+ # Entity key is an integer in entity ranges, while a string in the entity map.
44
+ data = str(r["key"])
45
+ start = r["offset"]
46
+ stop = start + r["length"]
47
+ commands.append(Command("start_entity", start, data))
48
+ commands.append(Command("stop_entity", stop, data))
49
+
50
+ return commands
51
+
52
+ @staticmethod
53
+ def from_style_ranges(block: Block) -> list["Command"]:
54
+ """Create start and stop commands from a block's inline style ranges.
55
+
56
+ Parameters:
57
+ block: The block containing ``inlineStyleRanges``.
58
+
59
+ Returns:
60
+ A list of start_inline_style and stop_inline_style commands.
61
+ """
62
+ commands: list["Command"] = []
63
+ for r in block.get("inlineStyleRanges", []):
64
+ data = r["style"]
65
+ start = r["offset"]
66
+ stop = start + r["length"]
67
+ commands.append(Command("start_inline_style", start, data))
68
+ commands.append(Command("stop_inline_style", stop, data))
69
+ return commands
@@ -0,0 +1,137 @@
1
+ """Apply regex-based composite decorators to text while rendering blocks."""
2
+
3
+ import re
4
+ from collections.abc import Generator
5
+ from operator import itemgetter
6
+ from typing import Any
7
+
8
+ from draftjs_exporter.dom import DOM
9
+ from draftjs_exporter.engines.base import DOMEngine
10
+ from draftjs_exporter.types import Block, CompositeDecorators, Decorator, Element
11
+
12
+ br = "\n"
13
+ """Line-break character handled by the default decorator strategy."""
14
+
15
+ br_strategy = re.compile(r"\n")
16
+ """Default decorator strategy matching single line breaks."""
17
+
18
+
19
+ def get_decorations(
20
+ decorators: CompositeDecorators, text: str
21
+ ) -> list[tuple[int, int, Any, Decorator]]:
22
+ """Collect non-overlapping decorator matches for the given text.
23
+
24
+ Parameters:
25
+ decorators: Composite decorator definitions.
26
+ text: The block text to decorate.
27
+
28
+ Returns:
29
+ A sorted list of decorations as ``(start, end, match, decorator)`` tuples.
30
+ """
31
+ occupied: dict[int, int] = {}
32
+ decorations = []
33
+
34
+ for decorator in decorators:
35
+ for match in decorator["strategy"].finditer(text):
36
+ begin, end = match.span()
37
+ if not any(occupied.get(i) for i in range(begin, end)):
38
+ for i in range(begin, end):
39
+ occupied[i] = 1
40
+ decorations.append((begin, end, match, decorator))
41
+
42
+ decorations.sort(key=itemgetter(0))
43
+
44
+ return decorations
45
+
46
+
47
+ def apply_decorators(
48
+ decorators: CompositeDecorators,
49
+ text: str,
50
+ block: Block,
51
+ blocks: list[Block],
52
+ ) -> Generator[str, None, None]:
53
+ """Yield decorated text segments and decorator elements for a block.
54
+
55
+ Parameters:
56
+ decorators: Composite decorator definitions.
57
+ text: The block text to decorate.
58
+ block: The block currently being rendered.
59
+ blocks: All blocks in the content state.
60
+
61
+ Yields:
62
+ Plain text or decorator element nodes covering the full block text.
63
+ """
64
+ decorations = get_decorations(decorators, text)
65
+
66
+ pointer = 0
67
+ for begin, end, match, decorator in decorations:
68
+ if pointer < begin:
69
+ yield text[pointer:begin]
70
+
71
+ yield DOM.create_element(
72
+ decorator["component"],
73
+ {"match": match, "block": block, "blocks": blocks},
74
+ match.group(0),
75
+ )
76
+ pointer = end
77
+
78
+ if pointer < len(text):
79
+ yield text[pointer:]
80
+
81
+
82
+ def render_decorators(
83
+ decorators: CompositeDecorators,
84
+ text: str,
85
+ block: Block,
86
+ blocks: list[Block],
87
+ dom: type[DOMEngine],
88
+ ) -> Element:
89
+ """Render all decorator output for a block into a single element.
90
+
91
+ Parameters:
92
+ decorators: Composite decorator definitions.
93
+ text: The block text to decorate.
94
+ block: The block currently being rendered.
95
+ blocks: All blocks in the content state.
96
+ dom: The active DOM engine.
97
+
98
+ Returns:
99
+ A single element containing all decorated text, or the text itself.
100
+ """
101
+ decorated_children = list(apply_decorators(decorators, text, block, blocks))
102
+
103
+ if len(decorated_children) == 1:
104
+ decorated_node = decorated_children[0]
105
+ else:
106
+ decorated_node = DOM.create_element()
107
+ for decorated_child in decorated_children:
108
+ dom.append_child(decorated_node, decorated_child)
109
+
110
+ return decorated_node
111
+
112
+
113
+ def should_render_decorators(
114
+ decorators: CompositeDecorators,
115
+ text: str,
116
+ ) -> bool:
117
+ """Return whether decorators need to be processed for the given text.
118
+
119
+ Parameters:
120
+ decorators: Composite decorator definitions.
121
+ text: The block text to check.
122
+
123
+ Returns:
124
+ True when there are decorators and the default newline-only optimization does not apply.
125
+ """
126
+ nb_decorators = len(decorators)
127
+
128
+ if nb_decorators == 0:
129
+ return False
130
+
131
+ is_skippable_br = (
132
+ nb_decorators == 1
133
+ and decorators[0]["strategy"] == br_strategy
134
+ and br not in text
135
+ )
136
+
137
+ return not is_skippable_br
@@ -1,11 +1,36 @@
1
+ """Draft.js-compatible constants used by the exporter.
2
+
3
+ Defines the block types, inline styles, and entity categories supported
4
+ by Draft.js, plus a small enum helper.
5
+ """
6
+
7
+
1
8
  # http://stackoverflow.com/a/22723724/1798491
2
9
  class Enum:
10
+ """Minimal enum-like container exposing a fixed set of string attributes.
11
+
12
+ Accessing a registered attribute returns its name. Accessing any other
13
+ attribute raises ``AttributeError``.
14
+ """
15
+
3
16
  __slots__ = "elements"
4
17
 
5
18
  def __init__(self, *elements: str) -> None:
19
+ """Store the allowed attribute names for the enum."""
6
20
  self.elements = tuple(elements)
7
21
 
8
22
  def __getattr__(self, name: str) -> str:
23
+ """Return the attribute name if it is a registered enum element.
24
+
25
+ Parameters:
26
+ name: Attribute name being accessed.
27
+
28
+ Returns:
29
+ The requested attribute name.
30
+
31
+ Raises:
32
+ AttributeError: If the name is not a registered element.
33
+ """
9
34
  if name not in self.elements:
10
35
  raise AttributeError(f"'Enum' has no attribute '{name}'")
11
36
 
@@ -14,6 +39,8 @@ class Enum:
14
39
 
15
40
  # https://github.com/facebook/draft-js/blob/master/src/model/constants/DraftBlockType.js
16
41
  class BLOCK_TYPES:
42
+ """Draft.js block types mapped to HTML elements."""
43
+
17
44
  UNSTYLED = "unstyled"
18
45
  HEADER_ONE = "header-one"
19
46
  HEADER_TWO = "header-two"
@@ -40,6 +67,7 @@ ENTITY_TYPES = Enum(
40
67
  # Special type to configure handling of missing components.
41
68
  "FALLBACK",
42
69
  )
70
+ """Draft.js entity categories."""
43
71
 
44
72
  INLINE_STYLES = Enum(
45
73
  "BOLD",
@@ -59,3 +87,4 @@ INLINE_STYLES = Enum(
59
87
  # Special type to configure handling of missing components.
60
88
  "FALLBACK",
61
89
  )
90
+ """Draft.js inline style names."""
@@ -1,24 +1,28 @@
1
+ """Default block and style maps for the exporter.
2
+
3
+ The mappings connect Draft.js block types and inline styles to HTML
4
+ tags or component functions.
5
+ """
6
+
1
7
  from draftjs_exporter.constants import BLOCK_TYPES, INLINE_STYLES
2
8
  from draftjs_exporter.dom import DOM
3
- from draftjs_exporter.types import Element, Props
9
+ from draftjs_exporter.types import ConfigMap, Element, Props
4
10
 
5
11
 
6
12
  def render_children(props: Props) -> Element:
7
- """
8
- Renders the children of a component without any specific
9
- markup for the component itself.
10
- """
13
+ """Return the children of a component without wrapping markup."""
11
14
  return props["children"]
12
15
 
13
16
 
14
17
  def code_block(props: Props) -> Element:
18
+ """Render a code block inside a ``pre`` > ``code`` element tree."""
15
19
  return DOM.create_element(
16
20
  "pre", {}, DOM.create_element("code", {}, props["children"])
17
21
  )
18
22
 
19
23
 
20
24
  # Default block map to extend.
21
- BLOCK_MAP = {
25
+ BLOCK_MAP: ConfigMap = {
22
26
  BLOCK_TYPES.UNSTYLED: "p",
23
27
  BLOCK_TYPES.HEADER_ONE: "h1",
24
28
  BLOCK_TYPES.HEADER_TWO: "h2",
@@ -33,12 +37,14 @@ BLOCK_MAP = {
33
37
  BLOCK_TYPES.CODE: code_block,
34
38
  BLOCK_TYPES.ATOMIC: render_children,
35
39
  }
40
+ """Default mapping from block types to renderable tags or components."""
41
+
36
42
 
37
43
  # Default style map to extend.
38
44
  # Tags come from https://developer.mozilla.org/en-US/docs/Web/HTML/Element.
39
45
  # and are loosely aligned with https://github.com/jpuri/draftjs-to-html.
40
46
  # Only styles that map to HTML elements are allowed as defaults.
41
- STYLE_MAP = {
47
+ STYLE_MAP: ConfigMap = {
42
48
  INLINE_STYLES.BOLD: "strong",
43
49
  INLINE_STYLES.CODE: "code",
44
50
  INLINE_STYLES.ITALIC: "em",
@@ -54,3 +60,4 @@ STYLE_MAP = {
54
60
  INLINE_STYLES.DELETE: "del",
55
61
  INLINE_STYLES.KEYBOARD: "kbd",
56
62
  }
63
+ """Default mapping from inline styles to HTML tags."""