rapier-markdown-kit 1.2.12 → 1.2.13
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.
|
@@ -1217,7 +1217,7 @@ function* _rapierProjectPortableNodesSteps(semanticRoot, options) {
|
|
|
1217
1217
|
const alignment = paragraphLayout?.align || columnAlignment;
|
|
1218
1218
|
const imageLayout = element.tagName === 'IMG' ? globalThis.RapierMarkdownLayout.parseLayoutAttribute(element.getAttribute('data-rapier-image-layout')) : null;
|
|
1219
1219
|
const measurements = keepLayoutData && /^(?:P|H[1-6]|LI|OL|UL)$/.test(element.tagName)
|
|
1220
|
-
? ['text-indent', 'margin-inline-start'].map(property => [property, element.style.getPropertyValue(property)]) : [];
|
|
1220
|
+
? ['text-indent', 'margin-inline-start', 'margin-top', 'margin-bottom', 'line-height'].map(property => [property, element.style.getPropertyValue(property)]) : [];
|
|
1221
1221
|
if (keepLayoutData && element.tagName === 'P' && element.closest('table') && element.style.getPropertyValue('hyphens').trim() === 'auto')
|
|
1222
1222
|
measurements.push(['hyphens', 'auto']);
|
|
1223
1223
|
if (keepLayoutData && element.closest('pre')) for (const property of ['color', 'font-weight', 'font-style'])
|
|
@@ -1257,6 +1257,11 @@ function* _rapierProjectPortableNodesSteps(semanticRoot, options) {
|
|
|
1257
1257
|
for (const [property, value] of measurements) if (value) element.style.setProperty(property, value);
|
|
1258
1258
|
for (const [property, value] of runTypography) if (value) element.style.setProperty(property, value);
|
|
1259
1259
|
if (alignment) element.style.textAlign = alignment;
|
|
1260
|
+
if (paragraphLayout && /^(?:P|H[1-6])$/.test(element.tagName)) {
|
|
1261
|
+
if (paragraphLayout.line != null) element.style.lineHeight = String(paragraphLayout.line).replace(/\+$/, '');
|
|
1262
|
+
if (paragraphLayout.before != null) element.style.marginTop = paragraphLayout.before + 'pt';
|
|
1263
|
+
if (paragraphLayout.after != null) element.style.marginBottom = paragraphLayout.after + 'pt';
|
|
1264
|
+
}
|
|
1260
1265
|
if (!keepLayoutData && element.tagName === 'P' && !element.closest('table,pre')) {
|
|
1261
1266
|
if (paragraphLayout?.hyphens === 'auto') { element.style.hyphens = 'auto'; element.style.textWrap = 'pretty'; }
|
|
1262
1267
|
if (paragraphLayout?.hanging === 'on') element.style.setProperty('hanging-punctuation', 'first allow-end');
|
|
@@ -11,7 +11,7 @@ export const SPACING_PRESETS = Object.freeze({compact: .7, standard: 1, roomy: 1
|
|
|
11
11
|
const SPACING_SELECTORS = Object.freeze({paragraph: 'p', h1: 'h1', h2: 'h2', h3: 'h3', h4: 'h4', h5: 'h5', h6: 'h6',
|
|
12
12
|
list: ':is(ul,ol)', item: 'li', table: ':is(table,.table-scroll-wrap)', picture: 'p[data-md-picture]',
|
|
13
13
|
drawing: ':is(.diagram-block,p[data-md-picture]:has(img[data-md-svg],img[src^="data:image/svg+xml"]))', quote: 'blockquote',
|
|
14
|
-
code: 'pre', rule: 'hr:not(.footnotes-sep):not([data-md-break])', footnote: '.footnotes', toc: '.rapier-jump-list'});
|
|
14
|
+
code: 'pre', rule: 'hr:not(.footnotes-sep):not([data-md-break])', footnote: '.footnotes', toc: 'ul.rapier-jump-list'});
|
|
15
15
|
const HEADING_LINE = [1.75 / 2.2, 1.5 / 1.75, 1.2 / 1.5, 1 / 1.25, .9 / 1.1, .82];
|
|
16
16
|
|
|
17
17
|
export function normalizeDocumentSpacing(value) {
|
|
@@ -72,7 +72,10 @@ export function documentSpacingCss(settings, scope = '.md-render', defaults = fa
|
|
|
72
72
|
css += selector + '{margin-block:' + length(row.before) + ' ' + length(row.after) + ';line-height:' + row.line + '}';
|
|
73
73
|
if (settings?.word && /^h[1-6]$/.test(type)) css += selector + '{font-size:' + length(documentHeadingSize(settings, Number(type[1]))) + '}';
|
|
74
74
|
}
|
|
75
|
-
css += scope + ' :is(li,td,th,
|
|
75
|
+
css += scope + '>:first-child,' + scope + ' :is(blockquote,li,td,th,dd,.callout,details)>:first-child:not(input){margin-top:0}' +
|
|
76
|
+
scope + ' :is(li,td,th,blockquote,details,dd)>:last-child:not(input){margin-bottom:0}' +
|
|
77
|
+
scope + ' :is(p,h1,h2,h3,h4,h5,h6)[data-md-before]{margin-top:var(--md-before)}' +
|
|
78
|
+
scope + ' :is(p,h1,h2,h3,h4,h5,h6)[data-md-after]{margin-bottom:var(--md-after)}' +
|
|
76
79
|
scope + ' li:last-child{margin-bottom:0}' + scope + ' li>:is(ul,ol){margin-bottom:0}' +
|
|
77
80
|
scope + ' .table-scroll-wrap>table{margin-block:0}' +
|
|
78
81
|
scope + ' pre{font-size:calc(var(--md-text-body) * .7386)}' +
|
package/dist/spec/md-layout.mjs
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
|
|
3
|
-
export const fields = new Set(['align', 'width', 'lines', 'wrap', 'x', 'y', 'rotate', 'opacity', 'first', 'indent', 'marker', 'lock', 'hyphens', 'caps', 'hanging']);
|
|
3
|
+
export const fields = new Set(['align', 'width', 'lines', 'wrap', 'x', 'y', 'rotate', 'opacity', 'first', 'indent', 'marker', 'lock', 'hyphens', 'caps', 'hanging', 'before', 'after', 'line']);
|
|
4
|
+
export const SPACING_FIELDS = Object.freeze(['before', 'after', 'line']);
|
|
4
5
|
export const alignments = new Set(['left', 'center', 'right', 'justify']);
|
|
5
6
|
export const wraps = new Set(['around', 'box', 'behind', 'front']);
|
|
6
7
|
const has = (value, key) => Object.hasOwn(value, key);
|
|
7
8
|
const percent = value => typeof value === 'number' && Number.isFinite(value) && value >= 0 && value <= 100;
|
|
8
9
|
const lineCount = value => Number.isInteger(value) && value >= 1 && value <= 12;
|
|
10
|
+
const hundredths = value => Math.abs(value * 100 - Math.round(value * 100)) < 1e-9;
|
|
11
|
+
const spaceValue = value => typeof value === 'number' && Number.isFinite(value) && value >= 0 && value <= 720 && hundredths(value);
|
|
12
|
+
const linePoint = value => {
|
|
13
|
+
if (typeof value !== 'string') return null;
|
|
14
|
+
const match = /^(?:0|[1-9]\d{0,2})(?:\.\d{1,2})?pt(\+)?$/.exec(value);
|
|
15
|
+
if (!match) return null;
|
|
16
|
+
const points = Number(value.slice(0, match[1] ? -3 : -2));
|
|
17
|
+
return points > 0 && points <= 720 && hundredths(points) && value === decimal(points) + (match[1] ? 'pt+' : 'pt') ? {points, atLeast: !!match[1]} : null;
|
|
18
|
+
};
|
|
19
|
+
const lineValue = value => typeof value === 'number' ? Number.isFinite(value) && value >= .5 && value <= 4 && hundredths(value) : !!linePoint(value);
|
|
9
20
|
export const INDENT_LIMIT = 64;
|
|
10
21
|
export const indentLevel = value => typeof value === 'number' && Number.isFinite(value) && value !== 0 &&
|
|
11
22
|
Math.abs(value) <= INDENT_LIMIT && Number(value.toFixed(6)) === value;
|
|
@@ -34,6 +45,8 @@ export function validLayout(value) {
|
|
|
34
45
|
(!has(value, 'hyphens') || value.hyphens === 'auto') &&
|
|
35
46
|
(!has(value, 'caps') || value.caps === 'small') &&
|
|
36
47
|
(!has(value, 'hanging') || value.hanging === 'on') &&
|
|
48
|
+
(!has(value, 'before') || spaceValue(value.before)) && (!has(value, 'after') || spaceValue(value.after)) &&
|
|
49
|
+
(!has(value, 'line') || lineValue(value.line)) &&
|
|
37
50
|
!(has(value, 'align') && (has(value, 'wrap') || has(value, 'x')));
|
|
38
51
|
}
|
|
39
52
|
|
|
@@ -68,6 +81,15 @@ export function parseLayout(comment) {
|
|
|
68
81
|
} else if (key === 'lines') {
|
|
69
82
|
if (!/^[1-9]\d?$/.test(raw)) return null;
|
|
70
83
|
value.lines = Number(raw);
|
|
84
|
+
} else if (key === 'before' || key === 'after') {
|
|
85
|
+
if (!/^(?:0|[1-9]\d{0,2})(?:\.\d{1,2})?pt$/.test(raw)) return null;
|
|
86
|
+
value[key] = Number(raw.slice(0, -2));
|
|
87
|
+
} else if (key === 'line') {
|
|
88
|
+
if (/^[0-4](?:\.\d{1,2})?$/.test(raw)) value.line = Number(raw);
|
|
89
|
+
else if (/^(?:0|[1-9]\d{0,2})(?:\.\d{1,2})?pt\+?$/.test(raw)) {
|
|
90
|
+
const plus = raw.endsWith('+');
|
|
91
|
+
value.line = decimal(Number(raw.slice(0, plus ? -3 : -2))) + (plus ? 'pt+' : 'pt');
|
|
92
|
+
} else return null;
|
|
71
93
|
} else if (key === 'first' || key === 'indent' || key === 'marker') {
|
|
72
94
|
if (!/^-?(?:0|[1-9]\d?)(?:\.\d{1,6})?$/.test(raw)) return null;
|
|
73
95
|
value[key] = Number(raw);
|
|
@@ -94,19 +116,47 @@ export function textStyle(value, {portable = false, pointSize, indentOffset = 0}
|
|
|
94
116
|
'calc(' + measure + ' * var(--md-text-body))');
|
|
95
117
|
});
|
|
96
118
|
if (portable && value.hyphens === 'auto') css.push('hyphens:auto');
|
|
119
|
+
if (has(value, 'line')) {
|
|
120
|
+
const point = linePoint(value.line);
|
|
121
|
+
const unit = point && 'calc(' + decimal(Number((point.points / 12).toFixed(6))) + ' * var(--md-unit))';
|
|
122
|
+
css.push('line-height:' + (!point ? decimal(value.line) : portable ? decimal(point.points) + 'pt' : point.atLeast ? 'max(1.2em, ' + unit + ')' : unit));
|
|
123
|
+
}
|
|
124
|
+
for (const [key, prop] of [['before', 'margin-top'], ['after', 'margin-bottom']])
|
|
125
|
+
if (has(value, key)) css.push(portable ? prop + ':' + decimal(value[key]) + 'pt' :
|
|
126
|
+
'--md-' + key + ':calc(' + decimal(Number((value[key] / 12).toFixed(6))) + ' * var(--md-unit))');
|
|
97
127
|
return css.join(';');
|
|
98
128
|
}
|
|
99
129
|
|
|
100
130
|
export function textLayout(style, {listMarker = false, pointSize, offset = 0} = {}) {
|
|
131
|
+
const get = property => (typeof style?.getPropertyValue === 'function' ? style.getPropertyValue(property) :
|
|
132
|
+
style?.[property] ?? style?.[property.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase())] ?? '').trim();
|
|
101
133
|
const value = {};
|
|
102
134
|
for (const [key, property] of (listMarker ? [['marker', 'margin-inline-start']] : [['first', 'text-indent'], ['indent', 'margin-inline-start']])) {
|
|
103
|
-
const raw =
|
|
135
|
+
const raw = get(property);
|
|
104
136
|
const match = /^(-?(?:0|[1-9]\d*)(?:\.\d{1,6})?)(em|pt)$/.exec(raw);
|
|
105
137
|
const level = Number(((match ? Number(match[1]) / (match[2] === 'pt' ? pointSize : 1) / 2 : 0) +
|
|
106
138
|
(key === 'first' ? 0 : offset)).toFixed(6));
|
|
107
139
|
if (Number.isFinite(level) && level) value[key] = level;
|
|
108
140
|
}
|
|
109
|
-
if (!listMarker
|
|
141
|
+
if (!listMarker) {
|
|
142
|
+
if (get('hyphens') === 'auto') value.hyphens = 'auto';
|
|
143
|
+
for (const [key, property] of [['before', 'margin-top'], ['after', 'margin-bottom']]) {
|
|
144
|
+
const raw = get(property);
|
|
145
|
+
if (/^(?:0|[1-9]\d{0,2})(?:\.\d{1,2})?pt$/i.test(raw)) {
|
|
146
|
+
const points = Number(raw.slice(0, -2));
|
|
147
|
+
if (spaceValue(points)) value[key] = points;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const line = get('line-height');
|
|
151
|
+
if (/^[0-4](?:\.\d{1,2})?$/.test(line)) {
|
|
152
|
+
const factor = Number(line);
|
|
153
|
+
if (lineValue(factor)) value.line = factor;
|
|
154
|
+
} else if (/^(?:0|[1-9]\d{0,2})(?:\.\d{1,2})?pt\+?$/i.test(line)) {
|
|
155
|
+
const atLeast = line.endsWith('+'), points = Number(line.slice(0, atLeast ? -3 : -2));
|
|
156
|
+
const formatted = decimal(points) + (atLeast ? 'pt+' : 'pt');
|
|
157
|
+
if (lineValue(formatted)) value.line = formatted;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
110
160
|
return value;
|
|
111
161
|
}
|
|
112
162
|
|
|
@@ -173,7 +223,8 @@ export function formatLayout(value) {
|
|
|
173
223
|
if (has(value, key) && !(key === 'y' && value.y === 0) && !(key === 'rotate' && value.rotate === 0) &&
|
|
174
224
|
!(key === 'opacity' && value.opacity === 100)) pairs.push(key + '=' +
|
|
175
225
|
(key === 'width' || key === 'x' || key === 'opacity' ? decimal(value[key]) + '%' : key === 'y' ? decimal(value.y) + 'em' :
|
|
176
|
-
key === 'rotate' ? decimal(value.rotate) + 'deg' : value[key])
|
|
226
|
+
key === 'rotate' ? decimal(value.rotate) + 'deg' : key === 'before' || key === 'after' ? decimal(value[key]) + 'pt' :
|
|
227
|
+
key === 'line' ? (typeof value.line === 'number' ? decimal(value.line) : value.line) : value[key]));
|
|
177
228
|
}
|
|
178
229
|
return pairs.length ? '<!--md-layout:v1 ' + pairs.join(' ') + '-->' : '';
|
|
179
230
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rapier-markdown-kit",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.13",
|
|
4
4
|
"description": "Read, render and write Self-contained Markdown: one .md file that carries its pictures, drawings and layout, and that any Markdown app can read. HTML renderer, stylesheet, text layout, Will/1 agent permissions, and an edit history with authorship and offline merge. MIT, no dependencies.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"markdown",
|
package/style.css
CHANGED
|
@@ -300,6 +300,8 @@
|
|
|
300
300
|
.md-render h6{font-size:var(--md-text-body);font-weight:var(--md-fw-semibold);color:var(--md-heading-muted-color)}
|
|
301
301
|
.md-render p{margin:0 0 var(--md-gap-paragraph)}
|
|
302
302
|
.md-render p[data-md-picture]{margin-bottom:var(--md-gap-block)}
|
|
303
|
+
.md-render :is(p,h1,h2,h3,h4,h5,h6)[data-md-before]{--md-before:0px;margin-top:var(--md-before)}
|
|
304
|
+
.md-render :is(p,h1,h2,h3,h4,h5,h6)[data-md-after]{--md-after:0px;margin-bottom:var(--md-after)}
|
|
303
305
|
.md-render ul,.md-render ol{margin:0 0 var(--md-gap-block);padding-inline-start:var(--md-space-5)}
|
|
304
306
|
.md-render ul{list-style:none}
|
|
305
307
|
.md-render ul>li{position:relative;--md-marker:0px}
|