@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,114 @@
1
+ <script lang="ts">
2
+ import TextEditor from '../TextEditor';
3
+ import type { BlockDraft } from './types.js';
4
+
5
+ let {
6
+ block,
7
+ onUpdateItem,
8
+ onInsertItemAfter,
9
+ onMergeListItemWithPrevious,
10
+ onCreateParagraphAfter,
11
+ onRemoveListItem,
12
+ focusItemIndex,
13
+ focusPosition,
14
+ onFocused
15
+ } = $props<{
16
+ block: BlockDraft;
17
+ onUpdateItem: (blockID: string, index: number, value: string) => void;
18
+ onInsertItemAfter?: (
19
+ blockID: string,
20
+ index: number,
21
+ text?: string,
22
+ currentText?: string | null
23
+ ) => void;
24
+ onMergeListItemWithPrevious?: (blockID: string, index: number) => void;
25
+ onCreateParagraphAfter?: (id: string, text?: string, currentText?: string | null) => void;
26
+ onRemoveListItem?: (blockID: string, index: number) => void;
27
+ focusItemIndex?: number | null;
28
+ focusPosition?: number | null;
29
+ onFocused?: () => void;
30
+ }>();
31
+
32
+ const handleItemKeyDown = (event: KeyboardEvent, index: number) => {
33
+ const textarea = event.currentTarget as HTMLTextAreaElement;
34
+
35
+ if (event.key === 'Enter' && !event.shiftKey) {
36
+ event.preventDefault();
37
+ const text = textarea.value;
38
+ const before = text.slice(0, textarea.selectionStart);
39
+ const after = text.slice(textarea.selectionEnd);
40
+ if (!text.trim()) {
41
+ onRemoveListItem?.(block.id, index);
42
+ return;
43
+ }
44
+ onInsertItemAfter?.(block.id, index, after, before);
45
+ }
46
+
47
+ if (
48
+ event.key === 'Backspace' &&
49
+ !event.shiftKey &&
50
+ !event.metaKey &&
51
+ !event.ctrlKey &&
52
+ !event.altKey &&
53
+ textarea.selectionStart === 0 &&
54
+ textarea.selectionEnd === 0
55
+ ) {
56
+ event.preventDefault();
57
+ onMergeListItemWithPrevious?.(block.id, index);
58
+ }
59
+ };
60
+ </script>
61
+
62
+ {#if block.type === 'numbered_list'}
63
+ <ol
64
+ class="article-editor-list list-decimal space-y-1 py-1 pl-6 marker:text-[15px] marker:leading-7 marker:font-medium marker:text-zinc-500 marker:tabular-nums"
65
+ >
66
+ {#each block.items ?? [] as item, index}
67
+ <li class="article-editor-list-item pl-2">
68
+ <TextEditor
69
+ autosize
70
+ rows={1}
71
+ value={item}
72
+ onInput={(event) =>
73
+ onUpdateItem(block.id, index, (event.currentTarget as HTMLTextAreaElement).value)}
74
+ onKeyDown={(event) => handleItemKeyDown(event, index)}
75
+ shouldFocus={focusItemIndex === index}
76
+ focusPosition={focusItemIndex === index ? focusPosition : null}
77
+ {onFocused}
78
+ className="text-[17px] leading-7 text-zinc-700 placeholder:text-zinc-300"
79
+ placeholder="List item"
80
+ />
81
+ </li>
82
+ {/each}
83
+ </ol>
84
+ {:else}
85
+ <ul
86
+ class="article-editor-list list-disc space-y-1 py-1 pl-6 marker:text-[15px] marker:leading-7 marker:text-zinc-500"
87
+ >
88
+ {#each block.items ?? [] as item, index}
89
+ <li class="article-editor-list-item pl-2">
90
+ <TextEditor
91
+ autosize
92
+ rows={1}
93
+ value={item}
94
+ onInput={(event) =>
95
+ onUpdateItem(block.id, index, (event.currentTarget as HTMLTextAreaElement).value)}
96
+ onKeyDown={(event) => handleItemKeyDown(event, index)}
97
+ shouldFocus={focusItemIndex === index}
98
+ focusPosition={focusItemIndex === index ? focusPosition : null}
99
+ {onFocused}
100
+ className="text-[17px] leading-7 text-zinc-700 placeholder:text-zinc-300"
101
+ placeholder="List item"
102
+ />
103
+ </li>
104
+ {/each}
105
+ </ul>
106
+ {/if}
107
+
108
+ <style>
109
+ .article-editor-list-item :global(textarea) {
110
+ display: inline-block;
111
+ width: 100%;
112
+ vertical-align: top;
113
+ }
114
+ </style>
@@ -0,0 +1,15 @@
1
+ import type { BlockDraft } from './types.js';
2
+ type $$ComponentProps = {
3
+ block: BlockDraft;
4
+ onUpdateItem: (blockID: string, index: number, value: string) => void;
5
+ onInsertItemAfter?: (blockID: string, index: number, text?: string, currentText?: string | null) => void;
6
+ onMergeListItemWithPrevious?: (blockID: string, index: number) => void;
7
+ onCreateParagraphAfter?: (id: string, text?: string, currentText?: string | null) => void;
8
+ onRemoveListItem?: (blockID: string, index: number) => void;
9
+ focusItemIndex?: number | null;
10
+ focusPosition?: number | null;
11
+ onFocused?: () => void;
12
+ };
13
+ declare const ArticleBlockList: import("svelte").Component<$$ComponentProps, {}, "">;
14
+ type ArticleBlockList = ReturnType<typeof ArticleBlockList>;
15
+ export default ArticleBlockList;
@@ -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-[17px] leading-8 text-zinc-700 placeholder:text-zinc-300"
78
+ placeholder="Type something thoughtful..."
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 ArticleBlockParagraph: import("svelte").Component<$$ComponentProps, {}, "">;
14
+ type ArticleBlockParagraph = ReturnType<typeof ArticleBlockParagraph>;
15
+ export default ArticleBlockParagraph;
@@ -0,0 +1,127 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import type { BlockInsertKind, BlockTextFormat } from './articleEditor.svelte.js';
4
+ import ArticleBlockDragControl from './ArticleBlockDragControl.svelte';
5
+ import ArticleBlockInsertControl from './ArticleBlockInsertControl.svelte';
6
+ import type { BlockDraft } from './types.js';
7
+
8
+ let {
9
+ block,
10
+ draggedBlockID,
11
+ dropPlacement,
12
+ textFormat,
13
+ canChangeTextFormat,
14
+ onSelect,
15
+ onChangeTextFormat,
16
+ onInsertBlockAfter,
17
+ onDragOver,
18
+ onDragLeave,
19
+ onDrop,
20
+ onDragStart,
21
+ onDragEnd,
22
+ children
23
+ } = $props<{
24
+ block: BlockDraft;
25
+ draggedBlockID: string | null;
26
+ dropPlacement: 'before' | 'after' | null;
27
+ textFormat: BlockTextFormat | null;
28
+ canChangeTextFormat: boolean;
29
+ onSelect: (id: string) => void;
30
+ onChangeTextFormat: (id: string, format: BlockTextFormat) => void;
31
+ onInsertBlockAfter: (id: string, kind: BlockInsertKind) => void;
32
+ onDragOver: (event: DragEvent, id: string) => void;
33
+ onDragLeave: (event: DragEvent) => void;
34
+ onDrop: (event: DragEvent, id: string) => void;
35
+ onDragStart: (event: DragEvent, id: string) => void;
36
+ onDragEnd: () => void;
37
+ children?: Snippet;
38
+ }>();
39
+
40
+ const shouldHandleBlockKey = (event: KeyboardEvent) => event.currentTarget === event.target;
41
+ </script>
42
+
43
+ <div
44
+ data-block-row={block.id}
45
+ role="button"
46
+ tabindex="0"
47
+ class="article-block-shell"
48
+ class:article-block-shell-dragging={draggedBlockID === block.id}
49
+ class:article-block-shell-drop-before={dropPlacement === 'before'}
50
+ class:article-block-shell-drop-after={dropPlacement === 'after'}
51
+ onclick={() => onSelect(block.id)}
52
+ onkeydown={(event: KeyboardEvent) => {
53
+ if (!shouldHandleBlockKey(event)) return;
54
+ if (event.key === 'Enter' || event.key === ' ') {
55
+ event.preventDefault();
56
+ onSelect(block.id);
57
+ }
58
+ }}
59
+ ondragover={(event: DragEvent) => onDragOver(event, block.id)}
60
+ ondragleave={onDragLeave}
61
+ ondrop={(event: DragEvent) => onDrop(event, block.id)}
62
+ >
63
+ <div class="article-block-shell-grid">
64
+ <div class="article-block-shell-handle">
65
+ <ArticleBlockInsertControl blockID={block.id} {onSelect} {onInsertBlockAfter} />
66
+ <ArticleBlockDragControl
67
+ {block}
68
+ {textFormat}
69
+ {canChangeTextFormat}
70
+ {onSelect}
71
+ {onChangeTextFormat}
72
+ {onDragStart}
73
+ {onDragEnd}
74
+ />
75
+ </div>
76
+
77
+ <div class="article-block-shell-content">
78
+ {#if children}
79
+ {@render children()}
80
+ {/if}
81
+ </div>
82
+ </div>
83
+ </div>
84
+
85
+ <style>
86
+ .article-block-shell {
87
+ border-block: 2px solid transparent;
88
+ transition: opacity 150ms;
89
+ }
90
+
91
+ .article-block-shell-dragging {
92
+ opacity: 0.45;
93
+ }
94
+
95
+ .article-block-shell-drop-before {
96
+ border-top-color: #18181b;
97
+ }
98
+
99
+ .article-block-shell-drop-after {
100
+ border-bottom-color: #18181b;
101
+ }
102
+
103
+ .article-block-shell-grid {
104
+ display: grid;
105
+ grid-template-columns: 72px minmax(0, 1fr);
106
+ padding: 0.25rem;
107
+ }
108
+
109
+ .article-block-shell-handle {
110
+ display: flex;
111
+ justify-content: center;
112
+ gap: 0.25rem;
113
+ padding-block: 0.75rem;
114
+ opacity: 0;
115
+ transition: opacity 150ms;
116
+ }
117
+
118
+ .article-block-shell:hover .article-block-shell-handle,
119
+ .article-block-shell:focus-within .article-block-shell-handle {
120
+ opacity: 1;
121
+ }
122
+
123
+ .article-block-shell-content {
124
+ min-width: 0;
125
+ padding: 0.75rem 1rem;
126
+ }
127
+ </style>
@@ -0,0 +1,22 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { BlockInsertKind, BlockTextFormat } from './articleEditor.svelte.js';
3
+ import type { BlockDraft } from './types.js';
4
+ type $$ComponentProps = {
5
+ block: BlockDraft;
6
+ draggedBlockID: string | null;
7
+ dropPlacement: 'before' | 'after' | null;
8
+ textFormat: BlockTextFormat | null;
9
+ canChangeTextFormat: boolean;
10
+ onSelect: (id: string) => void;
11
+ onChangeTextFormat: (id: string, format: BlockTextFormat) => void;
12
+ onInsertBlockAfter: (id: string, kind: BlockInsertKind) => void;
13
+ onDragOver: (event: DragEvent, id: string) => void;
14
+ onDragLeave: (event: DragEvent) => void;
15
+ onDrop: (event: DragEvent, id: string) => void;
16
+ onDragStart: (event: DragEvent, id: string) => void;
17
+ onDragEnd: () => void;
18
+ children?: Snippet;
19
+ };
20
+ declare const ArticleBlockShell: import("svelte").Component<$$ComponentProps, {}, "">;
21
+ type ArticleBlockShell = ReturnType<typeof ArticleBlockShell>;
22
+ export default ArticleBlockShell;
@@ -0,0 +1,274 @@
1
+ <script lang="ts">
2
+ import { Plus, Trash2 } from '@lucide/svelte';
3
+ import type { BlockDraft } from './types.js';
4
+
5
+ let { block, onUpdateHeader, onUpdateCell, onAddColumn, onAddRow, onRemoveColumn, onRemoveRow } =
6
+ $props<{
7
+ block: BlockDraft;
8
+ onUpdateHeader: (blockID: string, cellIndex: number, value: string) => void;
9
+ onUpdateCell: (blockID: string, rowIndex: number, cellIndex: number, value: string) => void;
10
+ onAddColumn: (blockID: string) => void;
11
+ onAddRow: (blockID: string) => void;
12
+ onRemoveColumn: (blockID: string, columnIndex: number) => void;
13
+ onRemoveRow: (blockID: string, rowIndex: number) => void;
14
+ }>();
15
+
16
+ const columnCount = $derived(
17
+ Math.max((block.columns ?? []).length, block.rows?.[0]?.length ?? 0, 1)
18
+ );
19
+ const rowCount = $derived(Math.max((block.rows ?? []).length, 1));
20
+
21
+ const columnHasContent = (columnIndex: number) =>
22
+ Boolean(block.columns?.[columnIndex]?.trim()) ||
23
+ Boolean(block.rows?.some((row: string[]) => row[columnIndex]?.trim()));
24
+
25
+ const rowHasContent = (rowIndex: number) =>
26
+ Boolean(block.rows?.[rowIndex]?.some((cell: string) => cell.trim()));
27
+
28
+ const confirmDestructiveChange = (message: string) =>
29
+ typeof window === 'undefined' || window.confirm(message);
30
+
31
+ const removeColumn = (columnIndex: number) => {
32
+ if (columnCount <= 1) return;
33
+ if (
34
+ columnHasContent(columnIndex) &&
35
+ !confirmDestructiveChange('Remove this column and its content?')
36
+ ) {
37
+ return;
38
+ }
39
+ onRemoveColumn(block.id, columnIndex);
40
+ };
41
+
42
+ const removeRow = (rowIndex: number) => {
43
+ if (rowCount <= 1) return;
44
+ if (rowHasContent(rowIndex) && !confirmDestructiveChange('Remove this row and its content?')) {
45
+ return;
46
+ }
47
+ onRemoveRow(block.id, rowIndex);
48
+ };
49
+ </script>
50
+
51
+ <div class="article-block-table-shell">
52
+ <div class="article-block-table-scroll">
53
+ <table class="article-block-table">
54
+ {#if (block.columns ?? []).length > 0}
55
+ <thead class="article-block-table-head">
56
+ <tr>
57
+ {#each block.columns ?? [] as column, columnIndex}
58
+ <th class="article-block-table-header">
59
+ <input
60
+ class="article-block-table-header-input"
61
+ value={column}
62
+ oninput={(event) =>
63
+ onUpdateHeader(
64
+ block.id,
65
+ columnIndex,
66
+ (event.currentTarget as HTMLInputElement).value
67
+ )}
68
+ />
69
+ <button
70
+ type="button"
71
+ aria-label="Remove column"
72
+ disabled={columnCount <= 1}
73
+ class="article-block-table-remove-column"
74
+ onclick={() => removeColumn(columnIndex)}
75
+ >
76
+ <Trash2 size={14} />
77
+ </button>
78
+ </th>
79
+ {/each}
80
+ </tr>
81
+ </thead>
82
+ {/if}
83
+ <tbody>
84
+ {#each block.rows ?? [] as row, rowIndex}
85
+ <tr class="article-block-table-row">
86
+ {#each row as cell, cellIndex}
87
+ <td class="article-block-table-cell">
88
+ <textarea
89
+ rows="2"
90
+ class="article-block-table-cell-input"
91
+ value={cell}
92
+ oninput={(event) =>
93
+ onUpdateCell(
94
+ block.id,
95
+ rowIndex,
96
+ cellIndex,
97
+ (event.currentTarget as HTMLTextAreaElement).value
98
+ )}
99
+ ></textarea>
100
+ </td>
101
+ {/each}
102
+ <td class="article-block-table-row-control">
103
+ <button
104
+ type="button"
105
+ aria-label="Remove row"
106
+ disabled={rowCount <= 1}
107
+ class="article-block-table-remove-row"
108
+ onclick={() => removeRow(rowIndex)}
109
+ >
110
+ <Trash2 size={14} />
111
+ </button>
112
+ </td>
113
+ </tr>
114
+ {/each}
115
+ </tbody>
116
+ </table>
117
+ </div>
118
+ <button
119
+ type="button"
120
+ aria-label="Add column"
121
+ class="article-block-table-add-column"
122
+ onclick={() => onAddColumn(block.id)}
123
+ >
124
+ <Plus size={16} />
125
+ </button>
126
+ <button
127
+ type="button"
128
+ aria-label="Add row"
129
+ class="article-block-table-add-row"
130
+ onclick={() => onAddRow(block.id)}
131
+ >
132
+ <Plus size={16} />
133
+ </button>
134
+ <div class="article-block-table-corner"></div>
135
+ </div>
136
+
137
+ <style>
138
+ .article-block-table-shell {
139
+ display: grid;
140
+ grid-template-columns: minmax(0, 1fr) 2.25rem;
141
+ grid-template-rows: auto 2.25rem;
142
+ }
143
+
144
+ .article-block-table-scroll {
145
+ overflow-x: auto;
146
+ border: 1px solid rgba(0, 0, 0, 0.08);
147
+ }
148
+
149
+ .article-block-table {
150
+ min-width: 100%;
151
+ border-collapse: collapse;
152
+ text-align: left;
153
+ font-size: 0.875rem;
154
+ }
155
+
156
+ .article-block-table-head {
157
+ background: #fafaf9;
158
+ }
159
+
160
+ .article-block-table-header {
161
+ position: relative;
162
+ border-bottom: 1px solid rgba(0, 0, 0, 0.08);
163
+ padding: 0.75rem;
164
+ }
165
+
166
+ .article-block-table-header-input {
167
+ width: 100%;
168
+ border: 0;
169
+ background: transparent;
170
+ padding-right: 2rem;
171
+ font-weight: 600;
172
+ outline: none;
173
+ }
174
+
175
+ .article-block-table-row {
176
+ border-top: 1px solid rgba(0, 0, 0, 0.08);
177
+ }
178
+
179
+ .article-block-table-cell {
180
+ padding: 0.75rem;
181
+ vertical-align: top;
182
+ }
183
+
184
+ .article-block-table-cell-input {
185
+ width: 100%;
186
+ resize: none;
187
+ border: 0;
188
+ background: transparent;
189
+ outline: none;
190
+ }
191
+
192
+ .article-block-table-row-control {
193
+ width: 2.25rem;
194
+ padding: 0.5rem 0.25rem;
195
+ vertical-align: middle;
196
+ }
197
+
198
+ .article-block-table-remove-column,
199
+ .article-block-table-remove-row,
200
+ .article-block-table-add-column,
201
+ .article-block-table-add-row {
202
+ display: flex;
203
+ align-items: center;
204
+ justify-content: center;
205
+ border: 0;
206
+ background: transparent;
207
+ color: #a1a1aa;
208
+ transition:
209
+ background-color 150ms,
210
+ color 150ms,
211
+ opacity 150ms;
212
+ }
213
+
214
+ .article-block-table-remove-column {
215
+ position: absolute;
216
+ top: 50%;
217
+ right: 0.5rem;
218
+ width: 1.5rem;
219
+ height: 1.5rem;
220
+ transform: translateY(-50%);
221
+ opacity: 0;
222
+ }
223
+
224
+ .article-block-table-remove-row {
225
+ width: 1.75rem;
226
+ height: 1.75rem;
227
+ opacity: 0;
228
+ }
229
+
230
+ .article-block-table-header:hover .article-block-table-remove-column,
231
+ .article-block-table-remove-column:focus,
232
+ .article-block-table-row:hover .article-block-table-remove-row,
233
+ .article-block-table-remove-row:focus {
234
+ opacity: 1;
235
+ }
236
+
237
+ .article-block-table-remove-column:hover,
238
+ .article-block-table-remove-row:hover {
239
+ background: #fef2f2;
240
+ color: #dc2626;
241
+ }
242
+
243
+ .article-block-table-remove-column:disabled,
244
+ .article-block-table-remove-row:disabled {
245
+ pointer-events: none;
246
+ opacity: 0;
247
+ }
248
+
249
+ .article-block-table-add-column,
250
+ .article-block-table-add-row {
251
+ border-color: rgba(0, 0, 0, 0.08);
252
+ border-style: solid;
253
+ }
254
+
255
+ .article-block-table-add-column {
256
+ border-width: 1px 1px 1px 0;
257
+ }
258
+
259
+ .article-block-table-add-row {
260
+ border-width: 0 1px 1px 1px;
261
+ }
262
+
263
+ .article-block-table-add-column:hover,
264
+ .article-block-table-add-row:hover {
265
+ background: #f5f5f4;
266
+ color: #3f3f46;
267
+ }
268
+
269
+ .article-block-table-corner {
270
+ border-right: 1px solid rgba(0, 0, 0, 0.08);
271
+ border-bottom: 1px solid rgba(0, 0, 0, 0.08);
272
+ background: rgba(250, 250, 249, 0.5);
273
+ }
274
+ </style>
@@ -0,0 +1,13 @@
1
+ import type { BlockDraft } from './types.js';
2
+ type $$ComponentProps = {
3
+ block: BlockDraft;
4
+ onUpdateHeader: (blockID: string, cellIndex: number, value: string) => void;
5
+ onUpdateCell: (blockID: string, rowIndex: number, cellIndex: number, value: string) => void;
6
+ onAddColumn: (blockID: string) => void;
7
+ onAddRow: (blockID: string) => void;
8
+ onRemoveColumn: (blockID: string, columnIndex: number) => void;
9
+ onRemoveRow: (blockID: string, rowIndex: number) => void;
10
+ };
11
+ declare const ArticleBlockTable: import("svelte").Component<$$ComponentProps, {}, "">;
12
+ type ArticleBlockTable = ReturnType<typeof ArticleBlockTable>;
13
+ export default ArticleBlockTable;