@vesk/runtime 0.1.14 → 0.2.9

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.
@@ -0,0 +1,342 @@
1
+ /**
2
+ * LoadingIndicator — a Nuxt-style page-navigation progress bar.
3
+ *
4
+ * A global singleton driven by the router: `loadingStart()` fires when an SPA
5
+ * navigation begins and `loadingFinish()` when its content (and route data)
6
+ * has settled. `<LoadingIndicator/>` renders the bar anywhere in a layout;
7
+ * `useLoadingIndicator()` exposes the reactive state for fully custom UIs.
8
+ *
9
+ * Progress backs off as it approaches 100% (atan curve) so long loads never
10
+ * prematurely complete; short navigations stay invisible thanks to `throttle`.
11
+ * State lives in tracked cells so any `effect()`-driven UI updates live.
12
+ */
13
+ import { tracked, get, set } from '@vesk/runtime/src/ripple-runtime';
14
+ import { effect } from '@vesk/runtime/src/ripple-blocks';
15
+ import { __isHydrating } from '@vesk/runtime/src/router-components';
16
+ function defaultEstimatedProgress(duration, elapsed) {
17
+ const completionPercentage = (elapsed / duration) * 100;
18
+ return ((2 / Math.PI) * 100) * Math.atan(completionPercentage / 50);
19
+ }
20
+ const globalOpts = {
21
+ duration: 2000,
22
+ throttle: 200,
23
+ hideDelay: 500,
24
+ resetDelay: 400,
25
+ estimatedProgress: defaultEstimatedProgress,
26
+ };
27
+ /** Merges option overrides into the global singleton (used by the component's props). */
28
+ export function configureLoadingIndicator(opts) {
29
+ if (!opts)
30
+ return;
31
+ if (typeof opts.duration === 'number' && opts.duration > 0)
32
+ globalOpts.duration = opts.duration;
33
+ if (typeof opts.throttle === 'number' && opts.throttle >= 0)
34
+ globalOpts.throttle = opts.throttle;
35
+ if (typeof opts.hideDelay === 'number' && opts.hideDelay >= 0)
36
+ globalOpts.hideDelay = opts.hideDelay;
37
+ if (typeof opts.resetDelay === 'number' && opts.resetDelay >= 0)
38
+ globalOpts.resetDelay = opts.resetDelay;
39
+ if (typeof opts.estimatedProgress === 'function')
40
+ globalOpts.estimatedProgress = opts.estimatedProgress;
41
+ }
42
+ // ── Reactive state ───────────────────────────────────────────
43
+ const progressCell = tracked(0);
44
+ const loadingCell = tracked(false);
45
+ const errorCell = tracked(false);
46
+ function isServer() {
47
+ // Gated on the SSR-render flag (resource-module convention): during an
48
+ // actual server render no timers should ever be scheduled, while plain
49
+ // Node consumers (unit tests, scripts) get the full client behavior.
50
+ return !!globalThis.__vsk_ssr;
51
+ }
52
+ function now() {
53
+ if (typeof performance !== 'undefined' && typeof performance.now === 'function')
54
+ return performance.now();
55
+ return Date.now();
56
+ }
57
+ let rafId = null;
58
+ let throttleTimer = null;
59
+ let hideTimer = null;
60
+ let resetTimer = null;
61
+ let animating = false;
62
+ function clearAnim() {
63
+ animating = false;
64
+ if (throttleTimer !== null) {
65
+ clearTimeout(throttleTimer);
66
+ throttleTimer = null;
67
+ }
68
+ if (rafId !== null) {
69
+ clearTimeout(rafId);
70
+ rafId = null;
71
+ }
72
+ }
73
+ function clearTimers() {
74
+ if (hideTimer !== null) {
75
+ clearTimeout(hideTimer);
76
+ hideTimer = null;
77
+ }
78
+ if (resetTimer !== null) {
79
+ clearTimeout(resetTimer);
80
+ resetTimer = null;
81
+ }
82
+ }
83
+ /**
84
+ * Runs the estimator loop from 0 elapsed. The loop stops whenever anything
85
+ * else takes control of progress (`loadingSet`, `loadingFinish`, `loadingClear`).
86
+ */
87
+ function startProgress() {
88
+ animating = true;
89
+ let startTimeStamp = null;
90
+ const step = () => {
91
+ rafId = null;
92
+ if (!animating || isServer())
93
+ return;
94
+ const ts = now();
95
+ if (startTimeStamp === null)
96
+ startTimeStamp = ts;
97
+ const pct = globalOpts.estimatedProgress(globalOpts.duration, ts - startTimeStamp);
98
+ set(progressCell, Math.max(0, Math.min(100, pct)));
99
+ rafId = setTimeout(step, 16);
100
+ };
101
+ step();
102
+ }
103
+ /** Makes the bar visible immediately or after the throttle window. */
104
+ function present(opts) {
105
+ const throttleMs = opts?.force ? 0 : globalOpts.throttle;
106
+ if (isServer() || throttleMs <= 0) {
107
+ set(loadingCell, true);
108
+ return;
109
+ }
110
+ if (throttleTimer !== null)
111
+ clearTimeout(throttleTimer);
112
+ throttleTimer = setTimeout(() => {
113
+ throttleTimer = null;
114
+ set(loadingCell, true);
115
+ }, throttleMs);
116
+ }
117
+ /**
118
+ * Starts the loading animation from 0%. Without `{ force: true }` the bar
119
+ * waits `throttle` ms before becoming visible, so fast navigations never flash.
120
+ */
121
+ export function loadingStart(opts) {
122
+ clearTimers();
123
+ clearAnim();
124
+ set(errorCell, false);
125
+ set(progressCell, 0);
126
+ present(opts);
127
+ startProgress();
128
+ }
129
+ /**
130
+ * Jumps the bar to a specific progress value (0–100). Values ≥ 100 finish.
131
+ * A manual set takes control: the automatic estimation stops until the next
132
+ * `start()`, so the value sticks instead of being overwritten by a frame.
133
+ */
134
+ export function loadingSet(at, opts) {
135
+ if (__isHydrating)
136
+ return;
137
+ if ((at ?? 0) >= 100)
138
+ return loadingFinish({ force: opts?.force });
139
+ clearAnim();
140
+ clearTimers();
141
+ set(progressCell, Math.max(0, at ?? 0));
142
+ present(opts);
143
+ }
144
+ function hide() {
145
+ hideTimer = setTimeout(() => {
146
+ hideTimer = null;
147
+ set(loadingCell, false);
148
+ resetTimer = setTimeout(() => {
149
+ resetTimer = null;
150
+ set(progressCell, 0);
151
+ }, globalOpts.resetDelay);
152
+ }, globalOpts.hideDelay);
153
+ }
154
+ /**
155
+ * Completes the animation at 100%. With `{ error: true }` the bar switches to
156
+ * the error color while hiding; with `{ force: true }` it resets instantly.
157
+ */
158
+ export function loadingFinish(opts) {
159
+ clearAnim();
160
+ set(progressCell, 100);
161
+ clearTimers();
162
+ if (opts?.error)
163
+ set(errorCell, true);
164
+ if (opts?.force) {
165
+ set(progressCell, 0);
166
+ set(loadingCell, false);
167
+ return;
168
+ }
169
+ if (!isServer())
170
+ hide();
171
+ }
172
+ /** Cancels the pending appearance timer and animation frame without changing state. */
173
+ export function loadingClear() {
174
+ clearAnim();
175
+ }
176
+ const handle = {
177
+ progress: progressCell,
178
+ isLoading: loadingCell,
179
+ error: errorCell,
180
+ start: loadingStart,
181
+ set: loadingSet,
182
+ finish: loadingFinish,
183
+ clear: loadingClear,
184
+ };
185
+ /**
186
+ * Accesses the shared loading-indicator singleton. Call this (or render
187
+ * `<LoadingIndicator/>`) once per app — every call returns the same state,
188
+ * so programmatic `start()`/`finish()` drive the same bar the router does.
189
+ */
190
+ export function useLoadingIndicator(options) {
191
+ configureLoadingIndicator(options);
192
+ return handle;
193
+ }
194
+ export function getLoadingProgress() {
195
+ return get(progressCell);
196
+ }
197
+ export function isLoadingActive() {
198
+ return get(loadingCell) === true;
199
+ }
200
+ export function getLoadingError() {
201
+ return get(errorCell) === true;
202
+ }
203
+ /** The raw tracked cells backing the shared singleton (used by the router). */
204
+ export function getLoadingState() {
205
+ return { progress: progressCell, isLoading: loadingCell, error: errorCell };
206
+ }
207
+ // ── Component ────────────────────────────────────────────────
208
+ export const LOADING_INDICATOR_DEFAULT_COLOR = 'repeating-linear-gradient(to right,#38bdf8 0%,#6366f1 50%,#8b5cf6 100%)';
209
+ export const LOADING_INDICATOR_DEFAULT_ERROR_COLOR = 'repeating-linear-gradient(to right,#f87171 0%,#ef4444 100%)';
210
+ const INDICATOR_ATTR = 'data-vesk-loading-indicator';
211
+ function heightCss(height) {
212
+ if (typeof height === 'number')
213
+ return `${height}px`;
214
+ if (typeof height === 'string' && height.trim() !== '')
215
+ return height;
216
+ return '3px';
217
+ }
218
+ function escapeAttr(v) {
219
+ let out = '';
220
+ for (const ch of v) {
221
+ if (ch === '&')
222
+ out += '&amp;';
223
+ else if (ch === '"')
224
+ out += '&quot;';
225
+ else if (ch === '<')
226
+ out += '&lt;';
227
+ else
228
+ out += ch;
229
+ }
230
+ return out;
231
+ }
232
+ function baseStyleEntries(props) {
233
+ const top = props.position !== 'bottom';
234
+ const entries = [
235
+ ['position', 'fixed'],
236
+ [top ? 'top' : 'bottom', '0'],
237
+ ['right', '0'],
238
+ ['left', '0'],
239
+ ['pointer-events', 'none'],
240
+ ['width', 'auto'],
241
+ ['height', heightCss(props.height)],
242
+ ['z-index', String(props.zIndex != null ? props.zIndex : 999999)],
243
+ ['transform-origin', 'left'],
244
+ ['transition', 'transform 0.1s, height 0.4s, opacity 0.4s'],
245
+ ];
246
+ return entries;
247
+ }
248
+ function styleToString(entries, extra) {
249
+ const parts = entries.map(([k, v]) => `${k}:${v}`);
250
+ for (const [k, v] of Object.entries(extra))
251
+ parts.push(`${k}:${v}`);
252
+ return parts.join(';');
253
+ }
254
+ function applyState(props) {
255
+ const progress = get(progressCell);
256
+ const isLoading = get(loadingCell) === true;
257
+ const errored = get(errorCell) === true;
258
+ const bg = errored
259
+ ? (props.errorColor || LOADING_INDICATOR_DEFAULT_ERROR_COLOR)
260
+ : (props.color === false ? undefined : (props.color || LOADING_INDICATOR_DEFAULT_COLOR));
261
+ const extra = {
262
+ opacity: isLoading ? '1' : '0',
263
+ transform: `scaleX(${progress}%)`,
264
+ };
265
+ if (bg !== undefined)
266
+ extra.background = bg;
267
+ if (progress > 0 && bg !== undefined) {
268
+ extra['background-size'] = `${(100 / Math.min(progress, 100)) * 100}% auto`;
269
+ }
270
+ return extra;
271
+ }
272
+ function wire(el, props, userStyle) {
273
+ const base = baseStyleEntries(props);
274
+ const paint = () => {
275
+ el.style.cssText = styleToString(base, applyState(props)) + (userStyle ? ';' + userStyle : '');
276
+ };
277
+ paint();
278
+ effect(paint);
279
+ }
280
+ function appendChildren(el, children) {
281
+ if (children == null)
282
+ return;
283
+ if (typeof children === 'string' || typeof children === 'number') {
284
+ el.appendChild(document.createTextNode(String(children)));
285
+ return;
286
+ }
287
+ if (children.nodeType) {
288
+ el.appendChild(children);
289
+ return;
290
+ }
291
+ if (Array.isArray(children)) {
292
+ for (const c of children)
293
+ appendChildren(el, c);
294
+ }
295
+ }
296
+ /**
297
+ * Renders the navigation progress bar. On the server it emits a hidden div
298
+ * snapshot (never flashes on first paint); on the client it claims that node
299
+ * during hydration or builds a fresh one for SPA mounts, then keeps its style
300
+ * in sync with the shared indicator state via an effect.
301
+ *
302
+ * Customize with `color`, `errorColor`, `height`, `duration`, `throttle`,
303
+ * `hideDelay`, `resetDelay`, `estimatedProgress`, `position`, `zIndex`,
304
+ * `class`/`style` — or pass `children` to replace the bar entirely and drive
305
+ * your own UI through `useLoadingIndicator()`.
306
+ */
307
+ export function LoadingIndicator(props = {}, _registry, hydrate) {
308
+ configureLoadingIndicator(props);
309
+ const classNameRaw = props.className != null ? String(props.className) : props.class != null ? String(props.class) : '';
310
+ const userStyle = props.style != null ? String(props.style) : '';
311
+ // Rendering-mode check: no document means the HTML-string branch, even
312
+ // outside a live SSR render (unit tests). State-machine gating uses
313
+ // __vsk_ssr instead — see isServer() above.
314
+ if (typeof document === 'undefined') {
315
+ const attrs = [
316
+ INDICATOR_ATTR,
317
+ classNameRaw ? `class="${escapeAttr(classNameRaw)}"` : '',
318
+ ].filter(Boolean).join(' ');
319
+ const styleAttr = escapeAttr(styleToString(baseStyleEntries(props), applyState(props)) + (userStyle ? ';' + userStyle : ''));
320
+ return `<div ${attrs} aria-hidden="true" role="presentation" style="${styleAttr}"></div>`;
321
+ }
322
+ let el;
323
+ if (hydrate && typeof hydrate.nextElement === 'function') {
324
+ el = hydrate.nextElement('div');
325
+ if (el && !el.parentNode && hydrate.root) {
326
+ const existing = hydrate.root.querySelector(`[${INDICATOR_ATTR}]`);
327
+ if (existing)
328
+ el = existing;
329
+ }
330
+ }
331
+ else {
332
+ el = document.createElement('div');
333
+ }
334
+ el.setAttribute(INDICATOR_ATTR, '');
335
+ if (classNameRaw)
336
+ el.className = classNameRaw;
337
+ appendChildren(el, props.children);
338
+ wire(el, props, userStyle);
339
+ if (el.parentNode)
340
+ return document.createDocumentFragment();
341
+ return el;
342
+ }
package/dist/md.d.ts CHANGED
@@ -1,17 +1,126 @@
1
1
  import type { HydrateWalker } from '@vesk/runtime/src/hydrate';
