@commonpub/editor 0.7.3 → 0.7.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@commonpub/editor",
3
- "version": "0.7.3",
3
+ "version": "0.7.4",
4
4
  "type": "module",
5
5
  "description": "TipTap block editor with 18+ maker-focused extensions for CommonPub",
6
6
  "license": "AGPL-3.0-or-later",
@@ -24,6 +24,8 @@ const flatBlocks = computed(() => {
24
24
  return props.groups.flatMap((g) => g.blocks);
25
25
  });
26
26
 
27
+ const isSearching = computed(() => search.value.trim().length > 0);
28
+
27
29
  const filteredBlocks = computed(() => {
28
30
  const q = search.value.toLowerCase();
29
31
  if (!q) return flatBlocks.value;
@@ -32,6 +34,13 @@ const filteredBlocks = computed(() => {
32
34
  );
33
35
  });
34
36
 
37
+ /** Flat index of a block across all groups (for keyboard nav) */
38
+ function globalIndex(groupIdx: number, blockIdx: number): number {
39
+ let idx = 0;
40
+ for (let g = 0; g < groupIdx; g++) idx += props.groups[g]!.blocks.length;
41
+ return idx + blockIdx;
42
+ }
43
+
35
44
  watch(() => props.visible, (v) => {
36
45
  if (v) {
37
46
  search.value = '';
@@ -104,7 +113,29 @@ onUnmounted(() => {
104
113
  />
105
114
  </div>
106
115
  <div class="cpub-picker-body">
107
- <template v-if="filteredBlocks.length > 0">
116
+ <!-- Grouped view (no search) -->
117
+ <template v-if="!isSearching && groups.length > 0">
118
+ <template v-for="(group, gi) in groups" :key="group.name">
119
+ <div class="cpub-picker-group-header">{{ group.name }}</div>
120
+ <button
121
+ v-for="(block, bi) in group.blocks"
122
+ :key="block.type + (block.attrs?.variant ?? '')"
123
+ :data-block="block.type"
124
+ class="cpub-picker-item"
125
+ :class="{ 'cpub-picker-item--active': globalIndex(gi, bi) === selectedIndex }"
126
+ @mouseenter="selectedIndex = globalIndex(gi, bi)"
127
+ @click="selectBlock(block)"
128
+ >
129
+ <span class="cpub-picker-icon"><i :class="['fa-solid', block.icon]"></i></span>
130
+ <span class="cpub-picker-text">
131
+ <span class="cpub-picker-label">{{ block.label }}</span>
132
+ <span v-if="block.description" class="cpub-picker-desc">{{ block.description }}</span>
133
+ </span>
134
+ </button>
135
+ </template>
136
+ </template>
137
+ <!-- Flat filtered view (searching) -->
138
+ <template v-else-if="filteredBlocks.length > 0">
108
139
  <button
109
140
  v-for="(block, i) in filteredBlocks"
110
141
  :key="block.type + (block.attrs?.variant ?? '')"
@@ -179,6 +210,21 @@ onUnmounted(() => {
179
210
  padding: 4px;
180
211
  }
181
212
 
213
+ .cpub-picker-group-header {
214
+ font-family: var(--font-mono);
215
+ font-size: 9px;
216
+ font-weight: 700;
217
+ text-transform: uppercase;
218
+ letter-spacing: 0.08em;
219
+ color: var(--text-faint);
220
+ padding: 8px 10px 4px;
221
+ margin-top: 2px;
222
+ }
223
+
224
+ .cpub-picker-group-header:first-child {
225
+ margin-top: 0;
226
+ }
227
+
182
228
  .cpub-picker-item {
183
229
  display: flex;
184
230
  align-items: center;
@@ -50,6 +50,15 @@ watch(() => props.selected, (sel) => {
50
50
  function onDragStart(event: DragEvent): void {
51
51
  event.dataTransfer?.setData('text/plain', props.block.id);
52
52
  event.dataTransfer!.effectAllowed = 'move';
53
+
54
+ // Custom drag preview showing block type
55
+ const preview = document.createElement('div');
56
+ preview.textContent = props.block.type.replace(/_/g, ' ');
57
+ preview.style.cssText = 'position:fixed;top:-999px;left:-999px;padding:6px 12px;background:#1a1a1a;color:#eee;font-family:monospace;font-size:11px;font-weight:600;text-transform:capitalize;border:2px solid #333;pointer-events:none;white-space:nowrap;';
58
+ document.body.appendChild(preview);
59
+ event.dataTransfer!.setDragImage(preview, 0, 0);
60
+ requestAnimationFrame(() => document.body.removeChild(preview));
61
+
53
62
  emit('drag-start', event);
54
63
  }
55
64