@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,111 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { Editor } from "@vizel/core";
|
|
3
|
+
|
|
4
|
+
export interface VizelBubbleMenuDefaultProps {
|
|
5
|
+
/** The editor instance */
|
|
6
|
+
editor: Editor;
|
|
7
|
+
/** Custom class name */
|
|
8
|
+
class?: string;
|
|
9
|
+
/** Enable embed option in link editor (requires Embed extension) */
|
|
10
|
+
enableEmbed?: boolean;
|
|
11
|
+
}
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<script lang="ts">
|
|
15
|
+
import { createVizelState } from "../runes/createVizelState.svelte.ts";
|
|
16
|
+
import VizelBubbleMenuButton from "./VizelBubbleMenuButton.svelte";
|
|
17
|
+
import VizelBubbleMenuColorPicker from "./VizelBubbleMenuColorPicker.svelte";
|
|
18
|
+
import VizelLinkEditor from "./VizelLinkEditor.svelte";
|
|
19
|
+
import VizelIcon from "./VizelIcon.svelte";
|
|
20
|
+
import VizelNodeSelector from "./VizelNodeSelector.svelte";
|
|
21
|
+
|
|
22
|
+
let { editor, class: className, enableEmbed }: VizelBubbleMenuDefaultProps = $props();
|
|
23
|
+
let showLinkEditor = $state(false);
|
|
24
|
+
|
|
25
|
+
// Subscribe to editor state changes to update active states
|
|
26
|
+
const editorState = createVizelState(() => editor);
|
|
27
|
+
|
|
28
|
+
// Create derived values that depend on editorState.current to trigger re-renders
|
|
29
|
+
const isBoldActive = $derived.by(() => {
|
|
30
|
+
void editorState.current; // Trigger reactivity
|
|
31
|
+
return editor.isActive("bold");
|
|
32
|
+
});
|
|
33
|
+
const isItalicActive = $derived.by(() => {
|
|
34
|
+
void editorState.current;
|
|
35
|
+
return editor.isActive("italic");
|
|
36
|
+
});
|
|
37
|
+
const isStrikeActive = $derived.by(() => {
|
|
38
|
+
void editorState.current;
|
|
39
|
+
return editor.isActive("strike");
|
|
40
|
+
});
|
|
41
|
+
const isUnderlineActive = $derived.by(() => {
|
|
42
|
+
void editorState.current;
|
|
43
|
+
return editor.isActive("underline");
|
|
44
|
+
});
|
|
45
|
+
const isCodeActive = $derived.by(() => {
|
|
46
|
+
void editorState.current;
|
|
47
|
+
return editor.isActive("code");
|
|
48
|
+
});
|
|
49
|
+
const isLinkActive = $derived.by(() => {
|
|
50
|
+
void editorState.current;
|
|
51
|
+
return editor.isActive("link");
|
|
52
|
+
});
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
{#if showLinkEditor}
|
|
56
|
+
<VizelLinkEditor {editor} {...(enableEmbed ? { enableEmbed } : {})} onclose={() => (showLinkEditor = false)} />
|
|
57
|
+
{:else}
|
|
58
|
+
<div class="vizel-bubble-menu-toolbar {className ?? ''}">
|
|
59
|
+
<VizelNodeSelector {editor} />
|
|
60
|
+
<VizelBubbleMenuButton
|
|
61
|
+
action="bold"
|
|
62
|
+
isActive={isBoldActive}
|
|
63
|
+
title="Bold (Cmd+B)"
|
|
64
|
+
onclick={() => editor.chain().focus().toggleBold().run()}
|
|
65
|
+
>
|
|
66
|
+
<VizelIcon name="bold" />
|
|
67
|
+
</VizelBubbleMenuButton>
|
|
68
|
+
<VizelBubbleMenuButton
|
|
69
|
+
action="italic"
|
|
70
|
+
isActive={isItalicActive}
|
|
71
|
+
title="Italic (Cmd+I)"
|
|
72
|
+
onclick={() => editor.chain().focus().toggleItalic().run()}
|
|
73
|
+
>
|
|
74
|
+
<VizelIcon name="italic" />
|
|
75
|
+
</VizelBubbleMenuButton>
|
|
76
|
+
<VizelBubbleMenuButton
|
|
77
|
+
action="strike"
|
|
78
|
+
isActive={isStrikeActive}
|
|
79
|
+
title="Strikethrough"
|
|
80
|
+
onclick={() => editor.chain().focus().toggleStrike().run()}
|
|
81
|
+
>
|
|
82
|
+
<VizelIcon name="strikethrough" />
|
|
83
|
+
</VizelBubbleMenuButton>
|
|
84
|
+
<VizelBubbleMenuButton
|
|
85
|
+
action="underline"
|
|
86
|
+
isActive={isUnderlineActive}
|
|
87
|
+
title="Underline (Cmd+U)"
|
|
88
|
+
onclick={() => editor.chain().focus().toggleUnderline().run()}
|
|
89
|
+
>
|
|
90
|
+
<VizelIcon name="underline" />
|
|
91
|
+
</VizelBubbleMenuButton>
|
|
92
|
+
<VizelBubbleMenuButton
|
|
93
|
+
action="code"
|
|
94
|
+
isActive={isCodeActive}
|
|
95
|
+
title="Code (Cmd+E)"
|
|
96
|
+
onclick={() => editor.chain().focus().toggleCode().run()}
|
|
97
|
+
>
|
|
98
|
+
<VizelIcon name="code" />
|
|
99
|
+
</VizelBubbleMenuButton>
|
|
100
|
+
<VizelBubbleMenuButton
|
|
101
|
+
action="link"
|
|
102
|
+
isActive={isLinkActive}
|
|
103
|
+
title="Link (Cmd+K)"
|
|
104
|
+
onclick={() => (showLinkEditor = true)}
|
|
105
|
+
>
|
|
106
|
+
<VizelIcon name="link" />
|
|
107
|
+
</VizelBubbleMenuButton>
|
|
108
|
+
<VizelBubbleMenuColorPicker {editor} type="textColor" />
|
|
109
|
+
<VizelBubbleMenuColorPicker {editor} type="highlight" />
|
|
110
|
+
</div>
|
|
111
|
+
{/if}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Editor } from "@vizel/core";
|
|
2
|
+
export interface VizelBubbleMenuDefaultProps {
|
|
3
|
+
/** The editor instance */
|
|
4
|
+
editor: Editor;
|
|
5
|
+
/** Custom class name */
|
|
6
|
+
class?: string;
|
|
7
|
+
/** Enable embed option in link editor (requires Embed extension) */
|
|
8
|
+
enableEmbed?: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare const VizelBubbleMenuDefault: import("svelte").Component<VizelBubbleMenuDefaultProps, {}, "">;
|
|
11
|
+
type VizelBubbleMenuDefault = ReturnType<typeof VizelBubbleMenuDefault>;
|
|
12
|
+
export default VizelBubbleMenuDefault;
|
|
13
|
+
//# sourceMappingURL=VizelBubbleMenuDefault.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VizelBubbleMenuDefault.svelte.d.ts","sourceRoot":"","sources":["../../src/components/VizelBubbleMenuDefault.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,2BAA2B;IAC1C,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,wBAAwB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAmFD,QAAA,MAAM,sBAAsB,iEAAwC,CAAC;AACrE,KAAK,sBAAsB,GAAG,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACxE,eAAe,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
export interface VizelBubbleMenuDividerProps {
|
|
3
|
+
/** Custom class name */
|
|
4
|
+
class?: string;
|
|
5
|
+
}
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<script lang="ts">
|
|
9
|
+
let { class: className }: VizelBubbleMenuDividerProps = $props();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<span class="vizel-bubble-menu-divider {className ?? ''}"></span>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface VizelBubbleMenuDividerProps {
|
|
2
|
+
/** Custom class name */
|
|
3
|
+
class?: string;
|
|
4
|
+
}
|
|
5
|
+
declare const VizelBubbleMenuDivider: import("svelte").Component<VizelBubbleMenuDividerProps, {}, "">;
|
|
6
|
+
type VizelBubbleMenuDivider = ReturnType<typeof VizelBubbleMenuDivider>;
|
|
7
|
+
export default VizelBubbleMenuDivider;
|
|
8
|
+
//# sourceMappingURL=VizelBubbleMenuDivider.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VizelBubbleMenuDivider.svelte.d.ts","sourceRoot":"","sources":["../../src/components/VizelBubbleMenuDivider.svelte.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,2BAA2B;IAC1C,wBAAwB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAYD,QAAA,MAAM,sBAAsB,iEAAwC,CAAC;AACrE,KAAK,sBAAsB,GAAG,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACxE,eAAe,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { VizelColorDefinition } from "@vizel/core";
|
|
3
|
+
|
|
4
|
+
export interface VizelColorPickerProps {
|
|
5
|
+
/** Color palette to display */
|
|
6
|
+
colors: VizelColorDefinition[];
|
|
7
|
+
/** Currently selected color */
|
|
8
|
+
value?: string;
|
|
9
|
+
/** Callback when color is selected */
|
|
10
|
+
onchange: (color: string) => void;
|
|
11
|
+
/** Label for accessibility */
|
|
12
|
+
label?: string;
|
|
13
|
+
/** Custom class name */
|
|
14
|
+
class?: string;
|
|
15
|
+
/** Enable custom HEX input (default: true) */
|
|
16
|
+
allowCustomColor?: boolean;
|
|
17
|
+
/** Recent colors to display */
|
|
18
|
+
recentColors?: string[];
|
|
19
|
+
/** Show recent colors section (default: true) */
|
|
20
|
+
showRecentColors?: boolean;
|
|
21
|
+
/** "None" option color values (e.g., ["transparent", "inherit"]) */
|
|
22
|
+
noneValues?: string[];
|
|
23
|
+
}
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<script lang="ts">
|
|
27
|
+
import { isVizelValidHexColor, normalizeVizelHexColor } from "@vizel/core";
|
|
28
|
+
import VizelIcon from "./VizelIcon.svelte";
|
|
29
|
+
|
|
30
|
+
const GRID_COLUMNS = 4;
|
|
31
|
+
|
|
32
|
+
let {
|
|
33
|
+
colors,
|
|
34
|
+
value,
|
|
35
|
+
onchange,
|
|
36
|
+
label = "Color palette",
|
|
37
|
+
class: className,
|
|
38
|
+
allowCustomColor = true,
|
|
39
|
+
recentColors = [],
|
|
40
|
+
showRecentColors = true,
|
|
41
|
+
noneValues = ["transparent", "inherit"],
|
|
42
|
+
}: VizelColorPickerProps = $props();
|
|
43
|
+
|
|
44
|
+
let inputValue = $state("");
|
|
45
|
+
let focusedIndex = $state(-1);
|
|
46
|
+
let swatchRefs: (HTMLButtonElement | null)[] = $state([]);
|
|
47
|
+
let inputRef: HTMLInputElement | null = $state(null);
|
|
48
|
+
|
|
49
|
+
// Clean up swatchRefs when colors decrease
|
|
50
|
+
$effect(() => {
|
|
51
|
+
const length = allColors.length;
|
|
52
|
+
if (swatchRefs.length > length) {
|
|
53
|
+
swatchRefs.length = length;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Build flat list of all selectable colors for keyboard navigation
|
|
58
|
+
const allColors = $derived([
|
|
59
|
+
...(showRecentColors ? recentColors : []),
|
|
60
|
+
...colors.map((c) => c.color),
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
// Calculate the offset for color palette indices (after recent colors)
|
|
64
|
+
const paletteOffset = $derived(showRecentColors ? recentColors.length : 0);
|
|
65
|
+
|
|
66
|
+
// Find color definition by color value
|
|
67
|
+
function findColorDef(color: string): VizelColorDefinition | undefined {
|
|
68
|
+
return colors.find((c) => c.color === color);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Get display name for a color
|
|
72
|
+
function getColorName(color: string): string {
|
|
73
|
+
const def = findColorDef(color);
|
|
74
|
+
return def?.name ?? color;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Check if a color is a "none" value
|
|
78
|
+
function isNoneValue(color: string): boolean {
|
|
79
|
+
return noneValues.includes(color);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Handle swatch selection
|
|
83
|
+
function handleSelect(color: string) {
|
|
84
|
+
onchange(color);
|
|
85
|
+
inputValue = "";
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Handle custom color input submit
|
|
89
|
+
function handleInputSubmit() {
|
|
90
|
+
const normalized = normalizeVizelHexColor(inputValue);
|
|
91
|
+
if (isVizelValidHexColor(normalized)) {
|
|
92
|
+
onchange(normalized);
|
|
93
|
+
inputValue = "";
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Handle input keydown
|
|
98
|
+
function handleInputKeyDown(e: KeyboardEvent) {
|
|
99
|
+
if (e.key === "Enter") {
|
|
100
|
+
e.preventDefault();
|
|
101
|
+
handleInputSubmit();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Keyboard navigation handler
|
|
106
|
+
function handleKeyDown(e: KeyboardEvent, currentIndex: number) {
|
|
107
|
+
const totalColors = allColors.length;
|
|
108
|
+
if (totalColors === 0) return;
|
|
109
|
+
|
|
110
|
+
let newIndex = currentIndex;
|
|
111
|
+
let handled = false;
|
|
112
|
+
|
|
113
|
+
switch (e.key) {
|
|
114
|
+
case "ArrowRight":
|
|
115
|
+
newIndex = (currentIndex + 1) % totalColors;
|
|
116
|
+
handled = true;
|
|
117
|
+
break;
|
|
118
|
+
case "ArrowLeft":
|
|
119
|
+
newIndex = (currentIndex - 1 + totalColors) % totalColors;
|
|
120
|
+
handled = true;
|
|
121
|
+
break;
|
|
122
|
+
case "ArrowDown":
|
|
123
|
+
newIndex = Math.min(currentIndex + GRID_COLUMNS, totalColors - 1);
|
|
124
|
+
handled = true;
|
|
125
|
+
break;
|
|
126
|
+
case "ArrowUp":
|
|
127
|
+
newIndex = Math.max(currentIndex - GRID_COLUMNS, 0);
|
|
128
|
+
handled = true;
|
|
129
|
+
break;
|
|
130
|
+
case "Home":
|
|
131
|
+
newIndex = 0;
|
|
132
|
+
handled = true;
|
|
133
|
+
break;
|
|
134
|
+
case "End":
|
|
135
|
+
newIndex = totalColors - 1;
|
|
136
|
+
handled = true;
|
|
137
|
+
break;
|
|
138
|
+
case "Enter":
|
|
139
|
+
case " ": {
|
|
140
|
+
e.preventDefault();
|
|
141
|
+
const selectedColor = allColors[currentIndex];
|
|
142
|
+
if (selectedColor) {
|
|
143
|
+
handleSelect(selectedColor);
|
|
144
|
+
}
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (handled) {
|
|
150
|
+
e.preventDefault();
|
|
151
|
+
focusedIndex = newIndex;
|
|
152
|
+
swatchRefs[newIndex]?.focus();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Update input value when value prop changes
|
|
157
|
+
$effect(() => {
|
|
158
|
+
if (value && !isNoneValue(value)) {
|
|
159
|
+
inputValue = value;
|
|
160
|
+
} else {
|
|
161
|
+
inputValue = "";
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// Focus first swatch or current value on mount (run only once)
|
|
166
|
+
$effect(() => {
|
|
167
|
+
const currentIndex = value ? allColors.indexOf(value) : -1;
|
|
168
|
+
if (currentIndex >= 0) {
|
|
169
|
+
focusedIndex = currentIndex;
|
|
170
|
+
} else if (allColors.length > 0) {
|
|
171
|
+
focusedIndex = 0;
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const isInputValid = $derived(isVizelValidHexColor(normalizeVizelHexColor(inputValue)));
|
|
176
|
+
const previewColor = $derived(isInputValid ? normalizeVizelHexColor(inputValue) : undefined);
|
|
177
|
+
</script>
|
|
178
|
+
|
|
179
|
+
<div
|
|
180
|
+
class="vizel-color-picker-content {className ?? ''}"
|
|
181
|
+
role="listbox"
|
|
182
|
+
aria-label={label}
|
|
183
|
+
>
|
|
184
|
+
<!-- Recent colors -->
|
|
185
|
+
{#if showRecentColors && recentColors.length > 0}
|
|
186
|
+
<div class="vizel-color-picker-section">
|
|
187
|
+
<div class="vizel-color-picker-label">Recent</div>
|
|
188
|
+
<div class="vizel-color-picker-recent">
|
|
189
|
+
{#each recentColors as color, idx}
|
|
190
|
+
<button
|
|
191
|
+
bind:this={swatchRefs[idx]}
|
|
192
|
+
type="button"
|
|
193
|
+
role="option"
|
|
194
|
+
aria-selected={value === color}
|
|
195
|
+
aria-label={color}
|
|
196
|
+
tabindex={focusedIndex === idx ? 0 : -1}
|
|
197
|
+
class="vizel-color-picker-swatch {value === color ? 'is-active' : ''}"
|
|
198
|
+
style="background-color: {isNoneValue(color) ? 'transparent' : color}"
|
|
199
|
+
data-color={color}
|
|
200
|
+
onclick={() => handleSelect(color)}
|
|
201
|
+
onkeydown={(e) => handleKeyDown(e, idx)}
|
|
202
|
+
>
|
|
203
|
+
{#if isNoneValue(color)}
|
|
204
|
+
<span class="vizel-color-picker-none"><VizelIcon name="x" /></span>
|
|
205
|
+
{/if}
|
|
206
|
+
</button>
|
|
207
|
+
{/each}
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
{/if}
|
|
211
|
+
|
|
212
|
+
<!-- Color palette -->
|
|
213
|
+
<div class="vizel-color-picker-section">
|
|
214
|
+
<div class="vizel-color-picker-grid">
|
|
215
|
+
{#each colors as colorDef, i}
|
|
216
|
+
{@const idx = paletteOffset + i}
|
|
217
|
+
<button
|
|
218
|
+
bind:this={swatchRefs[idx]}
|
|
219
|
+
type="button"
|
|
220
|
+
role="option"
|
|
221
|
+
aria-selected={value === colorDef.color}
|
|
222
|
+
aria-label={colorDef.name}
|
|
223
|
+
tabindex={focusedIndex === idx ? 0 : -1}
|
|
224
|
+
class="vizel-color-picker-swatch {value === colorDef.color ? 'is-active' : ''}"
|
|
225
|
+
style="background-color: {isNoneValue(colorDef.color) ? 'transparent' : colorDef.color}"
|
|
226
|
+
data-color={colorDef.color}
|
|
227
|
+
onclick={() => handleSelect(colorDef.color)}
|
|
228
|
+
onkeydown={(e) => handleKeyDown(e, idx)}
|
|
229
|
+
>
|
|
230
|
+
{#if isNoneValue(colorDef.color)}
|
|
231
|
+
<span class="vizel-color-picker-none"><VizelIcon name="x" /></span>
|
|
232
|
+
{/if}
|
|
233
|
+
</button>
|
|
234
|
+
{/each}
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
|
|
238
|
+
<!-- HEX input with preview -->
|
|
239
|
+
{#if allowCustomColor}
|
|
240
|
+
<div class="vizel-color-picker-input-row">
|
|
241
|
+
<span
|
|
242
|
+
class="vizel-color-picker-preview"
|
|
243
|
+
style="background-color: {previewColor || 'transparent'}"
|
|
244
|
+
aria-hidden="true"
|
|
245
|
+
></span>
|
|
246
|
+
<input
|
|
247
|
+
bind:this={inputRef}
|
|
248
|
+
type="text"
|
|
249
|
+
class="vizel-color-picker-input"
|
|
250
|
+
placeholder="#000000"
|
|
251
|
+
value={inputValue}
|
|
252
|
+
maxlength={7}
|
|
253
|
+
aria-label="Custom color hex value"
|
|
254
|
+
oninput={(e) => (inputValue = (e.target as HTMLInputElement).value)}
|
|
255
|
+
onkeydown={handleInputKeyDown}
|
|
256
|
+
/>
|
|
257
|
+
<button
|
|
258
|
+
type="button"
|
|
259
|
+
class="vizel-color-picker-apply"
|
|
260
|
+
disabled={!isInputValid}
|
|
261
|
+
title="Apply"
|
|
262
|
+
aria-label="Apply custom color"
|
|
263
|
+
onclick={handleInputSubmit}
|
|
264
|
+
>
|
|
265
|
+
<VizelIcon name="check" />
|
|
266
|
+
</button>
|
|
267
|
+
</div>
|
|
268
|
+
{/if}
|
|
269
|
+
</div>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { VizelColorDefinition } from "@vizel/core";
|
|
2
|
+
export interface VizelColorPickerProps {
|
|
3
|
+
/** Color palette to display */
|
|
4
|
+
colors: VizelColorDefinition[];
|
|
5
|
+
/** Currently selected color */
|
|
6
|
+
value?: string;
|
|
7
|
+
/** Callback when color is selected */
|
|
8
|
+
onchange: (color: string) => void;
|
|
9
|
+
/** Label for accessibility */
|
|
10
|
+
label?: string;
|
|
11
|
+
/** Custom class name */
|
|
12
|
+
class?: string;
|
|
13
|
+
/** Enable custom HEX input (default: true) */
|
|
14
|
+
allowCustomColor?: boolean;
|
|
15
|
+
/** Recent colors to display */
|
|
16
|
+
recentColors?: string[];
|
|
17
|
+
/** Show recent colors section (default: true) */
|
|
18
|
+
showRecentColors?: boolean;
|
|
19
|
+
/** "None" option color values (e.g., ["transparent", "inherit"]) */
|
|
20
|
+
noneValues?: string[];
|
|
21
|
+
}
|
|
22
|
+
declare const VizelColorPicker: import("svelte").Component<VizelColorPickerProps, {}, "">;
|
|
23
|
+
type VizelColorPicker = ReturnType<typeof VizelColorPicker>;
|
|
24
|
+
export default VizelColorPicker;
|
|
25
|
+
//# sourceMappingURL=VizelColorPicker.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VizelColorPicker.svelte.d.ts","sourceRoot":"","sources":["../../src/components/VizelColorPicker.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAExD,MAAM,WAAW,qBAAqB;IACpC,+BAA+B;IAC/B,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAC/B,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wBAAwB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,+BAA+B;IAC/B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,iDAAiD;IACjD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AA8MD,QAAA,MAAM,gBAAgB,2DAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Editor } from "@vizel/core";
|
|
2
|
+
export declare const VIZEL_CONTEXT_KEY: unique symbol;
|
|
3
|
+
/**
|
|
4
|
+
* Get the editor instance from VizelProvider context.
|
|
5
|
+
*
|
|
6
|
+
* @throws Error if used outside of VizelProvider
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```svelte
|
|
10
|
+
* <script lang="ts">
|
|
11
|
+
* import { getVizelContext } from '@vizel/svelte';
|
|
12
|
+
*
|
|
13
|
+
* const getEditor = getVizelContext();
|
|
14
|
+
* </script>
|
|
15
|
+
*
|
|
16
|
+
* <button onclick={() => getEditor()?.chain().focus().toggleBold().run()}>
|
|
17
|
+
* Bold
|
|
18
|
+
* </button>
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare function getVizelContext(): () => Editor | null;
|
|
22
|
+
/**
|
|
23
|
+
* Get the editor instance from context.
|
|
24
|
+
* Returns undefined if used outside of VizelProvider (does not throw).
|
|
25
|
+
*/
|
|
26
|
+
export declare function getVizelContextSafe(): (() => Editor | null) | undefined;
|
|
27
|
+
//# sourceMappingURL=VizelContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VizelContext.d.ts","sourceRoot":"","sources":["../../src/components/VizelContext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAG1C,eAAO,MAAM,iBAAiB,eAAyB,CAAC;AAExD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,IAAI,MAAM,MAAM,GAAG,IAAI,CAMrD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,SAAS,CAEvE"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { getContext } from "svelte";
|
|
2
|
+
export const VIZEL_CONTEXT_KEY = Symbol("vizel-editor");
|
|
3
|
+
/**
|
|
4
|
+
* Get the editor instance from VizelProvider context.
|
|
5
|
+
*
|
|
6
|
+
* @throws Error if used outside of VizelProvider
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```svelte
|
|
10
|
+
* <script lang="ts">
|
|
11
|
+
* import { getVizelContext } from '@vizel/svelte';
|
|
12
|
+
*
|
|
13
|
+
* const getEditor = getVizelContext();
|
|
14
|
+
* </script>
|
|
15
|
+
*
|
|
16
|
+
* <button onclick={() => getEditor()?.chain().focus().toggleBold().run()}>
|
|
17
|
+
* Bold
|
|
18
|
+
* </button>
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function getVizelContext() {
|
|
22
|
+
const getEditor = getContext(VIZEL_CONTEXT_KEY);
|
|
23
|
+
if (!getEditor) {
|
|
24
|
+
throw new Error("getVizelContext must be used within a VizelProvider");
|
|
25
|
+
}
|
|
26
|
+
return getEditor;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get the editor instance from context.
|
|
30
|
+
* Returns undefined if used outside of VizelProvider (does not throw).
|
|
31
|
+
*/
|
|
32
|
+
export function getVizelContextSafe() {
|
|
33
|
+
return getContext(VIZEL_CONTEXT_KEY);
|
|
34
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { Editor } from "@vizel/core";
|
|
3
|
+
|
|
4
|
+
export interface VizelEditorProps {
|
|
5
|
+
/** Override the editor from context */
|
|
6
|
+
editor?: Editor | null;
|
|
7
|
+
/** Custom class name */
|
|
8
|
+
class?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface VizelExposed {
|
|
12
|
+
/** The container DOM element */
|
|
13
|
+
container: HTMLDivElement | null;
|
|
14
|
+
}
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<script lang="ts">
|
|
18
|
+
import { getVizelContextSafe } from "./VizelContext.ts";
|
|
19
|
+
|
|
20
|
+
let { editor: editorProp, class: className }: VizelEditorProps = $props();
|
|
21
|
+
|
|
22
|
+
const contextEditor = getVizelContextSafe();
|
|
23
|
+
const editor = $derived(editorProp ?? contextEditor?.());
|
|
24
|
+
|
|
25
|
+
let element: HTMLDivElement | null = $state(null);
|
|
26
|
+
|
|
27
|
+
// Expose container element to parent component
|
|
28
|
+
export function getExposed(): VizelExposed {
|
|
29
|
+
return {
|
|
30
|
+
get container() {
|
|
31
|
+
return element;
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
$effect(() => {
|
|
37
|
+
if (!editor || !element) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const currentEditor = editor;
|
|
42
|
+
const currentElement = element;
|
|
43
|
+
|
|
44
|
+
// Mount the editor's DOM view to the container element
|
|
45
|
+
currentElement.appendChild(currentEditor.view.dom);
|
|
46
|
+
|
|
47
|
+
// Update editable state
|
|
48
|
+
currentEditor.view.setProps({
|
|
49
|
+
editable: () => currentEditor?.isEditable ?? false,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Cleanup: remove DOM element when editor changes or unmounts
|
|
53
|
+
return () => {
|
|
54
|
+
if (currentEditor.view.dom.parentNode === currentElement) {
|
|
55
|
+
currentElement.removeChild(currentEditor.view.dom);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
</script>
|
|
60
|
+
|
|
61
|
+
<div bind:this={element} class={className} data-vizel-content></div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Editor } from "@vizel/core";
|
|
2
|
+
export interface VizelEditorProps {
|
|
3
|
+
/** Override the editor from context */
|
|
4
|
+
editor?: Editor | null;
|
|
5
|
+
/** Custom class name */
|
|
6
|
+
class?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface VizelExposed {
|
|
9
|
+
/** The container DOM element */
|
|
10
|
+
container: HTMLDivElement | null;
|
|
11
|
+
}
|
|
12
|
+
declare const VizelEditor: import("svelte").Component<VizelEditorProps, {
|
|
13
|
+
getExposed: () => VizelExposed;
|
|
14
|
+
}, "">;
|
|
15
|
+
type VizelEditor = ReturnType<typeof VizelEditor>;
|
|
16
|
+
export default VizelEditor;
|
|
17
|
+
//# sourceMappingURL=VizelEditor.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VizelEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/components/VizelEditor.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,gBAAgB;IAC/B,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,wBAAwB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,gCAAgC;IAChC,SAAS,EAAE,cAAc,GAAG,IAAI,CAAC;CAClC;AAuDD,QAAA,MAAM,WAAW;sBAvCO,YAAY;MAuCqB,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|