@edc-motor/ui 0.4.28 → 0.4.29
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": "@edc-motor/ui",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.29",
|
|
4
4
|
"description": "EdC Motor — componentes públicos Vue 3 + tokens SCSS para webs de juegos de mesa (paquete fuente: lo compila el consumidor con Vite)",
|
|
5
5
|
"license": "GPL-3.0-only",
|
|
6
6
|
"type": "module",
|
|
@@ -3,6 +3,7 @@ import { computed, ref, watch, onBeforeUnmount, onMounted, nextTick } from 'vue'
|
|
|
3
3
|
import { useEditor, EditorContent } from '@tiptap/vue-3'
|
|
4
4
|
import StarterKit from '@tiptap/starter-kit'
|
|
5
5
|
import Image from '@tiptap/extension-image'
|
|
6
|
+
import { useDropdownPanel } from '../composables/useDropdownPanel'
|
|
6
7
|
import UnderlineExtension from '@tiptap/extension-underline'
|
|
7
8
|
import LinkExtension from '@tiptap/extension-link'
|
|
8
9
|
import TableExtension from '@tiptap/extension-table'
|
|
@@ -331,7 +332,12 @@ function insertTable() {
|
|
|
331
332
|
|
|
332
333
|
// --- Selector de iconos ---
|
|
333
334
|
const pickerOpen = ref(false)
|
|
334
|
-
const pickerRef = ref<HTMLElement>()
|
|
335
|
+
const pickerRef = ref<HTMLElement | null>(null)
|
|
336
|
+
const iconsPanelRef = ref<HTMLElement | null>(null)
|
|
337
|
+
// Top layer (popover): dentro de un modal, el overflow del cuerpo recortaba
|
|
338
|
+
// el panel y no se podían elegir todos los iconos. Ancho propio, sin igualar
|
|
339
|
+
// al trigger.
|
|
340
|
+
useDropdownPanel(pickerRef, iconsPanelRef, pickerOpen, { matchWidth: false })
|
|
335
341
|
|
|
336
342
|
function insertIcon(icon: RichIcon) {
|
|
337
343
|
editor.value?.chain().focus().setImage({ src: icon.url, alt: icon.name, title: icon.name }).run()
|
|
@@ -341,7 +347,9 @@ function insertIcon(icon: RichIcon) {
|
|
|
341
347
|
// --- Enlaces: mini-popover con la URL (mismo patrón que el selector de
|
|
342
348
|
// iconos: botón + panel flotante, cierra con Escape o click fuera) ---
|
|
343
349
|
const linkPopoverOpen = ref(false)
|
|
344
|
-
const linkPickerRef = ref<HTMLElement>()
|
|
350
|
+
const linkPickerRef = ref<HTMLElement | null>(null)
|
|
351
|
+
const linkPanelRef = ref<HTMLElement | null>(null)
|
|
352
|
+
useDropdownPanel(linkPickerRef, linkPanelRef, linkPopoverOpen, { matchWidth: false })
|
|
345
353
|
const linkInputRef = ref<HTMLInputElement>()
|
|
346
354
|
const linkUrlInput = ref('')
|
|
347
355
|
|
|
@@ -451,7 +459,12 @@ function onSourceInput(value: string) {
|
|
|
451
459
|
>
|
|
452
460
|
<LinkIcon :size="16" />
|
|
453
461
|
</button>
|
|
454
|
-
<div
|
|
462
|
+
<div
|
|
463
|
+
v-if="linkPopoverOpen"
|
|
464
|
+
ref="linkPanelRef"
|
|
465
|
+
class="rich-text__link-popover"
|
|
466
|
+
popover="manual"
|
|
467
|
+
>
|
|
455
468
|
<input
|
|
456
469
|
ref="linkInputRef"
|
|
457
470
|
v-model="linkUrlInput"
|
|
@@ -538,7 +551,7 @@ function onSourceInput(value: string) {
|
|
|
538
551
|
>
|
|
539
552
|
<Smile :size="16" />
|
|
540
553
|
</button>
|
|
541
|
-
<div v-if="pickerOpen" class="rich-text__icons">
|
|
554
|
+
<div v-if="pickerOpen" ref="iconsPanelRef" class="rich-text__icons" popover="manual">
|
|
542
555
|
<button
|
|
543
556
|
v-for="icon in icons"
|
|
544
557
|
:key="icon.url"
|
|
@@ -20,7 +20,14 @@ export function useDropdownPanel(
|
|
|
20
20
|
anchor: Ref<HTMLElement | null>,
|
|
21
21
|
panel: Ref<HTMLElement | null>,
|
|
22
22
|
open: Ref<boolean>,
|
|
23
|
+
options: {
|
|
24
|
+
/** Igualar el ancho del panel al del trigger (los select). Los popovers
|
|
25
|
+
* con ancho propio (selector de iconos, popover del enlace) lo apagan:
|
|
26
|
+
* conservan su ancho y solo se CLAMPEA su left para no salirse. */
|
|
27
|
+
matchWidth?: boolean
|
|
28
|
+
} = {},
|
|
23
29
|
) {
|
|
30
|
+
const { matchWidth = true } = options
|
|
24
31
|
const GAP = 4 // $space-1: aire entre trigger y panel, como el CSS absolute
|
|
25
32
|
|
|
26
33
|
/** Ancla el panel bajo el trigger (o encima, si abajo no cabe y arriba sí). */
|
|
@@ -29,8 +36,11 @@ export function useDropdownPanel(
|
|
|
29
36
|
const p = panel.value
|
|
30
37
|
if (!a || !p) return
|
|
31
38
|
const r = a.getBoundingClientRect()
|
|
32
|
-
p.style.width = `${r.width}px`
|
|
33
|
-
|
|
39
|
+
if (matchWidth) p.style.width = `${r.width}px`
|
|
40
|
+
const left = matchWidth
|
|
41
|
+
? r.left
|
|
42
|
+
: Math.max(GAP, Math.min(r.left, window.innerWidth - p.offsetWidth - GAP))
|
|
43
|
+
p.style.left = `${left}px`
|
|
34
44
|
const height = p.offsetHeight
|
|
35
45
|
const below = window.innerHeight - r.bottom - GAP
|
|
36
46
|
const openUp = height > below && r.top > window.innerHeight - r.bottom
|