@vizel/svelte 0.0.1-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +83 -0
- package/dist/components/Vizel.svelte +158 -0
- package/dist/components/Vizel.svelte.d.ts +82 -0
- package/dist/components/Vizel.svelte.d.ts.map +1 -0
- package/dist/components/VizelBubbleMenu.svelte +96 -0
- package/dist/components/VizelBubbleMenu.svelte.d.ts +28 -0
- package/dist/components/VizelBubbleMenu.svelte.d.ts.map +1 -0
- package/dist/components/VizelBubbleMenuButton.svelte +45 -0
- package/dist/components/VizelBubbleMenuButton.svelte.d.ts +21 -0
- package/dist/components/VizelBubbleMenuButton.svelte.d.ts.map +1 -0
- package/dist/components/VizelBubbleMenuColorPicker.svelte +135 -0
- package/dist/components/VizelBubbleMenuColorPicker.svelte.d.ts +19 -0
- package/dist/components/VizelBubbleMenuColorPicker.svelte.d.ts.map +1 -0
- package/dist/components/VizelBubbleMenuDefault.svelte +111 -0
- package/dist/components/VizelBubbleMenuDefault.svelte.d.ts +13 -0
- package/dist/components/VizelBubbleMenuDefault.svelte.d.ts.map +1 -0
- package/dist/components/VizelBubbleMenuDivider.svelte +12 -0
- package/dist/components/VizelBubbleMenuDivider.svelte.d.ts +8 -0
- package/dist/components/VizelBubbleMenuDivider.svelte.d.ts.map +1 -0
- package/dist/components/VizelColorPicker.svelte +269 -0
- package/dist/components/VizelColorPicker.svelte.d.ts +25 -0
- package/dist/components/VizelColorPicker.svelte.d.ts.map +1 -0
- package/dist/components/VizelContext.d.ts +27 -0
- package/dist/components/VizelContext.d.ts.map +1 -0
- package/dist/components/VizelContext.js +34 -0
- package/dist/components/VizelEditor.svelte +61 -0
- package/dist/components/VizelEditor.svelte.d.ts +17 -0
- package/dist/components/VizelEditor.svelte.d.ts.map +1 -0
- package/dist/components/VizelEmbedView.svelte +162 -0
- package/dist/components/VizelEmbedView.svelte.d.ts +13 -0
- package/dist/components/VizelEmbedView.svelte.d.ts.map +1 -0
- package/dist/components/VizelIcon.svelte +54 -0
- package/dist/components/VizelIcon.svelte.d.ts +32 -0
- package/dist/components/VizelIcon.svelte.d.ts.map +1 -0
- package/dist/components/VizelIconContext.d.ts +27 -0
- package/dist/components/VizelIconContext.d.ts.map +1 -0
- package/dist/components/VizelIconContext.js +31 -0
- package/dist/components/VizelIconProvider.svelte +43 -0
- package/dist/components/VizelIconProvider.svelte.d.ts +31 -0
- package/dist/components/VizelIconProvider.svelte.d.ts.map +1 -0
- package/dist/components/VizelLinkEditor.svelte +143 -0
- package/dist/components/VizelLinkEditor.svelte.d.ts +15 -0
- package/dist/components/VizelLinkEditor.svelte.d.ts.map +1 -0
- package/dist/components/VizelNodeSelector.svelte +172 -0
- package/dist/components/VizelNodeSelector.svelte.d.ts +13 -0
- package/dist/components/VizelNodeSelector.svelte.d.ts.map +1 -0
- package/dist/components/VizelPortal.svelte +70 -0
- package/dist/components/VizelPortal.svelte.d.ts +19 -0
- package/dist/components/VizelPortal.svelte.d.ts.map +1 -0
- package/dist/components/VizelProvider.svelte +26 -0
- package/dist/components/VizelProvider.svelte.d.ts +14 -0
- package/dist/components/VizelProvider.svelte.d.ts.map +1 -0
- package/dist/components/VizelSaveIndicator.svelte +94 -0
- package/dist/components/VizelSaveIndicator.svelte.d.ts +15 -0
- package/dist/components/VizelSaveIndicator.svelte.d.ts.map +1 -0
- package/dist/components/VizelSlashMenu.svelte +211 -0
- package/dist/components/VizelSlashMenu.svelte.d.ts +31 -0
- package/dist/components/VizelSlashMenu.svelte.d.ts.map +1 -0
- package/dist/components/VizelSlashMenuEmpty.svelte +22 -0
- package/dist/components/VizelSlashMenuEmpty.svelte.d.ts +11 -0
- package/dist/components/VizelSlashMenuEmpty.svelte.d.ts.map +1 -0
- package/dist/components/VizelSlashMenuItem.svelte +57 -0
- package/dist/components/VizelSlashMenuItem.svelte.d.ts +17 -0
- package/dist/components/VizelSlashMenuItem.svelte.d.ts.map +1 -0
- package/dist/components/VizelThemeProvider.svelte +79 -0
- package/dist/components/VizelThemeProvider.svelte.d.ts +11 -0
- package/dist/components/VizelThemeProvider.svelte.d.ts.map +1 -0
- package/dist/components/index.d.ts +23 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +64 -0
- package/dist/iconRenderer.d.ts +6 -0
- package/dist/iconRenderer.d.ts.map +1 -0
- package/dist/iconRenderer.js +7 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/runes/createVizelAutoSave.svelte.d.ts +44 -0
- package/dist/runes/createVizelAutoSave.svelte.d.ts.map +1 -0
- package/dist/runes/createVizelAutoSave.svelte.js +91 -0
- package/dist/runes/createVizelEditor.svelte.d.ts +43 -0
- package/dist/runes/createVizelEditor.svelte.d.ts.map +1 -0
- package/dist/runes/createVizelEditor.svelte.js +65 -0
- package/dist/runes/createVizelEditorState.svelte.d.ts +27 -0
- package/dist/runes/createVizelEditorState.svelte.d.ts.map +1 -0
- package/dist/runes/createVizelEditorState.svelte.js +35 -0
- package/dist/runes/createVizelMarkdown.svelte.d.ts +68 -0
- package/dist/runes/createVizelMarkdown.svelte.d.ts.map +1 -0
- package/dist/runes/createVizelMarkdown.svelte.js +123 -0
- package/dist/runes/createVizelSlashMenuRenderer.d.ts +22 -0
- package/dist/runes/createVizelSlashMenuRenderer.d.ts.map +1 -0
- package/dist/runes/createVizelSlashMenuRenderer.js +84 -0
- package/dist/runes/createVizelState.svelte.d.ts +22 -0
- package/dist/runes/createVizelState.svelte.d.ts.map +1 -0
- package/dist/runes/createVizelState.svelte.js +50 -0
- package/dist/runes/getVizelTheme.svelte.d.ts +23 -0
- package/dist/runes/getVizelTheme.svelte.d.ts.map +1 -0
- package/dist/runes/getVizelTheme.svelte.js +31 -0
- package/dist/runes/index.d.ts +8 -0
- package/dist/runes/index.d.ts.map +1 -0
- package/dist/runes/index.js +7 -0
- package/package.json +64 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { VizelEmbedData } from "@vizel/core";
|
|
3
|
+
|
|
4
|
+
export interface VizelEmbedViewProps {
|
|
5
|
+
/** Embed data */
|
|
6
|
+
data: VizelEmbedData;
|
|
7
|
+
/** Additional class name */
|
|
8
|
+
class?: string;
|
|
9
|
+
/** Whether the embed is selected */
|
|
10
|
+
selected?: boolean;
|
|
11
|
+
}
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<script lang="ts">
|
|
15
|
+
import VizelIcon from "./VizelIcon.svelte";
|
|
16
|
+
|
|
17
|
+
let { data, class: className, selected = false }: VizelEmbedViewProps = $props();
|
|
18
|
+
|
|
19
|
+
let containerRef: HTMLDivElement | null = $state(null);
|
|
20
|
+
|
|
21
|
+
const baseClass = $derived(
|
|
22
|
+
`vizel-embed ${data.loading ? "is-loading" : ""} ${selected ? "ProseMirror-selectednode" : ""} ${className ?? ""}`
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const isVideo = $derived(
|
|
26
|
+
["youtube", "vimeo", "loom", "tiktok"].includes(data.provider ?? "")
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const hasImage = $derived(Boolean(data.image));
|
|
30
|
+
|
|
31
|
+
const hostname = $derived.by(() => {
|
|
32
|
+
try {
|
|
33
|
+
return new URL(data.url).hostname;
|
|
34
|
+
} catch {
|
|
35
|
+
return data.url;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Handle oEmbed scripts
|
|
40
|
+
function loadScripts() {
|
|
41
|
+
if (data.type === "oembed" && data.html && containerRef) {
|
|
42
|
+
const scripts = containerRef.querySelectorAll("script");
|
|
43
|
+
for (const script of scripts) {
|
|
44
|
+
const newScript = document.createElement("script");
|
|
45
|
+
if (script.src) {
|
|
46
|
+
newScript.src = script.src;
|
|
47
|
+
} else {
|
|
48
|
+
newScript.textContent = script.textContent;
|
|
49
|
+
}
|
|
50
|
+
script.parentNode?.replaceChild(newScript, script);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Load Twitter widgets if present
|
|
54
|
+
if (data.provider === "twitter" && "twttr" in window) {
|
|
55
|
+
(window as { twttr?: { widgets?: { load?: () => void } } }).twttr?.widgets?.load?.();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Load scripts on mount and when data changes
|
|
61
|
+
$effect(() => {
|
|
62
|
+
loadScripts();
|
|
63
|
+
});
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
{#if data.loading}
|
|
67
|
+
<!-- Loading state -->
|
|
68
|
+
<div
|
|
69
|
+
class={baseClass}
|
|
70
|
+
data-embed-type="loading"
|
|
71
|
+
data-embed-provider={data.provider}
|
|
72
|
+
>
|
|
73
|
+
<div class="vizel-embed-loading">
|
|
74
|
+
<div class="vizel-embed-loading-spinner"></div>
|
|
75
|
+
<span>Loading embed...</span>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
{:else if data.type === "oembed" && data.html}
|
|
79
|
+
<!-- oEmbed (rich embed) -->
|
|
80
|
+
<div
|
|
81
|
+
bind:this={containerRef}
|
|
82
|
+
class={baseClass}
|
|
83
|
+
data-embed-type="oembed"
|
|
84
|
+
data-embed-provider={data.provider}
|
|
85
|
+
>
|
|
86
|
+
<div
|
|
87
|
+
class={isVideo ? "vizel-embed-video" : "vizel-embed-oembed"}
|
|
88
|
+
>
|
|
89
|
+
{@html data.html}
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
{:else if data.type === "ogp"}
|
|
93
|
+
<!-- OGP card -->
|
|
94
|
+
<div
|
|
95
|
+
class={baseClass}
|
|
96
|
+
data-embed-type="ogp"
|
|
97
|
+
data-embed-provider={data.provider}
|
|
98
|
+
>
|
|
99
|
+
<a
|
|
100
|
+
href={data.url}
|
|
101
|
+
target="_blank"
|
|
102
|
+
rel="noopener noreferrer"
|
|
103
|
+
class="vizel-embed-card {hasImage ? 'vizel-embed-card-horizontal' : ''}"
|
|
104
|
+
>
|
|
105
|
+
{#if hasImage}
|
|
106
|
+
<img
|
|
107
|
+
src={data.image}
|
|
108
|
+
alt=""
|
|
109
|
+
class="vizel-embed-card-image"
|
|
110
|
+
loading="lazy"
|
|
111
|
+
/>
|
|
112
|
+
{/if}
|
|
113
|
+
<div class="vizel-embed-card-content">
|
|
114
|
+
{#if data.siteName || data.favicon}
|
|
115
|
+
<div class="vizel-embed-card-site">
|
|
116
|
+
{#if data.favicon}
|
|
117
|
+
<img
|
|
118
|
+
src={data.favicon}
|
|
119
|
+
alt=""
|
|
120
|
+
class="vizel-embed-card-favicon"
|
|
121
|
+
/>
|
|
122
|
+
{/if}
|
|
123
|
+
{#if data.siteName}
|
|
124
|
+
<span>{data.siteName}</span>
|
|
125
|
+
{/if}
|
|
126
|
+
</div>
|
|
127
|
+
{/if}
|
|
128
|
+
{#if data.title}
|
|
129
|
+
<div class="vizel-embed-card-title">{data.title}</div>
|
|
130
|
+
{/if}
|
|
131
|
+
{#if data.description}
|
|
132
|
+
<div class="vizel-embed-card-description">{data.description}</div>
|
|
133
|
+
{/if}
|
|
134
|
+
<div class="vizel-embed-card-url">{hostname}</div>
|
|
135
|
+
</div>
|
|
136
|
+
</a>
|
|
137
|
+
</div>
|
|
138
|
+
{:else if data.type === "title" && data.title}
|
|
139
|
+
<!-- Title link -->
|
|
140
|
+
<div
|
|
141
|
+
class={baseClass}
|
|
142
|
+
data-embed-type="title"
|
|
143
|
+
data-embed-provider={data.provider}
|
|
144
|
+
>
|
|
145
|
+
<a href={data.url} target="_blank" rel="noopener noreferrer" class="vizel-embed-link">
|
|
146
|
+
<span class="vizel-embed-link-icon"><VizelIcon name="link" /></span>
|
|
147
|
+
<span class="vizel-embed-link-text">{data.title}</span>
|
|
148
|
+
</a>
|
|
149
|
+
</div>
|
|
150
|
+
{:else}
|
|
151
|
+
<!-- Plain link (fallback) -->
|
|
152
|
+
<div
|
|
153
|
+
class={baseClass}
|
|
154
|
+
data-embed-type="link"
|
|
155
|
+
data-embed-provider={data.provider}
|
|
156
|
+
>
|
|
157
|
+
<a href={data.url} target="_blank" rel="noopener noreferrer" class="vizel-embed-link">
|
|
158
|
+
<span class="vizel-embed-link-icon"><VizelIcon name="link" /></span>
|
|
159
|
+
<span class="vizel-embed-link-text">{data.url}</span>
|
|
160
|
+
</a>
|
|
161
|
+
</div>
|
|
162
|
+
{/if}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { VizelEmbedData } from "@vizel/core";
|
|
2
|
+
export interface VizelEmbedViewProps {
|
|
3
|
+
/** Embed data */
|
|
4
|
+
data: VizelEmbedData;
|
|
5
|
+
/** Additional class name */
|
|
6
|
+
class?: string;
|
|
7
|
+
/** Whether the embed is selected */
|
|
8
|
+
selected?: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare const VizelEmbedView: import("svelte").Component<VizelEmbedViewProps, {}, "">;
|
|
11
|
+
type VizelEmbedView = ReturnType<typeof VizelEmbedView>;
|
|
12
|
+
export default VizelEmbedView;
|
|
13
|
+
//# sourceMappingURL=VizelEmbedView.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VizelEmbedView.svelte.d.ts","sourceRoot":"","sources":["../../src/components/VizelEmbedView.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,WAAW,mBAAmB;IAClC,iBAAiB;IACjB,IAAI,EAAE,cAAc,CAAC;IACrB,4BAA4B;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA0HD,QAAA,MAAM,cAAc,yDAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { CustomIconMap, VizelIconName } from "@vizel/core";
|
|
3
|
+
|
|
4
|
+
export interface VizelIconProps {
|
|
5
|
+
/**
|
|
6
|
+
* The semantic icon name from Vizel's icon system.
|
|
7
|
+
*/
|
|
8
|
+
name: VizelIconName;
|
|
9
|
+
/**
|
|
10
|
+
* Custom icon mappings to override default Iconify icon IDs.
|
|
11
|
+
* If provided, will take precedence over context icons.
|
|
12
|
+
*/
|
|
13
|
+
customIcons?: CustomIconMap;
|
|
14
|
+
/**
|
|
15
|
+
* Icon width in pixels or CSS value.
|
|
16
|
+
*/
|
|
17
|
+
width?: string | number;
|
|
18
|
+
/**
|
|
19
|
+
* Icon height in pixels or CSS value.
|
|
20
|
+
*/
|
|
21
|
+
height?: string | number;
|
|
22
|
+
/**
|
|
23
|
+
* Icon color.
|
|
24
|
+
*/
|
|
25
|
+
color?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Additional CSS class.
|
|
28
|
+
*/
|
|
29
|
+
class?: string;
|
|
30
|
+
}
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<script lang="ts">
|
|
34
|
+
import type { IconifyIconProps } from "@iconify/svelte";
|
|
35
|
+
import Icon from "@iconify/svelte";
|
|
36
|
+
import { vizelDefaultIconIds } from "@vizel/core";
|
|
37
|
+
import { getVizelIconContext } from "./VizelIconContext";
|
|
38
|
+
|
|
39
|
+
const { name, customIcons, width, height, color, class: className }: VizelIconProps = $props();
|
|
40
|
+
const { customIcons: contextIcons } = getVizelIconContext();
|
|
41
|
+
|
|
42
|
+
const iconId = $derived(customIcons?.[name] ?? contextIcons?.[name] ?? vizelDefaultIconIds[name]);
|
|
43
|
+
|
|
44
|
+
// Build props object excluding undefined values to satisfy exactOptionalPropertyTypes
|
|
45
|
+
const iconProps = $derived.by(() => {
|
|
46
|
+
const props: IconifyIconProps = { icon: iconId };
|
|
47
|
+
if (width !== undefined) props.width = width;
|
|
48
|
+
if (height !== undefined) props.height = height;
|
|
49
|
+
if (color !== undefined) props.color = color;
|
|
50
|
+
return props;
|
|
51
|
+
});
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<Icon {...iconProps} class={className} style="pointer-events: none;" />
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { CustomIconMap, VizelIconName } from "@vizel/core";
|
|
2
|
+
export interface VizelIconProps {
|
|
3
|
+
/**
|
|
4
|
+
* The semantic icon name from Vizel's icon system.
|
|
5
|
+
*/
|
|
6
|
+
name: VizelIconName;
|
|
7
|
+
/**
|
|
8
|
+
* Custom icon mappings to override default Iconify icon IDs.
|
|
9
|
+
* If provided, will take precedence over context icons.
|
|
10
|
+
*/
|
|
11
|
+
customIcons?: CustomIconMap;
|
|
12
|
+
/**
|
|
13
|
+
* Icon width in pixels or CSS value.
|
|
14
|
+
*/
|
|
15
|
+
width?: string | number;
|
|
16
|
+
/**
|
|
17
|
+
* Icon height in pixels or CSS value.
|
|
18
|
+
*/
|
|
19
|
+
height?: string | number;
|
|
20
|
+
/**
|
|
21
|
+
* Icon color.
|
|
22
|
+
*/
|
|
23
|
+
color?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Additional CSS class.
|
|
26
|
+
*/
|
|
27
|
+
class?: string;
|
|
28
|
+
}
|
|
29
|
+
declare const VizelIcon: import("svelte").Component<VizelIconProps, {}, "">;
|
|
30
|
+
type VizelIcon = ReturnType<typeof VizelIcon>;
|
|
31
|
+
export default VizelIcon;
|
|
32
|
+
//# sourceMappingURL=VizelIcon.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VizelIcon.svelte.d.ts","sourceRoot":"","sources":["../../src/components/VizelIcon.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEhE,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,IAAI,EAAE,aAAa,CAAC;IACpB;;;OAGG;IACH,WAAW,CAAC,EAAE,aAAa,CAAC;IAC5B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAmCD,QAAA,MAAM,SAAS,oDAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { CustomIconMap, VizelIconContextValue } from "@vizel/core";
|
|
2
|
+
/**
|
|
3
|
+
* Set custom icon mappings for child components.
|
|
4
|
+
* Call this in a parent component to customize icons for all descendants.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```svelte
|
|
8
|
+
* <script lang="ts">
|
|
9
|
+
* import { setVizelIcons } from "@vizel/svelte";
|
|
10
|
+
*
|
|
11
|
+
* // Use Phosphor icons
|
|
12
|
+
* setVizelIcons({
|
|
13
|
+
* heading1: "ph:text-h-one",
|
|
14
|
+
* heading2: "ph:text-h-two",
|
|
15
|
+
* bold: "ph:text-b-bold",
|
|
16
|
+
* italic: "ph:text-italic",
|
|
17
|
+
* });
|
|
18
|
+
* </script>
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare function setVizelIcons(customIcons?: CustomIconMap): void;
|
|
22
|
+
/**
|
|
23
|
+
* Get custom icon mappings from parent context.
|
|
24
|
+
* Returns an empty object if no context is set.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getVizelIconContext(): VizelIconContextValue;
|
|
27
|
+
//# sourceMappingURL=VizelIconContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VizelIconContext.d.ts","sourceRoot":"","sources":["../../src/components/VizelIconContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAKxE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAAC,WAAW,CAAC,EAAE,aAAa,GAAG,IAAI,CAE/D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,qBAAqB,CAE3D"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { getContext, setContext } from "svelte";
|
|
2
|
+
const VIZEL_ICON_CONTEXT_KEY = Symbol("vizel-icon-context");
|
|
3
|
+
/**
|
|
4
|
+
* Set custom icon mappings for child components.
|
|
5
|
+
* Call this in a parent component to customize icons for all descendants.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```svelte
|
|
9
|
+
* <script lang="ts">
|
|
10
|
+
* import { setVizelIcons } from "@vizel/svelte";
|
|
11
|
+
*
|
|
12
|
+
* // Use Phosphor icons
|
|
13
|
+
* setVizelIcons({
|
|
14
|
+
* heading1: "ph:text-h-one",
|
|
15
|
+
* heading2: "ph:text-h-two",
|
|
16
|
+
* bold: "ph:text-b-bold",
|
|
17
|
+
* italic: "ph:text-italic",
|
|
18
|
+
* });
|
|
19
|
+
* </script>
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function setVizelIcons(customIcons) {
|
|
23
|
+
setContext(VIZEL_ICON_CONTEXT_KEY, { customIcons });
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Get custom icon mappings from parent context.
|
|
27
|
+
* Returns an empty object if no context is set.
|
|
28
|
+
*/
|
|
29
|
+
export function getVizelIconContext() {
|
|
30
|
+
return getContext(VIZEL_ICON_CONTEXT_KEY) ?? {};
|
|
31
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { CustomIconMap } from "@vizel/core";
|
|
3
|
+
import type { Snippet } from "svelte";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Props for VizelIconProvider component.
|
|
7
|
+
*/
|
|
8
|
+
export interface VizelIconProviderProps {
|
|
9
|
+
/**
|
|
10
|
+
* Custom icon mappings to override default Lucide icons.
|
|
11
|
+
* Any icon not specified will fall back to the default Lucide icon.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```svelte
|
|
15
|
+
* <VizelIconProvider icons={{ bold: "mdi:format-bold", italic: "mdi:format-italic" }}>
|
|
16
|
+
* <App />
|
|
17
|
+
* </VizelIconProvider>
|
|
18
|
+
*
|
|
19
|
+
* <VizelIconProvider icons={{ check: "heroicons:check", warning: "heroicons:exclamation-triangle" }}>
|
|
20
|
+
* <App />
|
|
21
|
+
* </VizelIconProvider>
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
icons?: CustomIconMap;
|
|
25
|
+
/**
|
|
26
|
+
* Child content to render inside the provider.
|
|
27
|
+
*/
|
|
28
|
+
children?: Snippet;
|
|
29
|
+
}
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<script lang="ts">
|
|
33
|
+
import { setVizelIcons } from "./VizelIconContext.ts";
|
|
34
|
+
|
|
35
|
+
const { icons, children }: VizelIconProviderProps = $props();
|
|
36
|
+
|
|
37
|
+
// Set icons in context for all descendants
|
|
38
|
+
setVizelIcons(icons);
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
{#if children}
|
|
42
|
+
{@render children()}
|
|
43
|
+
{/if}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CustomIconMap } from "@vizel/core";
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
/**
|
|
4
|
+
* Props for VizelIconProvider component.
|
|
5
|
+
*/
|
|
6
|
+
export interface VizelIconProviderProps {
|
|
7
|
+
/**
|
|
8
|
+
* Custom icon mappings to override default Lucide icons.
|
|
9
|
+
* Any icon not specified will fall back to the default Lucide icon.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```svelte
|
|
13
|
+
* <VizelIconProvider icons={{ bold: "mdi:format-bold", italic: "mdi:format-italic" }}>
|
|
14
|
+
* <App />
|
|
15
|
+
* </VizelIconProvider>
|
|
16
|
+
*
|
|
17
|
+
* <VizelIconProvider icons={{ check: "heroicons:check", warning: "heroicons:exclamation-triangle" }}>
|
|
18
|
+
* <App />
|
|
19
|
+
* </VizelIconProvider>
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
icons?: CustomIconMap;
|
|
23
|
+
/**
|
|
24
|
+
* Child content to render inside the provider.
|
|
25
|
+
*/
|
|
26
|
+
children?: Snippet;
|
|
27
|
+
}
|
|
28
|
+
declare const VizelIconProvider: import("svelte").Component<VizelIconProviderProps, {}, "">;
|
|
29
|
+
type VizelIconProvider = ReturnType<typeof VizelIconProvider>;
|
|
30
|
+
export default VizelIconProvider;
|
|
31
|
+
//# sourceMappingURL=VizelIconProvider.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VizelIconProvider.svelte.d.ts","sourceRoot":"","sources":["../../src/components/VizelIconProvider.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAsBD,QAAA,MAAM,iBAAiB,4DAAwC,CAAC;AAChE,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC9D,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { Editor } from "@vizel/core";
|
|
3
|
+
|
|
4
|
+
export interface VizelLinkEditorProps {
|
|
5
|
+
/** The editor instance */
|
|
6
|
+
editor: Editor;
|
|
7
|
+
/** Custom class name */
|
|
8
|
+
class?: string;
|
|
9
|
+
/** Close handler */
|
|
10
|
+
onclose?: () => void;
|
|
11
|
+
/** Enable embed option (requires Embed extension) */
|
|
12
|
+
enableEmbed?: boolean;
|
|
13
|
+
}
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<script lang="ts">
|
|
17
|
+
import { detectVizelEmbedProvider } from "@vizel/core";
|
|
18
|
+
import { untrack } from "svelte";
|
|
19
|
+
import VizelIcon from "./VizelIcon.svelte";
|
|
20
|
+
|
|
21
|
+
let {
|
|
22
|
+
editor,
|
|
23
|
+
class: className,
|
|
24
|
+
onclose,
|
|
25
|
+
enableEmbed = false,
|
|
26
|
+
}: VizelLinkEditorProps = $props();
|
|
27
|
+
|
|
28
|
+
let formElement: HTMLFormElement;
|
|
29
|
+
let inputElement: HTMLInputElement;
|
|
30
|
+
let currentHref = $derived(editor.getAttributes("link").href || "");
|
|
31
|
+
let url = $state(untrack(() => editor.getAttributes("link").href || ""));
|
|
32
|
+
let asEmbed = $state(false);
|
|
33
|
+
|
|
34
|
+
// Check if embed extension is available
|
|
35
|
+
const canEmbed = $derived.by(() => {
|
|
36
|
+
if (!enableEmbed) return false;
|
|
37
|
+
// Check if embed extension is loaded
|
|
38
|
+
const extensionManager = editor.extensionManager;
|
|
39
|
+
return extensionManager.extensions.some((ext) => ext.name === "embed");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Check if URL is a known embed provider
|
|
43
|
+
const isEmbedProvider = $derived.by(() => {
|
|
44
|
+
if (!url.trim()) return false;
|
|
45
|
+
return detectVizelEmbedProvider(url.trim()) !== null;
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Handle click outside to close
|
|
49
|
+
function handleClickOutside(event: MouseEvent) {
|
|
50
|
+
if (formElement && !formElement.contains(event.target as Node)) {
|
|
51
|
+
onclose?.();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Handle Escape key to close
|
|
56
|
+
function handleKeyDown(event: KeyboardEvent) {
|
|
57
|
+
if (event.key === "Escape") {
|
|
58
|
+
event.preventDefault();
|
|
59
|
+
event.stopImmediatePropagation();
|
|
60
|
+
onclose?.();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
$effect(() => {
|
|
65
|
+
inputElement?.focus();
|
|
66
|
+
|
|
67
|
+
// Use setTimeout to avoid immediate trigger from the click that opened the editor
|
|
68
|
+
const timeoutId = setTimeout(() => {
|
|
69
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
70
|
+
}, 0);
|
|
71
|
+
// Use capture phase so this handler runs before BubbleMenu's handler
|
|
72
|
+
document.addEventListener("keydown", handleKeyDown, true);
|
|
73
|
+
|
|
74
|
+
return () => {
|
|
75
|
+
clearTimeout(timeoutId);
|
|
76
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
77
|
+
document.removeEventListener("keydown", handleKeyDown, true);
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
function handleSubmit(e: Event) {
|
|
82
|
+
e.preventDefault();
|
|
83
|
+
const trimmedUrl = url.trim();
|
|
84
|
+
|
|
85
|
+
if (!trimmedUrl) {
|
|
86
|
+
editor.chain().focus().unsetLink().run();
|
|
87
|
+
onclose?.();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (asEmbed && canEmbed) {
|
|
92
|
+
// Remove the link first, then insert embed
|
|
93
|
+
editor.chain().focus().unsetLink().setEmbed({ url: trimmedUrl }).run();
|
|
94
|
+
} else {
|
|
95
|
+
editor.chain().focus().setLink({ href: trimmedUrl }).run();
|
|
96
|
+
}
|
|
97
|
+
onclose?.();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function handleRemove() {
|
|
101
|
+
editor.chain().focus().unsetLink().run();
|
|
102
|
+
onclose?.();
|
|
103
|
+
}
|
|
104
|
+
</script>
|
|
105
|
+
|
|
106
|
+
<form
|
|
107
|
+
bind:this={formElement}
|
|
108
|
+
class="vizel-link-editor {className ?? ''}"
|
|
109
|
+
onsubmit={handleSubmit}
|
|
110
|
+
>
|
|
111
|
+
<div class="vizel-link-editor-row">
|
|
112
|
+
<input
|
|
113
|
+
bind:this={inputElement}
|
|
114
|
+
bind:value={url}
|
|
115
|
+
type="url"
|
|
116
|
+
placeholder="Enter URL..."
|
|
117
|
+
class="vizel-link-input"
|
|
118
|
+
/>
|
|
119
|
+
<button type="submit" class="vizel-link-button" title="Apply">
|
|
120
|
+
<VizelIcon name="check" />
|
|
121
|
+
</button>
|
|
122
|
+
{#if currentHref}
|
|
123
|
+
<button
|
|
124
|
+
type="button"
|
|
125
|
+
class="vizel-link-button vizel-link-remove"
|
|
126
|
+
title="Remove link"
|
|
127
|
+
onclick={handleRemove}
|
|
128
|
+
>
|
|
129
|
+
<VizelIcon name="x" />
|
|
130
|
+
</button>
|
|
131
|
+
{/if}
|
|
132
|
+
</div>
|
|
133
|
+
{#if canEmbed && isEmbedProvider}
|
|
134
|
+
<div class="vizel-link-editor-embed-toggle">
|
|
135
|
+
<input
|
|
136
|
+
id="vizel-embed-toggle"
|
|
137
|
+
type="checkbox"
|
|
138
|
+
bind:checked={asEmbed}
|
|
139
|
+
/>
|
|
140
|
+
<label for="vizel-embed-toggle">Embed as rich content</label>
|
|
141
|
+
</div>
|
|
142
|
+
{/if}
|
|
143
|
+
</form>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Editor } from "@vizel/core";
|
|
2
|
+
export interface VizelLinkEditorProps {
|
|
3
|
+
/** The editor instance */
|
|
4
|
+
editor: Editor;
|
|
5
|
+
/** Custom class name */
|
|
6
|
+
class?: string;
|
|
7
|
+
/** Close handler */
|
|
8
|
+
onclose?: () => void;
|
|
9
|
+
/** Enable embed option (requires Embed extension) */
|
|
10
|
+
enableEmbed?: boolean;
|
|
11
|
+
}
|
|
12
|
+
declare const VizelLinkEditor: import("svelte").Component<VizelLinkEditorProps, {}, "">;
|
|
13
|
+
type VizelLinkEditor = ReturnType<typeof VizelLinkEditor>;
|
|
14
|
+
export default VizelLinkEditor;
|
|
15
|
+
//# sourceMappingURL=VizelLinkEditor.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VizelLinkEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/components/VizelLinkEditor.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,oBAAoB;IACnC,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,wBAAwB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,qDAAqD;IACrD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAyHD,QAAA,MAAM,eAAe,0DAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
|