@x33025/sveltely 0.1.9 → 0.1.11

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.
Files changed (59) hide show
  1. package/dist/components/Library/ArticleEditor/ArticleBlockCode.svelte +21 -0
  2. package/dist/components/Library/ArticleEditor/ArticleBlockCode.svelte.d.ts +8 -0
  3. package/dist/components/Library/ArticleEditor/ArticleBlockDragControl.svelte +144 -0
  4. package/dist/components/Library/ArticleEditor/ArticleBlockDragControl.svelte.d.ts +14 -0
  5. package/dist/components/Library/ArticleEditor/ArticleBlockFAQ.svelte +47 -0
  6. package/dist/components/Library/ArticleEditor/ArticleBlockFAQ.svelte.d.ts +8 -0
  7. package/dist/components/Library/ArticleEditor/ArticleBlockFallback.svelte +79 -0
  8. package/dist/components/Library/ArticleEditor/ArticleBlockFallback.svelte.d.ts +15 -0
  9. package/dist/components/Library/ArticleEditor/ArticleBlockHeading.svelte +73 -0
  10. package/dist/components/Library/ArticleEditor/ArticleBlockHeading.svelte.d.ts +14 -0
  11. package/dist/components/Library/ArticleEditor/ArticleBlockImage.svelte +48 -0
  12. package/dist/components/Library/ArticleEditor/ArticleBlockImage.svelte.d.ts +9 -0
  13. package/dist/components/Library/ArticleEditor/ArticleBlockInsertControl.svelte +120 -0
  14. package/dist/components/Library/ArticleEditor/ArticleBlockInsertControl.svelte.d.ts +9 -0
  15. package/dist/components/Library/ArticleEditor/ArticleBlockList.svelte +114 -0
  16. package/dist/components/Library/ArticleEditor/ArticleBlockList.svelte.d.ts +15 -0
  17. package/dist/components/Library/ArticleEditor/ArticleBlockParagraph.svelte +79 -0
  18. package/dist/components/Library/ArticleEditor/ArticleBlockParagraph.svelte.d.ts +15 -0
  19. package/dist/components/Library/ArticleEditor/ArticleBlockShell.svelte +127 -0
  20. package/dist/components/Library/ArticleEditor/ArticleBlockShell.svelte.d.ts +22 -0
  21. package/dist/components/Library/ArticleEditor/ArticleBlockTable.svelte +274 -0
  22. package/dist/components/Library/ArticleEditor/ArticleBlockTable.svelte.d.ts +13 -0
  23. package/dist/components/Library/ArticleEditor/ArticleEditor.svelte +192 -0
  24. package/dist/components/Library/ArticleEditor/ArticleEditor.svelte.d.ts +39 -0
  25. package/dist/components/Library/ArticleEditor/ArticleEditorBody.svelte +328 -0
  26. package/dist/components/Library/ArticleEditor/ArticleEditorBody.svelte.d.ts +31 -0
  27. package/dist/components/Library/ArticleEditor/ArticleEditorHeader.svelte +57 -0
  28. package/dist/components/Library/ArticleEditor/ArticleEditorHeader.svelte.d.ts +11 -0
  29. package/dist/components/Library/ArticleEditor/ArticleImagePreview.svelte +71 -0
  30. package/dist/components/Library/ArticleEditor/ArticleImagePreview.svelte.d.ts +8 -0
  31. package/dist/components/Library/ArticleEditor/articleEditor.svelte.js +532 -0
  32. package/dist/components/Library/ArticleEditor/index.d.ts +18 -0
  33. package/dist/components/Library/ArticleEditor/index.js +16 -0
  34. package/dist/components/Library/ArticleEditor/types.d.ts +37 -0
  35. package/dist/components/Library/ArticleEditor/types.js +1 -0
  36. package/dist/components/Library/Floating/Floating.svelte +8 -8
  37. package/dist/components/Library/Grid/index.d.ts +1 -0
  38. package/dist/components/Library/Grid/index.js +1 -0
  39. package/dist/components/Library/Sheet/Sheet.svelte +1 -0
  40. package/dist/components/Library/TextEditor/TextEditor.svelte +90 -0
  41. package/dist/components/Library/TextEditor/TextEditor.svelte.d.ts +17 -0
  42. package/dist/components/Library/TextEditor/index.d.ts +1 -0
  43. package/dist/components/Library/TextEditor/index.js +1 -0
  44. package/dist/components/Local/ComponentGrid.svelte +1 -1
  45. package/dist/index.d.ts +3 -1
  46. package/dist/index.js +3 -1
  47. package/dist/style/index.css +1 -0
  48. package/dist/style/layout.d.ts +2 -2
  49. package/dist/style/layout.js +2 -3
  50. package/dist/style/loader.d.ts +2 -2
  51. package/dist/style/loader.js +2 -3
  52. package/dist/style/surface.d.ts +2 -2
  53. package/dist/style/surface.js +2 -3
  54. package/dist/style.css +233 -0
  55. package/package.json +1 -1
  56. package/dist/components/Library/GridItem/index.d.ts +0 -1
  57. package/dist/components/Library/GridItem/index.js +0 -1
  58. /package/dist/components/Library/{GridItem → Grid}/GridItem.svelte +0 -0
  59. /package/dist/components/Library/{GridItem → Grid}/GridItem.svelte.d.ts +0 -0