2
2
  export declare function escapeHtml(s: string): string;
3
- export declare function renderMarkdown(md: string): string;
3
+ /** Allows http/https/mailto/tel plus relative URLs; anything else → '#'. */
4
+ export declare function sanitizeUrl(url: string): string;
5
+ interface RefDef {
6
+ url: string;
7
+ title: string;
8
+ }
9
+ /**
10
+ * Highlights `code` as `lang` into class-tokenized HTML. Everything is
11
+ * escaped; unknown languages fall back to escaped plain text. Supported:
12
+ * js/ts/jsx/tsx/vsk/vesk family, json, python, go, rust, sql, bash/shell, yaml/toml,
13
+ * css/scss, html/xml/svg/vue/svelte, diff/patch.
14
+ */
15
+ export declare function highlightCode(code: string, lang: string): string;
16
+ export interface InlineOptions {
17
+ autolink?: boolean;
18
+ defs?: Map<string, RefDef>;
19
+ htmlMode?: MdHtmlMode;
20
+ allowTags?: string[];
21
+ rawHtmlWarnings?: MdHtmlWarning[];
22
+ }
23
+ export interface MarkdownOptions {
24
+ /** Highlight fenced code with the built-in tokenizer. Default false. */
25
+ highlight?: boolean;
26
+ /** Wrap code in .md-code chrome with a language badge + copy button. Default false. */
27
+ chrome?: boolean;
28
+ /** Render per-line spans for CSS counter line numbers inside chrome. Default false. */
29
+ lineNumbers?: boolean;
30
+ /** Emit a copy button in the code bar. Default true when chrome is on. */
31
+ copy?: boolean;
32
+ /** Add slug anchors to headings. Default false. */
33
+ ids?: boolean;
34
+ /** Linkify bare http(s)/www/mailto URLs. Default false. */
35
+ autolink?: boolean;
36
+ /** Honor two-space / backslash hard line breaks in paragraphs. Default false. */
37
+ hardBreaks?: boolean;
38
+ /** Raw-HTML policy (see MdHtmlMode). Default 'escape' — every HTML-ish
39
+ * construct renders as visible text. */
40
+ html?: MdHtmlMode;
41
+ /** Tag allowlist for html:'allowlist'. Defaults to MD_DEFAULT_ALLOW_TAGS. */
42
+ allowTags?: string[];
43
+ }
44
+ export type MdHtmlMode = 'escape' | 'allow' | 'allowlist';
45
+ /**
46
+ * Tags allowed by default when html = 'allowlist'. Inline, formatting-level
47
+ * tags only — structural/embedding tags (script, iframe, img, div, …) must be
48
+ * opted into explicitly via allowTags. Keep in sync with
49
+ * packages/compiler/src/config.ts MD_DEFAULT_ALLOW_TAGS.
50
+ */
51
+ export declare const MD_DEFAULT_ALLOW_TAGS: string[];
52
+ /** One raw-HTML passthrough observed while rendering. */
53
+ export interface MdHtmlWarning {
54
+ tag: string;
55
+ /** Short sample of the source snippet (bounded). */
56
+ sample: string;
57
+ }
58
+ export declare const MD_BASE_CSS = "\n.vesk-md { color: #24292f; font-size: 16px; line-height: 1.7; word-wrap: break-word; }\n.vesk-md h1,.vesk-md h2,.vesk-md h3,.vesk-md h4,.vesk-md h5,.vesk-md h6 { margin: 1.4em 0 .6em; font-weight: 650; line-height: 1.25; }\n.vesk-md h1 { font-size: 2em; }\n.vesk-md h2 { font-size: 1.5em; }\n.vesk-md h3 { font-size: 1.25em; } .vesk-md h4 { font-size: 1em; }\n.vesk-md p { margin: .8em 0; }\n.vesk-md a { color: #0969da; text-decoration: none; } .vesk-md a:hover { text-decoration: underline; }\n.vesk-md img { max-width: 100%; border-radius: 6px; }\n.vesk-md hr { border: 0; height: 1px; background: #d0d7de; margin: 1.6em 0; }\n.vesk-md blockquote { margin: .8em 0; padding: .2em 1em; color: #57606a; border-left: .25em solid #d0d7de; }\n.vesk-md ul,.vesk-md ol { margin: .8em 0; padding-left: 2em; }\n.vesk-md ul { list-style: disc; } .vesk-md ul ul { list-style: circle; } .vesk-md ul ul ul { list-style: square; }\n.vesk-md ol { list-style: decimal; } .vesk-md ol ol { list-style: lower-alpha; }\n.vesk-md li { margin: .25em 0; }\n.vesk-md li.md-task { list-style: none; margin-left: -1.4em; display: flex; gap: .5em; align-items: baseline; }\n.vesk-md code:not(pre code) { background: rgba(175,184,193,.2); padding: .15em .35em; border-radius: 5px; font-family: ui-monospace,SFMono-Regular,Menlo,Consolas,monospace; font-size: 85%; }\n.vesk-md .md-table-wrap { overflow-x: auto; margin: .8em 0; }\n.vesk-md table.md-table { border-collapse: collapse; width: max-content; max-width: 100%; font-size: .95em; }\n.vesk-md .md-table th,.vesk-md .md-table td { border: 1px solid #d0d7de; padding: 6px 13px; }\n.vesk-md .md-table th { background: #f6f8fa; font-weight: 650; }\n.vesk-md .md-table tr:nth-child(2n) td { background: #f6f8fa80; }\n.vesk-md .md-code { --md-code-bg: #f6f8fa; margin: 1em 0; border-radius: 8px; overflow: hidden; background: var(--md-code-bg); border: 1px solid #d1d9e0; }\n.vesk-md .md-code-bar { display: flex; justify-content: space-between; align-items: center; padding: 6px 12px; background: var(--md-code-bg); border-bottom: 1px solid #d1d9e0; }\n.vesk-md .md-code-lang { font-family: ui-monospace,monospace; font-size: 11px; letter-spacing: .04em; text-transform: uppercase; color: #59636e; }\n.vesk-md .md-copy { all: unset; cursor: pointer; font: 11px ui-monospace,monospace; color: #59636e; padding: 2px 8px; border-radius: 6px; }\n.vesk-md .md-copy:hover { color: #1f2328; background: #eaeef2; }\n.vesk-md .md-copy.md-copied { color: #1a7f37; }\n.vesk-md .md-code pre { margin: 0; overflow-x: auto; padding: 14px 16px; }\n.vesk-md .md-code code { font-family: ui-monospace,SFMono-Regular,Menlo,Consolas,monospace; font-size: 13.5px; line-height: 1.55; color: var(--md-code-fg,#1f2328); background: none; padding: 0; }\n.vesk-md code[md-lines] { counter-reset: ln; display: block; }\n.vesk-md code[md-lines] .tok-line { display: block; counter-increment: ln; padding-left: 3.2em; position: relative; }\n.vesk-md code[md-lines] .tok-line::before { content: counter(ln); position: absolute; left: 0; width: 2.4em; text-align: right; color: #8c959f; user-select: none; }\n.tok-kw { color: #cf222e; } .tok-lit { color: #0550ae; } .tok-str { color: #0a3069; }\n.tok-num { color: #0550ae; } .tok-com { color: #59636e; font-style: italic; }\n.tok-fn { color: #8250df; } .tok-attr { color: #0550ae; } .tok-prop { color: #0550ae; }\n.tok-sel { color: #116329; } .tok-add { color: #116329; background: #dafbe1; display: inline-block; width: 100%; }\n.tok-del { color: #cf222e; background: #ffebe9; display: inline-block; width: 100%; }\n.vesk-md-dark { --md-code-bg: #0d1117; --md-code-fg: #c9d1d9; }\n.vesk-md-dark .md-code-bar { border-bottom-color: #30363d; }\n.vesk-md-dark .md-code-lang { color: #8b949e; }\n.vesk-md-dark .md-copy { color: #8b949e; }\n.vesk-md-dark .md-copy:hover { color: #c9d1d9; background: #30363d; }\n.vesk-md-dark .md-copy.md-copied { color: #3fb950; }\n.vesk-md-dark code[md-lines] .tok-line::before { color: #484f58; }\n.vesk-md-dark .tok-kw { color: #ff7b72; } .vesk-md-dark .tok-lit { color: #79c0ff; }\n.vesk-md-dark .tok-str { color: #a5d6ff; } .vesk-md-dark .tok-num { color: #f2cc60; }\n.vesk-md-dark .tok-com { color: #8b949e; font-style: italic; }\n.vesk-md-dark .tok-fn { color: #d2a8ff; } .vesk-md-dark .tok-attr { color: #79c0ff; }\n.vesk-md-dark .tok-prop { color: #79c0ff; } .vesk-md-dark .tok-sel { color: #7ee787; }\n.vesk-md-dark .tok-add { color: #aff5b4; background: rgba(46,160,67,.15); }\n.vesk-md-dark .tok-del { color: #ffdcd7; background: rgba(248,81,73,.15); }\n";
59
+ /**
60
+ * Renders markdown to HTML with default (legacy) options — output shape is
61
+ * stable for existing consumers. Pass options for advanced features:
62
+ * `{ highlight, chrome, lineNumbers, copy, ids, autolink, hardBreaks }`.
63
+ */
64
+ export declare function renderMarkdown(md: string, options?: MarkdownOptions): string;
65
+ /** Like renderMarkdown, but also returns the raw-HTML passthrough warnings. */
66
+ export declare function renderMarkdownEx(md: string, options?: MarkdownOptions): {
67
+ html: string;
68
+ warnings: MdHtmlWarning[];
69
+ };
70
+ /**
71
+ * Sets the process-wide default raw-HTML policy for `<Md>`. Called by the CLI
72
+ * and servers with the `md` key from vesk.config.ts. Individual `<Md>` usages
73
+ * can still override per-instance via the `html` / `allowTags` props.
74
+ */
75
+ export declare function configureMd(policy?: {
76
+ html?: MdHtmlMode;
77
+ allowTags?: string[];
78
+ }): void;
79
+ /** The effective process-wide policy (after configureMd). */
80
+ export declare function getMdPolicy(): {
81
+ html: MdHtmlMode;
82
+ allowTags: string[];
83
+ };
84
+ export declare function setMdConsoleWarnings(enabled: boolean): void;
85
+ /** Drains the collected passthrough samples (for build-time summaries). */
86
+ export declare function drainMdHtmlWarnings(): MdHtmlWarning[];
4
87
  export interface MdProps {
5
- content?: string;
88
+ /** Markdown source — a plain string or a tracked cell (reactive on client). */
89
+ content?: string | {
90
+ get: () => string;
91
+ };
92
+ /** Default background for all code blocks (CSS color or 'none'). Fence-level bg= wins. */
93
+ codeBg?: string;
94
+ /** Default code text color. Fence-level fg= wins. */
95
+ codeFg?: string;
96
+ /** Code theme preset: 'light' (default) or 'dark'. Per-fence bg=/fg= still win. */
97
+ theme?: 'light' | 'dark';
6
98
  class?: string;
7
99
  className?: string;
8
100
  style?: string;
101
+ /** Inject MD_BASE_CSS (true), a custom stylesheet string, or nothing (false/default). */
102
+ css?: boolean | string;
103
+ /** Per-line spans for CSS-counter line numbers in code chrome. */
104
+ lineNumbers?: boolean;
105
+ /** Copy buttons on code blocks (client-wired when hydrated). Default true. */
106
+ copy?: boolean;
107
+ highlight?: boolean;
108
+ ids?: boolean;
109
+ autolink?: boolean;
110
+ hardBreaks?: boolean;
111
+ /** Per-instance raw-HTML policy — overrides the global md.html config. */
112
+ html?: MdHtmlMode | string;
113
+ /** Per-instance tag allowlist — overrides the global md.allowTags config. */
114
+ allowTags?: string[];
9
115
  [k: string]: unknown;
10
116
  }
11
117
  /**
12
118
  * Renders markdown as HTML. On the server it returns an HTML string; on the
13
119
  * client it claims the SSR-rendered subtree during hydration (or builds a
14
- * fresh wrapper element for SPA navigation).
120
+ * fresh wrapper element for SPA navigation). Advanced rendering (highlighted
121
+ * code with chrome, heading anchors, autolinks) is on by default; tune with
122
+ * the css / lineNumbers / copy / highlight / ids / autolink / hardBreaks props.
15
123
  */
16
124
  export declare function Md(props: MdProps, _registry?: Map<string, unknown>, hydrate?: HydrateWalker): Node | string;
125
+ export {};
17
126
  //# sourceMappingURL=md.d.ts.map
package/dist/md.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"md.d.ts","sourceRoot":"","sources":["../src/md.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAU/D,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAW5C;AA2cD,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED,MAAM,WAAW,OAAO;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACrB;AAMD;;;;GAIG;AACH,wBAAgB,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI,GAAG,MAAM,CA6B3G"}
1
+ {"version":3,"file":"md.d.ts","sourceRoot":"","sources":["../src/md.ts"],"names":[],"mappings":"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"}