@damiro/stylo 0.5.0 → 0.9.0
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 +42 -19
- package/dist/{InPlaceView-B1GXXnoz.js → InPlaceView-Bu91_3Ig.js} +1200 -855
- package/dist/InPlaceView-Bu91_3Ig.js.map +1 -0
- package/dist/Preview-AaGGwLQP.js +170 -0
- package/dist/Preview-AaGGwLQP.js.map +1 -0
- package/dist/SplitView.d.ts +5 -2
- package/dist/SplitView.d.ts.map +1 -1
- package/dist/Stylo.d.ts.map +1 -1
- package/dist/editor/SourceView.d.ts +6 -2
- package/dist/editor/SourceView.d.ts.map +1 -1
- package/dist/editor/extensions.d.ts +2 -2
- package/dist/editor/extensions.d.ts.map +1 -1
- package/dist/editor/theme.d.ts.map +1 -1
- package/dist/editor/useCodeMirror.d.ts +6 -2
- package/dist/editor/useCodeMirror.d.ts.map +1 -1
- package/dist/editor/wikilink-complete.d.ts +17 -0
- package/dist/editor/wikilink-complete.d.ts.map +1 -0
- package/dist/embed-B2Dfkpd_.js +124 -0
- package/dist/embed-B2Dfkpd_.js.map +1 -0
- package/dist/embed.d.ts +14 -0
- package/dist/embed.d.ts.map +1 -0
- package/dist/frontmatter-DGUkb9z-.js +39 -0
- package/dist/frontmatter-DGUkb9z-.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/inplace/InPlaceView.d.ts +13 -2
- package/dist/inplace/InPlaceView.d.ts.map +1 -1
- package/dist/inplace/config.d.ts +8 -0
- package/dist/inplace/config.d.ts.map +1 -1
- package/dist/inplace/context-menu-actions.d.ts +5 -14
- package/dist/inplace/context-menu-actions.d.ts.map +1 -1
- package/dist/inplace/context-menu-helpers.d.ts +30 -0
- package/dist/inplace/context-menu-helpers.d.ts.map +1 -0
- package/dist/inplace/context-menu-shell.d.ts +23 -0
- package/dist/inplace/context-menu-shell.d.ts.map +1 -0
- package/dist/inplace/context-menu-types.d.ts +46 -0
- package/dist/inplace/context-menu-types.d.ts.map +1 -0
- package/dist/inplace/context-menu.d.ts +2 -42
- package/dist/inplace/context-menu.d.ts.map +1 -1
- package/dist/inplace/decorate.d.ts.map +1 -1
- package/dist/inplace/edit-boundaries.d.ts +1 -25
- package/dist/inplace/edit-boundaries.d.ts.map +1 -1
- package/dist/inplace/edit-divider.d.ts +27 -0
- package/dist/inplace/edit-divider.d.ts.map +1 -0
- package/dist/inplace/embed-registry.d.ts +39 -0
- package/dist/inplace/embed-registry.d.ts.map +1 -0
- package/dist/inplace/embed.d.ts +8 -0
- package/dist/inplace/embed.d.ts.map +1 -0
- package/dist/inplace/extension.d.ts +6 -0
- package/dist/inplace/extension.d.ts.map +1 -1
- package/dist/inplace/inline-md.d.ts +6 -1
- package/dist/inplace/inline-md.d.ts.map +1 -1
- package/dist/inplace/link-row.d.ts +21 -0
- package/dist/inplace/link-row.d.ts.map +1 -0
- package/dist/inplace/math-edit.d.ts +36 -0
- package/dist/inplace/math-edit.d.ts.map +1 -0
- package/dist/inplace/math.d.ts +12 -0
- package/dist/inplace/math.d.ts.map +1 -1
- package/dist/inplace/menu-plugin.d.ts.map +1 -1
- package/dist/inplace/nodes-blocks.d.ts +14 -0
- package/dist/inplace/nodes-blocks.d.ts.map +1 -0
- package/dist/inplace/nodes-inline.d.ts +16 -0
- package/dist/inplace/nodes-inline.d.ts.map +1 -0
- package/dist/inplace/nodes.d.ts +3 -2
- package/dist/inplace/nodes.d.ts.map +1 -1
- package/dist/inplace/scan.d.ts +6 -0
- package/dist/inplace/scan.d.ts.map +1 -1
- package/dist/inplace/selection-bar-position.d.ts +31 -0
- package/dist/inplace/selection-bar-position.d.ts.map +1 -0
- package/dist/inplace/selection-bar.d.ts +0 -2
- package/dist/inplace/selection-bar.d.ts.map +1 -1
- package/dist/inplace/table-widget-caret.d.ts +11 -0
- package/dist/inplace/table-widget-caret.d.ts.map +1 -0
- package/dist/inplace/table-widget-render.d.ts +18 -0
- package/dist/inplace/table-widget-render.d.ts.map +1 -0
- package/dist/inplace/table-widget.d.ts +5 -2
- package/dist/inplace/table-widget.d.ts.map +1 -1
- package/dist/inplace/tables.d.ts.map +1 -1
- package/dist/inplace/theme-callout.d.ts +50 -0
- package/dist/inplace/theme-callout.d.ts.map +1 -0
- package/dist/inplace/theme-canvas.d.ts +166 -0
- package/dist/inplace/theme-canvas.d.ts.map +1 -0
- package/dist/inplace/theme-fonts.d.ts +4 -0
- package/dist/inplace/theme-fonts.d.ts.map +1 -0
- package/dist/inplace/theme-menu.d.ts +87 -0
- package/dist/inplace/theme-menu.d.ts.map +1 -0
- package/dist/inplace/theme-popups.d.ts +94 -0
- package/dist/inplace/theme-popups.d.ts.map +1 -0
- package/dist/inplace/theme-table-gizmos.d.ts +57 -0
- package/dist/inplace/theme-table-gizmos.d.ts.map +1 -0
- package/dist/inplace/theme-table.d.ts +30 -0
- package/dist/inplace/theme-table.d.ts.map +1 -0
- package/dist/inplace/theme.d.ts +5 -0
- package/dist/inplace/theme.d.ts.map +1 -1
- package/dist/inplace/wikilinks.d.ts.map +1 -1
- package/dist/inplace/wrap-at.d.ts +32 -0
- package/dist/inplace/wrap-at.d.ts.map +1 -0
- package/dist/{markdown-N3lRmU2n.js → markdown-BYXs9Tj8.js} +2 -2
- package/dist/{markdown-N3lRmU2n.js.map → markdown-BYXs9Tj8.js.map} +1 -1
- package/dist/render/Embed.d.ts +24 -0
- package/dist/render/Embed.d.ts.map +1 -0
- package/dist/render/Preview.d.ts +6 -2
- package/dist/render/Preview.d.ts.map +1 -1
- package/dist/render/embed-cache.d.ts +10 -0
- package/dist/render/embed-cache.d.ts.map +1 -0
- package/dist/render/remark-embed.d.ts +19 -0
- package/dist/render/remark-embed.d.ts.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/stylo.js +75 -54
- package/dist/stylo.js.map +1 -1
- package/dist/toolbar/block.d.ts +0 -26
- package/dist/toolbar/block.d.ts.map +1 -1
- package/dist/toolbar/command-helpers.d.ts +57 -0
- package/dist/toolbar/command-helpers.d.ts.map +1 -0
- package/dist/toolbar/commands.d.ts +1 -21
- package/dist/toolbar/commands.d.ts.map +1 -1
- package/dist/toolbar/frontmatter-toggle.d.ts +13 -0
- package/dist/toolbar/frontmatter-toggle.d.ts.map +1 -0
- package/dist/toolbar/heading.d.ts +10 -0
- package/dist/toolbar/heading.d.ts.map +1 -0
- package/dist/toolbar/inline-ops.d.ts +3 -53
- package/dist/toolbar/inline-ops.d.ts.map +1 -1
- package/dist/toolbar/link-ops.d.ts +22 -0
- package/dist/toolbar/link-ops.d.ts.map +1 -0
- package/dist/toolbar/rule.d.ts +11 -0
- package/dist/toolbar/rule.d.ts.map +1 -0
- package/dist/toolbar/table-position.d.ts +32 -0
- package/dist/toolbar/table-position.d.ts.map +1 -0
- package/dist/toolbar/table.d.ts +1 -16
- package/dist/toolbar/table.d.ts.map +1 -1
- package/dist/toolbar/underline-ops.d.ts +15 -0
- package/dist/toolbar/underline-ops.d.ts.map +1 -0
- package/dist/toolbar/wikilink-ops.d.ts +22 -0
- package/dist/toolbar/wikilink-ops.d.ts.map +1 -0
- package/dist/types.d.ts +73 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/{useCodeMirror-hLeJQw6e.js → useCodeMirror-DtwupFgc.js} +590 -526
- package/dist/useCodeMirror-DtwupFgc.js.map +1 -0
- package/package.json +5 -1
- package/dist/InPlaceView-B1GXXnoz.js.map +0 -1
- package/dist/Preview-Dxb9zPVv.js +0 -93
- package/dist/Preview-Dxb9zPVv.js.map +0 -1
- package/dist/callout-oLE630ZP.js +0 -37
- package/dist/callout-oLE630ZP.js.map +0 -1
- package/dist/useCodeMirror-hLeJQw6e.js.map +0 -1
- package/dist/wikilink-BFpTehto.js +0 -42
- package/dist/wikilink-BFpTehto.js.map +0 -1
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { EmbedSource, ResolveErrorInfo } from "../types";
|
|
2
|
+
interface EmbedProps {
|
|
3
|
+
/** The raw `![[ref]]` reference, trimmed. */
|
|
4
|
+
reference: string;
|
|
5
|
+
source: EmbedSource;
|
|
6
|
+
/** Notified if `source` rejects; the literal fallback still renders. */
|
|
7
|
+
onError?: (error: unknown, info: ResolveErrorInfo) => void;
|
|
8
|
+
/**
|
|
9
|
+
* Render as phrasing content in a `<span>` (a `![[…]]` mid-sentence) rather
|
|
10
|
+
* than the default block `<div>`. The host node should be inline in this mode.
|
|
11
|
+
*/
|
|
12
|
+
inline?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Renders one `![[ref]]` embed. Resolves the reference through `embedSource` —
|
|
16
|
+
* via a shared cache (`embed-cache.ts`), so an embed re-mounted by a scroll or a
|
|
17
|
+
* `preview` re-render is not re-fetched — and drops the result into
|
|
18
|
+
* `<div class="stylo-embed-content">`, or a `<span>` when `inline`. While it
|
|
19
|
+
* resolves — and if it rejects, or resolves to `null` — the literal `![[ref]]`
|
|
20
|
+
* text stands in, so a reference is never silently lost.
|
|
21
|
+
*/
|
|
22
|
+
export declare function Embed({ reference, source, onError, inline }: EmbedProps): import("react").JSX.Element;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=Embed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Embed.d.ts","sourceRoot":"","sources":["../../src/render/Embed.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAG7D,UAAU,UAAU;IAClB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,WAAW,CAAA;IACnB,wEAAwE;IACxE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAA;IAC1D;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAID;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,UAAU,+BAoCvE"}
|
package/dist/render/Preview.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import type { FrontmatterDisplay } from "../types";
|
|
1
|
+
import type { EmbedSource, FrontmatterDisplay, ResolveErrorInfo } from "../types";
|
|
2
2
|
export interface PreviewProps {
|
|
3
3
|
value: string;
|
|
4
4
|
onWikiLinkClick?: (target: string) => void;
|
|
5
|
+
/** Resolves `![[ref]]` embeds. Omit and `![[…]]` stays literal. */
|
|
6
|
+
embedSource?: EmbedSource;
|
|
7
|
+
/** Notified when `embedSource` rejects; the literal fallback still renders. */
|
|
8
|
+
onResolveError?: (error: unknown, info: ResolveErrorInfo) => void;
|
|
5
9
|
/** `"code"` renders the `---` block as a styled `<pre>`; `"hidden"` (default) drops it. */
|
|
6
10
|
frontmatter?: FrontmatterDisplay;
|
|
7
11
|
}
|
|
8
12
|
/** Rendered Markdown + KaTeX view. A pure function of the string. */
|
|
9
|
-
export declare function Preview({ value, onWikiLinkClick, frontmatter }: PreviewProps): import("react").JSX.Element;
|
|
13
|
+
export declare function Preview({ value, onWikiLinkClick, embedSource, onResolveError, frontmatter, }: PreviewProps): import("react").JSX.Element;
|
|
10
14
|
//# sourceMappingURL=Preview.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Preview.d.ts","sourceRoot":"","sources":["../../src/render/Preview.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Preview.d.ts","sourceRoot":"","sources":["../../src/render/Preview.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAQjF,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,mEAAmE;IACnE,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,+EAA+E;IAC/E,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAA;IACjE,2FAA2F;IAC3F,WAAW,CAAC,EAAE,kBAAkB,CAAA;CACjC;AAED,qEAAqE;AACrE,wBAAgB,OAAO,CAAC,EACtB,KAAK,EACL,eAAe,EACf,WAAW,EACX,cAAc,EACd,WAAsB,GACvB,EAAE,YAAY,+BA6Ed"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { EmbedSource } from "../types";
|
|
3
|
+
/** A settled result for `ref`, or `undefined` while it is unresolved or absent. */
|
|
4
|
+
export declare function peekEmbed(source: EmbedSource, ref: string): {
|
|
5
|
+
node: ReactNode;
|
|
6
|
+
} | undefined;
|
|
7
|
+
/** Resolve `ref` through the cache — reusing an in-flight or settled entry, or
|
|
8
|
+
* calling `source` on a miss. */
|
|
9
|
+
export declare function resolveEmbed(source: EmbedSource, ref: string): Promise<ReactNode>;
|
|
10
|
+
//# sourceMappingURL=embed-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embed-cache.d.ts","sourceRoot":"","sources":["../../src/render/embed-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAwC3C,mFAAmF;AACnF,wBAAgB,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GAAG,SAAS,CAG3F;AAED;kCACkC;AAClC,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CA2BjF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Root } from "mdast";
|
|
2
|
+
/**
|
|
3
|
+
* Turns `![[ref]]` transclusion syntax into empty carrier elements the `Embed`
|
|
4
|
+
* component (wired in `Preview`) fills from the host's `embedSource`.
|
|
5
|
+
*
|
|
6
|
+
* - A **lone** `![[ref]]` — the whole paragraph, trimmed — becomes a block
|
|
7
|
+
* `<div class="stylo-embed" data-stylo-embed="ref">`.
|
|
8
|
+
* - A `![[ref]]` **inside other text** becomes an inline
|
|
9
|
+
* `<span class="stylo-embed" data-stylo-embed-inline="ref">`, and the
|
|
10
|
+
* surrounding text is preserved around it. The host node should be phrasing
|
|
11
|
+
* content in this case.
|
|
12
|
+
*
|
|
13
|
+
* `![[…]]` inside inline or fenced code is left literal (it is not a `text`
|
|
14
|
+
* node). Must run before `remarkWikilink`, or the inner `[[ref]]` is rewritten
|
|
15
|
+
* to a link first. Off unless the consumer passes `embedSource` — `Preview` only
|
|
16
|
+
* adds this plugin then.
|
|
17
|
+
*/
|
|
18
|
+
export declare function remarkEmbed(): (tree: Root) => void;
|
|
19
|
+
//# sourceMappingURL=remark-embed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remark-embed.d.ts","sourceRoot":"","sources":["../../src/render/remark-embed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA8B,IAAI,EAAQ,MAAM,OAAO,CAAA;AAInE;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,WACX,IAAI,UA+CnB"}
|
package/dist/styles.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
._root_18e48_1{min-height:0;color:var(--stylo-text);background:var(--stylo-bg);border:1px solid var(--stylo-border);border-radius:var(--stylo-radius);flex-direction:column;display:flex;overflow:hidden}._root_18e48_1 .cm-scroller{scrollbar-width:thin;scrollbar-color:color-mix(in srgb, var(--stylo-border) 90%, transparent) transparent}._root_18e48_1 .cm-scroller::-webkit-scrollbar{width:10px;height:10px}._root_18e48_1 .cm-scroller::-webkit-scrollbar-thumb{background:color-mix(in srgb, var(--stylo-border) 90%, transparent);background-clip:padding-box;border:3px solid #0000;border-radius:6px}._root_18e48_1 .cm-scroller::-webkit-scrollbar-thumb:hover{background:color-mix(in srgb, var(--stylo-text-muted) 55%, transparent);background-clip:padding-box}._root_18e48_1 .cm-scroller::-webkit-scrollbar-corner{background:0 0}._source_18e48_42{flex:auto;min-height:0;overflow:auto}._source_18e48_42 .cm-editor{height:100%}._source_18e48_42 .cm-editor.cm-focused{outline:2px solid var(--stylo-ring);outline-offset:-2px}._inplace_18e48_57{flex:auto;min-height:0;overflow:auto}._toolbar_18e48_63{background:var(--stylo-bg);border-bottom:1px solid var(--stylo-border);flex-wrap:wrap;align-items:center;gap:2px;padding:4px 6px;display:flex}._toolbarButton_18e48_73{box-sizing:border-box;border-radius:calc(var(--stylo-radius) - 3px);min-width:28px;height:28px;color:var(--stylo-text-muted);font:inherit;cursor:pointer;background:0 0;border:0;justify-content:center;align-items:center;padding:0 5px;font-size:.75rem;font-weight:600;line-height:1;display:inline-flex}._toolbarButton_18e48_73:hover:not(:disabled){background:color-mix(in srgb, var(--stylo-border) 45%, transparent);color:var(--stylo-text)}._toolbarButton_18e48_73[data-active]{background:color-mix(in srgb, var(--stylo-accent) 12%, transparent);color:var(--stylo-text)}._toolbarButton_18e48_73:disabled{opacity:.4;cursor:default}._toolbarButton_18e48_73:focus-visible{outline:2px solid var(--stylo-ring);outline-offset:-2px}._toolbarButton_18e48_73 svg{width:16px;height:16px;display:block}._toolbarButton_18e48_73 code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.8125rem;font-weight:500}._toolbarSep_18e48_125{background:var(--stylo-border);align-self:stretch;width:1px;margin:4px 3px}._toolbarSticky_18e48_135{z-index:50;-webkit-overflow-scrolling:touch;scrollbar-width:none;flex-wrap:nowrap;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;transition:opacity .15s;overflow-x:auto}._toolbarSticky_18e48_135::-webkit-scrollbar{display:none}._toolbarSticky_18e48_135 ._toolbarButton_18e48_73{flex:none;min-width:40px;height:40px}._toolbarStickyBottom_18e48_135{border-bottom:none;border-top:1px solid var(--stylo-border);box-shadow:0 -2px 8px color-mix(in srgb, var(--stylo-text) 10%, transparent);position:fixed;bottom:0;left:0;right:0}._toolbarStickyTop_18e48_135{box-shadow:0 2px 8px color-mix(in srgb, var(--stylo-text) 10%, transparent);position:fixed;top:0;left:0;right:0}._toolbarStickyHidden_18e48_194{opacity:0;pointer-events:none}._stickyToolbarRootBottom_18e48_205 ._source_18e48_42,._stickyToolbarRootBottom_18e48_205 ._inplace_18e48_57{padding-bottom:52px}._stickyToolbarRootTop_18e48_210 ._source_18e48_42,._stickyToolbarRootTop_18e48_210 ._inplace_18e48_57{padding-top:52px}._inplace_18e48_57 .cm-editor{height:100%}._inplace_18e48_57 .cm-editor.cm-focused{outline:2px solid var(--stylo-ring);outline-offset:-2px}._split_18e48_224{flex:1;grid-template-columns:1fr 1fr;min-height:0;display:grid}._splitPane_18e48_231{box-sizing:border-box;flex-direction:column;min-height:0;display:flex;overflow:auto}._splitPane_18e48_231+._splitPane_18e48_231{border-left:1px solid var(--stylo-border)}._splitPane_18e48_231>._source_18e48_42{flex:1;min-height:0}._preview_18e48_251{overflow-wrap:break-word;padding:.75rem 1rem;font-size:.9375rem;line-height:1.75}._preview_18e48_251>:first-child{margin-top:0}._preview_18e48_251>:last-child{margin-bottom:0}._preview_18e48_251 :is(h1,h2,h3,h4,h5,h6){font-weight:600}._preview_18e48_251 h1{margin:0 0 .888889em;font-size:2.25em;line-height:1.11111}._preview_18e48_251 h2{margin:2em 0 1em;font-size:1.5em;line-height:1.33333}._preview_18e48_251 h3{margin:1.6em 0 .6em;font-size:1.25em;line-height:1.6}._preview_18e48_251 :is(h4,h5,h6){margin:1.5em 0 .5em;line-height:1.5}._preview_18e48_251 p{margin:1.25em 0}._preview_18e48_251 :is(ul,ol){margin:1.25em 0;padding-left:1.625em}._preview_18e48_251 li{margin:.5em 0}._preview_18e48_251 li>:is(ul,ol){margin:.75em 0}._preview_18e48_251 a{color:var(--stylo-link);text-decoration:none}._preview_18e48_251 code{border-radius:calc(var(--stylo-radius) - 3px);background:color-mix(in srgb, var(--stylo-border) 45%, transparent);padding:.1em .35em;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.9em}._preview_18e48_251 pre{border-radius:var(--stylo-radius);background:color-mix(in srgb, var(--stylo-border) 35%, transparent);margin:1.71429em 0;padding:.75rem .9rem;overflow-x:auto}._preview_18e48_251 pre code{background:0 0;padding:0;font-size:.85em}.stylo-frontmatter{border-left:3px solid var(--stylo-border);border-radius:calc(var(--stylo-radius) - 3px);background:color-mix(in srgb, var(--stylo-border) 22%, transparent);color:var(--stylo-text-muted);white-space:pre-wrap;margin:0 0 1.2em;padding:.7rem .9rem;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.8125rem;line-height:1.5;overflow-x:auto}.stylo-frontmatter:before{content:"Frontmatter";letter-spacing:.04em;text-transform:uppercase;margin-bottom:.5em;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-size:.7rem;font-weight:600;display:block}._preview_18e48_251 blockquote{border-left:.25rem solid var(--stylo-border);color:var(--stylo-text-muted);margin:1.6em 0;padding-left:1em}._preview_18e48_251 .stylo-callout{border-left:.25rem solid var(--stylo-callout-accent,var(--stylo-border));border-radius:var(--stylo-radius);background:color-mix(in srgb, var(--stylo-callout-accent,var(--stylo-border)) 10%, transparent);color:var(--stylo-text);margin:1.6em 0;padding:.6em 1em}._preview_18e48_251 .stylo-callout:before{content:attr(data-callout);letter-spacing:.04em;text-transform:uppercase;color:var(--stylo-callout-accent,var(--stylo-text-muted));margin-bottom:.2em;font-size:.8em;font-weight:700;display:block}._preview_18e48_251 .stylo-callout-note{--stylo-callout-accent:var(--stylo-callout-note,#3b82f6)}._preview_18e48_251 .stylo-callout-tip{--stylo-callout-accent:var(--stylo-callout-tip,#22c55e)}._preview_18e48_251 .stylo-callout-warn{--stylo-callout-accent:var(--stylo-callout-warn,#f59e0b)}._preview_18e48_251 .stylo-callout-danger{--stylo-callout-accent:var(--stylo-callout-danger,#ef4444)}._preview_18e48_251 .stylo-callout-example{--stylo-callout-accent:var(--stylo-callout-example,#a855f7)}._preview_18e48_251 table{border-collapse:collapse;margin:2em 0;display:block;overflow-x:auto}._preview_18e48_251 :is(th,td){border:1px solid var(--stylo-table-border);text-align:left;padding:.35em .6em}._preview_18e48_251 thead th{background:var(--stylo-table-header-bg);font-weight:600}._preview_18e48_251 tbody tr:nth-child(2n) td{background:var(--stylo-table-stripe-bg)}._preview_18e48_251 hr{border:none;border-top:1px solid var(--stylo-border);margin:1em 0}._preview_18e48_251 .katex-display{padding:.25em 0;overflow:auto hidden}.stylo{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light;--stylo-bg:#fff;--stylo-surface-floating:#fff;--stylo-text:#09090b;--stylo-text-muted:#71717a;--stylo-border:#e4e4e7;--stylo-accent:#18181b;--stylo-link:#2563eb;--stylo-ring:#a1a1aa;--stylo-radius:.5rem;--stylo-font-size:.9375rem;--stylo-table-border:var(--stylo-border);--stylo-table-header-bg:color-mix(in srgb, var(--stylo-border) 30%, transparent);--stylo-table-stripe-bg:transparent;--stylo-guide:var(--stylo-border);--stylo-syntax-keyword:#7c3aed;--stylo-syntax-string:#0a7c2f;--stylo-syntax-escape:#b45309;--stylo-syntax-comment:#8a8f98;--stylo-syntax-number:#b45309;--stylo-syntax-constant:#b45309;--stylo-syntax-function:#2563eb;--stylo-syntax-type:#a16207;--stylo-syntax-property:#0f766e;--stylo-syntax-tag:#cf222e;--stylo-syntax-invalid:#dc2626}:where(.dark,[data-theme=dark]) .stylo,.stylo:where(.dark,[data-theme=dark]){--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark;--stylo-bg:#09090b;--stylo-surface-floating:#09090b;--stylo-text:#fafafa;--stylo-text-muted:#a1a1aa;--stylo-border:#27272a;--stylo-accent:#fafafa;--stylo-link:#60a5fa;--stylo-ring:#52525b;--stylo-syntax-keyword:#c678dd;--stylo-syntax-string:#98c379;--stylo-syntax-escape:#d19a66;--stylo-syntax-comment:#7f848e;--stylo-syntax-number:#d19a66;--stylo-syntax-constant:#d19a66;--stylo-syntax-function:#61afef;--stylo-syntax-type:#e5c07b;--stylo-syntax-property:#56b6c2;--stylo-syntax-tag:#e06c75;--stylo-syntax-invalid:#e06c75}._root_18hcd_3{color:var(--stylo-text);font:inherit;grid-template-columns:1fr 1fr;gap:12px;display:grid}@media (width<=460px){._root_18hcd_3{grid-template-columns:1fr}}._col_18hcd_17{border:1px solid var(--stylo-border);border-radius:var(--stylo-radius);background:var(--stylo-bg);flex-direction:column;min-width:0;display:flex}._colHead_18hcd_26{border-bottom:1px solid var(--stylo-border);letter-spacing:.04em;text-transform:uppercase;color:var(--stylo-text-muted);margin:0;padding:8px 12px;font-size:.75rem;font-weight:600}._list_18hcd_37{flex-direction:column;flex:1;gap:2px;margin:0;padding:4px;list-style:none;display:flex}._row_18hcd_47{border-radius:calc(var(--stylo-radius) - 3px);background:var(--stylo-bg);align-items:center;gap:8px;padding:5px 6px;display:flex}._row_18hcd_47:focus-visible{outline:2px solid var(--stylo-ring);outline-offset:-2px}._row_18hcd_47:hover{background:color-mix(in srgb, var(--stylo-border) 30%, transparent)}._row_18hcd_47[data-dragging]{background:var(--stylo-surface-floating,#fff);opacity:.9;box-shadow:0 4px 16px #00000024}._handle_18hcd_73{border-radius:calc(var(--stylo-radius) - 4px);width:20px;height:22px;color:var(--stylo-text-muted);font:inherit;cursor:grab;touch-action:none;background:0 0;border:1px solid #0000;flex:none;justify-content:center;align-items:center;padding:0;line-height:1;display:inline-flex}._handle_18hcd_73:hover{background:color-mix(in srgb, var(--stylo-border) 45%, transparent);color:var(--stylo-text)}._handle_18hcd_73:focus-visible{outline:2px solid var(--stylo-ring);outline-offset:-1px}._handle_18hcd_73:active{cursor:grabbing}._glyph_18hcd_105{width:18px;height:18px;color:var(--stylo-text-muted);flex:none;justify-content:center;align-items:center;display:inline-flex}._glyph_18hcd_105 svg{width:16px;height:16px;display:block}._label_18hcd_121{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;font-size:.8125rem;overflow:hidden}._rowActions_18hcd_130{flex:none;gap:2px;display:flex}._iconButton_18hcd_136,._textButton_18hcd_137{box-sizing:border-box;border-radius:calc(var(--stylo-radius) - 4px);color:var(--stylo-text-muted);font:inherit;cursor:pointer;background:0 0;border:1px solid #0000}._iconButton_18hcd_136{width:22px;height:22px;font-size:.8125rem;line-height:1}._textButton_18hcd_137{padding:3px 8px;font-size:.75rem}._iconButton_18hcd_136:hover:not(:disabled),._textButton_18hcd_137:hover:not(:disabled){background:color-mix(in srgb, var(--stylo-border) 45%, transparent);color:var(--stylo-text)}._iconButton_18hcd_136:focus-visible,._textButton_18hcd_137:focus-visible{outline:2px solid var(--stylo-ring);outline-offset:-1px}._iconButton_18hcd_136:disabled{opacity:.35;cursor:default}._footer_18hcd_176{border-top:1px solid var(--stylo-border);flex-wrap:wrap;gap:6px;padding:6px;display:flex}._empty_18hcd_184{color:var(--stylo-text-muted);padding:8px 6px;font-size:.8125rem}._srOnly_18hcd_190{clip:rect(0 0 0 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}
|
|
1
|
+
._root_1y1lh_1{min-height:0;color:var(--stylo-text);background:var(--stylo-bg);border:1px solid var(--stylo-border);border-radius:var(--stylo-radius);flex-direction:column;display:flex;overflow:hidden}._root_1y1lh_1 .cm-scroller{scrollbar-width:thin;scrollbar-color:color-mix(in srgb, var(--stylo-border) 90%, transparent) transparent}._root_1y1lh_1 .cm-scroller::-webkit-scrollbar{width:10px;height:10px}._root_1y1lh_1 .cm-scroller::-webkit-scrollbar-thumb{background:color-mix(in srgb, var(--stylo-border) 90%, transparent);background-clip:padding-box;border:3px solid #0000;border-radius:6px}._root_1y1lh_1 .cm-scroller::-webkit-scrollbar-thumb:hover{background:color-mix(in srgb, var(--stylo-text-muted) 55%, transparent);background-clip:padding-box}._root_1y1lh_1 .cm-scroller::-webkit-scrollbar-corner{background:0 0}._source_1y1lh_42{flex:auto;min-height:0;overflow:auto}._source_1y1lh_42 .cm-editor{height:100%}._source_1y1lh_42 .cm-editor.cm-focused{outline:2px solid var(--stylo-ring);outline-offset:-2px}._inplace_1y1lh_57{flex:auto;min-height:0;overflow:auto}._toolbar_1y1lh_63{background:var(--stylo-bg);border-bottom:1px solid var(--stylo-border);flex-wrap:wrap;align-items:center;gap:2px;padding:4px 6px;display:flex}._toolbarButton_1y1lh_73{box-sizing:border-box;border-radius:calc(var(--stylo-radius) - 3px);min-width:28px;height:28px;color:var(--stylo-text-muted);font:inherit;cursor:pointer;background:0 0;border:0;justify-content:center;align-items:center;padding:0 5px;font-size:.75rem;font-weight:600;line-height:1;display:inline-flex}._toolbarButton_1y1lh_73:hover:not(:disabled){background:color-mix(in srgb, var(--stylo-border) 45%, transparent);color:var(--stylo-text)}._toolbarButton_1y1lh_73[data-active]{background:color-mix(in srgb, var(--stylo-accent) 12%, transparent);color:var(--stylo-text)}._toolbarButton_1y1lh_73:disabled{opacity:.4;cursor:default}._toolbarButton_1y1lh_73:focus-visible{outline:2px solid var(--stylo-ring);outline-offset:-2px}._toolbarButton_1y1lh_73 svg{width:16px;height:16px;display:block}._toolbarButton_1y1lh_73 code{font-family:var(--stylo-font-family-mono,ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);font-size:.8125rem;font-weight:500}._toolbarSep_1y1lh_132{background:var(--stylo-border);align-self:stretch;width:1px;margin:4px 3px}._toolbarSticky_1y1lh_142{z-index:50;-webkit-overflow-scrolling:touch;scrollbar-width:none;font-family:var(--stylo-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif);flex-wrap:nowrap;transition:opacity .15s;overflow-x:auto}._toolbarSticky_1y1lh_142::-webkit-scrollbar{display:none}._toolbarSticky_1y1lh_142 ._toolbarButton_1y1lh_73{flex:none;min-width:40px;height:40px}._toolbarStickyBottom_1y1lh_142{border-bottom:none;border-top:1px solid var(--stylo-border);box-shadow:0 -2px 8px color-mix(in srgb, var(--stylo-text) 10%, transparent);position:fixed;bottom:0;left:0;right:0}._toolbarStickyTop_1y1lh_142{box-shadow:0 2px 8px color-mix(in srgb, var(--stylo-text) 10%, transparent);position:fixed;top:0;left:0;right:0}._toolbarStickyHidden_1y1lh_211{opacity:0;pointer-events:none}._stickyToolbarRootBottom_1y1lh_222 ._source_1y1lh_42,._stickyToolbarRootBottom_1y1lh_222 ._inplace_1y1lh_57{padding-bottom:52px}._stickyToolbarRootTop_1y1lh_227 ._source_1y1lh_42,._stickyToolbarRootTop_1y1lh_227 ._inplace_1y1lh_57{padding-top:52px}._inplace_1y1lh_57 .cm-editor{height:100%}._inplace_1y1lh_57 .cm-editor.cm-focused{outline:2px solid var(--stylo-ring);outline-offset:-2px}._split_1y1lh_241{flex:1;grid-template-columns:1fr 1fr;min-height:0;display:grid}._splitPane_1y1lh_248{box-sizing:border-box;flex-direction:column;min-height:0;display:flex;overflow:auto}._splitPane_1y1lh_248+._splitPane_1y1lh_248{border-left:1px solid var(--stylo-border)}._splitPane_1y1lh_248>._source_1y1lh_42{flex:1;min-height:0}._preview_1y1lh_268{overflow-wrap:break-word;padding:.75rem 1rem;font-size:.9375rem;line-height:1.75}._preview_1y1lh_268>:first-child{margin-top:0}._preview_1y1lh_268>:last-child{margin-bottom:0}._preview_1y1lh_268 :is(h1,h2,h3,h4,h5,h6){font-weight:600}._preview_1y1lh_268 h1{margin:0 0 .888889em;font-size:2.25em;line-height:1.11111}._preview_1y1lh_268 h2{margin:2em 0 1em;font-size:1.5em;line-height:1.33333}._preview_1y1lh_268 h3{margin:1.6em 0 .6em;font-size:1.25em;line-height:1.6}._preview_1y1lh_268 :is(h4,h5,h6){margin:1.5em 0 .5em;line-height:1.5}._preview_1y1lh_268 p{margin:1.25em 0}._preview_1y1lh_268 :is(ul,ol){margin:1.25em 0;padding-left:1.625em}._preview_1y1lh_268 li{margin:.5em 0}._preview_1y1lh_268 li>:is(ul,ol){margin:.75em 0}._preview_1y1lh_268 a{color:var(--stylo-link);text-decoration:none}._preview_1y1lh_268 code{font-family:var(--stylo-font-family-mono,ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);border-radius:calc(var(--stylo-radius) - 3px);background:color-mix(in srgb, var(--stylo-border) 45%, transparent);padding:.1em .35em;font-size:.9em}._preview_1y1lh_268 pre{border-radius:var(--stylo-radius);background:color-mix(in srgb, var(--stylo-border) 35%, transparent);margin:1.71429em 0;padding:.75rem .9rem;overflow-x:auto}._preview_1y1lh_268 pre code{background:0 0;padding:0;font-size:.85em}.stylo-frontmatter{border-left:3px solid var(--stylo-border);border-radius:calc(var(--stylo-radius) - 3px);background:color-mix(in srgb, var(--stylo-border) 22%, transparent);color:var(--stylo-text-muted);font-family:var(--stylo-font-family-mono,ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);white-space:pre-wrap;margin:0 0 1.2em;padding:.7rem .9rem;font-size:.8125rem;line-height:1.5;overflow-x:auto}.stylo-frontmatter:before{content:"Frontmatter";font-family:var(--stylo-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif);letter-spacing:.04em;text-transform:uppercase;margin-bottom:.5em;font-size:.7rem;font-weight:600;display:block}._preview_1y1lh_268 blockquote{border-left:.25rem solid var(--stylo-border);color:var(--stylo-text-muted);margin:1.6em 0;padding-left:1em}._preview_1y1lh_268 .stylo-callout{border-left:.25rem solid var(--stylo-callout-accent,var(--stylo-border));border-radius:var(--stylo-radius);background:color-mix(in srgb, var(--stylo-callout-accent,var(--stylo-border)) 10%, transparent);color:var(--stylo-text);margin:1.6em 0;padding:.6em 1em}._preview_1y1lh_268 .stylo-callout:before{content:attr(data-callout);letter-spacing:.04em;text-transform:uppercase;color:var(--stylo-callout-accent,var(--stylo-text-muted));margin-bottom:.2em;font-size:.8em;font-weight:700;display:block}._preview_1y1lh_268 .stylo-callout-note{--stylo-callout-accent:var(--stylo-callout-note,#3b82f6)}._preview_1y1lh_268 .stylo-callout-tip{--stylo-callout-accent:var(--stylo-callout-tip,#22c55e)}._preview_1y1lh_268 .stylo-callout-warn{--stylo-callout-accent:var(--stylo-callout-warn,#f59e0b)}._preview_1y1lh_268 .stylo-callout-danger{--stylo-callout-accent:var(--stylo-callout-danger,#ef4444)}._preview_1y1lh_268 .stylo-callout-example{--stylo-callout-accent:var(--stylo-callout-example,#a855f7)}._preview_1y1lh_268 .stylo-embed{border-left:.25rem solid var(--stylo-embed-accent,var(--stylo-border));margin:1.6em 0;padding-left:1em}._preview_1y1lh_268 .stylo-embed-content>:first-child{margin-top:0}._preview_1y1lh_268 .stylo-embed-content>:last-child{margin-bottom:0}._preview_1y1lh_268 table{border-collapse:collapse;margin:2em 0;display:block;overflow-x:auto}._preview_1y1lh_268 :is(th,td){border:1px solid var(--stylo-table-border);text-align:left;padding:.35em .6em}._preview_1y1lh_268 thead th{background:var(--stylo-table-header-bg);font-weight:600}._preview_1y1lh_268 tbody tr:nth-child(2n) td{background:var(--stylo-table-stripe-bg)}._preview_1y1lh_268 hr{border:none;border-top:1px solid var(--stylo-border);margin:1em 0}._preview_1y1lh_268 .katex-display{padding:.25em 0;overflow:auto hidden}.stylo{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light;--stylo-bg:#fff;--stylo-surface-floating:#fff;--stylo-text:#09090b;--stylo-text-muted:#71717a;--stylo-border:#e4e4e7;--stylo-accent:#18181b;--stylo-link:#2563eb;--stylo-ring:#a1a1aa;--stylo-radius:.5rem;--stylo-font-size:.9375rem;--stylo-font-family:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;--stylo-font-family-mono:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;--stylo-table-border:var(--stylo-border);--stylo-table-header-bg:color-mix(in srgb, var(--stylo-border) 30%, transparent);--stylo-table-stripe-bg:transparent;--stylo-guide:var(--stylo-border);--stylo-syntax-keyword:#7c3aed;--stylo-syntax-string:#0a7c2f;--stylo-syntax-escape:#b45309;--stylo-syntax-comment:#8a8f98;--stylo-syntax-number:#b45309;--stylo-syntax-constant:#b45309;--stylo-syntax-function:#2563eb;--stylo-syntax-type:#a16207;--stylo-syntax-property:#0f766e;--stylo-syntax-tag:#cf222e;--stylo-syntax-invalid:#dc2626}:where(.dark,[data-theme=dark]) .stylo,.stylo:where(.dark,[data-theme=dark]){--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark;--stylo-bg:#09090b;--stylo-surface-floating:#09090b;--stylo-text:#fafafa;--stylo-text-muted:#a1a1aa;--stylo-border:#27272a;--stylo-accent:#fafafa;--stylo-link:#60a5fa;--stylo-ring:#52525b;--stylo-syntax-keyword:#c678dd;--stylo-syntax-string:#98c379;--stylo-syntax-escape:#d19a66;--stylo-syntax-comment:#7f848e;--stylo-syntax-number:#d19a66;--stylo-syntax-constant:#d19a66;--stylo-syntax-function:#61afef;--stylo-syntax-type:#e5c07b;--stylo-syntax-property:#56b6c2;--stylo-syntax-tag:#e06c75;--stylo-syntax-invalid:#e06c75}._root_18hcd_3{color:var(--stylo-text);font:inherit;grid-template-columns:1fr 1fr;gap:12px;display:grid}@media (width<=460px){._root_18hcd_3{grid-template-columns:1fr}}._col_18hcd_17{border:1px solid var(--stylo-border);border-radius:var(--stylo-radius);background:var(--stylo-bg);flex-direction:column;min-width:0;display:flex}._colHead_18hcd_26{border-bottom:1px solid var(--stylo-border);letter-spacing:.04em;text-transform:uppercase;color:var(--stylo-text-muted);margin:0;padding:8px 12px;font-size:.75rem;font-weight:600}._list_18hcd_37{flex-direction:column;flex:1;gap:2px;margin:0;padding:4px;list-style:none;display:flex}._row_18hcd_47{border-radius:calc(var(--stylo-radius) - 3px);background:var(--stylo-bg);align-items:center;gap:8px;padding:5px 6px;display:flex}._row_18hcd_47:focus-visible{outline:2px solid var(--stylo-ring);outline-offset:-2px}._row_18hcd_47:hover{background:color-mix(in srgb, var(--stylo-border) 30%, transparent)}._row_18hcd_47[data-dragging]{background:var(--stylo-surface-floating,#fff);opacity:.9;box-shadow:0 4px 16px #00000024}._handle_18hcd_73{border-radius:calc(var(--stylo-radius) - 4px);width:20px;height:22px;color:var(--stylo-text-muted);font:inherit;cursor:grab;touch-action:none;background:0 0;border:1px solid #0000;flex:none;justify-content:center;align-items:center;padding:0;line-height:1;display:inline-flex}._handle_18hcd_73:hover{background:color-mix(in srgb, var(--stylo-border) 45%, transparent);color:var(--stylo-text)}._handle_18hcd_73:focus-visible{outline:2px solid var(--stylo-ring);outline-offset:-1px}._handle_18hcd_73:active{cursor:grabbing}._glyph_18hcd_105{width:18px;height:18px;color:var(--stylo-text-muted);flex:none;justify-content:center;align-items:center;display:inline-flex}._glyph_18hcd_105 svg{width:16px;height:16px;display:block}._label_18hcd_121{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;font-size:.8125rem;overflow:hidden}._rowActions_18hcd_130{flex:none;gap:2px;display:flex}._iconButton_18hcd_136,._textButton_18hcd_137{box-sizing:border-box;border-radius:calc(var(--stylo-radius) - 4px);color:var(--stylo-text-muted);font:inherit;cursor:pointer;background:0 0;border:1px solid #0000}._iconButton_18hcd_136{width:22px;height:22px;font-size:.8125rem;line-height:1}._textButton_18hcd_137{padding:3px 8px;font-size:.75rem}._iconButton_18hcd_136:hover:not(:disabled),._textButton_18hcd_137:hover:not(:disabled){background:color-mix(in srgb, var(--stylo-border) 45%, transparent);color:var(--stylo-text)}._iconButton_18hcd_136:focus-visible,._textButton_18hcd_137:focus-visible{outline:2px solid var(--stylo-ring);outline-offset:-1px}._iconButton_18hcd_136:disabled{opacity:.35;cursor:default}._footer_18hcd_176{border-top:1px solid var(--stylo-border);flex-wrap:wrap;gap:6px;padding:6px;display:flex}._empty_18hcd_184{color:var(--stylo-text-muted);padding:8px 6px;font-size:.8125rem}._srOnly_18hcd_190{clip:rect(0 0 0 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}
|
|
2
2
|
/*$vite$:1*/
|
package/dist/stylo.js
CHANGED
|
@@ -1,46 +1,48 @@
|
|
|
1
|
-
import { i as e,
|
|
2
|
-
import { n, t as r } from "./useCodeMirror-
|
|
1
|
+
import { i as e, n as t } from "./frontmatter-DGUkb9z-.js";
|
|
2
|
+
import { n, t as r } from "./useCodeMirror-DtwupFgc.js";
|
|
3
3
|
import { n as i, r as a } from "./config-DTBxVhtH.js";
|
|
4
4
|
import { Suspense as o, forwardRef as s, lazy as c, useEffect as l, useImperativeHandle as u, useReducer as d, useRef as f, useState as p } from "react";
|
|
5
5
|
import { EditorView as m } from "@codemirror/view";
|
|
6
6
|
import { jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
7
7
|
//#region src/editor/SourceView.tsx
|
|
8
|
-
function _({ value: t, onChange: n, readOnly: i, placeholder: a, codeLanguages: o,
|
|
9
|
-
let
|
|
8
|
+
function _({ value: t, onChange: n, readOnly: i, placeholder: a, codeLanguages: o, wikiLinkSource: s, onResolveError: c, onSave: l, onViewChange: u }) {
|
|
9
|
+
let d = r({
|
|
10
10
|
value: t,
|
|
11
11
|
onChange: n,
|
|
12
12
|
readOnly: i,
|
|
13
13
|
placeholder: a,
|
|
14
14
|
codeLanguages: o,
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
wikiLinkSource: s,
|
|
16
|
+
onResolveError: c,
|
|
17
|
+
onSave: l,
|
|
18
|
+
onViewChange: u
|
|
17
19
|
});
|
|
18
20
|
return /* @__PURE__ */ h("div", {
|
|
19
21
|
className: e.source,
|
|
20
|
-
ref:
|
|
22
|
+
ref: d
|
|
21
23
|
});
|
|
22
24
|
}
|
|
23
25
|
//#endregion
|
|
24
26
|
//#region src/inplace/lazyInPlace.ts
|
|
25
|
-
var v = c(async () => ({ default: (await import("./InPlaceView-
|
|
27
|
+
var v = c(async () => ({ default: (await import("./InPlaceView-Bu91_3Ig.js")).InPlaceView })), y = c(async () => ({ default: (await import("./Preview-AaGGwLQP.js")).Preview }));
|
|
26
28
|
//#endregion
|
|
27
29
|
//#region src/SplitView.tsx
|
|
28
|
-
function b({ value: t, onChange: n, onWikiLinkClick: r, readOnly: i, placeholder: a, codeLanguages: s,
|
|
29
|
-
let [
|
|
30
|
+
function b({ value: t, onChange: n, onWikiLinkClick: r, readOnly: i, placeholder: a, codeLanguages: s, wikiLinkSource: c, embedSource: u, onResolveError: d, frontmatter: m, onSave: v, onViewChange: b }) {
|
|
31
|
+
let [x, S] = p(null), C = f(null), w = f(!1);
|
|
30
32
|
return l(() => {
|
|
31
|
-
let e =
|
|
33
|
+
let e = x?.scrollDOM, t = C.current;
|
|
32
34
|
if (!e || !t) return;
|
|
33
35
|
let n = (e, t) => {
|
|
34
|
-
if (
|
|
36
|
+
if (w.current) return;
|
|
35
37
|
let n = e.scrollHeight - e.clientHeight;
|
|
36
|
-
n <= 0 || (
|
|
37
|
-
|
|
38
|
+
n <= 0 || (w.current = !0, t.scrollTop = e.scrollTop / n * (t.scrollHeight - t.clientHeight), requestAnimationFrame(() => {
|
|
39
|
+
w.current = !1;
|
|
38
40
|
}));
|
|
39
41
|
}, r = () => n(e, t), i = () => n(t, e);
|
|
40
42
|
return e.addEventListener("scroll", r, { passive: !0 }), t.addEventListener("scroll", i, { passive: !0 }), () => {
|
|
41
43
|
e.removeEventListener("scroll", r), t.removeEventListener("scroll", i);
|
|
42
44
|
};
|
|
43
|
-
}, [
|
|
45
|
+
}, [x]), /* @__PURE__ */ g("div", {
|
|
44
46
|
className: e.split,
|
|
45
47
|
children: [/* @__PURE__ */ h("div", {
|
|
46
48
|
className: e.splitPane,
|
|
@@ -50,14 +52,16 @@ function b({ value: t, onChange: n, onWikiLinkClick: r, readOnly: i, placeholder
|
|
|
50
52
|
readOnly: i,
|
|
51
53
|
placeholder: a,
|
|
52
54
|
codeLanguages: s,
|
|
53
|
-
|
|
55
|
+
wikiLinkSource: c,
|
|
56
|
+
onResolveError: d,
|
|
57
|
+
onSave: v,
|
|
54
58
|
onViewChange: (e) => {
|
|
55
|
-
|
|
59
|
+
S(e), b?.(e);
|
|
56
60
|
}
|
|
57
61
|
})
|
|
58
62
|
}), /* @__PURE__ */ h("div", {
|
|
59
63
|
className: e.splitPane,
|
|
60
|
-
ref:
|
|
64
|
+
ref: C,
|
|
61
65
|
children: /* @__PURE__ */ h(o, {
|
|
62
66
|
fallback: /* @__PURE__ */ h("div", {
|
|
63
67
|
className: e.preview,
|
|
@@ -65,7 +69,10 @@ function b({ value: t, onChange: n, onWikiLinkClick: r, readOnly: i, placeholder
|
|
|
65
69
|
}),
|
|
66
70
|
children: /* @__PURE__ */ h(y, {
|
|
67
71
|
value: t,
|
|
68
|
-
onWikiLinkClick: r
|
|
72
|
+
onWikiLinkClick: r,
|
|
73
|
+
embedSource: u,
|
|
74
|
+
onResolveError: d,
|
|
75
|
+
frontmatter: m
|
|
69
76
|
})
|
|
70
77
|
})
|
|
71
78
|
})]
|
|
@@ -186,64 +193,70 @@ function w({ view: t, items: n, icons: r, disabled: i, sticky: a, stickyVisibili
|
|
|
186
193
|
}
|
|
187
194
|
//#endregion
|
|
188
195
|
//#region src/Stylo.tsx
|
|
189
|
-
var T = s(function({ value: n, onChange: r, mode: a = "in-place", onSave: s, onFrontmatter: c, onWikiLinkClick: d, onLinkClick: x, readOnly: S, placeholder: C, className: T, inPlace: E, codeLanguages: D,
|
|
190
|
-
let
|
|
191
|
-
|
|
192
|
-
let
|
|
196
|
+
var T = s(function({ value: n, onChange: r, mode: a = "in-place", onSave: s, onFrontmatter: c, onWikiLinkClick: d, onLinkClick: x, readOnly: S, placeholder: C, className: T, inPlace: E, codeLanguages: D, wikiLinkSource: O, embedSource: k, onResolveError: A, toolbar: j, icons: M, frontmatter: N }, P) {
|
|
197
|
+
let F = a === "preview" || a === "split" || a === "in-place" ? a : "source", [I, L] = p(null), R = F === "preview" ? null : i(j), z = j && typeof j == "object" ? j.render : void 0, B = j && typeof j == "object" ? j.sticky : void 0, V = B === "top" ? "top" : B ? "bottom" : !1, H = j && typeof j == "object" ? j.stickyVisibility : void 0, U = f(c);
|
|
198
|
+
U.current = c;
|
|
199
|
+
let W = f(A);
|
|
200
|
+
W.current = A;
|
|
201
|
+
let G = f((e, t) => {
|
|
202
|
+
W.current?.(e, t);
|
|
203
|
+
}).current, K = f(void 0);
|
|
193
204
|
l(() => {
|
|
194
205
|
let e = t(n)?.frontmatter ?? null;
|
|
195
|
-
e !==
|
|
196
|
-
}, [n]), u(
|
|
197
|
-
focus: () =>
|
|
198
|
-
getView: () =>
|
|
206
|
+
e !== K.current && (K.current = e, U.current?.(e));
|
|
207
|
+
}, [n]), u(P, () => ({
|
|
208
|
+
focus: () => I?.focus(),
|
|
209
|
+
getView: () => I,
|
|
199
210
|
insertAtCursor: (e) => {
|
|
200
|
-
|
|
211
|
+
I && (I.dispatch(I.state.replaceSelection(e)), I.focus());
|
|
201
212
|
},
|
|
202
213
|
scrollToHeading: (e) => {
|
|
203
|
-
if (!
|
|
204
|
-
let t = e.trim().toLowerCase(), { doc: n } =
|
|
214
|
+
if (!I) return !1;
|
|
215
|
+
let t = e.trim().toLowerCase(), { doc: n } = I.state;
|
|
205
216
|
for (let e = 1; e <= n.lines; e++) {
|
|
206
217
|
let r = n.line(e), i = /^ {0,3}#{1,6}[ \t]+(.*?)(?:[ \t]+#+)?[ \t]*$/.exec(r.text);
|
|
207
|
-
if (!(!i || i[1] === void 0) && i[1].trim().toLowerCase() === t) return
|
|
218
|
+
if (!(!i || i[1] === void 0) && i[1].trim().toLowerCase() === t) return I.dispatch({
|
|
208
219
|
selection: { anchor: r.from },
|
|
209
220
|
effects: m.scrollIntoView(r.from, { y: "start" })
|
|
210
|
-
}),
|
|
221
|
+
}), I.focus(), !0;
|
|
211
222
|
}
|
|
212
223
|
return !1;
|
|
213
224
|
}
|
|
214
|
-
}), [
|
|
215
|
-
let
|
|
225
|
+
}), [I]);
|
|
226
|
+
let q = [
|
|
216
227
|
e.root,
|
|
217
|
-
|
|
218
|
-
|
|
228
|
+
V === "bottom" && e.stickyToolbarRootBottom,
|
|
229
|
+
V === "top" && e.stickyToolbarRootTop,
|
|
219
230
|
"stylo",
|
|
220
231
|
T
|
|
221
232
|
].filter(Boolean).join(" ");
|
|
222
233
|
return /* @__PURE__ */ g("div", {
|
|
223
|
-
className:
|
|
224
|
-
"data-stylo-mode":
|
|
234
|
+
className: q,
|
|
235
|
+
"data-stylo-mode": F,
|
|
225
236
|
children: [
|
|
226
|
-
|
|
237
|
+
R && (() => {
|
|
227
238
|
let e = /* @__PURE__ */ h(w, {
|
|
228
|
-
view:
|
|
229
|
-
items:
|
|
230
|
-
icons:
|
|
239
|
+
view: I,
|
|
240
|
+
items: R,
|
|
241
|
+
icons: M,
|
|
231
242
|
disabled: S,
|
|
232
|
-
sticky:
|
|
233
|
-
stickyVisibility:
|
|
243
|
+
sticky: V,
|
|
244
|
+
stickyVisibility: H
|
|
234
245
|
});
|
|
235
|
-
return
|
|
246
|
+
return z ? z(e, { view: I }) : e;
|
|
236
247
|
})(),
|
|
237
|
-
|
|
248
|
+
F === "source" && /* @__PURE__ */ h(_, {
|
|
238
249
|
value: n,
|
|
239
250
|
onChange: r,
|
|
240
251
|
readOnly: S,
|
|
241
252
|
placeholder: C,
|
|
242
253
|
codeLanguages: D,
|
|
254
|
+
wikiLinkSource: O,
|
|
255
|
+
onResolveError: G,
|
|
243
256
|
onSave: s,
|
|
244
|
-
onViewChange:
|
|
257
|
+
onViewChange: L
|
|
245
258
|
}),
|
|
246
|
-
|
|
259
|
+
F === "preview" && /* @__PURE__ */ h(o, {
|
|
247
260
|
fallback: /* @__PURE__ */ h("div", {
|
|
248
261
|
className: e.preview,
|
|
249
262
|
"aria-busy": "true"
|
|
@@ -251,21 +264,26 @@ var T = s(function({ value: n, onChange: r, mode: a = "in-place", onSave: s, onF
|
|
|
251
264
|
children: /* @__PURE__ */ h(y, {
|
|
252
265
|
value: n,
|
|
253
266
|
onWikiLinkClick: d,
|
|
254
|
-
|
|
267
|
+
embedSource: k,
|
|
268
|
+
onResolveError: G,
|
|
269
|
+
frontmatter: N
|
|
255
270
|
})
|
|
256
271
|
}),
|
|
257
|
-
|
|
272
|
+
F === "split" && /* @__PURE__ */ h(b, {
|
|
258
273
|
value: n,
|
|
259
274
|
onChange: r,
|
|
260
275
|
onWikiLinkClick: d,
|
|
261
276
|
readOnly: S,
|
|
262
277
|
placeholder: C,
|
|
263
278
|
codeLanguages: D,
|
|
264
|
-
|
|
279
|
+
wikiLinkSource: O,
|
|
280
|
+
embedSource: k,
|
|
281
|
+
onResolveError: G,
|
|
282
|
+
frontmatter: N,
|
|
265
283
|
onSave: s,
|
|
266
|
-
onViewChange:
|
|
284
|
+
onViewChange: L
|
|
267
285
|
}),
|
|
268
|
-
|
|
286
|
+
F === "in-place" && /* @__PURE__ */ h(o, {
|
|
269
287
|
fallback: /* @__PURE__ */ h("div", {
|
|
270
288
|
className: e.inplace,
|
|
271
289
|
"aria-busy": "true"
|
|
@@ -279,8 +297,11 @@ var T = s(function({ value: n, onChange: r, mode: a = "in-place", onSave: s, onF
|
|
|
279
297
|
onLinkClick: x,
|
|
280
298
|
inPlace: E,
|
|
281
299
|
codeLanguages: D,
|
|
300
|
+
wikiLinkSource: O,
|
|
301
|
+
embedSource: k,
|
|
302
|
+
onResolveError: G,
|
|
282
303
|
onSave: s,
|
|
283
|
-
onViewChange:
|
|
304
|
+
onViewChange: L
|
|
284
305
|
})
|
|
285
306
|
})
|
|
286
307
|
]
|
package/dist/stylo.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stylo.js","names":[],"sources":["../src/editor/SourceView.tsx","../src/inplace/lazyInPlace.ts","../src/render/lazyPreview.ts","../src/SplitView.tsx","../src/toolbar/floating-watchdog.ts","../src/toolbar/keyboard-inset.ts","../src/toolbar/Toolbar.tsx","../src/Stylo.tsx"],"sourcesContent":["import type { EditorView } from \"@codemirror/view\"\nimport styles from \"../styles/stylo.module.css\"\nimport type { CodeLanguages } from \"../types\"\nimport { useCodeMirror } from \"./useCodeMirror\"\n\nexport interface SourceViewProps {\n value: string\n onChange: (next: string) => void\n readOnly?: boolean\n placeholder?: string\n /** Fenced-code grammars, forwarded to the Markdown language. Read once. */\n codeLanguages?: CodeLanguages\n /** Called with the doc string on `Mod-s`. */\n onSave?: (value: string) => void\n /** Called with the `EditorView` once created, and with `null` on teardown. */\n onViewChange?: (view: EditorView | null) => void\n}\n\n/** Raw CodeMirror 6 Markdown surface bound to the canonical string. */\nexport function SourceView({\n value,\n onChange,\n readOnly,\n placeholder,\n codeLanguages,\n onSave,\n onViewChange,\n}: SourceViewProps) {\n const ref = useCodeMirror({\n value,\n onChange,\n readOnly,\n placeholder,\n codeLanguages,\n onSave,\n onViewChange,\n })\n return <div className={styles.source} ref={ref} />\n}\n","import { lazy } from \"react\"\n\n/**\n * The in-place canvas carries the decoration plugin (and, in later increments,\n * its KaTeX widgets). It loads only when `mode` resolves to `in-place`, so\n * `source` consumers never fetch it.\n */\nexport const LazyInPlaceView = lazy(async () => ({\n default: (await import(\"./InPlaceView\")).InPlaceView,\n}))\n","import { lazy } from \"react\"\n\n/**\n * Preview pulls in react-markdown + remark/rehype + KaTeX. It is loaded only\n * when a rendered mode (`preview`, `split`) is actually used, so `mode=\"source\"`\n * consumers never pay for it. Both callers share this one wrapper, so the render\n * pipeline stays a single lazy chunk.\n */\nexport const LazyPreview = lazy(async () => ({\n default: (await import(\"./Preview\")).Preview,\n}))\n","import { Suspense, useEffect, useRef, useState } from \"react\"\nimport type { EditorView } from \"@codemirror/view\"\nimport { SourceView } from \"./editor/SourceView\"\nimport { LazyPreview } from \"./render/lazyPreview\"\nimport styles from \"./styles/stylo.module.css\"\nimport type { CodeLanguages, FrontmatterDisplay } from \"./types\"\n\nexport interface SplitViewProps {\n value: string\n onChange: (next: string) => void\n onWikiLinkClick?: (target: string) => void\n readOnly?: boolean\n placeholder?: string\n codeLanguages?: CodeLanguages\n frontmatter?: FrontmatterDisplay\n /** Called with the doc string on `Mod-s`. */\n onSave?: (value: string) => void\n /** Forwarded the source pane's `EditorView` for the shared toolbar. */\n onViewChange?: (view: EditorView | null) => void\n}\n\n/**\n * Source and preview side by side. Both panes are a pure function of the same\n * string; the only link between them is a proportional scroll sync. Expects the\n * Stylo root to have a bounded height — otherwise both panes grow and the page\n * scrolls instead.\n */\nexport function SplitView({\n value,\n onChange,\n onWikiLinkClick,\n readOnly,\n placeholder,\n codeLanguages,\n frontmatter,\n onSave,\n onViewChange,\n}: SplitViewProps) {\n const [view, setView] = useState<EditorView | null>(null)\n const previewPane = useRef<HTMLDivElement | null>(null)\n const syncing = useRef(false)\n\n const handleView = (next: EditorView | null) => {\n setView(next)\n onViewChange?.(next)\n }\n\n useEffect(() => {\n const source = view?.scrollDOM\n const preview = previewPane.current\n if (!source || !preview) return\n\n const sync = (from: HTMLElement, to: HTMLElement) => {\n if (syncing.current) return\n const range = from.scrollHeight - from.clientHeight\n if (range <= 0) return\n syncing.current = true\n to.scrollTop = (from.scrollTop / range) * (to.scrollHeight - to.clientHeight)\n requestAnimationFrame(() => {\n syncing.current = false\n })\n }\n\n const fromSource = () => sync(source, preview)\n const fromPreview = () => sync(preview, source)\n source.addEventListener(\"scroll\", fromSource, { passive: true })\n preview.addEventListener(\"scroll\", fromPreview, { passive: true })\n return () => {\n source.removeEventListener(\"scroll\", fromSource)\n preview.removeEventListener(\"scroll\", fromPreview)\n }\n }, [view])\n\n return (\n <div className={styles.split}>\n <div className={styles.splitPane}>\n <SourceView\n value={value}\n onChange={onChange}\n readOnly={readOnly}\n placeholder={placeholder}\n codeLanguages={codeLanguages}\n onSave={onSave}\n onViewChange={handleView}\n />\n </div>\n <div className={styles.splitPane} ref={previewPane}>\n <Suspense fallback={<div className={styles.preview} aria-busy=\"true\" />}>\n <LazyPreview value={value} onWikiLinkClick={onWikiLinkClick} />\n </Suspense>\n </div>\n </div>\n )\n}\n","import { useEffect, type RefObject } from \"react\"\n\n/**\n * Continuously re-asserts a `transform` on a `position: fixed` element,\n * alternating an imperceptible sub-pixel jitter every animation frame,\n * instead of trusting the browser to keep it correctly composited on its\n * own. Several rounds of on-device testing found iOS Safari losing track of\n * this exact kind of element — across its own address-bar animation, and in\n * at least one report tied to the keyboard opening — in ways a one-time\n * static fix (a plain `translateZ(0)`) did not reliably prevent. A value\n * that never changes gives the browser nothing to recompute; alternating it\n * every frame forces a fresh compositor pass regardless of what triggered\n * the drift, so it can't stay wrong for more than one frame (~16ms).\n *\n * Writes to the DOM directly rather than through React state, so this never\n * causes a re-render — the transform is the only thing touched.\n */\nexport function useFloatingWatchdog(ref: RefObject<HTMLElement | null>, enabled: boolean): void {\n useEffect(() => {\n if (!enabled) return\n let raf = 0\n let jitter = false\n const tick = () => {\n const el = ref.current\n if (el) {\n jitter = !jitter\n el.style.transform = jitter ? \"translate3d(0, 0.01px, 0)\" : \"translate3d(0, 0, 0)\"\n }\n raf = requestAnimationFrame(tick)\n }\n raf = requestAnimationFrame(tick)\n return () => cancelAnimationFrame(raf)\n }, [ref, enabled])\n}\n","import { useEffect, useState } from \"react\"\n\n/**\n * How far the on-screen keyboard eats into the window, tracked through the\n * `visualViewport` API. 0 when `enabled` is false or the browser has no\n * `visualViewport` (older Safari, SSR, most desktop browsers). A mobile\n * keyboard shrinks the *visual* viewport, not the layout viewport a plain\n * `position: fixed` bottom offset is computed against — this is what lets the\n * sticky toolbar ride up above the keyboard instead of hiding behind it.\n */\nexport function useKeyboardInset(enabled: boolean): number {\n const [inset, setInset] = useState(0)\n\n useEffect(() => {\n const vv = typeof window === \"undefined\" ? null : window.visualViewport\n if (!enabled || !vv) {\n setInset(0)\n return\n }\n const update = () => setInset(Math.max(0, window.innerHeight - vv.height - vv.offsetTop))\n update()\n vv.addEventListener(\"resize\", update)\n vv.addEventListener(\"scroll\", update)\n return () => {\n vv.removeEventListener(\"resize\", update)\n vv.removeEventListener(\"scroll\", update)\n }\n }, [enabled])\n\n return inset\n}\n","import { useEffect, useReducer, useRef, useState } from \"react\"\nimport type { ReactNode } from \"react\"\nimport type { EditorState } from \"@codemirror/state\"\nimport type { EditorView } from \"@codemirror/view\"\nimport styles from \"../styles/stylo.module.css\"\nimport type { ToolbarCommandId } from \"../types\"\nimport { BUILTIN_BY_ID } from \"./commands\"\nimport type { ToolbarItem } from \"./config\"\nimport { useFloatingWatchdog } from \"./floating-watchdog\"\nimport { DEFAULT_ICONS } from \"./icons\"\nimport { useKeyboardInset } from \"./keyboard-inset\"\n\nexport interface ToolbarProps {\n /** The surface the commands act on. `null` while a lazy view is mounting. */\n view: EditorView | null\n /** Ordered items to render; `\"|\"` is a separator. */\n items: ToolbarItem[]\n /** Per-id glyph overrides; any id left out keeps its built-in icon. */\n icons?: Partial<Record<ToolbarCommandId, ReactNode>>\n /** Render every button inert (e.g. a read-only surface). */\n disabled?: boolean\n /** Fix the bar to a window edge (normalised from `ToolbarConfig.sticky`; the\n * caller resolves `true` to `\"bottom\"`). */\n sticky?: \"top\" | \"bottom\" | false\n /** Fade the bar out while the editing surface is unfocused (`ToolbarConfig.stickyVisibility`). */\n stickyVisibility?: \"consistent\" | \"dynamic\"\n}\n\n/** A button to render, normalised from a built-in id or a custom item. */\ninterface Btn {\n key: string\n icon: ReactNode\n title: string\n run: (view: EditorView) => unknown\n isActive?: (state: EditorState) => boolean\n disabled?: (state: EditorState) => boolean\n}\n\n/** Resolve one non-separator item to a renderable button, or `null` to skip it. */\nfunction toButton(item: Exclude<ToolbarItem, \"|\">, icons: ToolbarProps[\"icons\"]): Btn | null {\n if (typeof item !== \"string\") {\n const { id, icon, title, run, isActive, disabled } = item\n return { key: id, icon, title, run, isActive, disabled }\n }\n const cmd = BUILTIN_BY_ID[item]\n if (!cmd) return null\n return {\n key: item,\n icon: icons?.[item] ?? DEFAULT_ICONS[item],\n title: cmd.title,\n run: cmd.run,\n isActive: cmd.isActive,\n disabled: cmd.disabled,\n }\n}\n\n/**\n * Formatting bar above the editing surface. It holds no document state — each\n * button runs a command against the live `EditorView`. Pressed states are read\n * back from the view whenever the selection, keys, or pointer move. Built-in\n * ids and consumer-supplied {@link ToolbarCustomItem}s render through the same\n * button path.\n */\nexport function Toolbar({ view, items, icons, disabled, sticky, stickyVisibility }: ToolbarProps) {\n const [, refresh] = useReducer((n: number) => n + 1, 0)\n const [focused, setFocused] = useState(false)\n // Only \"bottom\" needs keyboard tracking — nothing eats into the top of the\n // screen the way a keyboard eats the bottom.\n const keyboardInset = useKeyboardInset(sticky === \"bottom\")\n const barRef = useRef<HTMLDivElement>(null)\n useFloatingWatchdog(barRef, sticky === \"top\")\n\n useEffect(() => {\n if (!view) return\n const el = view.contentDOM\n setFocused(view.hasFocus)\n const onFocus = () => {\n setFocused(true)\n refresh()\n }\n const onBlur = () => {\n setFocused(false)\n refresh()\n }\n const events = [\"keyup\", \"mouseup\", \"input\"] as const\n for (const ev of events) el.addEventListener(ev, refresh)\n el.addEventListener(\"focus\", onFocus)\n el.addEventListener(\"blur\", onBlur)\n return () => {\n for (const ev of events) el.removeEventListener(ev, refresh)\n el.removeEventListener(\"focus\", onFocus)\n el.removeEventListener(\"blur\", onBlur)\n }\n }, [view])\n\n // \"dynamic\" fades the bar out while nothing is focused, so it doesn't sit\n // over the content while the caret is elsewhere (e.g. scrolling to read).\n const dynamicHidden = Boolean(sticky) && stickyVisibility === \"dynamic\" && !focused\n\n const className = [\n styles.toolbar,\n sticky && styles.toolbarSticky,\n sticky === \"top\" && styles.toolbarStickyTop,\n sticky === \"bottom\" && styles.toolbarStickyBottom,\n dynamicHidden && styles.toolbarStickyHidden,\n ]\n .filter(Boolean)\n .join(\" \")\n // `transform`, not `bottom` — a `position: fixed` element repositioned via\n // `bottom` doesn't reliably repaint in step with the keyboard animation on\n // iOS Safari; `translateY` forces a compositor update on every\n // `visualViewport` event instead. The bar's resting position (keyboard\n // closed) is `bottom: 0` in CSS; this only nudges it up. `\"top\"` needs no\n // offset at all.\n const stickyStyle =\n sticky === \"bottom\" ? { transform: `translateY(-${keyboardInset}px)` } : undefined\n\n return (\n <div\n ref={barRef}\n className={className}\n role=\"toolbar\"\n aria-label=\"Formatting\"\n aria-hidden={dynamicHidden || undefined}\n style={stickyStyle}\n >\n {items.map((item, i) => {\n if (item === \"|\") {\n return <span key={`sep-${i}`} className={styles.toolbarSep} aria-hidden=\"true\" />\n }\n const btn = toButton(item, icons)\n if (!btn) return null\n const off = disabled || !view || Boolean(btn.disabled?.(view.state))\n const active = Boolean(!off && view && btn.isActive?.(view.state))\n return (\n <button\n key={btn.key}\n type=\"button\"\n className={styles.toolbarButton}\n data-command={btn.key}\n title={btn.title}\n aria-label={btn.title}\n aria-pressed={btn.isActive ? active : undefined}\n data-active={active ? \"\" : undefined}\n disabled={off}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => {\n if (!view) return\n btn.run(view)\n refresh()\n }}\n >\n {btn.icon}\n </button>\n )\n })}\n </div>\n )\n}\n","import { forwardRef, Suspense, useEffect, useImperativeHandle, useRef, useState } from \"react\"\nimport { EditorView } from \"@codemirror/view\"\nimport { SourceView } from \"./editor/SourceView\"\nimport { LazyInPlaceView } from \"./inplace/lazyInPlace\"\nimport { LazyPreview } from \"./render/lazyPreview\"\nimport { SplitView } from \"./SplitView\"\nimport styles from \"./styles/stylo.module.css\"\nimport { Toolbar } from \"./toolbar/Toolbar\"\nimport { resolveToolbarItems } from \"./toolbar/config\"\nimport { splitFrontmatter } from \"./frontmatter\"\nimport \"./styles/tokens.css\"\nimport type { StyloHandle, StyloProps } from \"./types\"\n\n/**\n * Plain-text-first Markdown editor. `value` is the canonical Markdown string;\n * every view is a pure function of it.\n *\n * The default `mode` is `in-place`, the live decoration canvas (ADR-002 §1,\n * ADR-004). Pass `mode=\"source\"` for the plain surface with no lazy render\n * chunk. `preview` and `split` are also available.\n *\n * A formatting `toolbar` sits above every editing surface (all modes but\n * `preview`); pass `toolbar={false}` to drop it or a `ToolbarConfig` to trim it.\n */\nexport const Stylo = forwardRef<StyloHandle, StyloProps>(function Stylo(\n {\n value,\n onChange,\n mode = \"in-place\",\n onSave,\n onFrontmatter,\n onWikiLinkClick,\n onLinkClick,\n readOnly,\n placeholder,\n className,\n inPlace,\n codeLanguages,\n toolbar,\n icons,\n frontmatter,\n },\n ref,\n) {\n const resolved = mode === \"preview\" || mode === \"split\" || mode === \"in-place\" ? mode : \"source\"\n\n const [view, setView] = useState<EditorView | null>(null)\n const toolbarItems = resolved === \"preview\" ? null : resolveToolbarItems(toolbar)\n const toolbarRender = toolbar && typeof toolbar === \"object\" ? toolbar.render : undefined\n const stickyConfig = toolbar && typeof toolbar === \"object\" ? toolbar.sticky : undefined\n const stickyToolbar: \"top\" | \"bottom\" | false =\n stickyConfig === \"top\" ? \"top\" : stickyConfig ? \"bottom\" : false\n const stickyVisibility =\n toolbar && typeof toolbar === \"object\" ? toolbar.stickyVisibility : undefined\n\n // Report the raw frontmatter block on mount and whenever it changes. Stylo\n // does not parse it — the host passes `raw` to its own YAML parser.\n const onFrontmatterRef = useRef(onFrontmatter)\n onFrontmatterRef.current = onFrontmatter\n const lastFrontmatter = useRef<string | null | undefined>(undefined)\n useEffect(() => {\n const raw = splitFrontmatter(value)?.frontmatter ?? null\n if (raw === lastFrontmatter.current) return\n lastFrontmatter.current = raw\n onFrontmatterRef.current?.(raw)\n }, [value])\n\n useImperativeHandle(\n ref,\n () => ({\n focus: () => view?.focus(),\n getView: () => view,\n insertAtCursor: (md) => {\n if (!view) return\n view.dispatch(view.state.replaceSelection(md))\n view.focus()\n },\n scrollToHeading: (text) => {\n if (!view) return false\n const target = text.trim().toLowerCase()\n const { doc } = view.state\n for (let n = 1; n <= doc.lines; n++) {\n const line = doc.line(n)\n const m = /^ {0,3}#{1,6}[ \\t]+(.*?)(?:[ \\t]+#+)?[ \\t]*$/.exec(line.text)\n if (!m || m[1] === undefined) continue\n if (m[1].trim().toLowerCase() !== target) continue\n view.dispatch({\n selection: { anchor: line.from },\n effects: EditorView.scrollIntoView(line.from, { y: \"start\" }),\n })\n view.focus()\n return true\n }\n return false\n },\n }),\n [view],\n )\n\n const rootClass = [\n styles.root,\n stickyToolbar === \"bottom\" && styles.stickyToolbarRootBottom,\n stickyToolbar === \"top\" && styles.stickyToolbarRootTop,\n \"stylo\",\n className,\n ]\n .filter(Boolean)\n .join(\" \")\n\n return (\n <div className={rootClass} data-stylo-mode={resolved}>\n {toolbarItems &&\n (() => {\n const bar = (\n <Toolbar\n view={view}\n items={toolbarItems}\n icons={icons}\n disabled={readOnly}\n sticky={stickyToolbar}\n stickyVisibility={stickyVisibility}\n />\n )\n return toolbarRender ? toolbarRender(bar, { view }) : bar\n })()}\n\n {resolved === \"source\" && (\n <SourceView\n value={value}\n onChange={onChange}\n readOnly={readOnly}\n placeholder={placeholder}\n codeLanguages={codeLanguages}\n onSave={onSave}\n onViewChange={setView}\n />\n )}\n\n {resolved === \"preview\" && (\n <Suspense fallback={<div className={styles.preview} aria-busy=\"true\" />}>\n <LazyPreview value={value} onWikiLinkClick={onWikiLinkClick} frontmatter={frontmatter} />\n </Suspense>\n )}\n\n {resolved === \"split\" && (\n <SplitView\n value={value}\n onChange={onChange}\n onWikiLinkClick={onWikiLinkClick}\n readOnly={readOnly}\n placeholder={placeholder}\n codeLanguages={codeLanguages}\n frontmatter={frontmatter}\n onSave={onSave}\n onViewChange={setView}\n />\n )}\n\n {resolved === \"in-place\" && (\n <Suspense fallback={<div className={styles.inplace} aria-busy=\"true\" />}>\n <LazyInPlaceView\n value={value}\n onChange={onChange}\n readOnly={readOnly}\n placeholder={placeholder}\n onWikiLinkClick={onWikiLinkClick}\n onLinkClick={onLinkClick}\n inPlace={inPlace}\n codeLanguages={codeLanguages}\n onSave={onSave}\n onViewChange={setView}\n />\n </Suspense>\n )}\n </div>\n )\n})\n\nStylo.displayName = \"Stylo\"\n"],"mappings":";;;;;;;AAmBA,SAAgB,EAAW,EACzB,UACA,aACA,aACA,gBACA,kBACA,WACA,mBACkB;CAClB,IAAM,IAAM,EAAc;EACxB;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CACD,OAAO,kBAAC,OAAD;EAAK,WAAW,EAAO;EAAa;CAAM,CAAA;AACnD;;;AC/BA,IAAa,IAAkB,EAAK,aAAa,EAC/C,UAAU,MAAM,OAAO,6BAAA,CAAkB,YAC3C,EAAE,GCDW,IAAc,EAAK,aAAa,EAC3C,UAAU,MAAM,OAAO,yBAAA,CAAc,QACvC,EAAE;;;ACiBF,SAAgB,EAAU,EACxB,UACA,aACA,oBACA,aACA,gBACA,kBACA,gBACA,WACA,mBACiB;CACjB,IAAM,CAAC,GAAM,KAAW,EAA4B,IAAI,GAClD,IAAc,EAA8B,IAAI,GAChD,IAAU,EAAO,EAAK;CAiC5B,OA1BA,QAAgB;EACd,IAAM,IAAS,GAAM,WACf,IAAU,EAAY;EAC5B,IAAI,CAAC,KAAU,CAAC,GAAS;EAEzB,IAAM,KAAQ,GAAmB,MAAoB;GACnD,IAAI,EAAQ,SAAS;GACrB,IAAM,IAAQ,EAAK,eAAe,EAAK;GACnC,KAAS,MACb,EAAQ,UAAU,IAClB,EAAG,YAAa,EAAK,YAAY,KAAU,EAAG,eAAe,EAAG,eAChE,4BAA4B;IAC1B,EAAQ,UAAU;GACpB,CAAC;EACH,GAEM,UAAmB,EAAK,GAAQ,CAAO,GACvC,UAAoB,EAAK,GAAS,CAAM;EAG9C,OAFA,EAAO,iBAAiB,UAAU,GAAY,EAAE,SAAS,GAAK,CAAC,GAC/D,EAAQ,iBAAiB,UAAU,GAAa,EAAE,SAAS,GAAK,CAAC,SACpD;GAEX,AADA,EAAO,oBAAoB,UAAU,CAAU,GAC/C,EAAQ,oBAAoB,UAAU,CAAW;EACnD;CACF,GAAG,CAAC,CAAI,CAAC,GAGP,kBAAC,OAAD;EAAK,WAAW,EAAO;EAAvB,UAAA,CACE,kBAAC,OAAD;GAAK,WAAW,EAAO;GACrB,UAAA,kBAAC,GAAD;IACS;IACG;IACA;IACG;IACE;IACP;IACR,eAzCY,MAA4B;KAE9C,AADA,EAAQ,CAAI,GACZ,IAAe,CAAI;IACrB;GAuCO,CAAA;EACE,CAAA,GACL,kBAAC,OAAD;GAAK,WAAW,EAAO;GAAW,KAAK;GACrC,UAAA,kBAAC,GAAD;IAAU,UAAU,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAS,aAAU;IAAQ,CAAA;IACpE,UAAA,kBAAC,GAAD;KAAoB;KAAwB;IAAkB,CAAA;GACtD,CAAA;EACP,CAAA,CACF;;AAET;;;AC5EA,SAAgB,EAAoB,GAAoC,GAAwB;CAC9F,QAAgB;EACd,IAAI,CAAC,GAAS;EACd,IAAI,IAAM,GACN,IAAS,IACP,UAAa;GACjB,IAAM,IAAK,EAAI;GAKf,AAJI,MACF,IAAS,CAAC,GACV,EAAG,MAAM,YAAY,IAAS,8BAA8B,yBAE9D,IAAM,sBAAsB,CAAI;EAClC;EAEA,OADA,IAAM,sBAAsB,CAAI,SACnB,qBAAqB,CAAG;CACvC,GAAG,CAAC,GAAK,CAAO,CAAC;AACnB;;;ACvBA,SAAgB,EAAiB,GAA0B;CACzD,IAAM,CAAC,GAAO,KAAY,EAAS,CAAC;CAkBpC,OAhBA,QAAgB;EACd,IAAM,IAAK,OAAO,SAAW,MAAc,OAAO,OAAO;EACzD,IAAI,CAAC,KAAW,CAAC,GAAI;GACnB,EAAS,CAAC;GACV;EACF;EACA,IAAM,UAAe,EAAS,KAAK,IAAI,GAAG,OAAO,cAAc,EAAG,SAAS,EAAG,SAAS,CAAC;EAIxF,OAHA,EAAO,GACP,EAAG,iBAAiB,UAAU,CAAM,GACpC,EAAG,iBAAiB,UAAU,CAAM,SACvB;GAEX,AADA,EAAG,oBAAoB,UAAU,CAAM,GACvC,EAAG,oBAAoB,UAAU,CAAM;EACzC;CACF,GAAG,CAAC,CAAO,CAAC,GAEL;AACT;;;ACSA,SAAS,EAAS,GAAiC,GAA0C;CAC3F,IAAI,OAAO,KAAS,UAAU;EAC5B,IAAM,EAAE,OAAI,SAAM,UAAO,QAAK,aAAU,gBAAa;EACrD,OAAO;GAAE,KAAK;GAAI;GAAM;GAAO;GAAK;GAAU;EAAS;CACzD;CACA,IAAM,IAAM,EAAc;CAE1B,OADK,IACE;EACL,KAAK;EACL,MAAM,IAAQ,MAAS,EAAc;EACrC,OAAO,EAAI;EACX,KAAK,EAAI;EACT,UAAU,EAAI;EACd,UAAU,EAAI;CAChB,IARiB;AASnB;AASA,SAAgB,EAAQ,EAAE,SAAM,UAAO,UAAO,aAAU,WAAQ,uBAAkC;CAChG,IAAM,GAAG,KAAW,GAAY,MAAc,IAAI,GAAG,CAAC,GAChD,CAAC,GAAS,KAAc,EAAS,EAAK,GAGtC,IAAgB,EAAiB,MAAW,QAAQ,GACpD,IAAS,EAAuB,IAAI;CAG1C,AAFA,EAAoB,GAAQ,MAAW,KAAK,GAE5C,QAAgB;EACd,IAAI,CAAC,GAAM;EACX,IAAM,IAAK,EAAK;EAChB,EAAW,EAAK,QAAQ;EACxB,IAAM,UAAgB;GAEpB,AADA,EAAW,EAAI,GACf,EAAQ;EACV,GACM,UAAe;GAEnB,AADA,EAAW,EAAK,GAChB,EAAQ;EACV,GACM,IAAS;GAAC;GAAS;GAAW;EAAO;EAC3C,KAAK,IAAM,KAAM,GAAQ,EAAG,iBAAiB,GAAI,CAAO;EAGxD,OAFA,EAAG,iBAAiB,SAAS,CAAO,GACpC,EAAG,iBAAiB,QAAQ,CAAM,SACrB;GACX,KAAK,IAAM,KAAM,GAAQ,EAAG,oBAAoB,GAAI,CAAO;GAE3D,AADA,EAAG,oBAAoB,SAAS,CAAO,GACvC,EAAG,oBAAoB,QAAQ,CAAM;EACvC;CACF,GAAG,CAAC,CAAI,CAAC;CAIT,IAAM,IAAgB,EAAQ,KAAW,MAAqB,aAAa,CAAC,GAEtE,IAAY;EAChB,EAAO;EACP,KAAU,EAAO;EACjB,MAAW,SAAS,EAAO;EAC3B,MAAW,YAAY,EAAO;EAC9B,KAAiB,EAAO;CAC1B,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG,GAOL,IACJ,MAAW,WAAW,EAAE,WAAW,eAAe,EAAc,KAAK,IAAI,KAAA;CAE3E,OACE,kBAAC,OAAD;EACE,KAAK;EACM;EACX,MAAK;EACL,cAAW;EACX,eAAa,KAAiB,KAAA;EAC9B,OAAO;EAEN,UAAA,EAAM,KAAK,GAAM,MAAM;GACtB,IAAI,MAAS,KACX,OAAO,kBAAC,QAAD;IAAuB,WAAW,EAAO;IAAY,eAAY;GAAQ,GAA9D,OAAO,GAAuD;GAElF,IAAM,IAAM,EAAS,GAAM,CAAK;GAChC,IAAI,CAAC,GAAK,OAAO;GACjB,IAAM,IAAM,KAAY,CAAC,KAAQ,EAAQ,EAAI,WAAW,EAAK,KAAK,GAC5D,IAAS,GAAQ,CAAC,KAAO,KAAQ,EAAI,WAAW,EAAK,KAAK;GAChE,OACE,kBAAC,UAAD;IAEE,MAAK;IACL,WAAW,EAAO;IAClB,gBAAc,EAAI;IAClB,OAAO,EAAI;IACX,cAAY,EAAI;IAChB,gBAAc,EAAI,WAAW,IAAS,KAAA;IACtC,eAAa,IAAS,KAAK,KAAA;IAC3B,UAAU;IACV,cAAc,MAAM,EAAE,eAAe;IACrC,eAAe;KACR,MACL,EAAI,IAAI,CAAI,GACZ,EAAQ;IACV;IAEC,UAAA,EAAI;GACC,GAjBD,EAAI,GAiBH;EAEZ,CAAC;CACE,CAAA;AAET;;;ACtIA,IAAa,IAAQ,EAAoC,SACvD,EACE,UACA,aACA,UAAO,YACP,WACA,kBACA,oBACA,gBACA,aACA,gBACA,cACA,YACA,kBACA,YACA,UACA,kBAEF,GACA;CACA,IAAM,IAAW,MAAS,aAAa,MAAS,WAAW,MAAS,aAAa,IAAO,UAElF,CAAC,GAAM,KAAW,EAA4B,IAAI,GAClD,IAAe,MAAa,YAAY,OAAO,EAAoB,CAAO,GAC1E,IAAgB,KAAW,OAAO,KAAY,WAAW,EAAQ,SAAS,KAAA,GAC1E,IAAe,KAAW,OAAO,KAAY,WAAW,EAAQ,SAAS,KAAA,GACzE,IACJ,MAAiB,QAAQ,QAAQ,IAAe,WAAW,IACvD,IACJ,KAAW,OAAO,KAAY,WAAW,EAAQ,mBAAmB,KAAA,GAIhE,IAAmB,EAAO,CAAa;CAC7C,EAAiB,UAAU;CAC3B,IAAM,IAAkB,EAAkC,KAAA,CAAS;CAQnE,AAPA,QAAgB;EACd,IAAM,IAAM,EAAiB,CAAK,CAAC,EAAE,eAAe;EAChD,MAAQ,EAAgB,YAC5B,EAAgB,UAAU,GAC1B,EAAiB,UAAU,CAAG;CAChC,GAAG,CAAC,CAAK,CAAC,GAEV,EACE,UACO;EACL,aAAa,GAAM,MAAM;EACzB,eAAe;EACf,iBAAiB,MAAO;GACjB,MACL,EAAK,SAAS,EAAK,MAAM,iBAAiB,CAAE,CAAC,GAC7C,EAAK,MAAM;EACb;EACA,kBAAkB,MAAS;GACzB,IAAI,CAAC,GAAM,OAAO;GAClB,IAAM,IAAS,EAAK,KAAK,CAAC,CAAC,YAAY,GACjC,EAAE,WAAQ,EAAK;GACrB,KAAK,IAAI,IAAI,GAAG,KAAK,EAAI,OAAO,KAAK;IACnC,IAAM,IAAO,EAAI,KAAK,CAAC,GACjB,IAAI,+CAA+C,KAAK,EAAK,IAAI;IACnE,OAAC,KAAK,EAAE,OAAO,KAAA,MACf,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,YAAY,MAAM,GAMlC,OALA,EAAK,SAAS;KACZ,WAAW,EAAE,QAAQ,EAAK,KAAK;KAC/B,SAAS,EAAW,eAAe,EAAK,MAAM,EAAE,GAAG,QAAQ,CAAC;IAC9D,CAAC,GACD,EAAK,MAAM,GACJ;GACT;GACA,OAAO;EACT;CACF,IACA,CAAC,CAAI,CACP;CAEA,IAAM,IAAY;EAChB,EAAO;EACP,MAAkB,YAAY,EAAO;EACrC,MAAkB,SAAS,EAAO;EAClC;EACA;CACF,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CAEX,OACE,kBAAC,OAAD;EAAK,WAAW;EAAW,mBAAiB;EAA5C,UAAA;GACG,YACQ;IACL,IAAM,IACJ,kBAAC,GAAD;KACQ;KACN,OAAO;KACA;KACP,UAAU;KACV,QAAQ;KACU;IACnB,CAAA;IAEH,OAAO,IAAgB,EAAc,GAAK,EAAE,QAAK,CAAC,IAAI;GACxD,EAAA,CAAG;GAEJ,MAAa,YACZ,kBAAC,GAAD;IACS;IACG;IACA;IACG;IACE;IACP;IACR,cAAc;GACf,CAAA;GAGF,MAAa,aACZ,kBAAC,GAAD;IAAU,UAAU,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAS,aAAU;IAAQ,CAAA;IACpE,UAAA,kBAAC,GAAD;KAAoB;KAAwB;KAA8B;IAAc,CAAA;GAChF,CAAA;GAGX,MAAa,WACZ,kBAAC,GAAD;IACS;IACG;IACO;IACP;IACG;IACE;IACF;IACL;IACR,cAAc;GACf,CAAA;GAGF,MAAa,cACZ,kBAAC,GAAD;IAAU,UAAU,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAS,aAAU;IAAQ,CAAA;IACpE,UAAA,kBAAC,GAAD;KACS;KACG;KACA;KACG;KACI;KACJ;KACJ;KACM;KACP;KACR,cAAc;IACf,CAAA;GACO,CAAA;EAET;;AAET,CAAC;AAED,EAAM,cAAc"}
|
|
1
|
+
{"version":3,"file":"stylo.js","names":[],"sources":["../src/editor/SourceView.tsx","../src/inplace/lazyInPlace.ts","../src/render/lazyPreview.ts","../src/SplitView.tsx","../src/toolbar/floating-watchdog.ts","../src/toolbar/keyboard-inset.ts","../src/toolbar/Toolbar.tsx","../src/Stylo.tsx"],"sourcesContent":["import type { EditorView } from \"@codemirror/view\"\nimport styles from \"../styles/stylo.module.css\"\nimport type { CodeLanguages, ResolveErrorInfo, WikiLinkSource } from \"../types\"\nimport { useCodeMirror } from \"./useCodeMirror\"\n\nexport interface SourceViewProps {\n value: string\n onChange: (next: string) => void\n readOnly?: boolean\n placeholder?: string\n /** Fenced-code grammars, forwarded to the Markdown language. Read once. */\n codeLanguages?: CodeLanguages\n /** `[[wikilink]]` autocomplete source. Read once. */\n wikiLinkSource?: WikiLinkSource\n /** Notified when `wikiLinkSource` rejects. */\n onResolveError?: (error: unknown, info: ResolveErrorInfo) => void\n /** Called with the doc string on `Mod-s`. */\n onSave?: (value: string) => void\n /** Called with the `EditorView` once created, and with `null` on teardown. */\n onViewChange?: (view: EditorView | null) => void\n}\n\n/** Raw CodeMirror 6 Markdown surface bound to the canonical string. */\nexport function SourceView({\n value,\n onChange,\n readOnly,\n placeholder,\n codeLanguages,\n wikiLinkSource,\n onResolveError,\n onSave,\n onViewChange,\n}: SourceViewProps) {\n const ref = useCodeMirror({\n value,\n onChange,\n readOnly,\n placeholder,\n codeLanguages,\n wikiLinkSource,\n onResolveError,\n onSave,\n onViewChange,\n })\n return <div className={styles.source} ref={ref} />\n}\n","import { lazy } from \"react\"\n\n/**\n * The in-place canvas carries the decoration plugin (and, in later increments,\n * its KaTeX widgets). It loads only when `mode` resolves to `in-place`, so\n * `source` consumers never fetch it.\n */\nexport const LazyInPlaceView = lazy(async () => ({\n default: (await import(\"./InPlaceView\")).InPlaceView,\n}))\n","import { lazy } from \"react\"\n\n/**\n * Preview pulls in react-markdown + remark/rehype + KaTeX. It is loaded only\n * when a rendered mode (`preview`, `split`) is actually used, so `mode=\"source\"`\n * consumers never pay for it. Both callers share this one wrapper, so the render\n * pipeline stays a single lazy chunk.\n */\nexport const LazyPreview = lazy(async () => ({\n default: (await import(\"./Preview\")).Preview,\n}))\n","import { Suspense, useEffect, useRef, useState } from \"react\"\nimport type { EditorView } from \"@codemirror/view\"\nimport { SourceView } from \"./editor/SourceView\"\nimport { LazyPreview } from \"./render/lazyPreview\"\nimport styles from \"./styles/stylo.module.css\"\nimport type {\n CodeLanguages,\n EmbedSource,\n FrontmatterDisplay,\n ResolveErrorInfo,\n WikiLinkSource,\n} from \"./types\"\n\nexport interface SplitViewProps {\n value: string\n onChange: (next: string) => void\n onWikiLinkClick?: (target: string) => void\n readOnly?: boolean\n placeholder?: string\n codeLanguages?: CodeLanguages\n wikiLinkSource?: WikiLinkSource\n embedSource?: EmbedSource\n onResolveError?: (error: unknown, info: ResolveErrorInfo) => void\n frontmatter?: FrontmatterDisplay\n /** Called with the doc string on `Mod-s`. */\n onSave?: (value: string) => void\n /** Forwarded the source pane's `EditorView` for the shared toolbar. */\n onViewChange?: (view: EditorView | null) => void\n}\n\n/**\n * Source and preview side by side. Both panes are a pure function of the same\n * string; the only link between them is a proportional scroll sync. Expects the\n * Stylo root to have a bounded height — otherwise both panes grow and the page\n * scrolls instead.\n */\nexport function SplitView({\n value,\n onChange,\n onWikiLinkClick,\n readOnly,\n placeholder,\n codeLanguages,\n wikiLinkSource,\n embedSource,\n onResolveError,\n frontmatter,\n onSave,\n onViewChange,\n}: SplitViewProps) {\n const [view, setView] = useState<EditorView | null>(null)\n const previewPane = useRef<HTMLDivElement | null>(null)\n const syncing = useRef(false)\n\n const handleView = (next: EditorView | null) => {\n setView(next)\n onViewChange?.(next)\n }\n\n useEffect(() => {\n const source = view?.scrollDOM\n const preview = previewPane.current\n if (!source || !preview) return\n\n const sync = (from: HTMLElement, to: HTMLElement) => {\n if (syncing.current) return\n const range = from.scrollHeight - from.clientHeight\n if (range <= 0) return\n syncing.current = true\n to.scrollTop = (from.scrollTop / range) * (to.scrollHeight - to.clientHeight)\n requestAnimationFrame(() => {\n syncing.current = false\n })\n }\n\n const fromSource = () => sync(source, preview)\n const fromPreview = () => sync(preview, source)\n source.addEventListener(\"scroll\", fromSource, { passive: true })\n preview.addEventListener(\"scroll\", fromPreview, { passive: true })\n return () => {\n source.removeEventListener(\"scroll\", fromSource)\n preview.removeEventListener(\"scroll\", fromPreview)\n }\n }, [view])\n\n return (\n <div className={styles.split}>\n <div className={styles.splitPane}>\n <SourceView\n value={value}\n onChange={onChange}\n readOnly={readOnly}\n placeholder={placeholder}\n codeLanguages={codeLanguages}\n wikiLinkSource={wikiLinkSource}\n onResolveError={onResolveError}\n onSave={onSave}\n onViewChange={handleView}\n />\n </div>\n <div className={styles.splitPane} ref={previewPane}>\n <Suspense fallback={<div className={styles.preview} aria-busy=\"true\" />}>\n <LazyPreview\n value={value}\n onWikiLinkClick={onWikiLinkClick}\n embedSource={embedSource}\n onResolveError={onResolveError}\n frontmatter={frontmatter}\n />\n </Suspense>\n </div>\n </div>\n )\n}\n","import { useEffect, type RefObject } from \"react\"\n\n/**\n * Continuously re-asserts a `transform` on a `position: fixed` element,\n * alternating an imperceptible sub-pixel jitter every animation frame,\n * instead of trusting the browser to keep it correctly composited on its\n * own. Several rounds of on-device testing found iOS Safari losing track of\n * this exact kind of element — across its own address-bar animation, and in\n * at least one report tied to the keyboard opening — in ways a one-time\n * static fix (a plain `translateZ(0)`) did not reliably prevent. A value\n * that never changes gives the browser nothing to recompute; alternating it\n * every frame forces a fresh compositor pass regardless of what triggered\n * the drift, so it can't stay wrong for more than one frame (~16ms).\n *\n * Writes to the DOM directly rather than through React state, so this never\n * causes a re-render — the transform is the only thing touched.\n */\nexport function useFloatingWatchdog(ref: RefObject<HTMLElement | null>, enabled: boolean): void {\n useEffect(() => {\n if (!enabled) return\n let raf = 0\n let jitter = false\n const tick = () => {\n const el = ref.current\n if (el) {\n jitter = !jitter\n el.style.transform = jitter ? \"translate3d(0, 0.01px, 0)\" : \"translate3d(0, 0, 0)\"\n }\n raf = requestAnimationFrame(tick)\n }\n raf = requestAnimationFrame(tick)\n return () => cancelAnimationFrame(raf)\n }, [ref, enabled])\n}\n","import { useEffect, useState } from \"react\"\n\n/**\n * How far the on-screen keyboard eats into the window, tracked through the\n * `visualViewport` API. 0 when `enabled` is false or the browser has no\n * `visualViewport` (older Safari, SSR, most desktop browsers). A mobile\n * keyboard shrinks the *visual* viewport, not the layout viewport a plain\n * `position: fixed` bottom offset is computed against — this is what lets the\n * sticky toolbar ride up above the keyboard instead of hiding behind it.\n */\nexport function useKeyboardInset(enabled: boolean): number {\n const [inset, setInset] = useState(0)\n\n useEffect(() => {\n const vv = typeof window === \"undefined\" ? null : window.visualViewport\n if (!enabled || !vv) {\n setInset(0)\n return\n }\n const update = () => setInset(Math.max(0, window.innerHeight - vv.height - vv.offsetTop))\n update()\n vv.addEventListener(\"resize\", update)\n vv.addEventListener(\"scroll\", update)\n return () => {\n vv.removeEventListener(\"resize\", update)\n vv.removeEventListener(\"scroll\", update)\n }\n }, [enabled])\n\n return inset\n}\n","import { useEffect, useReducer, useRef, useState } from \"react\"\nimport type { ReactNode } from \"react\"\nimport type { EditorState } from \"@codemirror/state\"\nimport type { EditorView } from \"@codemirror/view\"\nimport styles from \"../styles/stylo.module.css\"\nimport type { ToolbarCommandId } from \"../types\"\nimport { BUILTIN_BY_ID } from \"./commands\"\nimport type { ToolbarItem } from \"./config\"\nimport { useFloatingWatchdog } from \"./floating-watchdog\"\nimport { DEFAULT_ICONS } from \"./icons\"\nimport { useKeyboardInset } from \"./keyboard-inset\"\n\nexport interface ToolbarProps {\n /** The surface the commands act on. `null` while a lazy view is mounting. */\n view: EditorView | null\n /** Ordered items to render; `\"|\"` is a separator. */\n items: ToolbarItem[]\n /** Per-id glyph overrides; any id left out keeps its built-in icon. */\n icons?: Partial<Record<ToolbarCommandId, ReactNode>>\n /** Render every button inert (e.g. a read-only surface). */\n disabled?: boolean\n /** Fix the bar to a window edge (normalised from `ToolbarConfig.sticky`; the\n * caller resolves `true` to `\"bottom\"`). */\n sticky?: \"top\" | \"bottom\" | false\n /** Fade the bar out while the editing surface is unfocused (`ToolbarConfig.stickyVisibility`). */\n stickyVisibility?: \"consistent\" | \"dynamic\"\n}\n\n/** A button to render, normalised from a built-in id or a custom item. */\ninterface Btn {\n key: string\n icon: ReactNode\n title: string\n run: (view: EditorView) => unknown\n isActive?: (state: EditorState) => boolean\n disabled?: (state: EditorState) => boolean\n}\n\n/** Resolve one non-separator item to a renderable button, or `null` to skip it. */\nfunction toButton(item: Exclude<ToolbarItem, \"|\">, icons: ToolbarProps[\"icons\"]): Btn | null {\n if (typeof item !== \"string\") {\n const { id, icon, title, run, isActive, disabled } = item\n return { key: id, icon, title, run, isActive, disabled }\n }\n const cmd = BUILTIN_BY_ID[item]\n if (!cmd) return null\n return {\n key: item,\n icon: icons?.[item] ?? DEFAULT_ICONS[item],\n title: cmd.title,\n run: cmd.run,\n isActive: cmd.isActive,\n disabled: cmd.disabled,\n }\n}\n\n/**\n * Formatting bar above the editing surface. It holds no document state — each\n * button runs a command against the live `EditorView`. Pressed states are read\n * back from the view whenever the selection, keys, or pointer move. Built-in\n * ids and consumer-supplied {@link ToolbarCustomItem}s render through the same\n * button path.\n */\nexport function Toolbar({ view, items, icons, disabled, sticky, stickyVisibility }: ToolbarProps) {\n const [, refresh] = useReducer((n: number) => n + 1, 0)\n const [focused, setFocused] = useState(false)\n // Only \"bottom\" needs keyboard tracking — nothing eats into the top of the\n // screen the way a keyboard eats the bottom.\n const keyboardInset = useKeyboardInset(sticky === \"bottom\")\n const barRef = useRef<HTMLDivElement>(null)\n useFloatingWatchdog(barRef, sticky === \"top\")\n\n useEffect(() => {\n if (!view) return\n const el = view.contentDOM\n setFocused(view.hasFocus)\n const onFocus = () => {\n setFocused(true)\n refresh()\n }\n const onBlur = () => {\n setFocused(false)\n refresh()\n }\n const events = [\"keyup\", \"mouseup\", \"input\"] as const\n for (const ev of events) el.addEventListener(ev, refresh)\n el.addEventListener(\"focus\", onFocus)\n el.addEventListener(\"blur\", onBlur)\n return () => {\n for (const ev of events) el.removeEventListener(ev, refresh)\n el.removeEventListener(\"focus\", onFocus)\n el.removeEventListener(\"blur\", onBlur)\n }\n }, [view])\n\n // \"dynamic\" fades the bar out while nothing is focused, so it doesn't sit\n // over the content while the caret is elsewhere (e.g. scrolling to read).\n const dynamicHidden = Boolean(sticky) && stickyVisibility === \"dynamic\" && !focused\n\n const className = [\n styles.toolbar,\n sticky && styles.toolbarSticky,\n sticky === \"top\" && styles.toolbarStickyTop,\n sticky === \"bottom\" && styles.toolbarStickyBottom,\n dynamicHidden && styles.toolbarStickyHidden,\n ]\n .filter(Boolean)\n .join(\" \")\n // `transform`, not `bottom` — a `position: fixed` element repositioned via\n // `bottom` doesn't reliably repaint in step with the keyboard animation on\n // iOS Safari; `translateY` forces a compositor update on every\n // `visualViewport` event instead. The bar's resting position (keyboard\n // closed) is `bottom: 0` in CSS; this only nudges it up. `\"top\"` needs no\n // offset at all.\n const stickyStyle =\n sticky === \"bottom\" ? { transform: `translateY(-${keyboardInset}px)` } : undefined\n\n return (\n <div\n ref={barRef}\n className={className}\n role=\"toolbar\"\n aria-label=\"Formatting\"\n aria-hidden={dynamicHidden || undefined}\n style={stickyStyle}\n >\n {items.map((item, i) => {\n if (item === \"|\") {\n return <span key={`sep-${i}`} className={styles.toolbarSep} aria-hidden=\"true\" />\n }\n const btn = toButton(item, icons)\n if (!btn) return null\n const off = disabled || !view || Boolean(btn.disabled?.(view.state))\n const active = Boolean(!off && view && btn.isActive?.(view.state))\n return (\n <button\n key={btn.key}\n type=\"button\"\n className={styles.toolbarButton}\n data-command={btn.key}\n title={btn.title}\n aria-label={btn.title}\n aria-pressed={btn.isActive ? active : undefined}\n data-active={active ? \"\" : undefined}\n disabled={off}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => {\n if (!view) return\n btn.run(view)\n refresh()\n }}\n >\n {btn.icon}\n </button>\n )\n })}\n </div>\n )\n}\n","import { forwardRef, Suspense, useEffect, useImperativeHandle, useRef, useState } from \"react\"\nimport { EditorView } from \"@codemirror/view\"\nimport { SourceView } from \"./editor/SourceView\"\nimport { LazyInPlaceView } from \"./inplace/lazyInPlace\"\nimport { LazyPreview } from \"./render/lazyPreview\"\nimport { SplitView } from \"./SplitView\"\nimport styles from \"./styles/stylo.module.css\"\nimport { Toolbar } from \"./toolbar/Toolbar\"\nimport { resolveToolbarItems } from \"./toolbar/config\"\nimport { splitFrontmatter } from \"./frontmatter\"\nimport \"./styles/tokens.css\"\nimport type { ResolveErrorInfo, StyloHandle, StyloProps } from \"./types\"\n\n/**\n * Plain-text-first Markdown editor. `value` is the canonical Markdown string;\n * every view is a pure function of it.\n *\n * The default `mode` is `in-place`, the live decoration canvas (ADR-002 §1,\n * ADR-004). Pass `mode=\"source\"` for the plain surface with no lazy render\n * chunk. `preview` and `split` are also available.\n *\n * A formatting `toolbar` sits above every editing surface (all modes but\n * `preview`); pass `toolbar={false}` to drop it or a `ToolbarConfig` to trim it.\n */\nexport const Stylo = forwardRef<StyloHandle, StyloProps>(function Stylo(\n {\n value,\n onChange,\n mode = \"in-place\",\n onSave,\n onFrontmatter,\n onWikiLinkClick,\n onLinkClick,\n readOnly,\n placeholder,\n className,\n inPlace,\n codeLanguages,\n wikiLinkSource,\n embedSource,\n onResolveError,\n toolbar,\n icons,\n frontmatter,\n },\n ref,\n) {\n const resolved = mode === \"preview\" || mode === \"split\" || mode === \"in-place\" ? mode : \"source\"\n\n const [view, setView] = useState<EditorView | null>(null)\n const toolbarItems = resolved === \"preview\" ? null : resolveToolbarItems(toolbar)\n const toolbarRender = toolbar && typeof toolbar === \"object\" ? toolbar.render : undefined\n const stickyConfig = toolbar && typeof toolbar === \"object\" ? toolbar.sticky : undefined\n const stickyToolbar: \"top\" | \"bottom\" | false =\n stickyConfig === \"top\" ? \"top\" : stickyConfig ? \"bottom\" : false\n const stickyVisibility =\n toolbar && typeof toolbar === \"object\" ? toolbar.stickyVisibility : undefined\n\n // Report the raw frontmatter block on mount and whenever it changes. Stylo\n // does not parse it — the host passes `raw` to its own YAML parser.\n const onFrontmatterRef = useRef(onFrontmatter)\n onFrontmatterRef.current = onFrontmatter\n\n // Stable wrapper so a changed `onResolveError` needs no editor rebuild and\n // does not thrash the embed effect. Passed to every surface.\n const onResolveErrorRef = useRef(onResolveError)\n onResolveErrorRef.current = onResolveError\n const resolveError = useRef((error: unknown, info: ResolveErrorInfo) => {\n onResolveErrorRef.current?.(error, info)\n }).current\n const lastFrontmatter = useRef<string | null | undefined>(undefined)\n useEffect(() => {\n const raw = splitFrontmatter(value)?.frontmatter ?? null\n if (raw === lastFrontmatter.current) return\n lastFrontmatter.current = raw\n onFrontmatterRef.current?.(raw)\n }, [value])\n\n useImperativeHandle(\n ref,\n () => ({\n focus: () => view?.focus(),\n getView: () => view,\n insertAtCursor: (md) => {\n if (!view) return\n view.dispatch(view.state.replaceSelection(md))\n view.focus()\n },\n scrollToHeading: (text) => {\n if (!view) return false\n const target = text.trim().toLowerCase()\n const { doc } = view.state\n for (let n = 1; n <= doc.lines; n++) {\n const line = doc.line(n)\n const m = /^ {0,3}#{1,6}[ \\t]+(.*?)(?:[ \\t]+#+)?[ \\t]*$/.exec(line.text)\n if (!m || m[1] === undefined) continue\n if (m[1].trim().toLowerCase() !== target) continue\n view.dispatch({\n selection: { anchor: line.from },\n effects: EditorView.scrollIntoView(line.from, { y: \"start\" }),\n })\n view.focus()\n return true\n }\n return false\n },\n }),\n [view],\n )\n\n const rootClass = [\n styles.root,\n stickyToolbar === \"bottom\" && styles.stickyToolbarRootBottom,\n stickyToolbar === \"top\" && styles.stickyToolbarRootTop,\n \"stylo\",\n className,\n ]\n .filter(Boolean)\n .join(\" \")\n\n return (\n <div className={rootClass} data-stylo-mode={resolved}>\n {toolbarItems &&\n (() => {\n const bar = (\n <Toolbar\n view={view}\n items={toolbarItems}\n icons={icons}\n disabled={readOnly}\n sticky={stickyToolbar}\n stickyVisibility={stickyVisibility}\n />\n )\n return toolbarRender ? toolbarRender(bar, { view }) : bar\n })()}\n\n {resolved === \"source\" && (\n <SourceView\n value={value}\n onChange={onChange}\n readOnly={readOnly}\n placeholder={placeholder}\n codeLanguages={codeLanguages}\n wikiLinkSource={wikiLinkSource}\n onResolveError={resolveError}\n onSave={onSave}\n onViewChange={setView}\n />\n )}\n\n {resolved === \"preview\" && (\n <Suspense fallback={<div className={styles.preview} aria-busy=\"true\" />}>\n <LazyPreview\n value={value}\n onWikiLinkClick={onWikiLinkClick}\n embedSource={embedSource}\n onResolveError={resolveError}\n frontmatter={frontmatter}\n />\n </Suspense>\n )}\n\n {resolved === \"split\" && (\n <SplitView\n value={value}\n onChange={onChange}\n onWikiLinkClick={onWikiLinkClick}\n readOnly={readOnly}\n placeholder={placeholder}\n codeLanguages={codeLanguages}\n wikiLinkSource={wikiLinkSource}\n embedSource={embedSource}\n onResolveError={resolveError}\n frontmatter={frontmatter}\n onSave={onSave}\n onViewChange={setView}\n />\n )}\n\n {resolved === \"in-place\" && (\n <Suspense fallback={<div className={styles.inplace} aria-busy=\"true\" />}>\n <LazyInPlaceView\n value={value}\n onChange={onChange}\n readOnly={readOnly}\n placeholder={placeholder}\n onWikiLinkClick={onWikiLinkClick}\n onLinkClick={onLinkClick}\n inPlace={inPlace}\n codeLanguages={codeLanguages}\n wikiLinkSource={wikiLinkSource}\n embedSource={embedSource}\n onResolveError={resolveError}\n onSave={onSave}\n onViewChange={setView}\n />\n </Suspense>\n )}\n </div>\n )\n})\n\nStylo.displayName = \"Stylo\"\n"],"mappings":"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"}
|
package/dist/toolbar/block.d.ts
CHANGED
|
@@ -2,14 +2,6 @@ import type { EditorState } from "@codemirror/state";
|
|
|
2
2
|
import type { EditorView } from "@codemirror/view";
|
|
3
3
|
/** The 1-based line numbers the primary selection touches. */
|
|
4
4
|
export declare function selectedLines(state: EditorState): [number, number];
|
|
5
|
-
/**
|
|
6
|
-
* Set, swap, or clear an ATX heading prefix on every line the selection touches.
|
|
7
|
-
* A line already at `level` is cleared; any other level (or none) is set to it.
|
|
8
|
-
*/
|
|
9
|
-
export declare function toggleHeading(view: EditorView, level: number): boolean;
|
|
10
|
-
/** Strip any ATX heading prefix from every line the selection touches — the
|
|
11
|
-
* explicit "back to body text" that toggling a heading level does obliquely. */
|
|
12
|
-
export declare function clearHeading(view: EditorView): boolean;
|
|
13
5
|
export interface LinePrefixSpec {
|
|
14
6
|
/** Detects this exact prefix; `match[0]` (from line start) is what gets stripped. */
|
|
15
7
|
match: RegExp;
|
|
@@ -35,22 +27,4 @@ export interface LinePrefixSpec {
|
|
|
35
27
|
export declare function toggleLinePrefix(view: EditorView, spec: LinePrefixSpec): boolean;
|
|
36
28
|
/** True when the primary caret's line carries the prefix. */
|
|
37
29
|
export declare function linePrefixActive(state: EditorState, match: RegExp): boolean;
|
|
38
|
-
/**
|
|
39
|
-
* Insert a `---` thematic break, or remove the one the caret is on. A blank line
|
|
40
|
-
* is inserted before the rule when the current line has content — otherwise
|
|
41
|
-
* CommonMark reads `text` + `---` as a setext H2, not a divider.
|
|
42
|
-
*/
|
|
43
|
-
export declare function toggleHorizontalRule(view: EditorView): boolean;
|
|
44
|
-
/** True when the primary caret's line is a thematic break. */
|
|
45
|
-
export declare function horizontalRuleActive(state: EditorState): boolean;
|
|
46
|
-
/**
|
|
47
|
-
* Toggle the leading `---` YAML block. With none present, the top of the
|
|
48
|
-
* document — line 1 through the last selected line — is wrapped in `---` fences
|
|
49
|
-
* (so the "type it, select it, click" flow works). With one present, only the
|
|
50
|
-
* two fence lines are removed; the YAML text stays in the document. Keeping it
|
|
51
|
-
* out of rendered output is the preview pipeline's job, not this toggle's.
|
|
52
|
-
*/
|
|
53
|
-
export declare function toggleFrontmatter(view: EditorView): boolean;
|
|
54
|
-
/** True when the document has a leading `---` YAML block. */
|
|
55
|
-
export declare function frontmatterActive(state: EditorState): boolean;
|
|
56
30
|
//# sourceMappingURL=block.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block.d.ts","sourceRoot":"","sources":["../../src/toolbar/block.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"block.d.ts","sourceRoot":"","sources":["../../src/toolbar/block.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAElD,8DAA8D;AAC9D,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAGlE;AAED,MAAM,WAAW,cAAc;IAC7B,qFAAqF;IACrF,KAAK,EAAE,MAAM,CAAA;IACb;;;;OAIG;IACH,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC,CAAA;IACxC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAsChF;AAED,6DAA6D;AAC7D,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAE3E"}
|