@@ -0,0 +1,21 @@
1
+ <script lang="ts">
2
+ import TextEditor from '../TextEditor';
3
+ import type { BlockDraft } from './types.js';
4
+
5
+ let { block, onUpdate } = $props<{
6
+ block: BlockDraft;
7
+ onUpdate: (id: string, patch: Partial<BlockDraft>) => void;
8
+ }>();
9
+ </script>
10
+
11
+ <TextEditor
12
+ autosize
13
+ rows={6}
14
+ value={block.code ?? ''}
15
+ onInput={(event) =>
16
+ onUpdate(block.id, {
17
+ code: (event.currentTarget as HTMLTextAreaElement).value
18
+ })}
19
+ className="bg-zinc-950 px-4 py-4 font-mono text-sm leading-6 text-zinc-100"
20
+ placeholder="Code block"
21
+ />
@@ -0,0 +1,8 @@
1
+ import type { BlockDraft } from './types.js';
2
+ type $$ComponentProps = {
3
+ block: BlockDraft;
4
+ onUpdate: (id: string, patch: Partial<BlockDraft>) => void;
5
+ };
6
+ declare const ArticleBlockCode: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type ArticleBlockCode = ReturnType<typeof ArticleBlockCode>;
8
+ export default ArticleBlockCode;
@@ -0,0 +1,144 @@
1
+ <script lang="ts">
2
+ import { GripVertical, Heading2, Heading3, List, ListOrdered, Type } from '@lucide/svelte';
3
+ import Dropdown from '../Dropdown';
4
+ import { articleBlockLabel, type BlockTextFormat } from './articleEditor.svelte.js';
5
+ import type { BlockDraft } from './types.js';
6
+
7
+ let {
8
+ block,
9
+ textFormat,
10
+ canChangeTextFormat,
11
+ onSelect,
12
+ onChangeTextFormat,
13
+ onDragStart,
14
+ onDragEnd
15
+ } = $props<{
16
+ block: BlockDraft;
17
+ textFormat: BlockTextFormat | null;
18
+ canChangeTextFormat: boolean;
19
+ onSelect: (id: string) => void;
20
+ onChangeTextFormat: (id: string, format: BlockTextFormat) => void;
21
+ onDragStart: (event: DragEvent, id: string) => void;
22
+ onDragEnd: () => void;
23
+ }>();
24
+
25
+ const blockTextFormatLabels: Record<BlockTextFormat, string> = {
26
+ paragraph: 'Text',
27
+ 'heading-2': 'Heading 2',
28
+ 'heading-3': 'Heading 3',
29
+ bullet_list: 'Bulleted list',
30
+ numbered_list: 'Numbered list'
31
+ };
32
+
33
+ const selectedLabel = () =>
34
+ textFormat ? blockTextFormatLabels[textFormat as BlockTextFormat] : articleBlockLabel(block);
35
+ </script>
36
+
37
+ <Dropdown
38
+ value={textFormat}
39
+ selectedLabel={selectedLabel()}
40
+ placement="bottom"
41
+ showCheck={true}
42
+ onValueChange={(value: BlockTextFormat | null) => {
43
+ if (typeof value !== 'string') return;
44
+ onChangeTextFormat(block.id, value);
45
+ }}
46
+ >
47
+ {#snippet trigger(triggerState: any)}
48
+ <button
49
+ use:triggerState.useTrigger
50
+ type="button"
51
+ draggable="true"
52
+ aria-label="Block options and drag to reorder"
53
+ aria-expanded={triggerState.open}
54
+ aria-haspopup="dialog"
55
+ class="article-block-control-button"
56
+ onclick={(event: MouseEvent) => {
57
+ event.stopPropagation();
58
+ onSelect(block.id);
59
+ triggerState.toggle();
60
+ }}
61
+ onkeydown={(event: KeyboardEvent) => {
62
+ if (event.key === 'Enter' || event.key === ' ') {
63
+ event.preventDefault();
64
+ event.stopPropagation();
65
+ onSelect(block.id);
66
+ triggerState.toggle();
67
+ }
68
+ }}
69
+ ondragstart={(event: DragEvent) => onDragStart(event, block.id)}
70
+ ondragend={onDragEnd}
71
+ >
72
+ <GripVertical size={15} />
73
+ </button>
74
+ {/snippet}
75
+
76
+ <Dropdown.Section label="Text style">
77
+ <Dropdown.Item value={'paragraph' as BlockTextFormat} disabled={!canChangeTextFormat}>
78
+ <span class="article-block-control-menu-item">
79
+ <Type size={14} />
80
+ <span>Text</span>
81
+ </span>
82
+ </Dropdown.Item>
83
+ <Dropdown.Item value={'heading-2' as BlockTextFormat} disabled={!canChangeTextFormat}>
84
+ <span class="article-block-control-menu-item">
85
+ <Heading2 size={14} />
86
+ <span>Heading 2</span>
87
+ </span>
88
+ </Dropdown.Item>
89
+ <Dropdown.Item value={'heading-3' as BlockTextFormat} disabled={!canChangeTextFormat}>
90
+ <span class="article-block-control-menu-item">
91
+ <Heading3 size={14} />
92
+ <span>Heading 3</span>
93
+ </span>
94
+ </Dropdown.Item>
95
+ <Dropdown.Item value={'bullet_list' as BlockTextFormat} disabled={!canChangeTextFormat}>
96
+ <span class="article-block-control-menu-item">
97
+ <List size={14} />
98
+ <span>Bulleted list</span>
99
+ </span>
100
+ </Dropdown.Item>
101
+ <Dropdown.Item value={'numbered_list' as BlockTextFormat} disabled={!canChangeTextFormat}>
102
+ <span class="article-block-control-menu-item">
103
+ <ListOrdered size={14} />
104
+ <span>Numbered list</span>
105
+ </span>
106
+ </Dropdown.Item>
107
+ </Dropdown.Section>
108
+ </Dropdown>
109
+
110
+ <style>
111
+ .article-block-control-button {
112
+ display: flex;
113
+ width: 1.75rem;
114
+ height: 1.75rem;
115
+ cursor: grab;
116
+ align-items: center;
117
+ justify-content: center;
118
+ border: 0;
119
+ background: transparent;
120
+ color: #a1a1aa;
121
+ transition:
122
+ background-color 150ms,
123
+ color 150ms;
124
+ }
125
+
126
+ .article-block-control-button:hover {
127
+ background: #f5f5f4;
128
+ color: #3f3f46;
129
+ }
130
+
131
+ .article-block-control-button:active {
132
+ cursor: grabbing;
133
+ }
134
+
135
+ .article-block-control-menu-item {
136
+ display: inline-flex;
137
+ align-items: center;
138
+ gap: 0.5rem;
139
+ }
140
+
141
+ .article-block-control-menu-item :global(svg) {
142
+ flex: 0 0 auto;
143
+ }
144
+ </style>
@@ -0,0 +1,14 @@
1
+ import { type BlockTextFormat } from './articleEditor.svelte.js';
2
+ import type { BlockDraft } from './types.js';
3
+ type $$ComponentProps = {
4
+ block: BlockDraft;
5
+ textFormat: BlockTextFormat | null;
6
+ canChangeTextFormat: boolean;
7
+ onSelect: (id: string) => void;
8
+ onChangeTextFormat: (id: string, format: BlockTextFormat) => void;
9
+ onDragStart: (event: DragEvent, id: string) => void;
10
+ onDragEnd: () => void;
11
+ };
12
+ declare const ArticleBlockDragControl: import("svelte").Component<$$ComponentProps, {}, "">;
13
+ type ArticleBlockDragControl = ReturnType<typeof ArticleBlockDragControl>;
14
+ export default ArticleBlockDragControl;
@@ -0,0 +1,47 @@
1
+ <script lang="ts">
2
+ import TextEditor from '../TextEditor';
3
+ import type { BlockDraft } from './types.js';
4
+
5
+ let { block, onUpdateItem } = $props<{
6
+ block: BlockDraft;
7
+ onUpdateItem: (
8
+ blockID: string,
9
+ index: number,
10
+ field: 'question' | 'answer',
11
+ value: string
12
+ ) => void;
13
+ }>();
14
+ </script>
15
+
16
+ <div class="space-y-4">
17
+ {#each block.faqItems ?? [] as item, index}
18
+ <div class="border-b border-zinc-200/70 pb-4 last:border-b-0 last:pb-0">
19
+ <input
20
+ class="mb-2 w-full border-0 bg-transparent px-0 text-[17px] leading-7 font-semibold text-zinc-950 outline-none placeholder:text-zinc-300"
21
+ value={item.question}
22
+ oninput={(event) =>
23
+ onUpdateItem(
24
+ block.id,
25
+ index,
26
+ 'question',
27
+ (event.currentTarget as HTMLInputElement).value
28
+ )}
29
+ placeholder="Question"
30
+ />
31
+ <TextEditor
32
+ autosize
33
+ rows={1}
34
+ className="text-[15px] leading-7 text-zinc-700 placeholder:text-zinc-300"
35
+ value={item.answer}
36
+ onInput={(event) =>
37
+ onUpdateItem(
38
+ block.id,
39
+ index,
40
+ 'answer',
41
+ (event.currentTarget as HTMLTextAreaElement).value
42
+ )}
43
+ placeholder="Answer"
44
+ />
45
+ </div>
46
+ {/each}
47
+ </div>
@@ -0,0 +1,8 @@
1
+ import type { BlockDraft } from './types.js';
2
+ type $$ComponentProps = {
3
+ block: BlockDraft;
4
+ onUpdateItem: (blockID: string, index: number, field: 'question' | 'answer', value: string) => void;
5
+ };
6
+ declare const ArticleBlockFAQ: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type ArticleBlockFAQ = ReturnType<typeof ArticleBlockFAQ>;
8
+ export default ArticleBlockFAQ;
@@ -0,0 +1,79 @@
1
+ <script lang="ts">
2
+ import TextEditor from '../TextEditor';
3
+ import type { BlockDraft } from './types.js';
4
+
5
+ let {
6
+ block,
7
+ onUpdate,
8
+ onCreateParagraphAfter,
9
+ onMergeBlockWithPrevious,
10
+ onConvertToList,
11
+ onRemoveBlock,
12
+ shouldFocus,
13
+ focusPosition,
14
+ onFocused
15
+ } = $props<{
16
+ block: BlockDraft;
17
+ onUpdate: (id: string, patch: Partial<BlockDraft>) => void;
18
+ onCreateParagraphAfter?: (id: string, text?: string, currentText?: string | null) => void;
19
+ onMergeBlockWithPrevious?: (id: string) => void;
20
+ onConvertToList?: (id: string, kind: 'bullet_list' | 'numbered_list') => void;
21
+ onRemoveBlock?: (id: string) => void;
22
+ shouldFocus?: boolean;
23
+ focusPosition?: number | null;
24
+ onFocused?: () => void;
25
+ }>();
26
+ </script>
27
+
28
+ <TextEditor
29
+ autosize
30
+ rows={1}
31
+ value={block.text ?? ''}
32
+ onInput={(event) =>
33
+ onUpdate(block.id, {
34
+ text: (event.currentTarget as HTMLTextAreaElement).value
35
+ })}
36
+ onKeyDown={(event) => {
37
+ const value = (event.currentTarget as HTMLTextAreaElement).value.trim();
38
+ if (event.key === ' ' && value === '-') {
39
+ event.preventDefault();
40
+ onConvertToList?.(block.id, 'bullet_list');
41
+ return;
42
+ }
43
+ if (event.key === ' ' && /^\d+\.$/.test(value)) {
44
+ event.preventDefault();
45
+ onConvertToList?.(block.id, 'numbered_list');
46
+ return;
47
+ }
48
+ if (event.key === 'Enter' && !event.shiftKey) {
49
+ event.preventDefault();
50
+ const textarea = event.currentTarget as HTMLTextAreaElement;
51
+ const text = textarea.value;
52
+ const before = text.slice(0, textarea.selectionStart);
53
+ const after = text.slice(textarea.selectionEnd);
54
+ if (!text.trim()) {
55
+ onRemoveBlock?.(block.id);
56
+ return;
57
+ }
58
+ onCreateParagraphAfter?.(block.id, after, before);
59
+ }
60
+ if (
61
+ event.key === 'Backspace' &&
62
+ !event.shiftKey &&
63
+ !event.metaKey &&
64
+ !event.ctrlKey &&
65
+ !event.altKey
66
+ ) {
67
+ const textarea = event.currentTarget as HTMLTextAreaElement;
68
+ if (textarea.selectionStart === 0 && textarea.selectionEnd === 0) {
69
+ event.preventDefault();
70
+ onMergeBlockWithPrevious?.(block.id);
71
+ }
72
+ }
73
+ }}
74
+ {shouldFocus}
75
+ {focusPosition}
76
+ {onFocused}
77
+ className="text-[16px] leading-7 text-zinc-700 placeholder:text-zinc-300"
78
+ placeholder="Block content"
79
+ />
@@ -0,0 +1,15 @@
1
+ import type { BlockDraft } from './types.js';
2
+ type $$ComponentProps = {
3
+ block: BlockDraft;
4
+ onUpdate: (id: string, patch: Partial<BlockDraft>) => void;
5
+ onCreateParagraphAfter?: (id: string, text?: string, currentText?: string | null) => void;
6
+ onMergeBlockWithPrevious?: (id: string) => void;
7
+ onConvertToList?: (id: string, kind: 'bullet_list' | 'numbered_list') => void;
8
+ onRemoveBlock?: (id: string) => void;
9
+ shouldFocus?: boolean;
10
+ focusPosition?: number | null;
11
+ onFocused?: () => void;
12
+ };
13
+ declare const ArticleBlockFallback: import("svelte").Component<$$ComponentProps, {}, "">;
14
+ type ArticleBlockFallback = ReturnType<typeof ArticleBlockFallback>;
15
+ export default ArticleBlockFallback;
@@ -0,0 +1,73 @@
1
+ <script lang="ts">
2
+ import TextEditor from '../TextEditor';
3
+ import type { BlockDraft } from './types.js';
4
+
5
+ let {
6
+ block,
7
+ onUpdate,
8
+ onCreateParagraphAfter,
9
+ onMergeBlockWithPrevious,
10
+ onRemoveBlock,
11
+ shouldFocus,
12
+ focusPosition,
13
+ onFocused
14
+ } = $props<{
15
+ block: BlockDraft;
16
+ onUpdate: (id: string, patch: Partial<BlockDraft>) => void;
17
+ onCreateParagraphAfter?: (id: string, text?: string, currentText?: string | null) => void;
18
+ onMergeBlockWithPrevious?: (id: string) => void;
19
+ onRemoveBlock?: (id: string) => void;
20
+ shouldFocus?: boolean;
21
+ focusPosition?: number | null;
22
+ onFocused?: () => void;
23
+ }>();
24
+ </script>
25
+
26
+ <TextEditor
27
+ autosize
28
+ rows={1}
29
+ value={block.text ?? ''}
30
+ onInput={(event) =>
31
+ onUpdate(block.id, {
32
+ text: (event.currentTarget as HTMLTextAreaElement).value
33
+ })}
34
+ onKeyDown={(event) => {
35
+ const value = (event.currentTarget as HTMLTextAreaElement).value.trim();
36
+ if (event.key === 'Enter' && !event.shiftKey) {
37
+ event.preventDefault();
38
+ const textarea = event.currentTarget as HTMLTextAreaElement;
39
+ const text = textarea.value;
40
+ const before = text.slice(0, textarea.selectionStart);
41
+ const after = text.slice(textarea.selectionEnd);
42
+ if (!text.trim()) {
43
+ onRemoveBlock?.(block.id);
44
+ return;
45
+ }
46
+ onCreateParagraphAfter?.(block.id, after, before);
47
+ }
48
+ if (
49
+ event.key === 'Backspace' &&
50
+ !event.shiftKey &&
51
+ !event.metaKey &&
52
+ !event.ctrlKey &&
53
+ !event.altKey
54
+ ) {
55
+ const textarea = event.currentTarget as HTMLTextAreaElement;
56
+ if (textarea.selectionStart === 0 && textarea.selectionEnd === 0) {
57
+ event.preventDefault();
58
+ onMergeBlockWithPrevious?.(block.id);
59
+ }
60
+ }
61
+ }}
62
+ {shouldFocus}
63
+ {focusPosition}
64
+ {onFocused}
65
+ className={`placeholder:text-zinc-300 ${
66
+ Number(block.level ?? 2) <= 1
67
+ ? 'text-3xl font-semibold tracking-[-0.03em]'
68
+ : Number(block.level ?? 2) === 2
69
+ ? 'text-2xl font-semibold tracking-[-0.025em]'
70
+ : 'text-xl font-semibold'
71
+ }`}
72
+ placeholder="Heading"
73
+ />
@@ -0,0 +1,14 @@
1
+ import type { BlockDraft } from './types.js';
2
+ type $$ComponentProps = {
3
+ block: BlockDraft;
4
+ onUpdate: (id: string, patch: Partial<BlockDraft>) => void;
5
+ onCreateParagraphAfter?: (id: string, text?: string, currentText?: string | null) => void;
6
+ onMergeBlockWithPrevious?: (id: string) => void;
7
+ onRemoveBlock?: (id: string) => void;
8
+ shouldFocus?: boolean;
9
+ focusPosition?: number | null;
10
+ onFocused?: () => void;
11
+ };
12
+ declare const ArticleBlockHeading: import("svelte").Component<$$ComponentProps, {}, "">;
13
+ type ArticleBlockHeading = ReturnType<typeof ArticleBlockHeading>;
14
+ export default ArticleBlockHeading;
@@ -0,0 +1,48 @@
1
+ <script lang="ts">
2
+ import ArticleImagePreview from './ArticleImagePreview.svelte';
3
+ import TextEditor from '../TextEditor';
4
+ import type { BlockDraft } from './types.js';
5
+
6
+ let { block, titleFallback, onUpdate } = $props<{
7
+ block: BlockDraft;
8
+ titleFallback: string;
9
+ onUpdate: (id: string, patch: Partial<BlockDraft>) => void;
10
+ }>();
11
+ </script>
12
+
13
+ <div class="article-block-image">
14
+ <ArticleImagePreview src={block.imageURL} alt={block.imageAlt ?? titleFallback} />
15
+ <div>
16
+ <TextEditor
17
+ autosize
18
+ rows={1}
19
+ className="article-block-image-description"
20
+ value={block.imageAlt ?? ''}
21
+ onInput={(event) =>
22
+ onUpdate(block.id, {
23
+ imageAlt: (event.currentTarget as HTMLTextAreaElement).value
24
+ })}
25
+ placeholder="Alt text"
26
+ />
27
+ </div>
28
+ </div>
29
+
30
+ <style>
31
+ .article-block-image {
32
+ display: grid;
33
+ gap: 1rem;
34
+ }
35
+
36
+ :global(.article-block-image-description) {
37
+ border: 0;
38
+ background: transparent;
39
+ padding: 0;
40
+ color: #3f3f46;
41
+ font-size: 0.875rem;
42
+ line-height: 1.5rem;
43
+ }
44
+
45
+ :global(.article-block-image-description::placeholder) {
46
+ color: #d4d4d8;
47
+ }
48
+ </style>
@@ -0,0 +1,9 @@
1
+ import type { BlockDraft } from './types.js';
2
+ type $$ComponentProps = {
3
+ block: BlockDraft;
4
+ titleFallback: string;
5
+ onUpdate: (id: string, patch: Partial<BlockDraft>) => void;
6
+ };
7
+ declare const ArticleBlockImage: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type ArticleBlockImage = ReturnType<typeof ArticleBlockImage>;
9
+ export default ArticleBlockImage;
@@ -0,0 +1,120 @@
1
+ <script lang="ts">
2
+ import { ImageIcon, List, ListOrdered, Plus, Table2, Type } from '@lucide/svelte';
3
+ import Dropdown from '../Dropdown';
4
+ import type { BlockInsertKind } from './articleEditor.svelte.js';
5
+
6
+ let { blockID, onSelect, onInsertBlockAfter } = $props<{
7
+ blockID: string;
8
+ onSelect: (id: string) => void;
9
+ onInsertBlockAfter: (id: string, kind: BlockInsertKind) => void;
10
+ }>();
11
+
12
+ const insertBlockLabels: Record<BlockInsertKind, string> = {
13
+ paragraph: 'Paragraph',
14
+ image: 'Image',
15
+ table: 'Table',
16
+ bullet_list: 'Bulleted list',
17
+ numbered_list: 'Numbered list'
18
+ };
19
+ </script>
20
+
21
+ <Dropdown
22
+ value={null}
23
+ selectedLabel="Add block"
24
+ placement="bottom"
25
+ showCheck={false}
26
+ onValueChange={(value: BlockInsertKind | null) => {
27
+ if (typeof value !== 'string') return;
28
+ onInsertBlockAfter(blockID, value);
29
+ }}
30
+ >
31
+ {#snippet trigger(triggerState: any)}
32
+ <button
33
+ use:triggerState.useTrigger
34
+ type="button"
35
+ aria-label="Add block after"
36
+ aria-expanded={triggerState.open}
37
+ aria-haspopup="dialog"
38
+ class="article-block-control-button"
39
+ onclick={(event: MouseEvent) => {
40
+ event.stopPropagation();
41
+ onSelect(blockID);
42
+ triggerState.toggle();
43
+ }}
44
+ onkeydown={(event: KeyboardEvent) => {
45
+ if (event.key === 'Enter' || event.key === ' ') {
46
+ event.preventDefault();
47
+ event.stopPropagation();
48
+ onSelect(blockID);
49
+ triggerState.toggle();
50
+ }
51
+ }}
52
+ >
53
+ <Plus size={15} />
54
+ </button>
55
+ {/snippet}
56
+
57
+ <Dropdown.Section label="Insert block">
58
+ <Dropdown.Item value={'paragraph' as BlockInsertKind}>
59
+ <span class="article-block-control-menu-item">
60
+ <Type size={14} />
61
+ <span>{insertBlockLabels.paragraph}</span>
62
+ </span>
63
+ </Dropdown.Item>
64
+ <Dropdown.Item value={'image' as BlockInsertKind}>
65
+ <span class="article-block-control-menu-item">
66
+ <ImageIcon size={14} />
67
+ <span>{insertBlockLabels.image}</span>
68
+ </span>
69
+ </Dropdown.Item>
70
+ <Dropdown.Item value={'table' as BlockInsertKind}>
71
+ <span class="article-block-control-menu-item">
72
+ <Table2 size={14} />
73
+ <span>{insertBlockLabels.table}</span>
74
+ </span>
75
+ </Dropdown.Item>
76
+ <Dropdown.Item value={'bullet_list' as BlockInsertKind}>
77
+ <span class="article-block-control-menu-item">
78
+ <List size={14} />
79
+ <span>{insertBlockLabels.bullet_list}</span>
80
+ </span>
81
+ </Dropdown.Item>
82
+ <Dropdown.Item value={'numbered_list' as BlockInsertKind}>
83
+ <span class="article-block-control-menu-item">
84
+ <ListOrdered size={14} />
85
+ <span>{insertBlockLabels.numbered_list}</span>
86
+ </span>
87
+ </Dropdown.Item>
88
+ </Dropdown.Section>
89
+ </Dropdown>
90
+
91
+ <style>
92
+ .article-block-control-button {
93
+ display: flex;
94
+ width: 1.75rem;
95
+ height: 1.75rem;
96
+ align-items: center;
97
+ justify-content: center;
98
+ border: 0;
99
+ background: transparent;
100
+ color: #a1a1aa;
101
+ transition:
102
+ background-color 150ms,
103
+ color 150ms;
104
+ }
105
+
106
+ .article-block-control-button:hover {
107
+ background: #f5f5f4;
108
+ color: #3f3f46;
109
+ }
110
+
111
+ .article-block-control-menu-item {
112
+ display: inline-flex;
113
+ align-items: center;
114
+ gap: 0.5rem;
115
+ }
116
+
117
+ .article-block-control-menu-item :global(svg) {
118
+ flex: 0 0 auto;
119
+ }
120
+ </style>
@@ -0,0 +1,9 @@
1
+ import type { BlockInsertKind } from './articleEditor.svelte.js';
2
+ type $$ComponentProps = {
3
+ blockID: string;
4
+ onSelect: (id: string) => void;
5
+ onInsertBlockAfter: (id: string, kind: BlockInsertKind) => void;
6
+ };
7
+ declare const ArticleBlockInsertControl: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type ArticleBlockInsertControl = ReturnType<typeof ArticleBlockInsertControl>;
9
+ export default ArticleBlockInsertControl;