pymdownx-mahjong 1.1.0__py3-none-any.whl → 1.2.0__py3-none-any.whl

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.
@@ -4,7 +4,7 @@ from .extension import MahjongExtension, makeExtension
4
4
  from .inline import INLINE_TILE_PATTERN, MahjongInlineProcessor
5
5
  from .parser import Hand, MahjongParser, Meld, Tile
6
6
  from .renderer import MahjongRenderer
7
- from .superfences import superfences_formatter, superfences_validator
7
+ from .superfences import configure_superfences, superfences_formatter, superfences_validator
8
8
 
9
9
  __all__ = [
10
10
  "MahjongExtension",
@@ -18,6 +18,7 @@ __all__ = [
18
18
  "Hand",
19
19
  "superfences_formatter",
20
20
  "superfences_validator",
21
+ "configure_superfences",
21
22
  ]
22
23
 
23
- __version__ = "1.1.0"
24
+ __version__ = "1.2.0"
@@ -19,6 +19,15 @@ if TYPE_CHECKING:
19
19
  from markdown.blockparser import BlockParser
20
20
 
21
21
 
22
+ def _to_bool(value: Any) -> bool:
23
+ """Convert a value to boolean, handling string 'true'/'false'."""
24
+ if isinstance(value, bool):
25
+ return value
26
+ if isinstance(value, str):
27
+ return value.lower() in ("true", "1", "yes")
28
+ return bool(value)
29
+
30
+
22
31
  class MahjongBlockProcessor(BlockProcessor):
23
32
  """Block processor that handles ```mahjong fenced code blocks.
24
33
 
@@ -43,10 +52,9 @@ class MahjongBlockProcessor(BlockProcessor):
43
52
  self.mj_parser = MahjongParser()
44
53
  self.renderer = MahjongRenderer(
45
54
  theme=config.get("theme", "light"),
46
- css_class=config.get("css_class", "mahjong-hand"),
47
- show_labels=config.get("show_labels", True),
48
- inline_svg=config.get("inline_svg", True),
55
+ inline_svg=_to_bool(config.get("inline_svg", True)),
49
56
  assets_path=config.get("assets_path"),
57
+ closed_kan_style=config.get("closed_kan_style", "outer"),
50
58
  )
51
59
 
52
60
  def test(self, parent: etree.Element, block: str) -> bool:
@@ -158,13 +166,13 @@ class MahjongExtension(markdown.Extension):
158
166
  **kwargs: Configuration options
159
167
  """
160
168
  # Define configuration options with defaults
169
+ # Note: Use strings for boolean defaults for YAML compatibility
161
170
  self.config = {
162
171
  "theme": ["auto", "Color theme: 'light', 'dark', or 'auto'"],
163
- "css_class": ["mahjong-hand", "CSS class for container"],
164
- "show_labels": [True, "Show tile names as title attributes"],
165
- "inline_svg": [True, "Inline SVG content vs img tags"],
172
+ "inline_svg": ["true", "Inline SVG content vs img tags"],
166
173
  "assets_path": ["", "Custom path to SVG assets"],
167
- "enable_inline": [True, "Enable inline tile syntax (:1m:)"],
174
+ "enable_inline": ["true", "Enable inline tile syntax (:1m:)"],
175
+ "closed_kan_style": ["outer", "Closed kan style: 'outer' or 'inner'"],
168
176
  }
169
177
  super().__init__(**kwargs)
170
178
 
@@ -184,7 +192,7 @@ class MahjongExtension(markdown.Extension):
184
192
 
185
193
  # Register inline processor if enabled
186
194
  # Priority 76 to run before pymdownx.emoji (which uses 75)
187
- if config.get("enable_inline", True):
195
+ if _to_bool(config.get("enable_inline", True)):
188
196
  inline_processor = MahjongInlineProcessor(INLINE_TILE_PATTERN, md, config)
189
197
  md.inlinePatterns.register(inline_processor, "mahjong_inline", 76)
190
198
 
@@ -20,6 +20,15 @@ if TYPE_CHECKING:
20
20
  INLINE_TILE_PATTERN: Final[str] = r":([0-9]+[mpsz])+:"
21
21
 
22
22
 
23
+ def _to_bool(value: Any) -> bool:
24
+ """Convert a value to boolean, handling string 'true'/'false'."""
25
+ if isinstance(value, bool):
26
+ return value
27
+ if isinstance(value, str):
28
+ return value.lower() in ("true", "1", "yes")
29
+ return bool(value)
30
+
31
+
23
32
  class MahjongInlineProcessor(InlineProcessor):
24
33
  """Inline processor for mahjong tile notation.
25
34
 
@@ -40,10 +49,9 @@ class MahjongInlineProcessor(InlineProcessor):
40
49
  self.parser = MahjongParser()
41
50
  self.renderer = MahjongRenderer(
42
51
  theme=config.get("theme", "auto"),
43
- css_class="mahjong-inline",
44
- show_labels=config.get("show_labels", True),
45
- inline_svg=config.get("inline_svg", True),
52
+ inline_svg=_to_bool(config.get("inline_svg", True)),
46
53
  assets_path=config.get("assets_path"),
54
+ css_class="mahjong-inline",
47
55
  )
48
56
 
49
57
  def handleMatch(self, m: re.Match, data: str) -> tuple[str | None, int | None, int | None]:
@@ -50,9 +50,8 @@ class MahjongRenderer:
50
50
 
51
51
  Configuration options:
52
52
  theme: 'light', 'dark', or 'auto'
53
- css_class: CSS class for the container
54
- show_labels: Whether to show tile names as titles
55
- inline_svg: Whether to inline SVG or use img tags
53
+ closed_kan_style: 'outer' (default) or 'inner'
54
+ inline_svg: Whether to inline SVG content (vs using img tags)
56
55
  """
57
56
 
58
57
  DEFAULT_TILE_WIDTH = 45
@@ -63,19 +62,21 @@ class MahjongRenderer:
63
62
  def __init__(
64
63
  self,
65
64
  theme: str = "light",
66
- css_class: str = "mahjong-hand",
67
- show_labels: bool = True,
68
65
  inline_svg: bool = True,
69
66
  assets_path: str | Path | None = None,
67
+ closed_kan_style: str = "outer",
68
+ css_class: str = "mahjong-hand",
70
69
  ) -> None:
71
70
  """Initialize the renderer.
72
71
 
73
72
  Args:
74
73
  theme: Color theme ('light', 'dark', or 'auto')
75
- css_class: CSS class for the container element
76
- show_labels: Show tile names as title attributes
77
74
  inline_svg: Inline SVG content vs img tags
78
75
  assets_path: Custom path to SVG assets
76
+ closed_kan_style: Style for closed kan back tiles:
77
+ 'outer' (default) - back tiles on edges (back, front, front, back)
78
+ 'inner' - back tiles in middle (front, back, back, front)
79
+ css_class: CSS class for container (internal use)
79
80
  """
80
81
  self.theme = theme
81
82
  self.tile_width = self.DEFAULT_TILE_WIDTH
@@ -83,9 +84,9 @@ class MahjongRenderer:
83
84
  self.tile_gap = self.DEFAULT_TILE_GAP
84
85
  self.meld_gap = self.DEFAULT_MELD_GAP
85
86
  self.css_class = css_class
86
- self.show_labels = show_labels
87
87
  self.inline_svg = inline_svg
88
88
  self.assets_path = Path(assets_path) if assets_path else None
89
+ self.closed_kan_style = closed_kan_style
89
90
  self._svg_id_counter = 0
90
91
 
91
92
  def render(
@@ -209,7 +210,7 @@ class MahjongRenderer:
209
210
  classes.append("mahjong-tile-added")
210
211
 
211
212
  class_str = " ".join(classes)
212
- title_attr = f' title="{info.display_name}"' if self.show_labels else ""
213
+ title_attr = f' title="{info.display_name}"'
213
214
 
214
215
  if self.inline_svg:
215
216
  svg_content = self._get_themed_svg_content(info)
@@ -271,9 +272,18 @@ class MahjongRenderer:
271
272
  parts.append(self._render_tile(meld.tiles[2]))
272
273
  else:
273
274
  for i, tile in enumerate(meld.tiles):
274
- # For closed kan, show back tiles for middle two
275
- if meld.meld_type == MeldType.KAN_CLOSED and i in (1, 2):
276
- parts.append(self._render_back_tile())
275
+ # For closed kan, show back tiles based on style setting
276
+ if meld.meld_type == MeldType.KAN_CLOSED:
277
+ if self.closed_kan_style == "inner":
278
+ # 'inner': back tiles in middle: front, back, back, front
279
+ is_back = i in (1, 2)
280
+ else:
281
+ # Default 'outer': back tiles on edges: back, front, front, back
282
+ is_back = i in (0, 3)
283
+ if is_back:
284
+ parts.append(self._render_back_tile())
285
+ else:
286
+ parts.append(self._render_tile(tile))
277
287
  else:
278
288
  parts.append(self._render_tile(tile))
279
289
 
@@ -17,20 +17,32 @@ class _SuperfencesState:
17
17
  """Encapsulates global state for superfences integration.
18
18
 
19
19
  Uses lazy initialization to create parser/renderer on first use.
20
+ Allows configuration via configure() method.
20
21
  """
21
22
 
22
23
  def __init__(self) -> None:
23
24
  self._renderer: MahjongRenderer | None = None
24
25
  self._parser: MahjongParser | None = None
26
+ self._config: dict[str, Any] = {}
27
+
28
+ def configure(self, **kwargs: Any) -> None:
29
+ """Configure the superfences state.
30
+
31
+ Args:
32
+ **kwargs: Configuration options (theme, closed_kan_style, etc.)
33
+ """
34
+ self._config.update(kwargs)
35
+ # Reset renderer to apply new config
36
+ self._renderer = None
25
37
 
26
38
  @property
27
39
  def renderer(self) -> MahjongRenderer:
28
40
  """Get or create the renderer instance."""
29
41
  if self._renderer is None:
30
42
  self._renderer = MahjongRenderer(
31
- theme="auto",
32
- show_labels=True,
33
- inline_svg=True,
43
+ theme=self._config.get("theme", "auto"),
44
+ inline_svg=self._config.get("inline_svg", True),
45
+ closed_kan_style=self._config.get("closed_kan_style", "outer"),
34
46
  )
35
47
  return self._renderer
36
48
 
@@ -46,6 +58,24 @@ class _SuperfencesState:
46
58
  _state = _SuperfencesState()
47
59
 
48
60
 
61
+ def configure_superfences(**kwargs: Any) -> None:
62
+ """Configure the superfences integration.
63
+
64
+ Call this before using superfences to set options like closed_kan_style.
65
+
66
+ Example:
67
+ from pymdownx_mahjong import configure_superfences
68
+ configure_superfences(closed_kan_style='outer')
69
+
70
+ Args:
71
+ **kwargs: Configuration options
72
+ - theme: 'light', 'dark', or 'auto'
73
+ - closed_kan_style: 'outer' or 'inner'
74
+ - inline_svg: bool
75
+ """
76
+ _state.configure(**kwargs)
77
+
78
+
49
79
  def superfences_validator(
50
80
  language: str,
51
81
  inputs: dict[str, str],
@@ -65,6 +95,14 @@ def superfences_validator(
65
95
  Returns:
66
96
  True if this is a valid mahjong fence
67
97
  """
98
+ # Try to get config from the markdown instance's extension
99
+ if hasattr(md, 'registeredExtensions'):
100
+ for ext in md.registeredExtensions:
101
+ if hasattr(ext, 'config') and 'closed_kan_style' in ext.config:
102
+ config = {key: ext.getConfig(key) for key in ext.config}
103
+ _state.configure(**config)
104
+ break
105
+
68
106
  return language == "mahjong"
69
107
 
70
108
 
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pymdownx-mahjong
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: Python Markdown extension to render and stylize Mahjong tiles.
5
5
  Project-URL: Homepage, https://github.com/tylernguyen/pymdownx-mahjong
6
- Project-URL: Documentation, https://github.com/tylernguyen/pymdownx-mahjong
6
+ Project-URL: Documentation, https://tylernguyen.github.io/pymdownx-mahjong/
7
7
  Project-URL: Repository, https://github.com/tylernguyen/pymdownx-mahjong
8
8
  Project-URL: Issues, https://github.com/tylernguyen/pymdownx-mahjong/issues
9
9
  Author: Tyler Nguyen
@@ -41,7 +41,7 @@ Description-Content-Type: text/markdown
41
41
 
42
42
  [Python Markdown](https://python-markdown.github.io) extension to render and stylize Mahjong tiles. Designed for use with [MkDocs](https://github.com/mkdocs/mkdocs) and [Zensical](https://github.com/zensical/zensical).
43
43
 
44
- ## Documentation
44
+ ## Demo and Documentation
45
45
 
46
46
  Demo and documentation can be found at [https://tylernguyen.github.io/pymdownx-mahjong/](https://tylernguyen.github.io/pymdownx-mahjong/).
47
47
 
@@ -1,9 +1,9 @@
1
- pymdownx_mahjong/__init__.py,sha256=mYyokR5i1zy1YoN3kFGPfL-VwlQgMH0yPyS12AT-Ki4,644
2
- pymdownx_mahjong/extension.py,sha256=aCRMkMQ8c0eenpcyR5eyLdN_OND9JpYFeRxodOeJyGo,6688
3
- pymdownx_mahjong/inline.py,sha256=QxnOmiZ-6cKjrLWsmNJwCCK3FVAjPvTgv97hfNnnnWg,2448
1
+ pymdownx_mahjong/__init__.py,sha256=TTW8ssjfwCA9CCZLi2_ISzBMdiiIC_0ukY2yYGMDbvc,696
2
+ pymdownx_mahjong/extension.py,sha256=HC-S_EUtSOyHHwJ72aDDsfyUGqxVUIwwycKpeap9YqY,6939
3
+ pymdownx_mahjong/inline.py,sha256=Q0_wxP4mR3DOOa3pH4d8EDmffOc9VV0eiyPIKFC5P50,2667
4
4
  pymdownx_mahjong/parser.py,sha256=I8wDlZO6oPMhTCqC0NFmsZJOQZCCCXyc78mk3vmmwcQ,12396
5
- pymdownx_mahjong/renderer.py,sha256=Lk52VCrULtwq9dGWr6J-E1_ZJAlO93nJDVSC0I_mhYI,16947
6
- pymdownx_mahjong/superfences.py,sha256=LXzG6P2EB8dU9A_5ncFbTJEA4Jy6RLwjjYXZS2wSjhs,3099
5
+ pymdownx_mahjong/renderer.py,sha256=wl_wJSntg-7YGIfD6aVgdI0rokOpr4Qz2oFVWG49BQQ,17522
6
+ pymdownx_mahjong/superfences.py,sha256=7rsTfhSlYZE25uwEJTfzmEDWUSblqvX0jMGnstwh92c,4493
7
7
  pymdownx_mahjong/tiles.py,sha256=ltA1xJeS9fVcZQyUwaIjyl1mHEZ0Kr_QUKy1jhCapDM,2583
8
8
  pymdownx_mahjong/utils.py,sha256=aHKX4wDCGM_rvaOwFIbd9qVJHpzzUjXWMviLxdwZrdo,2637
9
9
  pymdownx_mahjong/assets/README.md,sha256=HDNhZZlt8ffTER1fVNcTayUnFqOmB3tXoocT8iZgCz0,179
@@ -88,8 +88,8 @@ pymdownx_mahjong/assets/light/back.svg,sha256=HPAJfchslm_1uZQzpY8FUNF2s8hmbARGkh
88
88
  pymdownx_mahjong/assets/light/blank.svg,sha256=uKGioQLfrCZsSbMr66iDXv4w9lKHEqGym1l098-q5DM,8499
89
89
  pymdownx_mahjong/assets/light/front.svg,sha256=63TB5953_-10TDRd7K_kJnHoqt-6wd05MEGV2AcNsks,11906
90
90
  pymdownx_mahjong/css/mahjong.css,sha256=OpO9RR-UPFAbPF6Q8Wuz0Ak_Pg9rOrOsMAtnP0oj5LE,9307
91
- pymdownx_mahjong-1.1.0.dist-info/METADATA,sha256=8uXHaggPvIhroHgD2VdYNfDiJdtmM99XXAgIGjnlslc,2213
92
- pymdownx_mahjong-1.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
93
- pymdownx_mahjong-1.1.0.dist-info/entry_points.txt,sha256=dEty6XpsYCWl45PeRYHiH9ORxwSZA64LQU8gWF1CuyU,72
94
- pymdownx_mahjong-1.1.0.dist-info/licenses/LICENSE,sha256=Mnpx_G3eVz7AX5uTHGPaZWHJYiJYu4Y2_l01PsksHdg,19921
95
- pymdownx_mahjong-1.1.0.dist-info/RECORD,,
91
+ pymdownx_mahjong-1.2.0.dist-info/METADATA,sha256=S4NGo2aiURkBQXW-Z_oll-1cMjq4W8grUkzjLe1SP6Y,2222
92
+ pymdownx_mahjong-1.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
93
+ pymdownx_mahjong-1.2.0.dist-info/entry_points.txt,sha256=dEty6XpsYCWl45PeRYHiH9ORxwSZA64LQU8gWF1CuyU,72
94
+ pymdownx_mahjong-1.2.0.dist-info/licenses/LICENSE,sha256=Mnpx_G3eVz7AX5uTHGPaZWHJYiJYu4Y2_l01PsksHdg,19921
95
+ pymdownx_mahjong-1.2.0.dist-info/RECORD,,