@matfsw/docusaurus-plantuml-plugin 1.3.0 → 1.3.1

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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.3.1]
11
+
12
+ ### Fixed
13
+
14
+ - **The toolbar's controls are drawn rather than typed** ([#21]). `⛶` U+26F6 SQUARE FOUR
15
+ CORNERS, the maximize icon, has no glyph in any font that ships with a stock Linux desktop,
16
+ so that control rendered as an empty box for an entire platform's readers — on the demo site
17
+ included. The other four only worked because DejaVu Sans happens to be installed, which a
18
+ minimal container image or a locked-down desktop does not promise, so all of them are now
19
+ inline SVG and the plugin depends on no font at all.
20
+
21
+ The source toggle's `</>` went the same way. It is ASCII and never had the glyph problem, but
22
+ left as text it would have been the one control still drawn in the page font, at a different
23
+ weight and optical size from its neighbours.
24
+
25
+ Nothing about the accessible surface changes: every button keeps its `aria-label`,
26
+ `aria-pressed`, `aria-expanded` and `aria-controls`, and the icons are `aria-hidden`. The
27
+ icons inherit `currentColor` and `1em`, so both colour modes and reader font scaling behave
28
+ exactly as before, with no CSS change. The `Copy` text button and the `⚠` error glyph are
29
+ unchanged.
30
+
31
+ If you worked around this with a `font-family` override on `[class*='toolbarButton']`, it is
32
+ now a harmless no-op and can be removed.
33
+
34
+ ### Changed
35
+
36
+ - The example site records why its `onBrokenMarkdownLinks` stays at the top level rather than
37
+ moving to `markdown.hooks`, where Docusaurus 3.9 put it: 3.5's `markdown` schema rejects the
38
+ key outright, and CI builds that fixture against 3.5.2 — the oldest release this plugin's
39
+ peer range claims.
40
+
41
+ [#21]: https://github.com/matf/docusaurus-plantuml-plugin/issues/21
42
+
10
43
  ## [1.3.0]
11
44
 
12
45
  ### Added
@@ -347,7 +380,8 @@ Initial release.
347
380
  opt-out.
348
381
  - Plugin option validation that rejects unknown keys and out-of-range values at build time.
349
382
 
350
- [Unreleased]: https://github.com/matf/docusaurus-plantuml-plugin/compare/v1.3.0...HEAD
383
+ [Unreleased]: https://github.com/matf/docusaurus-plantuml-plugin/compare/v1.3.1...HEAD
384
+ [1.3.1]: https://github.com/matf/docusaurus-plantuml-plugin/compare/v1.3.0...v1.3.1
351
385
  [1.3.0]: https://github.com/matf/docusaurus-plantuml-plugin/compare/v1.2.0...v1.3.0
352
386
  [1.2.0]: https://github.com/matf/docusaurus-plantuml-plugin/compare/v1.1.2...v1.2.0
353
387
  [1.1.2]: https://github.com/matf/docusaurus-plantuml-plugin/compare/v1.1.1...v1.1.2
package/README.md CHANGED
@@ -898,6 +898,12 @@ The runtime requires:
898
898
  - `ResizeObserver` — optional; without it zoom still works, but the view is not re-clamped when
899
899
  the column is resized
900
900
 
901
+ It requires **no particular fonts**. The toolbar's controls are inline SVG rather than symbol
902
+ characters, which they were until 1.3.1: `⛶` U+26F6 (maximize) has no glyph in any font a stock
903
+ Linux desktop ships, so it rendered as an empty box for those readers, and the rest only worked
904
+ where DejaVu Sans happened to be installed. The icons inherit `currentColor` and `1em`, so they
905
+ follow the colour mode and the reader's font size the way the characters did.
906
+
901
907
  That is modern evergreen Chrome, Edge, Firefox and Safari. Internet Explorer is not
902
908
  supported and will not be.
903
909
 
@@ -0,0 +1,38 @@
1
+ /**
2
+ * The toolbar's icons, drawn rather than typed.
3
+ *
4
+ * These were symbol characters until 1.3.1, and one of them was invisible to a large group of
5
+ * readers: `⛶` U+26F6 SQUARE FOUR CORNERS has no glyph in any font that ships with a stock
6
+ * Linux desktop, so the maximize control rendered as a tofu box — on the demo site included.
7
+ * The other four only worked because DejaVu Sans happens to be installed, which a minimal
8
+ * container image or a locked-down corporate desktop does not promise. See issue #21.
9
+ *
10
+ * Two details keep the existing styling working with no CSS change at all:
11
+ *
12
+ * - `currentColor` inherits `.toolbarButton`'s `color: var(--ifm-font-color-base)`, so both
13
+ * colour modes keep working exactly as they did.
14
+ * - `1em` inherits its `font-size: 1rem`, so the icons size with the button — and with a
15
+ * reader who has scaled their font up — the way the characters used to.
16
+ *
17
+ * Every icon is `aria-hidden`: each `<button>` already carries an `aria-label`, which is the
18
+ * accessible name. Nothing here is announced.
19
+ */
20
+ import type { ReactElement } from 'react';
21
+ /** Replaces `−` U+2212. */
22
+ export declare function ZoomOutIcon(): ReactElement;
23
+ /** Replaces `+`. */
24
+ export declare function ZoomInIcon(): ReactElement;
25
+ /** Replaces `⟲` U+27F2: a circular arrow, open at the top right where the arrowhead sits. */
26
+ export declare function ResetZoomIcon(): ReactElement;
27
+ /** Replaces `⛶` U+26F6, the character that had no glyph. */
28
+ export declare function MaximizeIcon(): ReactElement;
29
+ /** Replaces `✕` U+2715, shown in place of maximize while the diagram fills the viewport. */
30
+ export declare function CloseIcon(): ReactElement;
31
+ /**
32
+ * Replaces the literal `</>` of the source toggle.
33
+ *
34
+ * ASCII, so it never had the glyph problem — but left as text it would be the one control in
35
+ * the row still drawn in the page font, at a different weight and optical size from its
36
+ * neighbours, and moving with the reader's font settings while they stayed put.
37
+ */
38
+ export declare function SourceIcon(): ReactElement;
@@ -0,0 +1,44 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ const iconProps = {
3
+ viewBox: '0 0 16 16',
4
+ width: '1em',
5
+ height: '1em',
6
+ fill: 'none',
7
+ stroke: 'currentColor',
8
+ strokeWidth: 1.5,
9
+ strokeLinecap: 'round',
10
+ strokeLinejoin: 'round',
11
+ 'aria-hidden': true,
12
+ // Keeps the SVG out of the tab order in browsers that made it focusable by default.
13
+ focusable: false,
14
+ };
15
+ /** Replaces `−` U+2212. */
16
+ export function ZoomOutIcon() {
17
+ return (_jsx("svg", { ...iconProps, children: _jsx("path", { d: "M3 8h10" }) }));
18
+ }
19
+ /** Replaces `+`. */
20
+ export function ZoomInIcon() {
21
+ return (_jsx("svg", { ...iconProps, children: _jsx("path", { d: "M8 3v10M3 8h10" }) }));
22
+ }
23
+ /** Replaces `⟲` U+27F2: a circular arrow, open at the top right where the arrowhead sits. */
24
+ export function ResetZoomIcon() {
25
+ return (_jsxs("svg", { ...iconProps, children: [_jsx("path", { d: "M13 8A5 5 0 1 1 11.4 4.3" }), _jsx("path", { d: "M13 2v3h-3" })] }));
26
+ }
27
+ /** Replaces `⛶` U+26F6, the character that had no glyph. */
28
+ export function MaximizeIcon() {
29
+ return (_jsx("svg", { ...iconProps, children: _jsx("path", { d: "M2 6V2h4M14 6V2h-4M2 10v4h4M14 10v4h-4" }) }));
30
+ }
31
+ /** Replaces `✕` U+2715, shown in place of maximize while the diagram fills the viewport. */
32
+ export function CloseIcon() {
33
+ return (_jsx("svg", { ...iconProps, children: _jsx("path", { d: "M4 4l8 8M12 4l-8 8" }) }));
34
+ }
35
+ /**
36
+ * Replaces the literal `</>` of the source toggle.
37
+ *
38
+ * ASCII, so it never had the glyph problem — but left as text it would be the one control in
39
+ * the row still drawn in the page font, at a different weight and optical size from its
40
+ * neighbours, and moving with the reader's font settings while they stayed put.
41
+ */
42
+ export function SourceIcon() {
43
+ return (_jsx("svg", { ...iconProps, children: _jsx("path", { d: "M6 4L2 8l4 4M10 4l4 4-4 4" }) }));
44
+ }
@@ -7,6 +7,7 @@ import { PlantUmlError } from '../../runtime/errors.js';
7
7
  import { renderGraphvizDiagram } from '../../runtime/graphvizRenderer.js';
8
8
  import { renderDiagram } from '../../runtime/renderer.js';
9
9
  import { usePlantUmlConfig } from '../usePlantUmlConfig.js';
10
+ import { CloseIcon, MaximizeIcon, ResetZoomIcon, SourceIcon, ZoomInIcon, ZoomOutIcon, } from './icons.js';
10
11
  import { useZoomPan } from './useZoomPan.js';
11
12
  import styles from './styles.module.css';
12
13
  /**
@@ -206,7 +207,7 @@ export default function PlantUmlDiagram({ source, title, language, engine = 'pla
206
207
  // Sanitized above unless `sanitizeSvg: false` was explicitly opted into.
207
208
  dangerouslySetInnerHTML: { __html: state.svg } }));
208
209
  const copyControl = sourceAvailable && sourceOpen && state.status === 'ready' && (_jsx("button", { type: "button", className: `${styles.toolbarButton} ${styles.toolbarTextButton}`, "aria-label": `Copy ${engineName} source to clipboard`, onClick: copySource, children: "Copy" }));
209
- const sourceToggle = sourceAvailable && (_jsx("button", { type: "button", className: styles.toolbarButton, "aria-label": sourceOpen ? 'Hide diagram source' : 'Show diagram source', "aria-expanded": sourceOpen, "aria-controls": sourcePanelId, onClick: () => setSourceOpen((open) => !open), children: _jsx("span", { "aria-hidden": "true", children: '</>' }) }));
210
+ const sourceToggle = sourceAvailable && (_jsx("button", { type: "button", className: styles.toolbarButton, "aria-label": sourceOpen ? 'Hide diagram source' : 'Show diagram source', "aria-expanded": sourceOpen, "aria-controls": sourcePanelId, onClick: () => setSourceOpen((open) => !open), children: _jsx(SourceIcon, {}) }));
210
211
  /**
211
212
  * The source *replaces the diagram in its own frame* rather than appearing beneath it.
212
213
  *
@@ -224,7 +225,7 @@ export default function PlantUmlDiagram({ source, title, language, engine = 'pla
224
225
  [DATA_ATTR.theme]: dark ? 'dark' : 'light',
225
226
  ...(interactive ? { [DATA_ATTR.interactive]: 'true' } : {}),
226
227
  ...(zoom.maximized ? { [DATA_ATTR.maximized]: 'true' } : {}),
227
- ...(sourceOpen ? { [DATA_ATTR.sourceOpen]: 'true' } : {}), children: [state.status === 'ready' && state.svg !== null && !interactive && canvas, state.status === 'ready' && state.svg !== null && !interactive && sourceView, state.status === 'ready' && state.svg !== null && !interactive && sourceAvailable && (_jsxs("div", { className: styles.plainToolbar, role: "group", "aria-label": `${label} source controls`, children: [sourceToggle, copyControl] })), state.status === 'ready' && state.svg !== null && interactive && (_jsxs("div", { ref: zoom.stageRef, className: zoom.maximized ? `${styles.stage} ${styles.maximized}` : styles.stage, children: [_jsxs("div", { className: styles.stageBody, children: [_jsx("div", { ref: zoom.viewportRef, className: sourceOpen ? `${styles.viewport} ${styles.invisibleView}` : styles.viewport, tabIndex: sourceOpen ? -1 : 0, "aria-describedby": hintId, "aria-keyshortcuts": "Plus Minus 0 ArrowUp ArrowDown ArrowLeft ArrowRight", onKeyDown: zoom.onKeyDown, [DATA_ATTR.zoom]: '1', children: _jsx("div", { ref: zoom.layerRef, className: styles.layer, children: canvas }) }), sourceView] }), _jsxs("div", { className: styles.toolbar, role: "group", "aria-label": `${label} zoom controls`, children: [!sourceOpen && (_jsx("button", { type: "button", className: styles.toolbarButton, "aria-label": "Zoom out", onClick: zoom.zoomOut, children: _jsx("span", { "aria-hidden": "true", children: "\u2212" }) })), !sourceOpen && (_jsx("button", { type: "button", className: styles.toolbarButton, "aria-label": "Zoom in", onClick: zoom.zoomIn, children: _jsx("span", { "aria-hidden": "true", children: "+" }) })), !sourceOpen && (_jsx("button", { type: "button", className: styles.toolbarButton, "aria-label": "Reset zoom", onClick: zoom.reset, children: _jsx("span", { "aria-hidden": "true", children: "\u27F2" }) })), _jsx("button", { type: "button", className: styles.toolbarButton, "aria-label": "Maximize diagram", "aria-pressed": zoom.maximized, onClick: zoom.toggleMaximize, children: _jsx("span", { "aria-hidden": "true", children: zoom.maximized ? '✕' : '⛶' }) }), sourceToggle, copyControl, _jsx("span", { ref: zoom.readoutRef, className: sourceOpen ? `${styles.readout} ${styles.hiddenView}` : styles.readout, "aria-hidden": "true", children: "100%" })] })] })), state.status === 'ready' && state.svg !== null && interactive && (_jsx("p", { id: hintId, className: styles.visuallyHidden, children: "Zoomable diagram. Use the zoom controls, or press plus and minus to zoom, the arrow keys to pan, and zero to reset." })), state.status !== 'ready' && state.status !== 'error' && (
228
+ ...(sourceOpen ? { [DATA_ATTR.sourceOpen]: 'true' } : {}), children: [state.status === 'ready' && state.svg !== null && !interactive && canvas, state.status === 'ready' && state.svg !== null && !interactive && sourceView, state.status === 'ready' && state.svg !== null && !interactive && sourceAvailable && (_jsxs("div", { className: styles.plainToolbar, role: "group", "aria-label": `${label} source controls`, children: [sourceToggle, copyControl] })), state.status === 'ready' && state.svg !== null && interactive && (_jsxs("div", { ref: zoom.stageRef, className: zoom.maximized ? `${styles.stage} ${styles.maximized}` : styles.stage, children: [_jsxs("div", { className: styles.stageBody, children: [_jsx("div", { ref: zoom.viewportRef, className: sourceOpen ? `${styles.viewport} ${styles.invisibleView}` : styles.viewport, tabIndex: sourceOpen ? -1 : 0, "aria-describedby": hintId, "aria-keyshortcuts": "Plus Minus 0 ArrowUp ArrowDown ArrowLeft ArrowRight", onKeyDown: zoom.onKeyDown, [DATA_ATTR.zoom]: '1', children: _jsx("div", { ref: zoom.layerRef, className: styles.layer, children: canvas }) }), sourceView] }), _jsxs("div", { className: styles.toolbar, role: "group", "aria-label": `${label} zoom controls`, children: [!sourceOpen && (_jsx("button", { type: "button", className: styles.toolbarButton, "aria-label": "Zoom out", onClick: zoom.zoomOut, children: _jsx(ZoomOutIcon, {}) })), !sourceOpen && (_jsx("button", { type: "button", className: styles.toolbarButton, "aria-label": "Zoom in", onClick: zoom.zoomIn, children: _jsx(ZoomInIcon, {}) })), !sourceOpen && (_jsx("button", { type: "button", className: styles.toolbarButton, "aria-label": "Reset zoom", onClick: zoom.reset, children: _jsx(ResetZoomIcon, {}) })), _jsx("button", { type: "button", className: styles.toolbarButton, "aria-label": "Maximize diagram", "aria-pressed": zoom.maximized, onClick: zoom.toggleMaximize, children: zoom.maximized ? _jsx(CloseIcon, {}) : _jsx(MaximizeIcon, {}) }), sourceToggle, copyControl, _jsx("span", { ref: zoom.readoutRef, className: sourceOpen ? `${styles.readout} ${styles.hiddenView}` : styles.readout, "aria-hidden": "true", children: "100%" })] })] })), state.status === 'ready' && state.svg !== null && interactive && (_jsx("p", { id: hintId, className: styles.visuallyHidden, children: "Zoomable diagram. Use the zoom controls, or press plus and minus to zoom, the arrow keys to pan, and zero to reset." })), state.status !== 'ready' && state.status !== 'error' && (
228
229
  // `aria-busy` on the figure already conveys progress; announcing every phase change
229
230
  // would make a page with several diagrams unusable with a screen reader.
230
231
  _jsxs("div", { className: styles.placeholder, children: [_jsx("span", { className: styles.spinner, "aria-hidden": "true" }), _jsxs("span", { children: [state.status === 'loading' ? `Loading ${engineName} runtime…` : null, state.status === 'rendering' ? `Rendering ${label}…` : null, state.status === 'idle' ? `${label} (waiting to render)` : null] })] })), state.status === 'error' && (_jsxs("div", { className: styles.error, role: "alert", children: [_jsxs("p", { className: styles.errorHeading, children: [_jsx("span", { className: styles.errorIcon, "aria-hidden": "true", children: "\u26A0" }), _jsxs("span", { children: ["Error: ", engineName, " diagram could not be rendered"] })] }), _jsx("pre", { className: styles.errorMessage, children: state.error }), config?.options.showSourceOnError !== false && (_jsxs("details", { className: styles.errorDetails, children: [_jsx("summary", { children: "Show diagram source" }), _jsx("pre", { className: styles.source, children: source })] }))] })), title !== undefined && _jsx("figcaption", { className: styles.caption, children: title }), _jsx("noscript", { dangerouslySetInnerHTML: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@matfsw/docusaurus-plantuml-plugin",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "Render PlantUML diagrams in Docusaurus 3 entirely in the browser - no Java, no PlantUML server, no CDN.",
5
5
  "keywords": [
6
6
  "docusaurus",