@memorysmithapp/markdown-renderer 0.8.2 → 0.8.4

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/README.md CHANGED
@@ -138,7 +138,7 @@ const notices = await diagnose(note, {
138
138
 
139
139
  A `notice` says the page will differ from the text — a fence never closed, a formula KaTeX cannot typeset, a diagram Mermaid cannot read, raw HTML, a footnote with no definition or no reference, a single-tilde strikethrough, a frontmatter never closed, a `name` that leaves the note unnamed or none at all, `aliases` or `tags` that are not a list, a body that does not start at `#` or skips a level. A `hint` says nothing is drawn wrong: no `aliases`, no `tags`, a link or an embed no note answers yet. Lines and columns count from 1 over the whole note, frontmatter included, and the `message` is English; a host words it in its own language from the `code`, which is stable. Mermaid is loaded only for a note that holds a diagram, and `diagrams: false` skips it.
140
140
 
141
- The host contract, the stylesheet's properties, the slots and the decisions behind them are in the repository's [`ARCHITECTURE.md`](https://github.com/memorysmithapp/memorysmithapp-markdown/blob/main/ARCHITECTURE.md).
141
+ The host contract, the stylesheet's properties, the slots and the decisions behind them are in the repository's [`ARCHITECTURE.md`](https://github.com/memorysmithapp/memorysmithapp-markdown/blob/main/docs/ARCHITECTURE.md).
142
142
 
143
143
  ## Licence
144
144
 
@@ -225,6 +225,8 @@ export function ImageBlock({ view, source, children }) {
225
225
  const frame = useRef(null);
226
226
  const size = readImageSize(source);
227
227
  const [image, setImage] = useState(null);
228
+ // A kept file that is not a picture — its card, its player — takes the column, as it is read (#122).
229
+ const [file, setFile] = useState(false);
228
230
  const [natural, setNatural] = useState(null);
229
231
  const [locked, setLocked] = useState(() => size?.height == null);
230
232
  const [unit, setUnit] = useState(() => (size?.percent == null ? 'px' : '%'));
@@ -239,7 +241,10 @@ export function ImageBlock({ view, source, children }) {
239
241
  const element = frame.current;
240
242
  if (!element)
241
243
  return;
242
- const look = () => setImage(element.querySelector('img'));
244
+ const look = () => {
245
+ setImage(element.querySelector('img'));
246
+ setFile(element.querySelector('.attachment-card, .attachment-player') !== null);
247
+ };
243
248
  look();
244
249
  if (typeof MutationObserver === 'undefined')
245
250
  return;
@@ -541,7 +546,7 @@ export function ImageBlock({ view, source, children }) {
541
546
  const offered = size !== null && image !== null;
542
547
  const unitWord = unit === '%' ? '%' : 'px';
543
548
  const invalid = (name) => (refused?.field === name ? { 'aria-invalid': true, title: words.imageOutOfRange(refused.range.min, refused.range.max, name === 'width' ? unitWord : 'px') } : {});
544
- return (_jsxs("span", { ref: frame, className: "edit-image", "data-resizing": dragged === null ? undefined : '', "data-ms-in-place": offered ? '' : undefined, onFocus: () => frame.current && (frame.current.dataset['msBusy'] = ''), onBlur: hold, onMouseDown: (event) => {
549
+ return (_jsxs("span", { ref: frame, className: "edit-image", "data-resizing": dragged === null ? undefined : '', "data-ms-in-place": offered ? '' : undefined, "data-ms-file": file ? '' : undefined, onFocus: () => frame.current && (frame.current.dataset['msBusy'] = ''), onBlur: hold, onMouseDown: (event) => {
545
550
  // The frame's own area is the space between the picture and its controls: a press there is
546
551
  // one meant for them, and shows nothing (#107).
547
552
  if (event.target === event.currentTarget) {
@@ -551,12 +556,13 @@ export function ImageBlock({ view, source, children }) {
551
556
  }, children: [children, offered && (_jsxs(_Fragment, { children: [_jsxs("span", { className: "edit-image-controls", "data-ms-control": "", onPointerDown: hold, onTouchStart: hold, onMouseDown: (event) => {
552
557
  // A press anywhere but on a field, a choice or a button — a gap between them, the
553
558
  // padding, a word beside a field — keeps the focus where it is. Its default would put
554
- // the editor's caret where the press fell, and the image would show its source (#107).
555
- if (!event.target.closest('input, select, textarea, button'))
559
+ // the editor's caret where the press fell, and the image would show its source (#107). A
560
+ // disabled one is a gap too: it takes no focus, and the caret would go where it fell (#121).
561
+ if (!event.target.closest('input:enabled, select:enabled, textarea:enabled, button:enabled'))
556
562
  event.preventDefault();
557
563
  }, children: [size.description ? (_jsx("input", { className: "edit-field edit-image-description", type: "text", "aria-label": words.imageDescription, title: words.imageDescription, placeholder: image.alt, value: typed.description ?? size.description.text, ...field('description') })) : (
558
564
  // An embed writes no description (§5.8): the file's own is shown, and is not edited here.
559
- _jsx("input", { className: "edit-field edit-image-description", type: "text", readOnly: true, "aria-label": words.imageDescription, title: words.imageDescription, placeholder: image.alt, value: "" })), _jsxs("span", { className: "edit-image-size", children: [_jsx("input", { className: "edit-field edit-image-width", type: "text", inputMode: "numeric", autoComplete: "off", "aria-label": words.imageWidth, title: words.imageWidth, placeholder: unit === '%' ? '' : natural === null ? '' : String(natural.width), value: typed.width ?? (shownWidth === null ? '' : String(shownWidth)), ...field('width'), ...invalid('width') }), _jsxs("select", { className: "edit-image-unit", "aria-label": words.imageUnit, title: words.imageUnit, value: unit, onChange: (event) => chooseUnit(event.target.value), children: [_jsx("option", { value: "px", children: "px" }), _jsx("option", { value: "%", children: "%" })] }), _jsx(Control, { label: locked ? words.imageKeepRatio : words.imageFreeRatio, onClick: toggleLock, pressed: locked, disabled: unit === '%', focusable: true, children: locked ? ICON_RATIO_LOCKED : ICON_RATIO_FREE }), _jsx("input", { className: "edit-field edit-image-height", type: "text", inputMode: "numeric", autoComplete: "off", "aria-label": words.imageHeight, title: words.imageHeight, disabled: unit === '%', placeholder: natural === null || unit === '%' ? '' : String(natural.height), value: unit === '%' ? '' : (typed.height ?? (shownHeight === null ? '' : String(shownHeight))), ...field('height'), ...invalid('height') }), _jsx("span", { className: "edit-image-unit-label", "aria-hidden": "true", children: "px" }), _jsx(Control, { label: words.imageOwnSize, onClick: () => resize(null), pressed: size.width === null && size.percent === null, focusable: true, children: ICON_OWN_SIZE }), _jsx(Control, { label: words.source, onClick: showSource, children: ICONS.source })] }), refused && (_jsx("span", { className: "edit-image-refused", role: "status", children: words.imageOutOfRange(refused.range.min, refused.range.max, refused.field === 'width' ? unitWord : 'px') }))] }), _jsx("span", { className: "edit-image-handle", "data-ms-control": "", "data-free": free ? '' : undefined, title: free ? words.imageResizeFree : words.imageResizeKeep, "aria-hidden": "true", onPointerDown: (event) => {
565
+ _jsx("input", { className: "edit-field edit-image-description", type: "text", readOnly: true, "aria-label": words.imageDescription, title: words.imageDescription, placeholder: image.alt, value: "" })), _jsxs("span", { className: "edit-image-size", "data-unit": unit, children: [_jsx("input", { className: "edit-field edit-image-width", type: "text", inputMode: "numeric", autoComplete: "off", "aria-label": words.imageWidth, title: words.imageWidth, placeholder: unit === '%' ? '' : natural === null ? '' : String(natural.width), value: typed.width ?? (shownWidth === null ? '' : String(shownWidth)), ...field('width'), ...invalid('width') }), _jsxs("select", { className: "edit-image-unit", "aria-label": words.imageUnit, title: words.imageUnit, value: unit, onChange: (event) => chooseUnit(event.target.value), children: [_jsx("option", { value: "px", children: "px" }), _jsx("option", { value: "%", children: "%" })] }), _jsx(Control, { label: locked ? words.imageKeepRatio : words.imageFreeRatio, onClick: toggleLock, pressed: locked, disabled: unit === '%', focusable: true, children: locked ? ICON_RATIO_LOCKED : ICON_RATIO_FREE }), _jsx("input", { className: "edit-field edit-image-height", type: "text", inputMode: "numeric", autoComplete: "off", "aria-label": words.imageHeight, title: words.imageHeight, disabled: unit === '%', placeholder: natural === null || unit === '%' ? '' : String(natural.height), value: unit === '%' ? '' : (typed.height ?? (shownHeight === null ? '' : String(shownHeight))), ...field('height'), ...invalid('height') }), _jsx("span", { className: "edit-image-unit-label", "aria-hidden": "true", children: "px" }), _jsx(Control, { label: words.imageOwnSize, onClick: () => resize(null), pressed: size.width === null && size.percent === null, focusable: true, children: ICON_OWN_SIZE }), _jsx(Control, { label: words.source, onClick: showSource, children: ICONS.source })] }), refused && (_jsx("span", { className: "edit-image-refused", role: "status", children: words.imageOutOfRange(refused.range.min, refused.range.max, refused.field === 'width' ? unitWord : 'px') }))] }), _jsx("span", { className: "edit-image-handle", "data-ms-control": "", "data-free": free ? '' : undefined, title: free ? words.imageResizeFree : words.imageResizeKeep, "aria-hidden": "true", onPointerDown: (event) => {
560
566
  event.preventDefault();
561
567
  event.stopPropagation();
562
568
  const now = drawn();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memorysmithapp/markdown-renderer",
3
- "version": "0.8.2",
3
+ "version": "0.8.4",
4
4
  "description": "A React component that draws a MemorySmith note exactly as MemorySmith's reading page does.",
5
5
  "keywords": [
6
6
  "markdown",
@@ -79,7 +79,7 @@
79
79
  "unified": "11.0.5"
80
80
  },
81
81
  "devDependencies": {
82
- "@memorysmithapp/markdown-spec": "0.8.2",
82
+ "@memorysmithapp/markdown-spec": "0.8.4",
83
83
  "@types/hast": "3.0.5",
84
84
  "@types/react": "19.2.18",
85
85
  "@types/react-dom": "19.2.4",
package/structure.css CHANGED
@@ -469,6 +469,11 @@
469
469
  max-width: 100%;
470
470
  vertical-align: middle;
471
471
  }
472
+ /* A kept file that is not a picture, a card or a player, has no width of its own
473
+ to shrink the frame to: it takes the column, as in reading mode (#122). */
474
+ .markdown .edit-image[data-ms-file] {
475
+ display: block;
476
+ }
472
477
  .markdown .edit-image-controls {
473
478
  position: absolute;
474
479
  top: var(--edit-image-bottom, 100%);
@@ -493,6 +498,11 @@
493
498
  .markdown .edit-image-height {
494
499
  width: 4.2em;
495
500
  }
501
+ /* Under a share of the page, the lock, the height and its unit mean nothing: they
502
+ are not shown, and keep their place so the controls after them stay put (#121). */
503
+ .markdown .edit-image-size[data-unit='%'] > :is(.edit-control:disabled, .edit-image-height, .edit-image-unit-label) {
504
+ visibility: hidden;
505
+ }
496
506
  .markdown .edit-image-description {
497
507
  flex: 1 1 10rem;
498
508
  min-width: 0;
package/theme-default.css CHANGED
@@ -1983,9 +1983,6 @@
1983
1983
  border-color: rgb(var(--ms-callout-stop));
1984
1984
  outline: 1px solid rgb(var(--ms-callout-stop));
1985
1985
  }
1986
- .markdown .edit-image-controls .edit-field:disabled {
1987
- opacity: 0.5;
1988
- }
1989
1986
  .markdown .edit-image-unit {
1990
1987
  height: 1.9rem;
1991
1988
  border: 1px solid var(--ms-border);