@glw907/cairn-cms 0.8.0 → 0.10.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/dist/components/ComponentForm.svelte +178 -0
- package/dist/components/ComponentForm.svelte.d.ts +20 -0
- package/dist/components/ComponentForm.svelte.d.ts.map +1 -0
- package/dist/components/ComponentInsertDialog.svelte +92 -0
- package/dist/components/ComponentInsertDialog.svelte.d.ts +20 -0
- package/dist/components/ComponentInsertDialog.svelte.d.ts.map +1 -0
- package/dist/components/EditPage.svelte +9 -8
- package/dist/components/EditPage.svelte.d.ts +4 -3
- package/dist/components/EditPage.svelte.d.ts.map +1 -1
- package/dist/components/EditorToolbar.svelte +61 -0
- package/dist/components/EditorToolbar.svelte.d.ts +15 -0
- package/dist/components/EditorToolbar.svelte.d.ts.map +1 -0
- package/dist/components/IconPicker.svelte +51 -0
- package/dist/components/IconPicker.svelte.d.ts +20 -0
- package/dist/components/IconPicker.svelte.d.ts.map +1 -0
- package/dist/components/MarkdownEditor.svelte +96 -57
- package/dist/components/MarkdownEditor.svelte.d.ts +5 -6
- package/dist/components/MarkdownEditor.svelte.d.ts.map +1 -1
- package/dist/components/index.d.ts +3 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +3 -1
- package/dist/components/markdown-format.d.ts +13 -0
- package/dist/components/markdown-format.d.ts.map +1 -0
- package/dist/components/markdown-format.js +23 -0
- package/dist/content/compose.d.ts.map +1 -1
- package/dist/content/compose.js +1 -0
- package/dist/content/types.d.ts +5 -0
- package/dist/content/types.d.ts.map +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/render/component-grammar.d.ts +10 -0
- package/dist/render/component-grammar.d.ts.map +1 -0
- package/dist/render/component-grammar.js +140 -0
- package/dist/render/component-insert.d.ts +14 -0
- package/dist/render/component-insert.d.ts.map +1 -0
- package/dist/render/component-insert.js +9 -0
- package/dist/render/component-reference.d.ts +11 -0
- package/dist/render/component-reference.d.ts.map +1 -0
- package/dist/render/component-reference.js +34 -0
- package/dist/render/component-validate.d.ts +10 -0
- package/dist/render/component-validate.d.ts.map +1 -0
- package/dist/render/component-validate.js +30 -0
- package/dist/render/pipeline.d.ts +1 -1
- package/dist/render/pipeline.js +1 -1
- package/dist/render/registry.d.ts +45 -1
- package/dist/render/registry.d.ts.map +1 -1
- package/dist/render/registry.js +13 -0
- package/dist/render/sanitize.js +2 -2
- package/package.json +8 -3
- package/src/lib/components/ComponentForm.svelte +178 -0
- package/src/lib/components/ComponentInsertDialog.svelte +92 -0
- package/src/lib/components/EditPage.svelte +9 -8
- package/src/lib/components/EditorToolbar.svelte +61 -0
- package/src/lib/components/IconPicker.svelte +51 -0
- package/src/lib/components/MarkdownEditor.svelte +96 -57
- package/src/lib/components/index.ts +3 -1
- package/src/lib/components/markdown-format.ts +39 -0
- package/src/lib/content/compose.ts +1 -0
- package/src/lib/content/types.ts +5 -0
- package/src/lib/index.ts +16 -2
- package/src/lib/render/component-grammar.ts +167 -0
- package/src/lib/render/component-insert.ts +15 -0
- package/src/lib/render/component-reference.ts +38 -0
- package/src/lib/render/component-validate.ts +36 -0
- package/src/lib/render/pipeline.ts +1 -1
- package/src/lib/render/registry.ts +61 -1
- package/src/lib/render/sanitize.ts +2 -2
- package/dist/components/ComponentPalette.svelte +0 -50
- package/dist/components/ComponentPalette.svelte.d.ts +0 -16
- package/dist/components/ComponentPalette.svelte.d.ts.map +0 -1
- package/src/lib/components/ComponentPalette.svelte +0 -50
|
@@ -5,6 +5,39 @@
|
|
|
5
5
|
// `ComponentRegistry` from here.
|
|
6
6
|
import type { Element } from 'hast';
|
|
7
7
|
|
|
8
|
+
/** The input types a component attribute or repeatable item field can take. */
|
|
9
|
+
export type FieldType = 'text' | 'select' | 'icon' | 'boolean';
|
|
10
|
+
|
|
11
|
+
/** One `{key="value"}` attribute on a component directive, or one field of a repeatable item. */
|
|
12
|
+
export interface AttributeField {
|
|
13
|
+
/** The attribute name as it appears in the directive, e.g. `icon`. */
|
|
14
|
+
key: string;
|
|
15
|
+
/** The form label. */
|
|
16
|
+
label: string;
|
|
17
|
+
type: FieldType;
|
|
18
|
+
required?: boolean;
|
|
19
|
+
/** Initial value; a string for text/select/icon, a boolean for boolean. */
|
|
20
|
+
default?: string | boolean;
|
|
21
|
+
/** Allowed values for `type: 'select'`. */
|
|
22
|
+
options?: string[];
|
|
23
|
+
/** Helper text shown under the field. */
|
|
24
|
+
help?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type SlotKind = 'markdown' | 'inline' | 'repeatable';
|
|
28
|
+
|
|
29
|
+
/** One named content region of a component. The slots named `title` and `body` are special: `title`
|
|
30
|
+
* serializes to the directive `[label]` and `body` to the unmarked content (see the canonical grammar). */
|
|
31
|
+
export interface SlotDef {
|
|
32
|
+
name: string;
|
|
33
|
+
label: string;
|
|
34
|
+
kind: SlotKind;
|
|
35
|
+
required?: boolean;
|
|
36
|
+
help?: string;
|
|
37
|
+
/** For `kind: 'repeatable'`: the fields composing each list item (v1 uses the first field). */
|
|
38
|
+
itemFields?: AttributeField[];
|
|
39
|
+
}
|
|
40
|
+
|
|
8
41
|
/** A site component: how it inserts (editor) and how it renders (rehype). */
|
|
9
42
|
export interface ComponentDef {
|
|
10
43
|
/** Directive name, e.g. 'card' (matches `:::card`). */
|
|
@@ -14,13 +47,19 @@ export interface ComponentDef {
|
|
|
14
47
|
/** Palette description. */
|
|
15
48
|
description: string;
|
|
16
49
|
/** Markdown scaffold inserted at the cursor by the editor palette. */
|
|
17
|
-
insertTemplate
|
|
50
|
+
insertTemplate?: string;
|
|
18
51
|
/** Build the final hast element from the stamped directive element. The engine
|
|
19
52
|
* stamps the entrance-stagger ordinal (`data-rise`) on the top-level result, so a
|
|
20
53
|
* build fn stays free of any motion concern. */
|
|
21
54
|
build: (node: Element) => Element;
|
|
22
55
|
/** Optional role-to-default-icon, e.g. `{ caution: 'warning' }`. */
|
|
23
56
|
defaultIconByRole?: Record<string, string>;
|
|
57
|
+
/** One line on when to reach for this component; feeds the picker and the reference file. */
|
|
58
|
+
use?: string;
|
|
59
|
+
/** The `{key="value"}` attributes this component accepts. */
|
|
60
|
+
attributes?: AttributeField[];
|
|
61
|
+
/** The named content regions this component accepts. */
|
|
62
|
+
slots?: SlotDef[];
|
|
24
63
|
}
|
|
25
64
|
|
|
26
65
|
export interface ComponentRegistry {
|
|
@@ -43,3 +82,24 @@ export function defineRegistry({ components }: { components: ComponentDef[] }):
|
|
|
43
82
|
defaultIcon: (name, role) => (role ? byName.get(name)?.defaultIconByRole?.[role] : undefined),
|
|
44
83
|
};
|
|
45
84
|
}
|
|
85
|
+
|
|
86
|
+
/** Guided-form values for one component: attribute values keyed by attribute key, slot values keyed
|
|
87
|
+
* by slot name (a string, or a string list for a repeatable slot). */
|
|
88
|
+
export interface ComponentValues {
|
|
89
|
+
attributes: Record<string, string | boolean>;
|
|
90
|
+
slots: Record<string, string | string[]>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Seed an empty {@link ComponentValues} from a component's schema: attribute defaults (or '' / false)
|
|
94
|
+
* and empty slot values ([] for repeatable, '' otherwise). */
|
|
95
|
+
export function emptyValues(def: ComponentDef): ComponentValues {
|
|
96
|
+
const attributes: Record<string, string | boolean> = {};
|
|
97
|
+
for (const field of def.attributes ?? []) {
|
|
98
|
+
attributes[field.key] = field.default ?? (field.type === 'boolean' ? false : '');
|
|
99
|
+
}
|
|
100
|
+
const slots: Record<string, string | string[]> = {};
|
|
101
|
+
for (const slot of def.slots ?? []) {
|
|
102
|
+
slots[slot.name] = slot.kind === 'repeatable' ? [] : '';
|
|
103
|
+
}
|
|
104
|
+
return { attributes, slots };
|
|
105
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// The live preview's sanitize floor.
|
|
2
|
-
//
|
|
1
|
+
// The live preview's sanitize floor. The MarkdownEditor edits raw markdown and never sanitizes,
|
|
2
|
+
// so the admin preview pane is the one barrier between editor-authored markdown and the DOM.
|
|
3
3
|
// DOMPurify needs a DOM, and the preview renders only in the browser after mount, so DOMPurify
|
|
4
4
|
// loads through a dynamic import: the module never evaluates a DOM library on the Worker, and a
|
|
5
5
|
// server import of this file pulls in nothing.
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
@component
|
|
3
|
-
The insert-component palette: a dropdown listing the site's registered directive components
|
|
4
|
-
(seam 3). Picking one inserts its template at the cursor through the editor's insert callback.
|
|
5
|
-
Renders nothing when the site configures no registry.
|
|
6
|
-
-->
|
|
7
|
-
<script lang="ts">
|
|
8
|
-
import type { ComponentRegistry } from '../render/registry.js';
|
|
9
|
-
|
|
10
|
-
interface Props {
|
|
11
|
-
/** The site's component registry; the palette derives its catalog from it. */
|
|
12
|
-
registry?: ComponentRegistry;
|
|
13
|
-
/** Insert a template at the editor's cursor. */
|
|
14
|
-
insert: (template: string) => void;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
let { registry, insert }: Props = $props();
|
|
18
|
-
|
|
19
|
-
const defs = $derived(registry?.defs ?? []);
|
|
20
|
-
let open = $state(false);
|
|
21
|
-
</script>
|
|
22
|
-
|
|
23
|
-
{#if defs.length > 0}
|
|
24
|
-
<div
|
|
25
|
-
class="dropdown"
|
|
26
|
-
class:dropdown-open={open}
|
|
27
|
-
role="presentation"
|
|
28
|
-
onkeydown={(e) => { if (e.key === 'Escape') open = false; }}
|
|
29
|
-
>
|
|
30
|
-
<button
|
|
31
|
-
type="button"
|
|
32
|
-
class="btn btn-sm btn-ghost"
|
|
33
|
-
aria-haspopup="listbox"
|
|
34
|
-
aria-expanded={open}
|
|
35
|
-
onclick={() => (open = !open)}
|
|
36
|
-
>Insert</button>
|
|
37
|
-
<ul class="dropdown-content menu rounded-box border border-base-300 bg-base-100 z-10 w-56 shadow" role="listbox">
|
|
38
|
-
{#each defs as def (def.name)}
|
|
39
|
-
<li role="option" aria-selected={false}>
|
|
40
|
-
<button type="button" onclick={() => { insert(def.insertTemplate); open = false; }}>
|
|
41
|
-
<span class="flex flex-col items-start">
|
|
42
|
-
<span class="font-medium">{def.label}</span>
|
|
43
|
-
<span class="text-xs text-[var(--color-muted)]">{def.description}</span>
|
|
44
|
-
</span>
|
|
45
|
-
</button>
|
|
46
|
-
</li>
|
|
47
|
-
{/each}
|
|
48
|
-
</ul>
|
|
49
|
-
</div>
|
|
50
|
-
{/if}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { ComponentRegistry } from '../render/registry.js';
|
|
2
|
-
interface Props {
|
|
3
|
-
/** The site's component registry; the palette derives its catalog from it. */
|
|
4
|
-
registry?: ComponentRegistry;
|
|
5
|
-
/** Insert a template at the editor's cursor. */
|
|
6
|
-
insert: (template: string) => void;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* The insert-component palette: a dropdown listing the site's registered directive components
|
|
10
|
-
* (seam 3). Picking one inserts its template at the cursor through the editor's insert callback.
|
|
11
|
-
* Renders nothing when the site configures no registry.
|
|
12
|
-
*/
|
|
13
|
-
declare const ComponentPalette: import("svelte").Component<Props, {}, "">;
|
|
14
|
-
type ComponentPalette = ReturnType<typeof ComponentPalette>;
|
|
15
|
-
export default ComponentPalette;
|
|
16
|
-
//# sourceMappingURL=ComponentPalette.svelte.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ComponentPalette.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/ComponentPalette.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAG7D,UAAU,KAAK;IACb,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,gDAAgD;IAChD,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAgCH;;;;GAIG;AACH,QAAA,MAAM,gBAAgB,2CAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
@component
|
|
3
|
-
The insert-component palette: a dropdown listing the site's registered directive components
|
|
4
|
-
(seam 3). Picking one inserts its template at the cursor through the editor's insert callback.
|
|
5
|
-
Renders nothing when the site configures no registry.
|
|
6
|
-
-->
|
|
7
|
-
<script lang="ts">
|
|
8
|
-
import type { ComponentRegistry } from '../render/registry.js';
|
|
9
|
-
|
|
10
|
-
interface Props {
|
|
11
|
-
/** The site's component registry; the palette derives its catalog from it. */
|
|
12
|
-
registry?: ComponentRegistry;
|
|
13
|
-
/** Insert a template at the editor's cursor. */
|
|
14
|
-
insert: (template: string) => void;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
let { registry, insert }: Props = $props();
|
|
18
|
-
|
|
19
|
-
const defs = $derived(registry?.defs ?? []);
|
|
20
|
-
let open = $state(false);
|
|
21
|
-
</script>
|
|
22
|
-
|
|
23
|
-
{#if defs.length > 0}
|
|
24
|
-
<div
|
|
25
|
-
class="dropdown"
|
|
26
|
-
class:dropdown-open={open}
|
|
27
|
-
role="presentation"
|
|
28
|
-
onkeydown={(e) => { if (e.key === 'Escape') open = false; }}
|
|
29
|
-
>
|
|
30
|
-
<button
|
|
31
|
-
type="button"
|
|
32
|
-
class="btn btn-sm btn-ghost"
|
|
33
|
-
aria-haspopup="listbox"
|
|
34
|
-
aria-expanded={open}
|
|
35
|
-
onclick={() => (open = !open)}
|
|
36
|
-
>Insert</button>
|
|
37
|
-
<ul class="dropdown-content menu rounded-box border border-base-300 bg-base-100 z-10 w-56 shadow" role="listbox">
|
|
38
|
-
{#each defs as def (def.name)}
|
|
39
|
-
<li role="option" aria-selected={false}>
|
|
40
|
-
<button type="button" onclick={() => { insert(def.insertTemplate); open = false; }}>
|
|
41
|
-
<span class="flex flex-col items-start">
|
|
42
|
-
<span class="font-medium">{def.label}</span>
|
|
43
|
-
<span class="text-xs text-[var(--color-muted)]">{def.description}</span>
|
|
44
|
-
</span>
|
|
45
|
-
</button>
|
|
46
|
-
</li>
|
|
47
|
-
{/each}
|
|
48
|
-
</ul>
|
|
49
|
-
</div>
|
|
50
|
-
{/if}
|