@atom-forge/brickee 0.0.0-stage → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/LICENSE +21 -0
- package/README-AI.md +286 -0
- package/README.md +41 -2
- package/dist/Editor.svelte +1956 -0
- package/dist/Editor.svelte.d.ts +19 -0
- package/dist/LinkPrompt.svelte +42 -0
- package/dist/LinkPrompt.svelte.d.ts +8 -0
- package/dist/PluginHost.svelte +41 -0
- package/dist/PluginHost.svelte.d.ts +13 -0
- package/dist/Preview.svelte +182 -0
- package/dist/Preview.svelte.d.ts +32 -0
- package/dist/PropsBar.svelte +405 -0
- package/dist/PropsBar.svelte.d.ts +17 -0
- package/dist/code.d.ts +12 -0
- package/dist/code.js +15 -0
- package/dist/dom.d.ts +29 -0
- package/dist/dom.js +224 -0
- package/dist/i18n.d.ts +7 -0
- package/dist/i18n.js +18 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +16 -0
- package/dist/kit/Empty.svelte +24 -0
- package/dist/kit/Empty.svelte.d.ts +8 -0
- package/dist/kit/Frame.svelte +76 -0
- package/dist/kit/Frame.svelte.d.ts +15 -0
- package/dist/kit/util.d.ts +13 -0
- package/dist/kit/util.js +28 -0
- package/dist/locales/hu.d.ts +2 -0
- package/dist/locales/hu.js +142 -0
- package/dist/markdown.d.ts +23 -0
- package/dist/markdown.js +219 -0
- package/dist/model.d.ts +21 -0
- package/dist/model.js +45 -0
- package/dist/palette.d.ts +19 -0
- package/dist/palette.js +23 -0
- package/dist/plugins/Gap.svelte +28 -0
- package/dist/plugins/Gap.svelte.d.ts +15 -0
- package/dist/plugins/GapPreview.svelte +17 -0
- package/dist/plugins/GapPreview.svelte.d.ts +5 -0
- package/dist/plugins/Map.svelte +47 -0
- package/dist/plugins/Map.svelte.d.ts +12 -0
- package/dist/plugins/MapPreview.svelte +26 -0
- package/dist/plugins/MapPreview.svelte.d.ts +5 -0
- package/dist/plugins/Table.svelte +537 -0
- package/dist/plugins/Table.svelte.d.ts +28 -0
- package/dist/plugins/TablePreview.svelte +62 -0
- package/dist/plugins/TablePreview.svelte.d.ts +5 -0
- package/dist/plugins/YouTube.svelte +52 -0
- package/dist/plugins/YouTube.svelte.d.ts +8 -0
- package/dist/plugins/YouTubePreview.svelte +76 -0
- package/dist/plugins/YouTubePreview.svelte.d.ts +5 -0
- package/dist/plugins/index.d.ts +20 -0
- package/dist/plugins/index.js +105 -0
- package/dist/plugins/util.d.ts +3 -0
- package/dist/plugins/util.js +8 -0
- package/dist/schema.d.ts +11 -0
- package/dist/schema.js +25 -0
- package/dist/scroll.d.ts +18 -0
- package/dist/scroll.js +57 -0
- package/dist/types.d.ts +132 -0
- package/dist/types.js +43 -0
- package/dist/view.d.ts +6 -0
- package/dist/view.js +11 -0
- package/docs/en/bundled-plugins.md +99 -0
- package/docs/en/documents-and-markdown.md +114 -0
- package/docs/en/editor-and-preview.md +139 -0
- package/docs/en/getting-started.md +85 -0
- package/docs/en/host-contexts.md +169 -0
- package/docs/en/index.md +38 -0
- package/docs/en/recipes-and-pitfalls.md +123 -0
- package/docs/en/server-side.md +95 -0
- package/docs/en/upgrading.md +71 -0
- package/docs/en/writing-plugins.md +405 -0
- package/docs/hu/bundled-plugins.md +99 -0
- package/docs/hu/documents-and-markdown.md +114 -0
- package/docs/hu/editor-and-preview.md +139 -0
- package/docs/hu/getting-started.md +85 -0
- package/docs/hu/host-contexts.md +169 -0
- package/docs/hu/index.md +38 -0
- package/docs/hu/recipes-and-pitfalls.md +123 -0
- package/docs/hu/server-side.md +95 -0
- package/docs/hu/upgrading.md +71 -0
- package/docs/hu/writing-plugins.md +405 -0
- package/package.json +114 -5
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Messages } from './i18n';
|
|
2
|
+
import { type BlockPlugin, type StoredBlock } from './types';
|
|
3
|
+
interface Props {
|
|
4
|
+
/** The document: built-in blocks as markdown snippets, plugin blocks with their props. */
|
|
5
|
+
value?: StoredBlock[];
|
|
6
|
+
readonly?: boolean;
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
/** Built-in block types and plugin types offered in the slash menu, in this order. Shortcuts and paste respect it too. */
|
|
9
|
+
palette?: string[];
|
|
10
|
+
/** Custom blocks this editor can show and offer. */
|
|
11
|
+
plugins?: BlockPlugin[];
|
|
12
|
+
/** Set by plugins with nested blocks: a compact editor inside another block. */
|
|
13
|
+
nested?: boolean;
|
|
14
|
+
/** UI text in the host's language (English text -> translation); nested editors share their parent's. */
|
|
15
|
+
messages?: Messages;
|
|
16
|
+
}
|
|
17
|
+
declare const Editor: import("svelte").Component<Props, {}, "value">;
|
|
18
|
+
type Editor = ReturnType<typeof Editor>;
|
|
19
|
+
export default Editor;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<!-- The link field of the formatting toolbar (Ctrl+K), in an atom-forge popup: resolves with the address, '' to remove the link. -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
import { Button, Input, getPopupManager } from '@atom-forge/ui';
|
|
4
|
+
import type { Translate } from './i18n';
|
|
5
|
+
|
|
6
|
+
let { href = '', tr }: { href?: string; tr: Translate } = $props();
|
|
7
|
+
const popups = getPopupManager();
|
|
8
|
+
// svelte-ignore state_referenced_locally
|
|
9
|
+
let url = $state(href);
|
|
10
|
+
let input = $state<{ focus: () => void }>();
|
|
11
|
+
$effect(() => input?.focus());
|
|
12
|
+
|
|
13
|
+
function onkeydown(e: KeyboardEvent) {
|
|
14
|
+
if (e.key === 'Enter') {
|
|
15
|
+
e.preventDefault();
|
|
16
|
+
popups.resolve(url.trim());
|
|
17
|
+
} else if (e.key === 'Escape') {
|
|
18
|
+
e.preventDefault();
|
|
19
|
+
popups.resolve(undefined);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
25
|
+
<div class="link" {onkeydown}>
|
|
26
|
+
<Input bind:this={input} compact monospace bind:value={url} placeholder="https://…" />
|
|
27
|
+
<Button compact accent label={tr('OK')} onclick={() => popups.resolve(url.trim())} />
|
|
28
|
+
{#if href}<Button compact ghost label={tr('Remove')} onclick={() => popups.resolve('')} />{/if}
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<style>
|
|
32
|
+
.link {
|
|
33
|
+
display: flex;
|
|
34
|
+
gap: 6px;
|
|
35
|
+
width: 340px;
|
|
36
|
+
padding: 8px;
|
|
37
|
+
background: var(--color-surface, #fff);
|
|
38
|
+
border: 1px solid var(--color-frame, #e5e5ea);
|
|
39
|
+
border-radius: 12px;
|
|
40
|
+
box-shadow: 0 10px 36px rgba(0, 0, 0, 0.2);
|
|
41
|
+
}
|
|
42
|
+
</style>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Translate } from './i18n';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
href?: string;
|
|
4
|
+
tr: Translate;
|
|
5
|
+
};
|
|
6
|
+
declare const LinkPrompt: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type LinkPrompt = ReturnType<typeof LinkPrompt>;
|
|
8
|
+
export default LinkPrompt;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<!-- One plugin block in the editor: its view, and its fields (PropsBar). A plugin drawn in a Frame gets the fields inside
|
|
2
|
+
the frame, on its top (the Frame claims them through the context); any other gets them above its view. A container
|
|
3
|
+
gets the host's palette narrowed to its `accepts`. -->
|
|
4
|
+
<script lang="ts" module>
|
|
5
|
+
import { getContext, setContext, type Snippet } from 'svelte';
|
|
6
|
+
|
|
7
|
+
const KEY = Symbol('block-fields');
|
|
8
|
+
type Host = { fields: Snippet | undefined; claimed: boolean };
|
|
9
|
+
|
|
10
|
+
/** For a frame: takes the block's fields to draw them itself; undefined when there are none (or read-only). */
|
|
11
|
+
export function claimFields(): Snippet | undefined {
|
|
12
|
+
const host = getContext<Host | undefined>(KEY);
|
|
13
|
+
if (!host) return undefined;
|
|
14
|
+
host.claimed = true;
|
|
15
|
+
return host.fields;
|
|
16
|
+
}
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<script lang="ts">
|
|
20
|
+
import { narrowPalette } from './palette';
|
|
21
|
+
import type { BlockPlugin, PluginViewProps } from './types';
|
|
22
|
+
|
|
23
|
+
interface Props extends Omit<PluginViewProps, 'props' | 'blocks'> {
|
|
24
|
+
plugin: BlockPlugin;
|
|
25
|
+
props: PluginViewProps['props'];
|
|
26
|
+
blocks: PluginViewProps['blocks'];
|
|
27
|
+
fields?: Snippet;
|
|
28
|
+
}
|
|
29
|
+
let { plugin, props = $bindable(), blocks = $bindable(), readonly, palette, plugins, fields }: Props = $props();
|
|
30
|
+
|
|
31
|
+
// svelte-ignore state_referenced_locally
|
|
32
|
+
const host = $state<Host>({ fields, claimed: false });
|
|
33
|
+
setContext(KEY, host);
|
|
34
|
+
$effect.pre(() => {
|
|
35
|
+
host.fields = fields;
|
|
36
|
+
});
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
{#if fields && !host.claimed}{@render fields()}{/if}
|
|
40
|
+
<!-- a container's nested editor offers only the blocks it accepts -->
|
|
41
|
+
<plugin.view bind:props bind:blocks {readonly} palette={narrowPalette(palette, plugin.accepts)} {plugins} />
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Snippet } from 'svelte';
|
|
2
|
+
/** For a frame: takes the block's fields to draw them itself; undefined when there are none (or read-only). */
|
|
3
|
+
export declare function claimFields(): Snippet | undefined;
|
|
4
|
+
import type { BlockPlugin, PluginViewProps } from './types';
|
|
5
|
+
interface Props extends Omit<PluginViewProps, 'props' | 'blocks'> {
|
|
6
|
+
plugin: BlockPlugin;
|
|
7
|
+
props: PluginViewProps['props'];
|
|
8
|
+
blocks: PluginViewProps['blocks'];
|
|
9
|
+
fields?: Snippet;
|
|
10
|
+
}
|
|
11
|
+
declare const PluginHost: import("svelte").Component<Props, {}, "blocks" | "props">;
|
|
12
|
+
type PluginHost = ReturnType<typeof PluginHost>;
|
|
13
|
+
export default PluginHost;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
<!-- Styles travel with the markup: the sites show the blocks as server-rendered HTML (see content.server.ts). -->
|
|
2
|
+
<svelte:options css="injected" />
|
|
3
|
+
|
|
4
|
+
<script lang="ts" module>
|
|
5
|
+
import type { StoredBlock } from './types';
|
|
6
|
+
|
|
7
|
+
const LIST = new Set(['md:ul', 'md:ol', 'md:todo']);
|
|
8
|
+
|
|
9
|
+
/** Consecutive list blocks as properly nested lists: an item one level deeper goes into the previous item. */
|
|
10
|
+
export type ListNode = { type: string; items: { block: StoredBlock; children: ListNode[] }[] };
|
|
11
|
+
export type Part = { kind: 'block'; block: StoredBlock } | { kind: 'lists'; lists: ListNode[] };
|
|
12
|
+
|
|
13
|
+
function nest(run: StoredBlock[], i: number, level: number): [ListNode[], number] {
|
|
14
|
+
const out: ListNode[] = [];
|
|
15
|
+
let cur: ListNode | null = null;
|
|
16
|
+
while (i < run.length && run[i].indent >= level) {
|
|
17
|
+
const b = run[i];
|
|
18
|
+
if (b.indent > level && cur) {
|
|
19
|
+
const [kids, next] = nest(run, i, level + 1);
|
|
20
|
+
cur.items[cur.items.length - 1].children.push(...kids);
|
|
21
|
+
i = next;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
// A different list type at the same level starts a new list.
|
|
25
|
+
if (!cur || cur.type !== b.type) out.push((cur = { type: b.type, items: [] }));
|
|
26
|
+
cur.items.push({ block: b, children: [] });
|
|
27
|
+
i++;
|
|
28
|
+
}
|
|
29
|
+
return [out, i];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function parts(blocks: StoredBlock[]): Part[] {
|
|
33
|
+
const out: Part[] = [];
|
|
34
|
+
for (let i = 0; i < blocks.length; ) {
|
|
35
|
+
if (!LIST.has(blocks[i].type)) {
|
|
36
|
+
out.push({ kind: 'block', block: blocks[i++] });
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
let j = i;
|
|
40
|
+
while (j < blocks.length && LIST.has(blocks[j].type)) j++;
|
|
41
|
+
const run = blocks.slice(i, j);
|
|
42
|
+
out.push({ kind: 'lists', lists: nest(run, 0, Math.min(...run.map((b) => b.indent)))[0] });
|
|
43
|
+
i = j;
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<script lang="ts">
|
|
50
|
+
import { useText } from './i18n';
|
|
51
|
+
import { inline } from './markdown';
|
|
52
|
+
import { provideText, type Messages } from './i18n';
|
|
53
|
+
import type { BlockPlugin } from './types';
|
|
54
|
+
|
|
55
|
+
interface Props {
|
|
56
|
+
blocks: StoredBlock[];
|
|
57
|
+
plugins: BlockPlugin[];
|
|
58
|
+
/** Set by plugins rendering their nested blocks; only the top level splits at the supporters-only divider. */
|
|
59
|
+
nested?: boolean;
|
|
60
|
+
/** UI text in the host's language; nested previews share their parent's. */
|
|
61
|
+
messages?: Messages;
|
|
62
|
+
/** Mark the blocks after a gate (the supporters-only divider) with a label and a dashed line; default: yes. */
|
|
63
|
+
markGated?: boolean;
|
|
64
|
+
}
|
|
65
|
+
let { blocks, plugins, nested = false, messages, markGated = true }: Props = $props();
|
|
66
|
+
|
|
67
|
+
provideText(() => messages);
|
|
68
|
+
const tr = useText();
|
|
69
|
+
|
|
70
|
+
const pluginOf = (type: string) => plugins.find((p) => p.type === type);
|
|
71
|
+
|
|
72
|
+
// Everything after a unique supporters-only divider is for supporters: shown here, marked as such.
|
|
73
|
+
const lockAt = $derived(nested || !markGated ? -1 : blocks.findIndex((b) => pluginOf(b.type)?.gate));
|
|
74
|
+
const open = $derived(lockAt < 0 ? blocks : blocks.slice(0, lockAt + 1));
|
|
75
|
+
const locked = $derived(lockAt < 0 ? [] : blocks.slice(lockAt + 1));
|
|
76
|
+
|
|
77
|
+
// Inline markdown -> html: text is escaped first, links are http(s), mailto, tel or site-relative only (see inline()).
|
|
78
|
+
const html = (b: StoredBlock) => inline(b.text ?? '');
|
|
79
|
+
const indent = (b: StoredBlock) => (b.indent ? `${b.indent * 1.5}em` : undefined);
|
|
80
|
+
</script>
|
|
81
|
+
|
|
82
|
+
{#snippet list(node: ListNode)}
|
|
83
|
+
{#if node.type === 'md:ol'}
|
|
84
|
+
<ol>{@render items(node)}</ol>
|
|
85
|
+
{:else}
|
|
86
|
+
<ul class:todo={node.type === 'md:todo'}>{@render items(node)}</ul>
|
|
87
|
+
{/if}
|
|
88
|
+
{/snippet}
|
|
89
|
+
|
|
90
|
+
{#snippet items(node: ListNode)}
|
|
91
|
+
{#each node.items as it, n (n)}
|
|
92
|
+
<li>
|
|
93
|
+
{#if node.type === 'md:todo'}
|
|
94
|
+
<input type="checkbox" checked={!!it.block.props?.checked} disabled aria-label={tr('Done')} />
|
|
95
|
+
{/if}
|
|
96
|
+
{@html html(it.block)}
|
|
97
|
+
{#each it.children as child, c (c)}{@render list(child)}{/each}
|
|
98
|
+
</li>
|
|
99
|
+
{/each}
|
|
100
|
+
{/snippet}
|
|
101
|
+
|
|
102
|
+
{#snippet run(items: StoredBlock[])}
|
|
103
|
+
{#each parts(items) as part, n (n)}
|
|
104
|
+
{#if part.kind === 'lists'}
|
|
105
|
+
{#each part.lists as l, m (m)}{@render list(l)}{/each}
|
|
106
|
+
{:else}
|
|
107
|
+
{@const b = part.block}
|
|
108
|
+
{@const plugin = pluginOf(b.type)}
|
|
109
|
+
{#if b.type === 'md:p'}
|
|
110
|
+
{#if b.text}<p style:margin-left={indent(b)}>{@html html(b)}</p>{/if}
|
|
111
|
+
{:else if b.type === 'md:h1'}
|
|
112
|
+
<h1>{@html html(b)}</h1>
|
|
113
|
+
{:else if b.type === 'md:h2'}
|
|
114
|
+
<h2>{@html html(b)}</h2>
|
|
115
|
+
{:else if b.type === 'md:h3'}
|
|
116
|
+
<h3>{@html html(b)}</h3>
|
|
117
|
+
{:else if b.type === 'md:h4'}
|
|
118
|
+
<h4>{@html html(b)}</h4>
|
|
119
|
+
{:else if b.type === 'md:h5'}
|
|
120
|
+
<h5>{@html html(b)}</h5>
|
|
121
|
+
{:else if b.type === 'md:h6'}
|
|
122
|
+
<h6>{@html html(b)}</h6>
|
|
123
|
+
{:else if b.type === 'md:quote'}
|
|
124
|
+
<blockquote style:margin-left={indent(b)}><p>{@html html(b)}</p></blockquote>
|
|
125
|
+
{:else if b.type === 'md:code'}
|
|
126
|
+
{@const lang = String(b.props?.lang ?? '')}
|
|
127
|
+
<pre><code class={lang ? `language-${lang}` : undefined}>{b.text ?? ''}</code></pre>
|
|
128
|
+
{:else if b.type === 'md:hr'}
|
|
129
|
+
<hr />
|
|
130
|
+
{:else if plugin?.preview}
|
|
131
|
+
<!-- a plugin without a preview is drawn by the app's own renderer, not here -->
|
|
132
|
+
<plugin.preview props={b.props ?? {}} blocks={b.blocks ?? []} {plugins} />
|
|
133
|
+
{/if}
|
|
134
|
+
{/if}
|
|
135
|
+
{/each}
|
|
136
|
+
{/snippet}
|
|
137
|
+
|
|
138
|
+
<div class="preview" class:nested>
|
|
139
|
+
{@render run(open)}
|
|
140
|
+
{#if locked.length}
|
|
141
|
+
<div class="supporters" aria-label={tr('For supporters only')}>
|
|
142
|
+
<p class="supporters-label">{tr('For supporters only')}</p>
|
|
143
|
+
{@render run(locked)}
|
|
144
|
+
</div>
|
|
145
|
+
{/if}
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
<style>
|
|
149
|
+
/* Only what the renderer itself adds; the article typography comes from the page that shows it. */
|
|
150
|
+
.supporters {
|
|
151
|
+
margin-top: 1.5em;
|
|
152
|
+
padding-top: 1em;
|
|
153
|
+
border-top: 2px dashed #f96854;
|
|
154
|
+
}
|
|
155
|
+
.supporters-label {
|
|
156
|
+
font: 600 11px/1 system-ui, sans-serif;
|
|
157
|
+
letter-spacing: 0.08em;
|
|
158
|
+
text-transform: uppercase;
|
|
159
|
+
color: #f96854;
|
|
160
|
+
}
|
|
161
|
+
.preview :global(ul.todo) {
|
|
162
|
+
list-style: none;
|
|
163
|
+
padding-left: 0.2em;
|
|
164
|
+
}
|
|
165
|
+
.preview :global(ul.todo input) {
|
|
166
|
+
margin-right: 0.5em;
|
|
167
|
+
}
|
|
168
|
+
.preview :global(img) {
|
|
169
|
+
max-width: 100%;
|
|
170
|
+
}
|
|
171
|
+
/* The content starts at its top edge, whatever its first block is (pages often align it with a sidebar). */
|
|
172
|
+
.preview:not(.nested) > :global(:first-child),
|
|
173
|
+
.preview:not(.nested) > :global(:first-child > :first-child) {
|
|
174
|
+
margin-top: 0;
|
|
175
|
+
}
|
|
176
|
+
/* Floating images and side boxes stay inside the content. */
|
|
177
|
+
.preview:not(.nested)::after {
|
|
178
|
+
content: '';
|
|
179
|
+
display: block;
|
|
180
|
+
clear: both;
|
|
181
|
+
}
|
|
182
|
+
</style>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { StoredBlock } from './types';
|
|
2
|
+
/** Consecutive list blocks as properly nested lists: an item one level deeper goes into the previous item. */
|
|
3
|
+
export type ListNode = {
|
|
4
|
+
type: string;
|
|
5
|
+
items: {
|
|
6
|
+
block: StoredBlock;
|
|
7
|
+
children: ListNode[];
|
|
8
|
+
}[];
|
|
9
|
+
};
|
|
10
|
+
export type Part = {
|
|
11
|
+
kind: 'block';
|
|
12
|
+
block: StoredBlock;
|
|
13
|
+
} | {
|
|
14
|
+
kind: 'lists';
|
|
15
|
+
lists: ListNode[];
|
|
16
|
+
};
|
|
17
|
+
export declare function parts(blocks: StoredBlock[]): Part[];
|
|
18
|
+
import { type Messages } from './i18n';
|
|
19
|
+
import type { BlockPlugin } from './types';
|
|
20
|
+
interface Props {
|
|
21
|
+
blocks: StoredBlock[];
|
|
22
|
+
plugins: BlockPlugin[];
|
|
23
|
+
/** Set by plugins rendering their nested blocks; only the top level splits at the supporters-only divider. */
|
|
24
|
+
nested?: boolean;
|
|
25
|
+
/** UI text in the host's language; nested previews share their parent's. */
|
|
26
|
+
messages?: Messages;
|
|
27
|
+
/** Mark the blocks after a gate (the supporters-only divider) with a label and a dashed line; default: yes. */
|
|
28
|
+
markGated?: boolean;
|
|
29
|
+
}
|
|
30
|
+
declare const Preview: import("svelte").Component<Props, {}, "">;
|
|
31
|
+
type Preview = ReturnType<typeof Preview>;
|
|
32
|
+
export default Preview;
|