@mythrantic/svelte-rich-text 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/components/ValiantRichText/editor.css +38 -0
- package/dist/components/ValiantRichText/headless/components/AudioPlaceHolder.svelte +36 -1
- package/dist/components/ValiantRichText/headless/components/ImagePlaceholder.svelte +36 -1
- package/dist/components/ValiantRichText/headless/components/VideoPlaceholder.svelte +36 -1
- package/dist/components/ValiantRichText/headless/components/toolbar/FontSize.svelte +11 -30
- package/dist/components/ValiantRichText/headless/components/toolbar/QuickColors.svelte +21 -39
- package/dist/components/ValiantRichText/headless/components/toolbar/SearchAndReplace.svelte +3 -2
- package/dist/components/ValiantRichText/headless/components/toolbar/ToolbarDropdown.svelte +177 -0
- package/dist/components/ValiantRichText/headless/components/toolbar/ToolbarDropdown.svelte.d.ts +29 -0
- package/dist/components/ValiantRichText/headless/editor.svelte +61 -34
- package/dist/components/ValiantRichText/headless/editor.svelte.d.ts +7 -0
- package/dist/components/ValiantRichText/headless/style.css +183 -42
- package/dist/components/ValiantRichText/headless/toolbar.svelte +140 -9
- package/dist/components/ValiantRichText/themes/default-dark.css +70 -0
- package/dist/components/ValiantRichText/themes/default-light.css +68 -0
- package/dist/components/ValiantRichText/themes/inherit.css +67 -0
- package/dist/components/ValiantRichText/themes/modern-dark.css +69 -0
- package/dist/components/ValiantRichText/themes/modern-light.css +67 -0
- package/dist/components/ValiantRichText/themes/professional-dark.css +69 -0
- package/dist/components/ValiantRichText/themes/professional-light.css +67 -0
- package/dist/components/ValiantRichText/types.d.ts +3 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
[](https://coder.valiantlynx.com/templates/docker/workspace?param.git_repo=git@github.com:mythrantic/svelte-rich-text.git)
|
|
2
|
+
|
|
1
3
|
# Valiant Rich Text Svelte Component
|
|
2
4
|
|
|
3
5
|

|
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
/* Base TipTap Editor Styles with Light/Dark Theme Support */
|
|
2
2
|
|
|
3
|
+
/* Default fallback theme */
|
|
4
|
+
:root {
|
|
5
|
+
--color-background: #ffffff;
|
|
6
|
+
--color-foreground: #0f172a;
|
|
7
|
+
--color-muted: #f1f5f9;
|
|
8
|
+
--color-muted-foreground: #64748b;
|
|
9
|
+
--color-primary: #ea580c;
|
|
10
|
+
--color-primary-light: #f97316;
|
|
11
|
+
--color-primary-dark: #c2410c;
|
|
12
|
+
--color-secondary: #f1f5f9;
|
|
13
|
+
--color-secondary-foreground: #0f172a;
|
|
14
|
+
--color-accent: #ea580c;
|
|
15
|
+
--color-accent-light: #f97316;
|
|
16
|
+
--color-accent-dark: #c2410c;
|
|
17
|
+
--color-destructive: #dc2626;
|
|
18
|
+
--color-input: #e2e8f0;
|
|
19
|
+
--color-border: #e2e8f0;
|
|
20
|
+
--blockquote-color: #475569;
|
|
21
|
+
--blockquote-border: #ea580c;
|
|
22
|
+
--border-color: #e2e8f0;
|
|
23
|
+
--border-color-hover: #cbd5e1;
|
|
24
|
+
--code-bg: #f1f5f9;
|
|
25
|
+
--codeblock-bg: #1e293b;
|
|
26
|
+
--table-border: #e2e8f0;
|
|
27
|
+
--table-bg-selected: #f0f9ff;
|
|
28
|
+
--table-bg-hover: #f8fafc;
|
|
29
|
+
--highlight-color: #fef3c7;
|
|
30
|
+
--highlight-border: #fbbf24;
|
|
31
|
+
--search-result-bg: #fef08a;
|
|
32
|
+
--search-result-current-bg: #fbbf24;
|
|
33
|
+
--task-completed-color: #94a3b8;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.valiant-editor {
|
|
37
|
+
background-color: var(--color-background);
|
|
38
|
+
color: var(--color-foreground);
|
|
39
|
+
}
|
|
40
|
+
|
|
3
41
|
.tiptap :first-child {
|
|
4
42
|
margin-top: 0;
|
|
5
43
|
}
|
|
@@ -6,12 +6,40 @@
|
|
|
6
6
|
const { editor }: NodeViewProps = $props();
|
|
7
7
|
import Audio from '@lucide/svelte/icons/audio-lines';
|
|
8
8
|
|
|
9
|
+
let fileInput = $state<HTMLInputElement | undefined>();
|
|
10
|
+
|
|
9
11
|
function handleClick() {
|
|
10
|
-
|
|
12
|
+
// Try to open file picker first
|
|
13
|
+
if (fileInput) {
|
|
14
|
+
fileInput.click();
|
|
15
|
+
} else {
|
|
16
|
+
// Fallback to URL input
|
|
17
|
+
promptForUrl();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function promptForUrl() {
|
|
22
|
+
const audioUrl = prompt('Enter audio URL or select a file');
|
|
11
23
|
if (audioUrl) {
|
|
12
24
|
editor.chain().focus().setAudio(audioUrl).run();
|
|
13
25
|
}
|
|
14
26
|
}
|
|
27
|
+
|
|
28
|
+
function handleFileSelect(e: Event) {
|
|
29
|
+
const input = e.target as HTMLInputElement;
|
|
30
|
+
const file = input.files?.[0];
|
|
31
|
+
|
|
32
|
+
if (file) {
|
|
33
|
+
const reader = new FileReader();
|
|
34
|
+
reader.onload = (event) => {
|
|
35
|
+
const src = event.target?.result as string;
|
|
36
|
+
if (src) {
|
|
37
|
+
editor.chain().focus().setAudio(src).run();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
reader.readAsDataURL(file);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
15
43
|
</script>
|
|
16
44
|
|
|
17
45
|
<NodeViewWrapper>
|
|
@@ -22,5 +50,12 @@
|
|
|
22
50
|
title="Insert an audio"
|
|
23
51
|
onClick={handleClick}
|
|
24
52
|
/>
|
|
53
|
+
<input
|
|
54
|
+
bind:this={fileInput}
|
|
55
|
+
type="file"
|
|
56
|
+
accept="audio/*"
|
|
57
|
+
onchange={handleFileSelect}
|
|
58
|
+
style="display: none;"
|
|
59
|
+
/>
|
|
25
60
|
{/if}
|
|
26
61
|
</NodeViewWrapper>
|
|
@@ -6,12 +6,40 @@
|
|
|
6
6
|
const { editor }: NodeViewProps = $props();
|
|
7
7
|
import Image from '@lucide/svelte/icons/image';
|
|
8
8
|
|
|
9
|
+
let fileInput = $state<HTMLInputElement | undefined>();
|
|
10
|
+
|
|
9
11
|
function handleClick() {
|
|
10
|
-
|
|
12
|
+
// Try to open file picker first
|
|
13
|
+
if (fileInput) {
|
|
14
|
+
fileInput.click();
|
|
15
|
+
} else {
|
|
16
|
+
// Fallback to URL input
|
|
17
|
+
promptForUrl();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function promptForUrl() {
|
|
22
|
+
const imageUrl = prompt('Enter image URL or select a file');
|
|
11
23
|
if (imageUrl) {
|
|
12
24
|
editor.chain().focus().setImage({ src: imageUrl }).run();
|
|
13
25
|
}
|
|
14
26
|
}
|
|
27
|
+
|
|
28
|
+
function handleFileSelect(e: Event) {
|
|
29
|
+
const input = e.target as HTMLInputElement;
|
|
30
|
+
const file = input.files?.[0];
|
|
31
|
+
|
|
32
|
+
if (file) {
|
|
33
|
+
const reader = new FileReader();
|
|
34
|
+
reader.onload = (event) => {
|
|
35
|
+
const src = event.target?.result as string;
|
|
36
|
+
if (src) {
|
|
37
|
+
editor.chain().focus().setImage({ src }).run();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
reader.readAsDataURL(file);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
15
43
|
</script>
|
|
16
44
|
|
|
17
45
|
<NodeViewWrapper>
|
|
@@ -22,5 +50,12 @@
|
|
|
22
50
|
title="Insert an image"
|
|
23
51
|
onClick={handleClick}
|
|
24
52
|
/>
|
|
53
|
+
<input
|
|
54
|
+
bind:this={fileInput}
|
|
55
|
+
type="file"
|
|
56
|
+
accept="image/*"
|
|
57
|
+
onchange={handleFileSelect}
|
|
58
|
+
style="display: none;"
|
|
59
|
+
/>
|
|
25
60
|
{/if}
|
|
26
61
|
</NodeViewWrapper>
|
|
@@ -6,12 +6,40 @@
|
|
|
6
6
|
const { editor }: NodeViewProps = $props();
|
|
7
7
|
import Video from '@lucide/svelte/icons/video';
|
|
8
8
|
|
|
9
|
+
let fileInput = $state<HTMLInputElement | undefined>();
|
|
10
|
+
|
|
9
11
|
function handleClick() {
|
|
10
|
-
|
|
12
|
+
// Try to open file picker first
|
|
13
|
+
if (fileInput) {
|
|
14
|
+
fileInput.click();
|
|
15
|
+
} else {
|
|
16
|
+
// Fallback to URL input
|
|
17
|
+
promptForUrl();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function promptForUrl() {
|
|
22
|
+
const videoUrl = prompt('Enter video URL or select a file');
|
|
11
23
|
if (videoUrl) {
|
|
12
24
|
editor.chain().focus().setVideo(videoUrl).run();
|
|
13
25
|
}
|
|
14
26
|
}
|
|
27
|
+
|
|
28
|
+
function handleFileSelect(e: Event) {
|
|
29
|
+
const input = e.target as HTMLInputElement;
|
|
30
|
+
const file = input.files?.[0];
|
|
31
|
+
|
|
32
|
+
if (file) {
|
|
33
|
+
const reader = new FileReader();
|
|
34
|
+
reader.onload = (event) => {
|
|
35
|
+
const src = event.target?.result as string;
|
|
36
|
+
if (src) {
|
|
37
|
+
editor.chain().focus().setVideo(src).run();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
reader.readAsDataURL(file);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
15
43
|
</script>
|
|
16
44
|
|
|
17
45
|
<NodeViewWrapper>
|
|
@@ -22,5 +50,12 @@
|
|
|
22
50
|
title="Insert a video"
|
|
23
51
|
onClick={handleClick}
|
|
24
52
|
/>
|
|
53
|
+
<input
|
|
54
|
+
bind:this={fileInput}
|
|
55
|
+
type="file"
|
|
56
|
+
accept="video/*"
|
|
57
|
+
onchange={handleFileSelect}
|
|
58
|
+
style="display: none;"
|
|
59
|
+
/>
|
|
25
60
|
{/if}
|
|
26
61
|
</NodeViewWrapper>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Editor } from '@tiptap/core';
|
|
3
|
+
import ToolbarDropdown from './ToolbarDropdown.svelte';
|
|
3
4
|
|
|
4
5
|
interface Props {
|
|
5
6
|
editor: Editor;
|
|
@@ -17,36 +18,16 @@
|
|
|
17
18
|
];
|
|
18
19
|
|
|
19
20
|
let currentSize = $derived.by(() => editor.getAttributes('textStyle').fontSize || '');
|
|
21
|
+
|
|
22
|
+
function handleFontSizeChange(value: string) {
|
|
23
|
+
editor.chain().focus().setFontSize(value).run();
|
|
24
|
+
}
|
|
20
25
|
</script>
|
|
21
26
|
|
|
22
|
-
<
|
|
27
|
+
<ToolbarDropdown
|
|
28
|
+
options={FONT_SIZE}
|
|
23
29
|
value={currentSize}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
.setFontSize((e.target as HTMLSelectElement).value)
|
|
29
|
-
.run();
|
|
30
|
-
}}
|
|
31
|
-
title="Font Size"
|
|
32
|
-
>
|
|
33
|
-
{#each FONT_SIZE as fontSize (fontSize)}
|
|
34
|
-
<option value={fontSize.value} label={fontSize.label.split(' ')[0]}></option>
|
|
35
|
-
{/each}
|
|
36
|
-
</select>
|
|
37
|
-
|
|
38
|
-
<style>
|
|
39
|
-
select {
|
|
40
|
-
display: inline-flex;
|
|
41
|
-
align-items: center;
|
|
42
|
-
justify-content: center;
|
|
43
|
-
border: none;
|
|
44
|
-
background-color: var(--edra-button-bg-color);
|
|
45
|
-
border-radius: var(--edra-button-border-radius);
|
|
46
|
-
cursor: pointer;
|
|
47
|
-
transition: background-color 0.2s ease-in-out;
|
|
48
|
-
padding: var(--edra-button-padding);
|
|
49
|
-
min-width: fit;
|
|
50
|
-
min-height: full;
|
|
51
|
-
}
|
|
52
|
-
</style>
|
|
30
|
+
label="Font Size"
|
|
31
|
+
placeholder="Size"
|
|
32
|
+
onchange={handleFontSizeChange}
|
|
33
|
+
/>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Editor } from '@tiptap/core';
|
|
3
|
+
import ToolbarDropdown from './ToolbarDropdown.svelte';
|
|
3
4
|
|
|
4
5
|
interface Props {
|
|
5
6
|
editor: Editor;
|
|
@@ -21,50 +22,31 @@
|
|
|
21
22
|
|
|
22
23
|
const currentColor = $derived.by(() => editor.getAttributes('textStyle').color ?? '');
|
|
23
24
|
const currentHighlight = $derived.by(() => editor.getAttributes('highlight').color ?? '');
|
|
25
|
+
|
|
26
|
+
function handleColorChange(color: string) {
|
|
27
|
+
editor.chain().focus().setColor(color).run();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function handleHighlightChange(color: string) {
|
|
31
|
+
editor.chain().focus().setHighlight({ color }).run();
|
|
32
|
+
}
|
|
24
33
|
</script>
|
|
25
34
|
|
|
26
|
-
<
|
|
35
|
+
<ToolbarDropdown
|
|
36
|
+
options={colors}
|
|
27
37
|
value={currentColor}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
style={`color: ${currentColor}`}
|
|
33
|
-
title="Text Color"
|
|
34
|
-
>
|
|
35
|
-
<option value="" label="Default"></option>
|
|
36
|
-
{#each colors as color (color)}
|
|
37
|
-
<option value={color.value} label={color.label}></option>
|
|
38
|
-
{/each}
|
|
39
|
-
</select>
|
|
38
|
+
label="Text Color"
|
|
39
|
+
placeholder="Color"
|
|
40
|
+
onchange={handleColorChange}
|
|
41
|
+
/>
|
|
40
42
|
|
|
41
|
-
<
|
|
43
|
+
<ToolbarDropdown
|
|
44
|
+
options={colors}
|
|
42
45
|
value={currentHighlight}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
style={`background-color: ${currentHighlight}50`}
|
|
48
|
-
title="Hightlight Color"
|
|
49
|
-
>
|
|
50
|
-
<option value="" label="Default"></option>
|
|
51
|
-
{#each colors as color (color)}
|
|
52
|
-
<option value={color.value} label={color.label}>A</option>
|
|
53
|
-
{/each}
|
|
54
|
-
</select>
|
|
46
|
+
label="Highlight Color"
|
|
47
|
+
placeholder="Highlight"
|
|
48
|
+
onchange={handleHighlightChange}
|
|
49
|
+
/>
|
|
55
50
|
|
|
56
51
|
<style>
|
|
57
|
-
select {
|
|
58
|
-
display: inline-flex;
|
|
59
|
-
align-items: center;
|
|
60
|
-
justify-content: center;
|
|
61
|
-
border: none;
|
|
62
|
-
background-color: var(--edra-button-bg-color);
|
|
63
|
-
border-radius: var(--edra-button-border-radius);
|
|
64
|
-
cursor: pointer;
|
|
65
|
-
transition: background-color 0.2s ease-in-out;
|
|
66
|
-
padding: var(--edra-button-padding);
|
|
67
|
-
min-width: fit;
|
|
68
|
-
min-height: var(--edra-button-size);
|
|
69
|
-
}
|
|
70
52
|
</style>
|
|
@@ -65,19 +65,20 @@
|
|
|
65
65
|
|
|
66
66
|
<div class="edra-search-and-replace">
|
|
67
67
|
<button
|
|
68
|
-
class="edra-command-button"
|
|
68
|
+
class="edra-command-button edra-filter-button"
|
|
69
69
|
onclick={() => {
|
|
70
70
|
show = !show;
|
|
71
71
|
clear();
|
|
72
72
|
updateSearchTerm();
|
|
73
73
|
}}
|
|
74
|
-
title={show ? 'Go Back' : '
|
|
74
|
+
title={show ? 'Go Back' : 'Filter and Search'}
|
|
75
75
|
>
|
|
76
76
|
{#if show}
|
|
77
77
|
<ArrowLeft class="edra-toolbar-icon" />
|
|
78
78
|
{:else}
|
|
79
79
|
<Search class="edra-toolbar-icon" />
|
|
80
80
|
{/if}
|
|
81
|
+
<span class="edra-filter-label">Filter</span>
|
|
81
82
|
</button>
|
|
82
83
|
{#if show}
|
|
83
84
|
<div class="edra-search-and-replace-content">
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import ChevronDown from '@lucide/svelte/icons/chevron-down';
|
|
3
|
+
|
|
4
|
+
interface Option {
|
|
5
|
+
label: string;
|
|
6
|
+
value: string;
|
|
7
|
+
icon?: any;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
options: Option[];
|
|
12
|
+
value?: string;
|
|
13
|
+
placeholder?: string;
|
|
14
|
+
label?: string;
|
|
15
|
+
onchange?: (value: string) => void;
|
|
16
|
+
icon?: any;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let { options, value, placeholder = 'Select...', label, onchange, icon: Icon }: Props = $props();
|
|
20
|
+
|
|
21
|
+
let isOpen = $state(false);
|
|
22
|
+
let container: HTMLDivElement;
|
|
23
|
+
let selectedOption = $derived(options.find((opt) => opt.value === value));
|
|
24
|
+
|
|
25
|
+
function handleSelect(val: string) {
|
|
26
|
+
onchange?.(val);
|
|
27
|
+
isOpen = false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function handleClickOutside(e: MouseEvent) {
|
|
31
|
+
const target = e.target as HTMLElement;
|
|
32
|
+
if (container && !container.contains(target)) {
|
|
33
|
+
isOpen = false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
$effect(() => {
|
|
38
|
+
if (isOpen) {
|
|
39
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
40
|
+
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<div class="toolbar-dropdown-container" bind:this={container}>
|
|
46
|
+
<button
|
|
47
|
+
class="toolbar-dropdown-trigger"
|
|
48
|
+
onclick={() => (isOpen = !isOpen)}
|
|
49
|
+
title={label}
|
|
50
|
+
aria-label={label}
|
|
51
|
+
aria-haspopup="listbox"
|
|
52
|
+
aria-expanded={isOpen}
|
|
53
|
+
>
|
|
54
|
+
{#if Icon}
|
|
55
|
+
<svelte:component this={Icon} size={16} />
|
|
56
|
+
{/if}
|
|
57
|
+
<span class="toolbar-dropdown-label">
|
|
58
|
+
{selectedOption?.label || placeholder}
|
|
59
|
+
</span>
|
|
60
|
+
<ChevronDown size={14} style={isOpen ? 'transform: rotate(180deg)' : ''} class="chevron" />
|
|
61
|
+
</button>
|
|
62
|
+
|
|
63
|
+
{#if isOpen}
|
|
64
|
+
<div class="toolbar-dropdown-content" role="listbox">
|
|
65
|
+
{#each options as option (option.value)}
|
|
66
|
+
<button
|
|
67
|
+
class="toolbar-dropdown-item"
|
|
68
|
+
class:active={option.value === value}
|
|
69
|
+
onclick={() => handleSelect(option.value)}
|
|
70
|
+
role="option"
|
|
71
|
+
aria-selected={option.value === value}
|
|
72
|
+
>
|
|
73
|
+
{#if option.icon}
|
|
74
|
+
<svelte:component this={option.icon} size={14} />
|
|
75
|
+
{/if}
|
|
76
|
+
<span>{option.label}</span>
|
|
77
|
+
</button>
|
|
78
|
+
{/each}
|
|
79
|
+
</div>
|
|
80
|
+
{/if}
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<style>
|
|
84
|
+
.toolbar-dropdown-container {
|
|
85
|
+
position: relative;
|
|
86
|
+
display: inline-flex;
|
|
87
|
+
align-items: center;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.toolbar-dropdown-trigger {
|
|
91
|
+
display: inline-flex;
|
|
92
|
+
align-items: center;
|
|
93
|
+
justify-content: center;
|
|
94
|
+
gap: 0.375rem;
|
|
95
|
+
border: 1px solid transparent;
|
|
96
|
+
background-color: transparent;
|
|
97
|
+
border-radius: 0.375rem;
|
|
98
|
+
cursor: pointer;
|
|
99
|
+
transition: all 0.15s ease-in-out;
|
|
100
|
+
padding: 0.375rem 0.5rem;
|
|
101
|
+
min-height: 2.5rem;
|
|
102
|
+
color: var(--edra-icon-color);
|
|
103
|
+
font-size: 0.875rem;
|
|
104
|
+
font-weight: 500;
|
|
105
|
+
white-space: nowrap;
|
|
106
|
+
flex-shrink: 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.toolbar-dropdown-trigger:hover {
|
|
110
|
+
background-color: var(--color-muted);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.toolbar-dropdown-trigger:active {
|
|
114
|
+
background-color: var(--color-muted);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.chevron {
|
|
118
|
+
transition: transform 0.2s ease-in-out;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.chevron.rotated {
|
|
122
|
+
transform: rotate(180deg);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.toolbar-dropdown-label {
|
|
126
|
+
max-width: 6rem;
|
|
127
|
+
overflow: hidden;
|
|
128
|
+
text-overflow: ellipsis;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.toolbar-dropdown-content {
|
|
132
|
+
position: absolute;
|
|
133
|
+
top: calc(100% + 0.25rem);
|
|
134
|
+
left: 0;
|
|
135
|
+
z-index: 50;
|
|
136
|
+
min-width: -moz-max-content;
|
|
137
|
+
min-width: max-content;
|
|
138
|
+
background-color: var(--color-background);
|
|
139
|
+
border: 1px solid var(--color-border);
|
|
140
|
+
border-radius: 0.5rem;
|
|
141
|
+
box-shadow:
|
|
142
|
+
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
|
143
|
+
0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
144
|
+
padding: 0.375rem;
|
|
145
|
+
display: flex;
|
|
146
|
+
flex-direction: column;
|
|
147
|
+
max-height: 20rem;
|
|
148
|
+
overflow-y: auto;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.toolbar-dropdown-item {
|
|
152
|
+
display: flex;
|
|
153
|
+
align-items: center;
|
|
154
|
+
gap: 0.5rem;
|
|
155
|
+
padding: 0.5rem 0.75rem;
|
|
156
|
+
background-color: transparent;
|
|
157
|
+
border: none;
|
|
158
|
+
border-radius: 0.375rem;
|
|
159
|
+
cursor: pointer;
|
|
160
|
+
color: var(--color-foreground);
|
|
161
|
+
font-size: 0.875rem;
|
|
162
|
+
transition: all 0.15s ease-in-out;
|
|
163
|
+
text-align: left;
|
|
164
|
+
min-width: 6rem;
|
|
165
|
+
font-weight: 400;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.toolbar-dropdown-item:hover {
|
|
169
|
+
background-color: var(--color-muted);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.toolbar-dropdown-item.active {
|
|
173
|
+
background-color: var(--color-muted);
|
|
174
|
+
font-weight: 600;
|
|
175
|
+
color: var(--color-primary);
|
|
176
|
+
}
|
|
177
|
+
</style>
|
package/dist/components/ValiantRichText/headless/components/toolbar/ToolbarDropdown.svelte.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
+
$$bindings?: Bindings;
|
|
4
|
+
} & Exports;
|
|
5
|
+
(internal: unknown, props: Props & {
|
|
6
|
+
$$events?: Events;
|
|
7
|
+
$$slots?: Slots;
|
|
8
|
+
}): Exports & {
|
|
9
|
+
$set?: any;
|
|
10
|
+
$on?: any;
|
|
11
|
+
};
|
|
12
|
+
z_$$bindings?: Bindings;
|
|
13
|
+
}
|
|
14
|
+
declare const ToolbarDropdown: $$__sveltets_2_IsomorphicComponent<{
|
|
15
|
+
options: {
|
|
16
|
+
label: string;
|
|
17
|
+
value: string;
|
|
18
|
+
icon?: any;
|
|
19
|
+
}[];
|
|
20
|
+
value?: string;
|
|
21
|
+
placeholder?: string;
|
|
22
|
+
label?: string;
|
|
23
|
+
onchange?: (value: string) => void;
|
|
24
|
+
icon?: any;
|
|
25
|
+
}, {
|
|
26
|
+
[evt: string]: CustomEvent<any>;
|
|
27
|
+
}, {}, {}, "">;
|
|
28
|
+
type ToolbarDropdown = InstanceType<typeof ToolbarDropdown>;
|
|
29
|
+
export default ToolbarDropdown;
|