@lapismd/mira 0.0.5 → 0.1.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 +46 -0
- package/dist/extensions/index.d.ts +12 -7
- package/dist/extensions/index.d.ts.map +1 -1
- package/dist/extensions/index.js +13 -3
- package/dist/extensions/inline-links.d.ts +8 -0
- package/dist/extensions/inline-links.d.ts.map +1 -0
- package/dist/extensions/inline-links.js +120 -0
- package/dist/extensions/markdown-editing.d.ts +32 -0
- package/dist/extensions/markdown-editing.d.ts.map +1 -0
- package/dist/extensions/markdown-editing.js +1 -0
- package/dist/internal/codemirror/base/index.d.ts.map +1 -1
- package/dist/internal/codemirror/base/index.js +3 -0
- package/dist/internal/codemirror/markdown/index.d.ts.map +1 -1
- package/dist/internal/codemirror/markdown/index.js +2 -1
- package/dist/internal/codemirror/rich/block-controls.d.ts.map +1 -1
- package/dist/internal/codemirror/rich/block-controls.js +5 -0
- package/dist/internal/codemirror/rich/block-gutter-accessibility.d.ts +15 -0
- package/dist/internal/codemirror/rich/block-gutter-accessibility.d.ts.map +1 -0
- package/dist/internal/codemirror/rich/block-gutter-accessibility.js +67 -0
- package/dist/internal/codemirror/rich/index.d.ts.map +1 -1
- package/dist/internal/codemirror/rich/index.js +45 -9
- package/dist/internal/codemirror/rich/utils/images.d.ts +6 -3
- package/dist/internal/codemirror/rich/utils/images.d.ts.map +1 -1
- package/dist/internal/codemirror/rich/utils/images.js +16 -29
- package/dist/internal/codemirror/rich/utils/measured-indent.d.ts.map +1 -1
- package/dist/internal/codemirror/rich/utils/measured-indent.js +13 -1
- package/dist/internal/codemirror/rich/utils/references.d.ts +15 -0
- package/dist/internal/codemirror/rich/utils/references.d.ts.map +1 -0
- package/dist/internal/codemirror/rich/utils/references.js +86 -0
- package/dist/internal/codemirror/rich/widgets/preview-widgets.d.ts +3 -0
- package/dist/internal/codemirror/rich/widgets/preview-widgets.d.ts.map +1 -1
- package/dist/internal/codemirror/rich/widgets/preview-widgets.js +31 -3
- package/dist/internal/inline-links/icons.d.ts +115 -0
- package/dist/internal/inline-links/icons.d.ts.map +1 -0
- package/dist/internal/inline-links/icons.js +148 -0
- package/dist/internal/inline-links/live-preview.d.ts +5 -0
- package/dist/internal/inline-links/live-preview.d.ts.map +1 -0
- package/dist/internal/inline-links/live-preview.js +135 -0
- package/dist/internal/inline-links/registry.d.ts +44 -0
- package/dist/internal/inline-links/registry.d.ts.map +1 -0
- package/dist/internal/inline-links/registry.js +153 -0
- package/dist/mira.svelte +2 -0
- package/dist/mira.svelte.d.ts +1 -1
- package/dist/mira.svelte.d.ts.map +1 -1
- package/dist/preview/asset-url-lease.d.ts +6 -0
- package/dist/preview/asset-url-lease.d.ts.map +1 -0
- package/dist/preview/asset-url-lease.js +28 -0
- package/dist/preview/components/embed.svelte +10 -5
- package/dist/preview/components/embed.svelte.d.ts.map +1 -1
- package/dist/preview/components/image.svelte +7 -2
- package/dist/preview/components/image.svelte.d.ts.map +1 -1
- package/dist/preview/components/inline-link.svelte +94 -0
- package/dist/preview/components/inline-link.svelte.d.ts +16 -0
- package/dist/preview/components/inline-link.svelte.d.ts.map +1 -0
- package/dist/preview/components/link-destination-tooltip.svelte +63 -0
- package/dist/preview/components/link-destination-tooltip.svelte.d.ts +7 -0
- package/dist/preview/components/link-destination-tooltip.svelte.d.ts.map +1 -0
- package/dist/preview/components/link-site-icon.svelte +39 -0
- package/dist/preview/components/link-site-icon.svelte.d.ts +10 -0
- package/dist/preview/components/link-site-icon.svelte.d.ts.map +1 -0
- package/dist/preview/components/link.svelte +19 -9
- package/dist/preview/components/link.svelte.d.ts.map +1 -1
- package/dist/preview/editable-markdown-preview/editable-markdown-surface.svelte +6 -1
- package/dist/preview/editable-markdown-preview/editable-markdown-surface.svelte.d.ts.map +1 -1
- package/dist/preview/editable-markdown-preview/editing-session.d.ts +2 -0
- package/dist/preview/editable-markdown-preview/editing-session.d.ts.map +1 -1
- package/dist/preview/editable-markdown-preview/editing-session.js +59 -6
- package/dist/preview/editable-markdown-preview/serialized-writer.d.ts +6 -8
- package/dist/preview/editable-markdown-preview/serialized-writer.d.ts.map +1 -1
- package/dist/preview/editable-markdown-preview/serialized-writer.js +76 -6
- package/dist/preview/index.d.ts +2 -0
- package/dist/preview/index.d.ts.map +1 -1
- package/dist/preview/index.js +2 -0
- package/dist/preview/markdown-preview.svelte +15 -3
- package/dist/preview/markdown-preview.svelte.d.ts.map +1 -1
- package/dist/preview/renderer/utils.js +0 -2
- package/dist/preview/styles/inline-links.css +38 -0
- package/dist/preview/styles/links-embeds-tags.css +2 -2
- package/dist/preview/styles/mermaid-highlight.css +4 -3
- package/dist/preview/styles/references.css +72 -0
- package/dist/preview/styles/source-mode.css +32 -3
- package/dist/preview/styles.css +2 -0
- package/dist/tables/editor-column.svelte +20 -7
- package/dist/tables/editor-column.svelte.d.ts +2 -0
- package/dist/tables/editor-column.svelte.d.ts.map +1 -1
- package/dist/tables/editor-table.svelte +4 -0
- package/dist/tables/editor-table.svelte.d.ts +2 -0
- package/dist/tables/editor-table.svelte.d.ts.map +1 -1
- package/dist/tables/grid-editor-column.svelte +6 -2
- package/dist/tables/grid-editor-column.svelte.d.ts +2 -0
- package/dist/tables/grid-editor-column.svelte.d.ts.map +1 -1
- package/dist/tables/grid-editor-table.svelte +4 -0
- package/dist/tables/grid-editor-table.svelte.d.ts +2 -0
- package/dist/tables/grid-editor-table.svelte.d.ts.map +1 -1
- package/dist/tables/index.d.ts +1 -0
- package/dist/tables/index.d.ts.map +1 -1
- package/dist/tables/index.js +1 -0
- package/dist/tables/markdown-table-data-cell.svelte +4 -0
- package/dist/tables/markdown-table-data-cell.svelte.d.ts +2 -0
- package/dist/tables/markdown-table-data-cell.svelte.d.ts.map +1 -1
- package/dist/tables/table-reader.svelte +101 -0
- package/dist/tables/table-reader.svelte.d.ts +21 -0
- package/dist/tables/table-reader.svelte.d.ts.map +1 -0
- package/dist/tables/types.d.ts +2 -0
- package/dist/tables/types.d.ts.map +1 -1
- package/dist/tables/widgets/grid-table-widget.d.ts +1 -1
- package/dist/tables/widgets/grid-table-widget.d.ts.map +1 -1
- package/dist/tables/widgets/grid-table-widget.js +5 -2
- package/dist/tables/widgets/lifecycle.d.ts +4 -0
- package/dist/tables/widgets/lifecycle.d.ts.map +1 -0
- package/dist/tables/widgets/lifecycle.js +13 -0
- package/dist/tables/widgets/pipe-table-widget.d.ts +1 -1
- package/dist/tables/widgets/pipe-table-widget.d.ts.map +1 -1
- package/dist/tables/widgets/pipe-table-widget.js +5 -2
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/context-menu/context-menu-radio-group.svelte.d.ts +1 -1
- package/dist/ui/dropdown-menu/dropdown-menu-radio-group.svelte.d.ts +1 -1
- package/dist/ui/toolbar/toolbar-group.svelte.d.ts +1 -1
- package/inline-links-NOTICE.md +31 -0
- package/package.json +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image.svelte.d.ts","sourceRoot":"","sources":["../../../src/preview/components/image.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"image.svelte.d.ts","sourceRoot":"","sources":["../../../src/preview/components/image.svelte.ts"],"names":[],"mappings":"AAcE,KAAK,KAAK,GAAG;IACX,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAC/B,CAAC;AAqNJ,QAAA,MAAM,KAAK,8CAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { getContext, type Snippet } from "svelte";
|
|
3
|
+
import {
|
|
4
|
+
miraAppearanceContextKey,
|
|
5
|
+
resolveMiraThemeAttribute,
|
|
6
|
+
resolveMiraColorModeAttribute,
|
|
7
|
+
type MiraAppearanceContext,
|
|
8
|
+
} from "../../internal/appearance-context";
|
|
9
|
+
import type { HTMLAnchorAttributes } from "svelte/elements";
|
|
10
|
+
import * as Tooltip from "../../ui/tooltip";
|
|
11
|
+
import LinkSiteIcon from "./link-site-icon.svelte";
|
|
12
|
+
import {
|
|
13
|
+
defaultMiraLinkIconRegistry,
|
|
14
|
+
parseInlineLinkUrl,
|
|
15
|
+
type MiraLinkIconRegistry,
|
|
16
|
+
} from "../../internal/inline-links/registry";
|
|
17
|
+
let {
|
|
18
|
+
href = "",
|
|
19
|
+
label,
|
|
20
|
+
registry = defaultMiraLinkIconRegistry,
|
|
21
|
+
children,
|
|
22
|
+
title,
|
|
23
|
+
class: className = "",
|
|
24
|
+
target = "_blank",
|
|
25
|
+
rel,
|
|
26
|
+
ref = $bindable(null),
|
|
27
|
+
tagName: _tagName,
|
|
28
|
+
sourcePath: _sourcePath,
|
|
29
|
+
dialog: _dialog,
|
|
30
|
+
...rest
|
|
31
|
+
}: Omit<HTMLAnchorAttributes, "children"> & {
|
|
32
|
+
registry?: MiraLinkIconRegistry;
|
|
33
|
+
label?: string;
|
|
34
|
+
children?: Snippet;
|
|
35
|
+
ref?: HTMLAnchorElement | null;
|
|
36
|
+
tagName?: string;
|
|
37
|
+
sourcePath?: string;
|
|
38
|
+
dialog?: boolean;
|
|
39
|
+
} = $props();
|
|
40
|
+
const safeHref = $derived(parseInlineLinkUrl(href ?? "")?.href);
|
|
41
|
+
const appearance = getContext<MiraAppearanceContext | undefined>(
|
|
42
|
+
miraAppearanceContextKey,
|
|
43
|
+
);
|
|
44
|
+
const appearanceTheme = $derived(
|
|
45
|
+
resolveMiraThemeAttribute(appearance?.theme, ref),
|
|
46
|
+
);
|
|
47
|
+
const appearanceMode = $derived(
|
|
48
|
+
resolveMiraColorModeAttribute(appearance?.colorMode, ref),
|
|
49
|
+
);
|
|
50
|
+
const showDestination = $derived(
|
|
51
|
+
Boolean(safeHref && (title || children || (label && label !== href))),
|
|
52
|
+
);
|
|
53
|
+
const safeRel = $derived(
|
|
54
|
+
target === "_blank"
|
|
55
|
+
? [
|
|
56
|
+
...new Set(`${rel ?? ""} noopener noreferrer`.trim().split(/\s+/u)),
|
|
57
|
+
].join(" ")
|
|
58
|
+
: rel,
|
|
59
|
+
);
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
<Tooltip.Provider delayDuration={200}>
|
|
63
|
+
<Tooltip.Root disabled={!showDestination}>
|
|
64
|
+
<Tooltip.Trigger>
|
|
65
|
+
{#snippet child({ props })}
|
|
66
|
+
<a
|
|
67
|
+
{...props}
|
|
68
|
+
{...rest}
|
|
69
|
+
bind:this={ref}
|
|
70
|
+
class={`mira-inline-link ${className}`.trim()}
|
|
71
|
+
href={safeHref}
|
|
72
|
+
{title}
|
|
73
|
+
{target}
|
|
74
|
+
rel={safeRel}
|
|
75
|
+
>
|
|
76
|
+
{#if safeHref}<LinkSiteIcon href={safeHref} {registry} />{/if}<span
|
|
77
|
+
>{#if children}{@render children()}{:else}{label || href}{/if}</span
|
|
78
|
+
>
|
|
79
|
+
</a>
|
|
80
|
+
{/snippet}
|
|
81
|
+
</Tooltip.Trigger>
|
|
82
|
+
<Tooltip.Content
|
|
83
|
+
role="tooltip"
|
|
84
|
+
side="top"
|
|
85
|
+
sideOffset={6}
|
|
86
|
+
data-mira-theme={appearanceTheme}
|
|
87
|
+
data-mira-color-mode={appearanceMode}
|
|
88
|
+
>
|
|
89
|
+
{#if title}<span>{title}</span><br />{/if}<span
|
|
90
|
+
class="mira-inline-link__destination">{safeHref}</span
|
|
91
|
+
>
|
|
92
|
+
</Tooltip.Content>
|
|
93
|
+
</Tooltip.Root>
|
|
94
|
+
</Tooltip.Provider>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type Snippet } from "svelte";
|
|
2
|
+
import type { HTMLAnchorAttributes } from "svelte/elements";
|
|
3
|
+
import { type MiraLinkIconRegistry } from "../../internal/inline-links/registry";
|
|
4
|
+
type $$ComponentProps = Omit<HTMLAnchorAttributes, "children"> & {
|
|
5
|
+
registry?: MiraLinkIconRegistry;
|
|
6
|
+
label?: string;
|
|
7
|
+
children?: Snippet;
|
|
8
|
+
ref?: HTMLAnchorElement | null;
|
|
9
|
+
tagName?: string;
|
|
10
|
+
sourcePath?: string;
|
|
11
|
+
dialog?: boolean;
|
|
12
|
+
};
|
|
13
|
+
declare const InlineLink: import("svelte").Component<$$ComponentProps, {}, "ref">;
|
|
14
|
+
type InlineLink = ReturnType<typeof InlineLink>;
|
|
15
|
+
export default InlineLink;
|
|
16
|
+
//# sourceMappingURL=inline-link.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inline-link.svelte.d.ts","sourceRoot":"","sources":["../../../src/preview/components/inline-link.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,KAAK,OAAO,EAAE,MAAM,QAAQ,CAAC;AAOlD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAG5D,OAAO,EAGH,KAAK,oBAAoB,EAC1B,MAAM,sCAAsC,CAAC;AAE/C,KAAK,gBAAgB,GAAI,IAAI,CAAC,oBAAoB,EAAE,UAAU,CAAC,GAAG;IAC/D,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AA8DJ,QAAA,MAAM,UAAU,yDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import * as Tooltip from "../../ui/tooltip";
|
|
3
|
+
let { anchor }: { anchor: HTMLAnchorElement } = $props();
|
|
4
|
+
const id = $props.id();
|
|
5
|
+
let open = $state(false);
|
|
6
|
+
const theme = $derived(
|
|
7
|
+
anchor.closest<HTMLElement>("[data-mira-theme]")?.dataset.miraTheme,
|
|
8
|
+
);
|
|
9
|
+
const colorMode = $derived(
|
|
10
|
+
anchor.closest<HTMLElement>("[data-mira-color-mode]")?.dataset
|
|
11
|
+
.miraColorMode,
|
|
12
|
+
);
|
|
13
|
+
$effect(() => {
|
|
14
|
+
const show = () => (open = true);
|
|
15
|
+
const hide = () => (open = false);
|
|
16
|
+
const escape = (event: KeyboardEvent) => {
|
|
17
|
+
if (event.key === "Escape") hide();
|
|
18
|
+
};
|
|
19
|
+
anchor.addEventListener("pointerenter", show);
|
|
20
|
+
anchor.addEventListener("pointerleave", hide);
|
|
21
|
+
anchor.addEventListener("focus", show);
|
|
22
|
+
anchor.addEventListener("blur", hide);
|
|
23
|
+
anchor.addEventListener("keydown", escape);
|
|
24
|
+
if (anchor.matches(":focus, :hover")) show();
|
|
25
|
+
return () => {
|
|
26
|
+
anchor.removeEventListener("pointerenter", show);
|
|
27
|
+
anchor.removeEventListener("pointerleave", hide);
|
|
28
|
+
anchor.removeEventListener("focus", show);
|
|
29
|
+
anchor.removeEventListener("blur", hide);
|
|
30
|
+
anchor.removeEventListener("keydown", escape);
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
$effect(() => {
|
|
34
|
+
if (!open) return;
|
|
35
|
+
const previous = anchor.getAttribute("aria-describedby");
|
|
36
|
+
anchor.setAttribute(
|
|
37
|
+
"aria-describedby",
|
|
38
|
+
[previous, id].filter(Boolean).join(" "),
|
|
39
|
+
);
|
|
40
|
+
return () => {
|
|
41
|
+
if (previous) anchor.setAttribute("aria-describedby", previous);
|
|
42
|
+
else anchor.removeAttribute("aria-describedby");
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<Tooltip.Provider>
|
|
48
|
+
<Tooltip.Root bind:open>
|
|
49
|
+
<Tooltip.Content
|
|
50
|
+
{id}
|
|
51
|
+
role="tooltip"
|
|
52
|
+
customAnchor={anchor}
|
|
53
|
+
side="top"
|
|
54
|
+
sideOffset={6}
|
|
55
|
+
data-mira-theme={theme}
|
|
56
|
+
data-mira-color-mode={colorMode}
|
|
57
|
+
>
|
|
58
|
+
{#if anchor.title}<span>{anchor.title}</span><br />{/if}<span
|
|
59
|
+
class="mira-inline-link__destination">{anchor.href}</span
|
|
60
|
+
>
|
|
61
|
+
</Tooltip.Content>
|
|
62
|
+
</Tooltip.Root>
|
|
63
|
+
</Tooltip.Provider>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
anchor: HTMLAnchorElement;
|
|
3
|
+
};
|
|
4
|
+
declare const LinkDestinationTooltip: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
5
|
+
type LinkDestinationTooltip = ReturnType<typeof LinkDestinationTooltip>;
|
|
6
|
+
export default LinkDestinationTooltip;
|
|
7
|
+
//# sourceMappingURL=link-destination-tooltip.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-destination-tooltip.svelte.d.ts","sourceRoot":"","sources":["../../../src/preview/components/link-destination-tooltip.svelte.ts"],"names":[],"mappings":"AAKC,KAAK,gBAAgB,GAAI;IAAE,MAAM,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAyDxD,QAAA,MAAM,sBAAsB,sDAAwC,CAAC;AACrE,KAAK,sBAAsB,GAAG,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACxE,eAAe,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
defaultMiraLinkIconRegistry,
|
|
4
|
+
type MiraLinkIconRegistry,
|
|
5
|
+
} from "../../internal/inline-links/registry";
|
|
6
|
+
let {
|
|
7
|
+
href,
|
|
8
|
+
registry = defaultMiraLinkIconRegistry,
|
|
9
|
+
class: className = "",
|
|
10
|
+
}: {
|
|
11
|
+
href: string;
|
|
12
|
+
registry?: MiraLinkIconRegistry;
|
|
13
|
+
class?: string;
|
|
14
|
+
} = $props();
|
|
15
|
+
const resolved = $derived(registry.resolve(href));
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
{#if resolved?.icon}
|
|
19
|
+
<svg
|
|
20
|
+
class={`mira-link-site-icon ${className}`.trim()}
|
|
21
|
+
data-link-site={resolved.id}
|
|
22
|
+
viewBox={resolved.icon.viewBox ?? "0 0 24 24"}
|
|
23
|
+
fill="currentColor"
|
|
24
|
+
aria-hidden="true"
|
|
25
|
+
focusable="false"
|
|
26
|
+
>
|
|
27
|
+
{#each resolved.icon.paths as path}
|
|
28
|
+
<path
|
|
29
|
+
d={path.d}
|
|
30
|
+
fill={path.fill}
|
|
31
|
+
stroke={path.stroke}
|
|
32
|
+
stroke-width={path.strokeWidth}
|
|
33
|
+
stroke-linecap={path.strokeLinecap}
|
|
34
|
+
stroke-linejoin={path.strokeLinejoin}
|
|
35
|
+
fill-rule={path.fillRule}
|
|
36
|
+
/>
|
|
37
|
+
{/each}
|
|
38
|
+
</svg>
|
|
39
|
+
{/if}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type MiraLinkIconRegistry } from "../../internal/inline-links/registry";
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
href: string;
|
|
4
|
+
registry?: MiraLinkIconRegistry;
|
|
5
|
+
class?: string;
|
|
6
|
+
};
|
|
7
|
+
declare const LinkSiteIcon: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
|
+
type LinkSiteIcon = ReturnType<typeof LinkSiteIcon>;
|
|
9
|
+
export default LinkSiteIcon;
|
|
10
|
+
//# sourceMappingURL=link-site-icon.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-site-icon.svelte.d.ts","sourceRoot":"","sources":["../../../src/preview/components/link-site-icon.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAEH,KAAK,oBAAoB,EAC1B,MAAM,sCAAsC,CAAC;AAE/C,KAAK,gBAAgB,GAAI;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAqBJ,QAAA,MAAM,YAAY,sDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
import { useMarkdownContext } from "../renderer/context.svelte";
|
|
20
20
|
import EditableMarkdownSurface from "../editable-markdown-preview/editable-markdown-surface.svelte";
|
|
21
21
|
import EmbeddedMarkdownPreview from "./embedded-markdown-preview.svelte";
|
|
22
|
+
import { createAssetUrlLease } from "../asset-url-lease";
|
|
22
23
|
|
|
23
24
|
type Props = {
|
|
24
25
|
href?: string;
|
|
@@ -69,7 +70,9 @@
|
|
|
69
70
|
const target = $derived(id || href);
|
|
70
71
|
const displayText = $derived(text || label || target);
|
|
71
72
|
const activeSourcePath = $derived(sourcePath || markdown.sourcePath);
|
|
72
|
-
const parsedTarget = $derived(
|
|
73
|
+
const parsedTarget = $derived(
|
|
74
|
+
parseMiraFileTarget(target, activeSourcePath, { decodeUri: !id }),
|
|
75
|
+
);
|
|
73
76
|
const hasFileAdapter = $derived(Boolean(markdown.fileAdapter));
|
|
74
77
|
const isExternal = $derived(isExternalHref(target));
|
|
75
78
|
const resolvedHref = $derived(
|
|
@@ -126,6 +129,14 @@
|
|
|
126
129
|
).then(
|
|
127
130
|
(file) => {
|
|
128
131
|
if (!cancelled) {
|
|
132
|
+
if (
|
|
133
|
+
resolvedFile?.path === file?.path &&
|
|
134
|
+
resolvedFile?.name === file?.name &&
|
|
135
|
+
resolvedFile?.extension === file?.extension &&
|
|
136
|
+
resolvedFile?.kind === file?.kind
|
|
137
|
+
) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
129
140
|
if (resolvedFile?.path !== file?.path) {
|
|
130
141
|
previewMarkdown = null;
|
|
131
142
|
previewAssetUrl = null;
|
|
@@ -174,14 +185,12 @@
|
|
|
174
185
|
}
|
|
175
186
|
|
|
176
187
|
let cancelled = false;
|
|
177
|
-
const markdownPromise =
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const
|
|
181
|
-
? Promise.resolve(adapter.readAssetUrl(file))
|
|
182
|
-
: Promise.resolve(null);
|
|
188
|
+
const markdownPromise = Promise.resolve().then(
|
|
189
|
+
() => adapter.readMarkdown?.(file) ?? null,
|
|
190
|
+
);
|
|
191
|
+
const asset = createAssetUrlLease(adapter, file);
|
|
183
192
|
|
|
184
|
-
Promise.all([markdownPromise,
|
|
193
|
+
Promise.all([markdownPromise, asset.result]).then(
|
|
185
194
|
([nextMarkdown, nextAssetUrl]) => {
|
|
186
195
|
if (cancelled) {
|
|
187
196
|
return;
|
|
@@ -205,6 +214,7 @@
|
|
|
205
214
|
|
|
206
215
|
return () => {
|
|
207
216
|
cancelled = true;
|
|
217
|
+
asset.release();
|
|
208
218
|
stopWatching?.();
|
|
209
219
|
};
|
|
210
220
|
});
|
|
@@ -324,7 +334,7 @@
|
|
|
324
334
|
src={previewAssetUrl}
|
|
325
335
|
alt={resolvedFile.name || displayText}
|
|
326
336
|
/>
|
|
327
|
-
{:else if previewMarkdown}
|
|
337
|
+
{:else if previewMarkdown !== null}
|
|
328
338
|
{#snippet renderedPreview(value: string)}
|
|
329
339
|
<EmbeddedMarkdownPreview
|
|
330
340
|
class="mira-link-preview__markdown"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link.svelte.d.ts","sourceRoot":"","sources":["../../../src/preview/components/link.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,EAAc,KAAK,OAAO,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"link.svelte.d.ts","sourceRoot":"","sources":["../../../src/preview/components/link.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,EAAc,KAAK,OAAO,EAAE,MAAM,QAAQ,CAAC;AAsBhD,KAAK,KAAK,GAAG;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CAC1B,CAAC;AAmTJ,QAAA,MAAM,IAAI,8CAAwC,CAAC;AACnD,KAAK,IAAI,GAAG,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC;AACpC,eAAe,IAAI,CAAC"}
|
|
@@ -131,9 +131,10 @@
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
let current = true;
|
|
134
|
+
let persist = write;
|
|
134
135
|
const activeWriter = new SerializedMarkdownWriter({
|
|
135
136
|
value: initialValue,
|
|
136
|
-
write,
|
|
137
|
+
write: (contents) => persist(contents),
|
|
137
138
|
onStateChange(state) {
|
|
138
139
|
if (!current) return;
|
|
139
140
|
writerState = state;
|
|
@@ -151,8 +152,12 @@
|
|
|
151
152
|
register: adapter?.registerEditingSession
|
|
152
153
|
? (path, session) => adapter.registerEditingSession?.(path, session)
|
|
153
154
|
: undefined,
|
|
155
|
+
bind: adapter?.bindMarkdownEditingSession
|
|
156
|
+
? (path, session) => adapter.bindMarkdownEditingSession!(path, session)
|
|
157
|
+
: undefined,
|
|
154
158
|
synchronizeProtection: tick,
|
|
155
159
|
});
|
|
160
|
+
persist = attached.write ?? write;
|
|
156
161
|
|
|
157
162
|
return () => {
|
|
158
163
|
current = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editable-markdown-surface.svelte.d.ts","sourceRoot":"","sources":["../../../src/preview/editable-markdown-preview/editable-markdown-surface.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,KAAK,OAAO,EAAE,MAAM,QAAQ,CAAC;AACrD,OAAO,KAAK,EACR,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,2BAA2B,EAC5B,MAAM,0BAA0B,CAAC;AAclC,KAAK,mBAAmB,GAAG,CACzB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,KACP,IAAI,CAAC;AAEV,KAAK,KAAK,GAAG;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3B,eAAe,CAAC,EAAE,mBAAmB,CAAC;IACtC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,aAAa,EAAE,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,SAAS,CAAC,EAAE,2BAA2B,CAAC;IACxC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,mBAAmB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CACrE,CAAC;
|
|
1
|
+
{"version":3,"file":"editable-markdown-surface.svelte.d.ts","sourceRoot":"","sources":["../../../src/preview/editable-markdown-preview/editable-markdown-surface.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,KAAK,OAAO,EAAE,MAAM,QAAQ,CAAC;AACrD,OAAO,KAAK,EACR,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,2BAA2B,EAC5B,MAAM,0BAA0B,CAAC;AAclC,KAAK,mBAAmB,GAAG,CACzB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,KACP,IAAI,CAAC;AAEV,KAAK,KAAK,GAAG;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3B,eAAe,CAAC,EAAE,mBAAmB,CAAC;IACtC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,aAAa,EAAE,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,SAAS,CAAC,EAAE,2BAA2B,CAAC;IACxC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,mBAAmB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CACrE,CAAC;AAqUJ,QAAA,MAAM,uBAAuB;iBA1CF,OAAO,CAAC,OAAO,CAAC;gBAIjB,OAAO,CAAC,OAAO,CAAC;iCAsC2B,CAAC;AACtE,KAAK,uBAAuB,GAAG,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAC1E,eAAe,uBAAuB,CAAC"}
|
|
@@ -5,9 +5,11 @@ export declare function attachMarkdownEditingSession(options: {
|
|
|
5
5
|
writer: SerializedMarkdownWriter;
|
|
6
6
|
sourcePath?: string;
|
|
7
7
|
register?: MiraFileAdapter["registerEditingSession"];
|
|
8
|
+
bind?: MiraFileAdapter["bindMarkdownEditingSession"];
|
|
8
9
|
synchronizeProtection?: () => Promise<void>;
|
|
9
10
|
}): {
|
|
10
11
|
session: MiraMarkdownEditingSession;
|
|
12
|
+
write?: (value: string) => void | Promise<void>;
|
|
11
13
|
detach(): void;
|
|
12
14
|
};
|
|
13
15
|
//# sourceMappingURL=editing-session.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editing-session.d.ts","sourceRoot":"","sources":["../../../src/preview/editable-markdown-preview/editing-session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,0BAA0B,EAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAEpE,+FAA+F;AAC/F,wBAAgB,4BAA4B,CAAC,OAAO,EAAE;IACpD,MAAM,EAAE,wBAAwB,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,eAAe,CAAC,wBAAwB,CAAC,CAAC;IACrD,qBAAqB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C,GAAG;
|
|
1
|
+
{"version":3,"file":"editing-session.d.ts","sourceRoot":"","sources":["../../../src/preview/editable-markdown-preview/editing-session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,0BAA0B,EAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAEpE,+FAA+F;AAC/F,wBAAgB,4BAA4B,CAAC,OAAO,EAAE;IACpD,MAAM,EAAE,wBAAwB,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,eAAe,CAAC,wBAAwB,CAAC,CAAC;IACrD,IAAI,CAAC,EAAE,eAAe,CAAC,4BAA4B,CAAC,CAAC;IACrD,qBAAqB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C,GAAG;IACF,OAAO,EAAE,0BAA0B,CAAC;IACpC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,IAAI,IAAI,CAAC;CAChB,CAiGA"}
|
|
@@ -3,18 +3,38 @@ export function attachMarkdownEditingSession(options) {
|
|
|
3
3
|
const { writer } = options;
|
|
4
4
|
let detached = false;
|
|
5
5
|
let remove;
|
|
6
|
+
let stop;
|
|
7
|
+
let releaseError;
|
|
8
|
+
let write;
|
|
9
|
+
function releaseIfClean() {
|
|
10
|
+
const state = writer.state;
|
|
11
|
+
if (!detached || state.dirty || state.saving || state.error !== null)
|
|
12
|
+
return;
|
|
13
|
+
try {
|
|
14
|
+
remove?.();
|
|
15
|
+
remove = undefined;
|
|
16
|
+
releaseError = undefined;
|
|
17
|
+
stop?.();
|
|
18
|
+
stop = undefined;
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
releaseError = error ?? new Error("Markdown binding release failed");
|
|
22
|
+
}
|
|
23
|
+
}
|
|
6
24
|
const session = {
|
|
7
25
|
get dirty() {
|
|
8
26
|
const state = writer.state;
|
|
9
|
-
return state.dirty ||
|
|
27
|
+
return (state.dirty ||
|
|
28
|
+
state.saving ||
|
|
29
|
+
state.error !== null ||
|
|
30
|
+
releaseError !== undefined);
|
|
10
31
|
},
|
|
11
32
|
async flush() {
|
|
12
33
|
if (!(await writer.flush()))
|
|
13
34
|
throw writer.state.error ?? new Error("Unable to save Markdown");
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
35
|
+
releaseIfClean();
|
|
36
|
+
if (releaseError !== undefined)
|
|
37
|
+
throw releaseError;
|
|
18
38
|
},
|
|
19
39
|
async protect() {
|
|
20
40
|
const release = await writer.protect();
|
|
@@ -27,10 +47,42 @@ export function attachMarkdownEditingSession(options) {
|
|
|
27
47
|
throw error;
|
|
28
48
|
}
|
|
29
49
|
},
|
|
50
|
+
text: {
|
|
51
|
+
get state() {
|
|
52
|
+
return writer.state;
|
|
53
|
+
},
|
|
54
|
+
subscribe: (listener) => writer.subscribe(listener),
|
|
55
|
+
async protectRecovery() {
|
|
56
|
+
const lease = await writer.protectRecovery();
|
|
57
|
+
try {
|
|
58
|
+
await options.synchronizeProtection?.();
|
|
59
|
+
return lease;
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
lease.release();
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
},
|
|
30
67
|
};
|
|
31
68
|
try {
|
|
32
|
-
if (options.
|
|
69
|
+
if (options.bind) {
|
|
70
|
+
if (!options.sourcePath)
|
|
71
|
+
throw new Error("A Markdown binding requires a stable source path");
|
|
72
|
+
const binding = options.bind(options.sourcePath, session);
|
|
73
|
+
if (!binding ||
|
|
74
|
+
typeof binding.write !== "function" ||
|
|
75
|
+
typeof binding.release !== "function") {
|
|
76
|
+
if (typeof binding?.release === "function")
|
|
77
|
+
binding.release();
|
|
78
|
+
throw new Error("Invalid Markdown editing binding");
|
|
79
|
+
}
|
|
80
|
+
remove = () => binding.release();
|
|
81
|
+
write = (value) => binding.write(value);
|
|
82
|
+
}
|
|
83
|
+
else if (options.sourcePath)
|
|
33
84
|
remove = options.register?.(options.sourcePath, session);
|
|
85
|
+
stop = writer.subscribe(releaseIfClean);
|
|
34
86
|
}
|
|
35
87
|
catch (error) {
|
|
36
88
|
writer.destroy();
|
|
@@ -38,6 +90,7 @@ export function attachMarkdownEditingSession(options) {
|
|
|
38
90
|
}
|
|
39
91
|
return {
|
|
40
92
|
session,
|
|
93
|
+
write,
|
|
41
94
|
detach() {
|
|
42
95
|
if (detached)
|
|
43
96
|
return;
|
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
dirty: boolean;
|
|
4
|
-
saving: boolean;
|
|
5
|
-
error: Error | null;
|
|
6
|
-
value: string;
|
|
7
|
-
persistedValue: string;
|
|
8
|
-
};
|
|
1
|
+
import type { MiraMarkdownRecoveryLease, MiraMarkdownTextState } from "../../extensions/markdown-editing";
|
|
2
|
+
export type SerializedMarkdownWriterState = MiraMarkdownTextState;
|
|
9
3
|
type Options = {
|
|
10
4
|
value: string;
|
|
11
5
|
write: (value: string) => void | Promise<void>;
|
|
@@ -22,11 +16,15 @@ export declare class SerializedMarkdownWriter {
|
|
|
22
16
|
private persistedValue;
|
|
23
17
|
private saving;
|
|
24
18
|
private protections;
|
|
19
|
+
private recoveries;
|
|
20
|
+
private readonly listeners;
|
|
25
21
|
private destroyed;
|
|
26
22
|
private error;
|
|
27
23
|
constructor(options: Options);
|
|
28
24
|
get state(): SerializedMarkdownWriterState;
|
|
29
25
|
update(value: string): boolean;
|
|
26
|
+
subscribe(listener: (state: SerializedMarkdownWriterState) => void): () => void;
|
|
27
|
+
protectRecovery(): Promise<MiraMarkdownRecoveryLease>;
|
|
30
28
|
protect(): Promise<() => void>;
|
|
31
29
|
replaceExternal(value: string): boolean;
|
|
32
30
|
flush(): Promise<boolean>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serialized-writer.d.ts","sourceRoot":"","sources":["../../../src/preview/editable-markdown-preview/serialized-writer.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"serialized-writer.d.ts","sourceRoot":"","sources":["../../../src/preview/editable-markdown-preview/serialized-writer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EACzB,qBAAqB,EACtB,MAAM,mCAAmC,CAAC;AAC3C,MAAM,MAAM,6BAA6B,GAAG,qBAAqB,CAAC;AAElE,KAAK,OAAO,GAAG;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,6BAA6B,KAAK,IAAI,CAAC;CAChE,CAAC;AAEF,qBAAa,wBAAwB;IACnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IAEzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAE/B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAA2B;IAE1D,OAAO,CAAC,KAAK,CAA8C;IAE3D,OAAO,CAAC,YAAY,CAAiC;IAErD,OAAO,CAAC,KAAK,CAAS;IAEtB,OAAO,CAAC,cAAc,CAAS;IAE/B,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAEtB;IAEJ,OAAO,CAAC,SAAS,CAAS;IAE1B,OAAO,CAAC,KAAK,CAAsB;gBAEvB,OAAO,EAAE,OAAO;IAS5B,IAAI,KAAK,IAAI,6BAA6B,CASzC;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAQ9B,SAAS,CACP,QAAQ,EAAE,CAAC,KAAK,EAAE,6BAA6B,KAAK,IAAI,GACvD,MAAM,IAAI;IAQP,eAAe,IAAI,OAAO,CAAC,yBAAyB,CAAC;IA2CrD,OAAO,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC;IAoBpC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAiBjC,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC;IA0B/B,OAAO,IAAI,IAAI;IASf,OAAO,CAAC,QAAQ;YAYF,WAAW;IA2BzB,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,IAAI;CAIb"}
|
|
@@ -8,6 +8,8 @@ export class SerializedMarkdownWriter {
|
|
|
8
8
|
persistedValue;
|
|
9
9
|
saving = false;
|
|
10
10
|
protections = 0;
|
|
11
|
+
recoveries = 0;
|
|
12
|
+
listeners = new Set();
|
|
11
13
|
destroyed = false;
|
|
12
14
|
error = null;
|
|
13
15
|
constructor(options) {
|
|
@@ -32,11 +34,63 @@ export class SerializedMarkdownWriter {
|
|
|
32
34
|
if (this.protections > 0 || this.destroyed)
|
|
33
35
|
return false;
|
|
34
36
|
this.value = value;
|
|
35
|
-
this.error = null;
|
|
36
37
|
this.schedule();
|
|
37
38
|
this.emit();
|
|
38
39
|
return true;
|
|
39
40
|
}
|
|
41
|
+
subscribe(listener) {
|
|
42
|
+
this.listeners.add(listener);
|
|
43
|
+
listener(this.state);
|
|
44
|
+
return () => {
|
|
45
|
+
this.listeners.delete(listener);
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async protectRecovery() {
|
|
49
|
+
this.protections++;
|
|
50
|
+
this.recoveries++;
|
|
51
|
+
let active = true;
|
|
52
|
+
const release = () => {
|
|
53
|
+
if (!active)
|
|
54
|
+
return;
|
|
55
|
+
active = false;
|
|
56
|
+
this.protections--;
|
|
57
|
+
this.recoveries--;
|
|
58
|
+
this.emit();
|
|
59
|
+
};
|
|
60
|
+
const assertHeld = () => {
|
|
61
|
+
if (!active)
|
|
62
|
+
throw new Error("Markdown recovery lease expired");
|
|
63
|
+
if (this.saving)
|
|
64
|
+
throw new Error("Markdown recovery must settle persistence first");
|
|
65
|
+
};
|
|
66
|
+
try {
|
|
67
|
+
this.clearTimer();
|
|
68
|
+
this.emit();
|
|
69
|
+
const flight = this.flushPromise;
|
|
70
|
+
if (flight)
|
|
71
|
+
await flight;
|
|
72
|
+
return {
|
|
73
|
+
acceptLocal: () => {
|
|
74
|
+
assertHeld();
|
|
75
|
+
this.persistedValue = this.value;
|
|
76
|
+
this.error = null;
|
|
77
|
+
this.emit();
|
|
78
|
+
},
|
|
79
|
+
useExternal: (value) => {
|
|
80
|
+
assertHeld();
|
|
81
|
+
this.value = value;
|
|
82
|
+
this.persistedValue = value;
|
|
83
|
+
this.error = null;
|
|
84
|
+
this.emit();
|
|
85
|
+
},
|
|
86
|
+
release,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
release();
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
40
94
|
async protect() {
|
|
41
95
|
this.protections++;
|
|
42
96
|
this.emit();
|
|
@@ -59,7 +113,10 @@ export class SerializedMarkdownWriter {
|
|
|
59
113
|
}
|
|
60
114
|
}
|
|
61
115
|
replaceExternal(value) {
|
|
62
|
-
if (this.
|
|
116
|
+
if (this.recoveries > 0 ||
|
|
117
|
+
this.state.dirty ||
|
|
118
|
+
this.saving ||
|
|
119
|
+
this.error !== null) {
|
|
63
120
|
return false;
|
|
64
121
|
}
|
|
65
122
|
this.value = value;
|
|
@@ -70,6 +127,8 @@ export class SerializedMarkdownWriter {
|
|
|
70
127
|
}
|
|
71
128
|
async flush() {
|
|
72
129
|
this.clearTimer();
|
|
130
|
+
if (this.recoveries > 0)
|
|
131
|
+
return false;
|
|
73
132
|
if (this.flushPromise) {
|
|
74
133
|
const saved = await this.flushPromise;
|
|
75
134
|
if (!saved) {
|
|
@@ -77,7 +136,14 @@ export class SerializedMarkdownWriter {
|
|
|
77
136
|
}
|
|
78
137
|
return this.state.dirty ? this.flush() : true;
|
|
79
138
|
}
|
|
80
|
-
|
|
139
|
+
// Reserve the flight before notifying subscribers, which may request recovery.
|
|
140
|
+
let resolve;
|
|
141
|
+
let reject;
|
|
142
|
+
this.flushPromise = new Promise((done, fail) => {
|
|
143
|
+
resolve = done;
|
|
144
|
+
reject = fail;
|
|
145
|
+
});
|
|
146
|
+
void this.flushLatest().then(resolve, reject);
|
|
81
147
|
try {
|
|
82
148
|
return await this.flushPromise;
|
|
83
149
|
}
|
|
@@ -89,13 +155,13 @@ export class SerializedMarkdownWriter {
|
|
|
89
155
|
this.destroyed = true;
|
|
90
156
|
this.clearTimer();
|
|
91
157
|
this.emit();
|
|
92
|
-
if (this.state.dirty) {
|
|
158
|
+
if (this.state.dirty || this.error !== null) {
|
|
93
159
|
void this.flush();
|
|
94
160
|
}
|
|
95
161
|
}
|
|
96
162
|
schedule() {
|
|
97
163
|
this.clearTimer();
|
|
98
|
-
if (!this.state.dirty) {
|
|
164
|
+
if (!this.state.dirty && this.error === null) {
|
|
99
165
|
return;
|
|
100
166
|
}
|
|
101
167
|
this.timer = setTimeout(() => {
|
|
@@ -104,7 +170,9 @@ export class SerializedMarkdownWriter {
|
|
|
104
170
|
}, this.delay);
|
|
105
171
|
}
|
|
106
172
|
async flushLatest() {
|
|
107
|
-
while (this.value !== this.persistedValue) {
|
|
173
|
+
while (this.value !== this.persistedValue || this.error !== null) {
|
|
174
|
+
if (this.recoveries > 0)
|
|
175
|
+
return false;
|
|
108
176
|
const snapshot = this.value;
|
|
109
177
|
this.saving = true;
|
|
110
178
|
this.error = null;
|
|
@@ -134,5 +202,7 @@ export class SerializedMarkdownWriter {
|
|
|
134
202
|
}
|
|
135
203
|
emit() {
|
|
136
204
|
this.onStateChange?.(this.state);
|
|
205
|
+
for (const listener of this.listeners)
|
|
206
|
+
listener(this.state);
|
|
137
207
|
}
|
|
138
208
|
}
|