Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d9023a0ddc | |||
| c646df9fe3 | |||
| 7fc072ad08 |
125
.playground/pages/composant/form/client.vue
Normal file
125
.playground/pages/composant/form/client.vue
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="flex justify-center mt-8">
|
||||||
|
<div>
|
||||||
|
<div class="w-[1348px] grid grid-cols-3 gap-x-[160px] gap-y-8">
|
||||||
|
<MalioInputText
|
||||||
|
label="Nom du client (Entreprise)"
|
||||||
|
/>
|
||||||
|
<MalioInputText
|
||||||
|
label="Nom du contact principal"
|
||||||
|
/>
|
||||||
|
<MalioInputText
|
||||||
|
label="Prénom du contact principal"
|
||||||
|
/>
|
||||||
|
<MalioSelectCheckbox
|
||||||
|
label="Catégorie"
|
||||||
|
v-model="multiselectValue"
|
||||||
|
:options="[
|
||||||
|
{label: 'Catégorie 1', value: 'Catégorie 1'},
|
||||||
|
{label: 'Catégorie 2', value: 'Catégorie 2'}
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
<MalioInputText
|
||||||
|
label="Téléphone"
|
||||||
|
/>
|
||||||
|
<MalioInputText
|
||||||
|
label="Email"
|
||||||
|
/>
|
||||||
|
<MalioSelect
|
||||||
|
value=""
|
||||||
|
label="Distributeur / Courtier"
|
||||||
|
:options="[
|
||||||
|
{label: 'Dépend du distributeur', value: 'Dépend du distributeur'},
|
||||||
|
{label: 'Distributeur', value: 'Distributeur'},
|
||||||
|
{label: 'Courtier', value: 'Courtier'},
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
<MalioSelect
|
||||||
|
value=""
|
||||||
|
label="Nom du courtier"
|
||||||
|
:options="[
|
||||||
|
{label: 'Nom 1', value: 'Nom 1'}
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
<MalioSelect
|
||||||
|
value=""
|
||||||
|
label="Distributeur / Courtier"
|
||||||
|
:options="[
|
||||||
|
{label: 'Nom 1', value: 'Nom 1'}
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
<MalioCheckbox label="Prestation de triage"/>
|
||||||
|
</div>
|
||||||
|
<div class="mt-16 flex justify-center">
|
||||||
|
<MalioButton label="Valider" variant="primary"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-center mt-16">
|
||||||
|
<div>
|
||||||
|
<div class="w-[1348px] grid grid-cols-3 gap-x-[80px] gap-y-8">
|
||||||
|
<MalioInputText
|
||||||
|
label="Nom du client (Entreprise)"
|
||||||
|
/>
|
||||||
|
<MalioInputText
|
||||||
|
label="Nom du contact principal"
|
||||||
|
/>
|
||||||
|
<MalioInputText
|
||||||
|
label="Prénom du contact principal"
|
||||||
|
/>
|
||||||
|
<MalioSelectCheckbox
|
||||||
|
label="Catégorie"
|
||||||
|
v-model="multiselectValue"
|
||||||
|
:options="[
|
||||||
|
{label: 'Catégorie 1', value: 'Catégorie 1'},
|
||||||
|
{label: 'Catégorie 2', value: 'Catégorie 2'}
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
<MalioInputText
|
||||||
|
label="Téléphone"
|
||||||
|
/>
|
||||||
|
<MalioInputText
|
||||||
|
label="Email"
|
||||||
|
/>
|
||||||
|
<MalioSelect
|
||||||
|
value=""
|
||||||
|
label="Distributeur / Courtier"
|
||||||
|
:options="[
|
||||||
|
{label: 'Dépend du distributeur', value: 'Dépend du distributeur'},
|
||||||
|
{label: 'Distributeur', value: 'Distributeur'},
|
||||||
|
{label: 'Courtier', value: 'Courtier'},
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
<MalioSelect
|
||||||
|
value=""
|
||||||
|
label="Nom du courtier"
|
||||||
|
:options="[
|
||||||
|
{label: 'Nom 1', value: 'Nom 1'}
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
<MalioSelect
|
||||||
|
value=""
|
||||||
|
label="Distributeur / Courtier"
|
||||||
|
:options="[
|
||||||
|
{label: 'Nom 1', value: 'Nom 1'}
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
<MalioCheckbox label="Prestation de triage"/>
|
||||||
|
</div>
|
||||||
|
<div class="mt-16 flex justify-center">
|
||||||
|
<MalioButton label="Valider" variant="primary"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {ref} from "vue";
|
||||||
|
import MalioSelect from "../../../../app/components/malio/select/Select.vue";
|
||||||
|
import MalioCheckbox from "../../../../app/components/malio/checkbox/Checkbox.vue";
|
||||||
|
import MalioButton from "../../../../app/components/malio/button/Button.vue";
|
||||||
|
|
||||||
|
const multiselectValue = ref<Array<string | number>>([])
|
||||||
|
</script>
|
||||||
@@ -113,12 +113,20 @@ const groups = computed<Group[]>(() => {
|
|||||||
categoryMap.get(category)!.push({name, label: name})
|
categoryMap.get(category)!.push({name, label: name})
|
||||||
})
|
})
|
||||||
|
|
||||||
return Array.from(categoryMap.entries())
|
const componentGroups = Array.from(categoryMap.entries())
|
||||||
.sort(([a], [b]) => a.localeCompare(b))
|
.sort(([a], [b]) => a.localeCompare(b))
|
||||||
.map(([category, items]) => ({
|
.map(([category, items]) => ({
|
||||||
category: category.charAt(0).toUpperCase() + category.slice(1),
|
category: category.charAt(0).toUpperCase() + category.slice(1),
|
||||||
items: items.sort((a, b) => a.label.localeCompare(b.label)),
|
items: items.sort((a, b) => a.label.localeCompare(b.label)),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
return [
|
||||||
|
...componentGroups,
|
||||||
|
{
|
||||||
|
category: 'Form',
|
||||||
|
items: [{name: 'client', label: 'Client'}],
|
||||||
|
},
|
||||||
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
const openCategories = reactive(new Set<string>())
|
const openCategories = reactive(new Set<string>())
|
||||||
|
|||||||
@@ -134,7 +134,9 @@ Zone de texte multiligne avec compteur et redimensionnement.
|
|||||||
|
|
||||||
## MalioInputRichText
|
## MalioInputRichText
|
||||||
|
|
||||||
Éditeur de texte riche basé sur **TipTap v3** + **StarterKit** + **tiptap-markdown**. Toolbar avec gras, italique, barré, titres H2/H3, listes, citation, code, code-block, lien, undo/redo. Sortie en markdown (par défaut) ou HTML.
|
Éditeur de texte riche basé sur **TipTap v3** + **StarterKit** + **tiptap-markdown** + **TextStyle/Color/Highlight**. Toolbar avec gras, italique, barré, titres H2/H3, listes, citation, code, code-block, lien, **couleur du texte**, **surlignage**, undo/redo. Sortie en HTML (par défaut) ou markdown.
|
||||||
|
|
||||||
|
> Couleurs et surlignages ne sont **pas persistés en markdown**. Pour les conserver au save/reload, utiliser `output-format="html"`.
|
||||||
|
|
||||||
| Prop | Type | Défaut | Description |
|
| Prop | Type | Défaut | Description |
|
||||||
|------|------|--------|-------------|
|
|------|------|--------|-------------|
|
||||||
@@ -149,7 +151,7 @@ Zone de texte multiligne avec compteur et redimensionnement.
|
|||||||
| `hint` | `string` | `''` | Message d'aide |
|
| `hint` | `string` | `''` | Message d'aide |
|
||||||
| `error` | `string` | `''` | Message d'erreur |
|
| `error` | `string` | `''` | Message d'erreur |
|
||||||
| `success` | `string` | `''` | Message de succès |
|
| `success` | `string` | `''` | Message de succès |
|
||||||
| `outputFormat` | `'markdown' \| 'html'` | `'markdown'` | Format émis dans `update:modelValue` |
|
| `outputFormat` | `'markdown' \| 'html'` | `'html'` | Format émis dans `update:modelValue` |
|
||||||
| `groupClass` | `string` | `''` | Classes CSS conteneur (twMerge) |
|
| `groupClass` | `string` | `''` | Classes CSS conteneur (twMerge) |
|
||||||
| `labelClass` | `string` | `''` | Classes CSS label (twMerge) |
|
| `labelClass` | `string` | `''` | Classes CSS label (twMerge) |
|
||||||
| `editorClass` | `string` | `''` | Classes CSS wrapper éditeur (twMerge) |
|
| `editorClass` | `string` | `''` | Classes CSS wrapper éditeur (twMerge) |
|
||||||
@@ -159,7 +161,7 @@ Zone de texte multiligne avec compteur et redimensionnement.
|
|||||||
```vue
|
```vue
|
||||||
<MalioInputRichText v-model="note" label="Note" placeholder="Écrire ici…" />
|
<MalioInputRichText v-model="note" label="Note" placeholder="Écrire ici…" />
|
||||||
<MalioInputRichText v-model="cr" label="Compte-rendu" error="Trop court" />
|
<MalioInputRichText v-model="cr" label="Compte-rendu" error="Trop court" />
|
||||||
<MalioInputRichText v-model="article" label="Article" output-format="html" min-height="240px" />
|
<MalioInputRichText v-model="article" label="Article" min-height="240px" />
|
||||||
<MalioInputRichText :model-value="content" :editable="false" />
|
<MalioInputRichText :model-value="content" :editable="false" />
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -201,8 +203,6 @@ Liste déroulante.
|
|||||||
| `success` | `string` | `''` | Message de succès |
|
| `success` | `string` | `''` | Message de succès |
|
||||||
| `disabled` | `boolean` | `false` | Désactivé |
|
| `disabled` | `boolean` | `false` | Désactivé |
|
||||||
| `groupClass` | `string` | `''` | Classes CSS conteneur (twMerge) |
|
| `groupClass` | `string` | `''` | Classes CSS conteneur (twMerge) |
|
||||||
| `minWidth` | `string` | `'w-96'` | Classe largeur minimum |
|
|
||||||
| `maxWidth` | `string` | `''` | Classe largeur maximum |
|
|
||||||
| `rounded` | `string` | `'rounded-md'` | Classe border-radius |
|
| `rounded` | `string` | `'rounded-md'` | Classe border-radius |
|
||||||
| `textField` | `string` | `'text-lg'` | Classe taille texte bouton |
|
| `textField` | `string` | `'text-lg'` | Classe taille texte bouton |
|
||||||
| `textValue` | `string` | `'text-lg'` | Classe taille texte valeur |
|
| `textValue` | `string` | `'text-lg'` | Classe taille texte valeur |
|
||||||
|
|||||||
@@ -101,14 +101,14 @@ const mergedGroupClass = computed(() =>
|
|||||||
|
|
||||||
const mergedInputClass = computed(() =>
|
const mergedInputClass = computed(() =>
|
||||||
twMerge(
|
twMerge(
|
||||||
'inp-cbx peer',
|
'inp-cbx peer ',
|
||||||
props.inputClass,
|
props.inputClass,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
const mergedLabelClass = computed(() =>
|
const mergedLabelClass = computed(() =>
|
||||||
twMerge(
|
twMerge(
|
||||||
'cbx text-black',
|
'cbx text-black text-lg',
|
||||||
disabled.value ? 'cursor-not-allowed text-black/60' : '',
|
disabled.value ? 'cursor-not-allowed text-black/60' : '',
|
||||||
hasError.value ? 'text-m-error' : '',
|
hasError.value ? 'text-m-error' : '',
|
||||||
hasSuccess.value ? 'text-m-success' : '',
|
hasSuccess.value ? 'text-m-success' : '',
|
||||||
|
|||||||
@@ -61,10 +61,42 @@ describe('MalioInputRichText', () => {
|
|||||||
expect(wrapper.find('button[title="Gras"]').exists()).toBe(true)
|
expect(wrapper.find('button[title="Gras"]').exists()).toBe(true)
|
||||||
expect(wrapper.find('button[title="Italique"]').exists()).toBe(true)
|
expect(wrapper.find('button[title="Italique"]').exists()).toBe(true)
|
||||||
expect(wrapper.find('button[title="Lien"]').exists()).toBe(true)
|
expect(wrapper.find('button[title="Lien"]').exists()).toBe(true)
|
||||||
|
expect(wrapper.find('button[title="Couleur du texte"]').exists()).toBe(true)
|
||||||
|
expect(wrapper.find('button[title="Surlignage"]').exists()).toBe(true)
|
||||||
expect(wrapper.find('button[title="Annuler"]').exists()).toBe(true)
|
expect(wrapper.find('button[title="Annuler"]').exists()).toBe(true)
|
||||||
expect(wrapper.find('button[title="Rétablir"]').exists()).toBe(true)
|
expect(wrapper.find('button[title="Rétablir"]').exists()).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('opens and closes the text color palette', async () => {
|
||||||
|
const wrapper = await mountComponent({modelValue: ''})
|
||||||
|
|
||||||
|
expect(wrapper.find('[aria-label="Palette couleur du texte"]').exists()).toBe(false)
|
||||||
|
|
||||||
|
await wrapper.get('button[title="Couleur du texte"]').trigger('click')
|
||||||
|
expect(wrapper.find('[aria-label="Palette couleur du texte"]').exists()).toBe(true)
|
||||||
|
|
||||||
|
await wrapper.get('button[title="Couleur du texte"]').trigger('click')
|
||||||
|
expect(wrapper.find('[aria-label="Palette couleur du texte"]').exists()).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('opens the highlight palette and closes the color palette', async () => {
|
||||||
|
const wrapper = await mountComponent({modelValue: ''})
|
||||||
|
|
||||||
|
await wrapper.get('button[title="Couleur du texte"]').trigger('click')
|
||||||
|
expect(wrapper.find('[aria-label="Palette couleur du texte"]').exists()).toBe(true)
|
||||||
|
|
||||||
|
await wrapper.get('button[title="Surlignage"]').trigger('click')
|
||||||
|
expect(wrapper.find('[aria-label="Palette de surlignage"]').exists()).toBe(true)
|
||||||
|
expect(wrapper.find('[aria-label="Palette couleur du texte"]').exists()).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('disables color and highlight buttons when readonly', async () => {
|
||||||
|
const wrapper = await mountComponent({readonly: true, modelValue: ''})
|
||||||
|
|
||||||
|
expect(wrapper.get('button[title="Couleur du texte"]').attributes('disabled')).toBeDefined()
|
||||||
|
expect(wrapper.get('button[title="Surlignage"]').attributes('disabled')).toBeDefined()
|
||||||
|
})
|
||||||
|
|
||||||
it('does not render the toolbar in readonly display mode (editable=false)', async () => {
|
it('does not render the toolbar in readonly display mode (editable=false)', async () => {
|
||||||
const wrapper = await mountComponent({editable: false, modelValue: '**hi**'})
|
const wrapper = await mountComponent({editable: false, modelValue: '**hi**'})
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,110 @@
|
|||||||
|
|
||||||
<span class="mx-1 h-5 w-px bg-m-border" aria-hidden="true" />
|
<span class="mx-1 h-5 w-px bg-m-border" aria-hidden="true" />
|
||||||
|
|
||||||
|
<div class="relative">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="flex h-8 w-8 flex-col items-center justify-center rounded text-m-text transition-colors hover:bg-m-primary/10 disabled:cursor-not-allowed disabled:opacity-40"
|
||||||
|
:class="colorPickerOpen ? 'bg-m-primary/15 text-m-primary' : ''"
|
||||||
|
title="Couleur du texte"
|
||||||
|
aria-label="Couleur du texte"
|
||||||
|
:aria-expanded="colorPickerOpen"
|
||||||
|
:disabled="disabled || readonly"
|
||||||
|
@mousedown.prevent
|
||||||
|
@click="toggleColorPicker"
|
||||||
|
>
|
||||||
|
<IconifyIcon icon="mdi:format-color-text" :width="18" :height="18" />
|
||||||
|
<span
|
||||||
|
class="-mt-0.5 block h-1 w-4 rounded-sm"
|
||||||
|
:style="{ backgroundColor: currentTextColor ?? 'transparent' }"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
v-if="colorPickerOpen"
|
||||||
|
class="absolute left-0 top-full z-10 mt-1 flex w-44 flex-col gap-2 rounded-md border border-m-border bg-white p-2 shadow-lg"
|
||||||
|
role="dialog"
|
||||||
|
aria-label="Palette couleur du texte"
|
||||||
|
>
|
||||||
|
<div class="grid grid-cols-4 gap-1">
|
||||||
|
<button
|
||||||
|
v-for="swatch in textColorSwatches"
|
||||||
|
:key="swatch.value"
|
||||||
|
type="button"
|
||||||
|
class="h-7 w-7 rounded border border-m-border transition-transform hover:scale-110"
|
||||||
|
:class="currentTextColor === swatch.value ? 'ring-2 ring-m-primary ring-offset-1' : ''"
|
||||||
|
:style="{ backgroundColor: swatch.value }"
|
||||||
|
:title="swatch.label"
|
||||||
|
:aria-label="swatch.label"
|
||||||
|
@mousedown.prevent
|
||||||
|
@click="applyTextColor(swatch.value)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="flex items-center justify-center gap-1 rounded border border-m-border px-2 py-1 text-xs text-m-text transition-colors hover:bg-m-bg"
|
||||||
|
@mousedown.prevent
|
||||||
|
@click="applyTextColor(null)"
|
||||||
|
>
|
||||||
|
<IconifyIcon icon="mdi:format-color-marker-cancel" :width="14" :height="14" />
|
||||||
|
Aucune couleur
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="relative">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="flex h-8 w-8 flex-col items-center justify-center rounded text-m-text transition-colors hover:bg-m-primary/10 disabled:cursor-not-allowed disabled:opacity-40"
|
||||||
|
:class="highlightPickerOpen ? 'bg-m-primary/15 text-m-primary' : ''"
|
||||||
|
title="Surlignage"
|
||||||
|
aria-label="Surlignage"
|
||||||
|
:aria-expanded="highlightPickerOpen"
|
||||||
|
:disabled="disabled || readonly"
|
||||||
|
@mousedown.prevent
|
||||||
|
@click="toggleHighlightPicker"
|
||||||
|
>
|
||||||
|
<IconifyIcon icon="mdi:marker" :width="18" :height="18" />
|
||||||
|
<span
|
||||||
|
class="-mt-0.5 block h-1 w-4 rounded-sm"
|
||||||
|
:style="{ backgroundColor: currentHighlightColor ?? 'transparent' }"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
v-if="highlightPickerOpen"
|
||||||
|
class="absolute left-0 top-full z-10 mt-1 flex w-44 flex-col gap-2 rounded-md border border-m-border bg-white p-2 shadow-lg"
|
||||||
|
role="dialog"
|
||||||
|
aria-label="Palette de surlignage"
|
||||||
|
>
|
||||||
|
<div class="grid grid-cols-4 gap-1">
|
||||||
|
<button
|
||||||
|
v-for="swatch in highlightSwatches"
|
||||||
|
:key="swatch.value"
|
||||||
|
type="button"
|
||||||
|
class="h-7 w-7 rounded border border-m-border transition-transform hover:scale-110"
|
||||||
|
:class="currentHighlightColor === swatch.value ? 'ring-2 ring-m-primary ring-offset-1' : ''"
|
||||||
|
:style="{ backgroundColor: swatch.value }"
|
||||||
|
:title="swatch.label"
|
||||||
|
:aria-label="swatch.label"
|
||||||
|
@mousedown.prevent
|
||||||
|
@click="applyHighlight(swatch.value)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="flex items-center justify-center gap-1 rounded border border-m-border px-2 py-1 text-xs text-m-text transition-colors hover:bg-m-bg"
|
||||||
|
@mousedown.prevent
|
||||||
|
@click="applyHighlight(null)"
|
||||||
|
>
|
||||||
|
<IconifyIcon icon="mdi:format-color-marker-cancel" :width="14" :height="14" />
|
||||||
|
Aucun surlignage
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span class="mx-1 h-5 w-px bg-m-border" aria-hidden="true" />
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="flex h-8 w-8 items-center justify-center rounded text-m-text transition-colors hover:bg-m-primary/10 disabled:cursor-not-allowed disabled:opacity-40"
|
class="flex h-8 w-8 items-center justify-center rounded text-m-text transition-colors hover:bg-m-primary/10 disabled:cursor-not-allowed disabled:opacity-40"
|
||||||
@@ -97,11 +201,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onBeforeUnmount, onMounted, shallowRef, useId, watch } from 'vue'
|
import { computed, onBeforeUnmount, onMounted, ref, shallowRef, useId, watch } from 'vue'
|
||||||
import { Icon as IconifyIcon } from '@iconify/vue'
|
import { Icon as IconifyIcon } from '@iconify/vue'
|
||||||
import { Editor, EditorContent } from '@tiptap/vue-3'
|
import { Editor, EditorContent } from '@tiptap/vue-3'
|
||||||
import StarterKit from '@tiptap/starter-kit'
|
import StarterKit from '@tiptap/starter-kit'
|
||||||
import Placeholder from '@tiptap/extension-placeholder'
|
import Placeholder from '@tiptap/extension-placeholder'
|
||||||
|
import { TextStyle } from '@tiptap/extension-text-style'
|
||||||
|
import Color from '@tiptap/extension-color'
|
||||||
|
import Highlight from '@tiptap/extension-highlight'
|
||||||
import { Markdown } from 'tiptap-markdown'
|
import { Markdown } from 'tiptap-markdown'
|
||||||
import { twMerge } from 'tailwind-merge'
|
import { twMerge } from 'tailwind-merge'
|
||||||
|
|
||||||
@@ -139,7 +246,7 @@ const props = withDefaults(
|
|||||||
hint: '',
|
hint: '',
|
||||||
error: '',
|
error: '',
|
||||||
success: '',
|
success: '',
|
||||||
outputFormat: 'markdown',
|
outputFormat: 'html',
|
||||||
groupClass: '',
|
groupClass: '',
|
||||||
labelClass: '',
|
labelClass: '',
|
||||||
editorClass: '',
|
editorClass: '',
|
||||||
@@ -207,9 +314,18 @@ const mergedReadonlyClass = computed(() =>
|
|||||||
|
|
||||||
const focusEditor = () => {
|
const focusEditor = () => {
|
||||||
if (isInteractionLocked.value) return
|
if (isInteractionLocked.value) return
|
||||||
|
closePickers()
|
||||||
editor.value?.commands.focus()
|
editor.value?.commands.focus()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const htmlPattern = /<\/?[a-z][\s\S]*>/i
|
||||||
|
|
||||||
|
const normalizeEditorInput = (value: string | null | undefined): string => {
|
||||||
|
const content = (value ?? '').replace(/\r\n?/g, '\n')
|
||||||
|
if (htmlPattern.test(content)) return content
|
||||||
|
return content.split('\n').join('\n\n').replace(/\n{3,}/g, '\n\n')
|
||||||
|
}
|
||||||
|
|
||||||
const promptForLink = () => {
|
const promptForLink = () => {
|
||||||
if (!editor.value) return
|
if (!editor.value) return
|
||||||
const previous = editor.value.getAttributes('link').href as string | undefined
|
const previous = editor.value.getAttributes('link').href as string | undefined
|
||||||
@@ -222,6 +338,78 @@ const promptForLink = () => {
|
|||||||
editor.value.chain().focus().extendMarkRange('link').setLink({ href: url }).run()
|
editor.value.chain().focus().extendMarkRange('link').setLink({ href: url }).run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ColorSwatch = { label: string; value: string }
|
||||||
|
|
||||||
|
const textColorSwatches: ColorSwatch[] = [
|
||||||
|
{ label: 'Rouge', value: '#bf2600' },
|
||||||
|
{ label: 'Orange', value: '#ff8b00' },
|
||||||
|
{ label: 'Jaune', value: '#ffc400' },
|
||||||
|
{ label: 'Vert', value: '#00875a' },
|
||||||
|
{ label: 'Turquoise', value: '#00a3bf' },
|
||||||
|
{ label: 'Bleu', value: '#0747a6' },
|
||||||
|
{ label: 'Violet', value: '#5243aa' },
|
||||||
|
{ label: 'Gris', value: '#42526e' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const highlightSwatches: ColorSwatch[] = [
|
||||||
|
{ label: 'Rouge', value: '#fdd0c8' },
|
||||||
|
{ label: 'Orange', value: '#ffe2c2' },
|
||||||
|
{ label: 'Jaune', value: '#fff0b3' },
|
||||||
|
{ label: 'Vert', value: '#c6edd0' },
|
||||||
|
{ label: 'Turquoise', value: '#c1ecf0' },
|
||||||
|
{ label: 'Bleu', value: '#cce0ff' },
|
||||||
|
{ label: 'Violet', value: '#dfd8fa' },
|
||||||
|
{ label: 'Gris', value: '#dfe1e6' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const colorPickerOpen = ref(false)
|
||||||
|
const highlightPickerOpen = ref(false)
|
||||||
|
|
||||||
|
const closePickers = () => {
|
||||||
|
colorPickerOpen.value = false
|
||||||
|
highlightPickerOpen.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleColorPicker = () => {
|
||||||
|
highlightPickerOpen.value = false
|
||||||
|
colorPickerOpen.value = !colorPickerOpen.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleHighlightPicker = () => {
|
||||||
|
colorPickerOpen.value = false
|
||||||
|
highlightPickerOpen.value = !highlightPickerOpen.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const applyTextColor = (value: string | null) => {
|
||||||
|
if (!editor.value) return
|
||||||
|
if (value === null) {
|
||||||
|
editor.value.chain().focus().unsetColor().run()
|
||||||
|
} else {
|
||||||
|
editor.value.chain().focus().setColor(value).run()
|
||||||
|
}
|
||||||
|
colorPickerOpen.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const applyHighlight = (value: string | null) => {
|
||||||
|
if (!editor.value) return
|
||||||
|
if (value === null) {
|
||||||
|
editor.value.chain().focus().unsetHighlight().run()
|
||||||
|
} else {
|
||||||
|
editor.value.chain().focus().setHighlight({ color: value }).run()
|
||||||
|
}
|
||||||
|
highlightPickerOpen.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentTextColor = computed(() => {
|
||||||
|
const attrs = editor.value?.getAttributes('textStyle') as { color?: string } | undefined
|
||||||
|
return attrs?.color ?? null
|
||||||
|
})
|
||||||
|
|
||||||
|
const currentHighlightColor = computed(() => {
|
||||||
|
const attrs = editor.value?.getAttributes('highlight') as { color?: string } | undefined
|
||||||
|
return attrs?.color ?? null
|
||||||
|
})
|
||||||
|
|
||||||
const toolbarButtons = computed(() => {
|
const toolbarButtons = computed(() => {
|
||||||
const e = editor.value
|
const e = editor.value
|
||||||
return [
|
return [
|
||||||
@@ -242,13 +430,34 @@ const toolbarButtons = computed(() => {
|
|||||||
const getCurrentValue = (): string => {
|
const getCurrentValue = (): string => {
|
||||||
if (!editor.value) return ''
|
if (!editor.value) return ''
|
||||||
if (props.outputFormat === 'html') return editor.value.getHTML()
|
if (props.outputFormat === 'html') return editor.value.getHTML()
|
||||||
const storage = editor.value.storage.markdown as { getMarkdown: () => string } | undefined
|
const storage = (editor.value.storage as unknown as Record<string, { getMarkdown?: () => string } | undefined>).markdown
|
||||||
return storage ? storage.getMarkdown() : editor.value.getHTML()
|
return storage?.getMarkdown ? storage.getMarkdown() : editor.value.getHTML()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDocumentMousedown = (event: MouseEvent) => {
|
||||||
|
if (!colorPickerOpen.value && !highlightPickerOpen.value) return
|
||||||
|
const target = event.target as Node | null
|
||||||
|
if (!target) return
|
||||||
|
const popovers = document.querySelectorAll(`#${editorId.value} [role="dialog"]`)
|
||||||
|
const triggers = document.querySelectorAll(`#${editorId.value} [aria-expanded]`)
|
||||||
|
for (const node of [...popovers, ...triggers]) {
|
||||||
|
if (node.contains(target)) return
|
||||||
|
}
|
||||||
|
closePickers()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDocumentKeydown = (event: KeyboardEvent) => {
|
||||||
|
if (event.key === 'Escape' && (colorPickerOpen.value || highlightPickerOpen.value)) {
|
||||||
|
closePickers()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
document.addEventListener('mousedown', handleDocumentMousedown)
|
||||||
|
document.addEventListener('keydown', handleDocumentKeydown)
|
||||||
|
|
||||||
editor.value = new Editor({
|
editor.value = new Editor({
|
||||||
content: props.modelValue ?? '',
|
content: normalizeEditorInput(props.modelValue),
|
||||||
editable: props.editable && !props.disabled && !props.readonly,
|
editable: props.editable && !props.disabled && !props.readonly,
|
||||||
extensions: [
|
extensions: [
|
||||||
StarterKit.configure({
|
StarterKit.configure({
|
||||||
@@ -259,11 +468,14 @@ onMounted(() => {
|
|||||||
HTMLAttributes: { rel: 'noopener noreferrer nofollow', target: '_blank' },
|
HTMLAttributes: { rel: 'noopener noreferrer nofollow', target: '_blank' },
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
TextStyle,
|
||||||
|
Color.configure({ types: ['textStyle'] }),
|
||||||
|
Highlight.configure({ multicolor: true }),
|
||||||
Placeholder.configure({
|
Placeholder.configure({
|
||||||
placeholder: props.placeholder,
|
placeholder: props.placeholder,
|
||||||
}),
|
}),
|
||||||
Markdown.configure({
|
Markdown.configure({
|
||||||
html: false,
|
html: true,
|
||||||
tightLists: true,
|
tightLists: true,
|
||||||
bulletListMarker: '-',
|
bulletListMarker: '-',
|
||||||
linkify: true,
|
linkify: true,
|
||||||
@@ -290,20 +502,22 @@ onMounted(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
|
document.removeEventListener('mousedown', handleDocumentMousedown)
|
||||||
|
document.removeEventListener('keydown', handleDocumentKeydown)
|
||||||
editor.value?.destroy()
|
editor.value?.destroy()
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(() => props.modelValue, (incoming) => {
|
watch(() => props.modelValue, (incoming) => {
|
||||||
if (!editor.value) return
|
if (!editor.value) return
|
||||||
if ((incoming ?? '') === getCurrentValue()) return
|
if ((incoming ?? '') === getCurrentValue()) return
|
||||||
editor.value.commands.setContent(incoming ?? '', { emitUpdate: false })
|
editor.value.commands.setContent(normalizeEditorInput(incoming), { emitUpdate: false })
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(() => [props.editable, props.disabled, props.readonly], () => {
|
watch(() => [props.editable, props.disabled, props.readonly], () => {
|
||||||
editor.value?.setEditable(props.editable && !props.disabled && !props.readonly)
|
editor.value?.setEditable(props.editable && !props.disabled && !props.readonly)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.malio-rich-text :deep(.ProseMirror) {
|
.malio-rich-text :deep(.ProseMirror) {
|
||||||
outline: none;
|
outline: none;
|
||||||
@@ -323,4 +537,38 @@ watch(() => [props.editable, props.disabled, props.readonly], () => {
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
height: 0;
|
height: 0;
|
||||||
}
|
}
|
||||||
|
.malio-rich-text :deep(h2) {
|
||||||
|
margin: 0.75rem 0 0.5rem;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
line-height: 2rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: rgb(var(--m-text));
|
||||||
|
}
|
||||||
|
.malio-rich-text :deep(h3) {
|
||||||
|
margin: 0.65rem 0 0.4rem;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
line-height: 1.75rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: rgb(var(--m-text));
|
||||||
|
}
|
||||||
|
.malio-rich-text :deep(p) {
|
||||||
|
margin: 0.45rem 0;
|
||||||
|
}
|
||||||
|
.malio-rich-text :deep(ul),
|
||||||
|
.malio-rich-text :deep(ol) {
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
}
|
||||||
|
.malio-rich-text :deep(ul) {
|
||||||
|
list-style: disc;
|
||||||
|
}
|
||||||
|
.malio-rich-text :deep(ol) {
|
||||||
|
list-style: decimal;
|
||||||
|
}
|
||||||
|
.malio-rich-text :deep(blockquote) {
|
||||||
|
margin: 0.75rem 0;
|
||||||
|
border-left: 3px solid rgb(var(--m-border));
|
||||||
|
padding-left: 0.75rem;
|
||||||
|
color: rgb(var(--m-muted));
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -7,15 +7,15 @@
|
|||||||
:name="name"
|
:name="name"
|
||||||
|
|
||||||
:autocomplete="autocomplete"
|
:autocomplete="autocomplete"
|
||||||
class="floating-input peer w-full border bg-white pl-3 pr-3 py-1 outline-none placeholder:text-transparent focus:border-2 overflow-auto"
|
class="floating-input peer w-full border-2 bg-white pl-3 pr-3 py-1 outline-none placeholder:text-transparent overflow-auto"
|
||||||
:class="[
|
:class="[
|
||||||
isFilled ? 'border-black' : 'border-m-muted',
|
isFilled ? 'border-black' : 'border-m-muted',
|
||||||
disabled ? 'cursor-not-allowed text-black/60 border-m-muted' : 'cursor-text',
|
disabled ? 'cursor-not-allowed text-black/60 border-m-muted' : 'cursor-text',
|
||||||
hasError
|
hasError
|
||||||
? 'border-m-danger focus:border-m-danger focus:pl-[11px]'
|
? 'border-m-danger focus:border-m-danger'
|
||||||
: hasSuccess
|
: hasSuccess
|
||||||
? 'border-m-success focus:border-m-success focus:pl-[11px]'
|
? 'border-m-success focus:border-m-success'
|
||||||
: 'focus:border-m-primary focus:pl-[11px]',
|
: 'focus:border-m-primary',
|
||||||
textInput,
|
textInput,
|
||||||
showCounterComputed ? 'pb-6' : '',
|
showCounterComputed ? 'pb-6' : '',
|
||||||
rounded,
|
rounded,
|
||||||
|
|||||||
@@ -16,8 +16,6 @@ type SelectProps = {
|
|||||||
hint?: string
|
hint?: string
|
||||||
error?: string
|
error?: string
|
||||||
success?: string
|
success?: string
|
||||||
minWidth?: string
|
|
||||||
maxWidth?: string
|
|
||||||
textField?: string
|
textField?: string
|
||||||
textValue?: string
|
textValue?: string
|
||||||
textLabel?: string
|
textLabel?: string
|
||||||
|
|||||||
@@ -101,8 +101,8 @@
|
|||||||
class="absolute left-0 right-0 z-20 max-h-60 w-full overflow-auto border-2 bg-white"
|
class="absolute left-0 right-0 z-20 max-h-60 w-full overflow-auto border-2 bg-white"
|
||||||
:class="[
|
:class="[
|
||||||
openDirection === 'down'
|
openDirection === 'down'
|
||||||
? 'top-[calc(100%-2px)] rounded-b-md border-t-0'
|
? 'top-[calc(100%-4px)] rounded-b-md border-t-0'
|
||||||
: 'bottom-[calc(100%-2px)] rounded-t-md border-b-0',
|
: 'bottom-[calc(100%-4px)] rounded-t-md border-b-0',
|
||||||
hasError
|
hasError
|
||||||
? 'select-scrollbar-error'
|
? 'select-scrollbar-error'
|
||||||
: hasSuccess
|
: hasSuccess
|
||||||
@@ -171,8 +171,6 @@ const props = withDefaults(defineProps<{
|
|||||||
hint?: string
|
hint?: string
|
||||||
error?: string
|
error?: string
|
||||||
success?: string
|
success?: string
|
||||||
minWidth?: string
|
|
||||||
maxWidth?: string
|
|
||||||
textField?: string
|
textField?: string
|
||||||
textValue?: string
|
textValue?: string
|
||||||
textLabel?: string
|
textLabel?: string
|
||||||
@@ -186,8 +184,6 @@ const props = withDefaults(defineProps<{
|
|||||||
hint: '',
|
hint: '',
|
||||||
error: '',
|
error: '',
|
||||||
success: '',
|
success: '',
|
||||||
minWidth: 'w-96',
|
|
||||||
maxWidth: '',
|
|
||||||
textField: 'text-lg',
|
textField: 'text-lg',
|
||||||
textValue: 'text-lg',
|
textValue: 'text-lg',
|
||||||
textLabel: 'text-sm',
|
textLabel: 'text-sm',
|
||||||
@@ -213,7 +209,7 @@ const normalizedOptions = computed<Option[]>(() => {
|
|||||||
return [{label: props.emptyOptionLabel, value: null}, ...props.options]
|
return [{label: props.emptyOptionLabel, value: null}, ...props.options]
|
||||||
})
|
})
|
||||||
const mergedGroupClass = computed(() =>
|
const mergedGroupClass = computed(() =>
|
||||||
twMerge('relative w-full', props.minWidth, props.maxWidth, props.groupClass),
|
twMerge('relative w-full h-12 flex items-center', props.groupClass),
|
||||||
)
|
)
|
||||||
const hasError = computed(() => !!props.error)
|
const hasError = computed(() => !!props.error)
|
||||||
const hasSuccess = computed(() => !!props.success && !hasError.value)
|
const hasSuccess = computed(() => !!props.success && !hasError.value)
|
||||||
|
|||||||
@@ -16,8 +16,6 @@ type SelectCheckboxProps = {
|
|||||||
hint?: string
|
hint?: string
|
||||||
error?: string
|
error?: string
|
||||||
success?: string
|
success?: string
|
||||||
minWidth?: string
|
|
||||||
maxWidth?: string
|
|
||||||
textField?: string
|
textField?: string
|
||||||
textValue?: string
|
textValue?: string
|
||||||
textLabel?: string
|
textLabel?: string
|
||||||
@@ -177,15 +175,6 @@ describe('MalioSelectCheckbox', () => {
|
|||||||
expect((checkboxes[0].element as HTMLInputElement).checked).toBe(false)
|
expect((checkboxes[0].element as HTMLInputElement).checked).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('applies minWidth via twMerge so it overrides w-full (parity with MalioSelect)', () => {
|
|
||||||
const wrapper = mount(SelectCheckboxForTest, {
|
|
||||||
props: {modelValue: [], options: [], minWidth: 'w-80'},
|
|
||||||
})
|
|
||||||
const root = wrapper.find('button').element.parentElement
|
|
||||||
expect(root?.className).toContain('w-80')
|
|
||||||
expect(root?.className).not.toContain('w-full')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('applies groupClass via twMerge', () => {
|
it('applies groupClass via twMerge', () => {
|
||||||
const wrapper = mount(SelectCheckboxForTest, {
|
const wrapper = mount(SelectCheckboxForTest, {
|
||||||
props: {modelValue: [], options: [], groupClass: 'mt-4'},
|
props: {modelValue: [], options: [], groupClass: 'mt-4'},
|
||||||
|
|||||||
@@ -129,8 +129,8 @@
|
|||||||
class="absolute left-0 right-0 z-20 max-h-60 w-full overflow-auto border-2 bg-white"
|
class="absolute left-0 right-0 z-20 max-h-60 w-full overflow-auto border-2 bg-white"
|
||||||
:class="[
|
:class="[
|
||||||
openDirection === 'down'
|
openDirection === 'down'
|
||||||
? 'top-[calc(100%-2px)] rounded-b-md border-t-0'
|
? 'top-[calc(100%-4px)] rounded-b-md border-t-0'
|
||||||
: 'bottom-[calc(100%-2px)] rounded-t-md border-b-0',
|
: 'bottom-[calc(100%-4px)] rounded-t-md border-b-0',
|
||||||
hasError
|
hasError
|
||||||
? 'select-scrollbar-error'
|
? 'select-scrollbar-error'
|
||||||
: hasSuccess
|
: hasSuccess
|
||||||
@@ -222,8 +222,6 @@ const props = withDefaults(defineProps<{
|
|||||||
hint?: string
|
hint?: string
|
||||||
error?: string
|
error?: string
|
||||||
success?: string
|
success?: string
|
||||||
minWidth?: string
|
|
||||||
maxWidth?: string
|
|
||||||
textField?: string
|
textField?: string
|
||||||
textValue?: string
|
textValue?: string
|
||||||
textLabel?: string
|
textLabel?: string
|
||||||
@@ -240,8 +238,6 @@ const props = withDefaults(defineProps<{
|
|||||||
hint: '',
|
hint: '',
|
||||||
error: '',
|
error: '',
|
||||||
success: '',
|
success: '',
|
||||||
minWidth: 'w-96',
|
|
||||||
maxWidth: '',
|
|
||||||
textField: 'text-lg',
|
textField: 'text-lg',
|
||||||
textValue: 'text-lg',
|
textValue: 'text-lg',
|
||||||
textLabel: 'text-sm',
|
textLabel: 'text-sm',
|
||||||
@@ -267,7 +263,7 @@ const listRef = ref<HTMLElement | null>(null)
|
|||||||
const listHeight = ref(0)
|
const listHeight = ref(0)
|
||||||
const normalizedOptions = computed<Option[]>(() => props.options)
|
const normalizedOptions = computed<Option[]>(() => props.options)
|
||||||
const mergedGroupClass = computed(() =>
|
const mergedGroupClass = computed(() =>
|
||||||
twMerge('relative w-full', props.minWidth, props.maxWidth, props.groupClass),
|
twMerge('relative w-full h-12 flex items-center', props.groupClass),
|
||||||
)
|
)
|
||||||
const hasError = computed(() => !!props.error)
|
const hasError = computed(() => !!props.error)
|
||||||
const hasSuccess = computed(() => !!props.success && !hasError.value)
|
const hasSuccess = computed(() => !!props.success && !hasError.value)
|
||||||
|
|||||||
@@ -72,6 +72,17 @@
|
|||||||
min-height="200px"
|
min-height="200px"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="rounded-lg border p-4 lg:col-span-2">
|
||||||
|
<h2 class="mb-4 text-xl font-bold">Couleurs & surlignage</h2>
|
||||||
|
<MalioInputRichText
|
||||||
|
v-model="colorValue"
|
||||||
|
label="Note colorée"
|
||||||
|
output-format="html"
|
||||||
|
min-height="180px"
|
||||||
|
hint="Tester les boutons couleur du texte et surlignage (palettes Jira-like)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Story>
|
</Story>
|
||||||
</template>
|
</template>
|
||||||
@@ -80,7 +91,7 @@
|
|||||||
# MalioInputRichText
|
# MalioInputRichText
|
||||||
|
|
||||||
Éditeur de texte riche basé sur **TipTap v3** + **StarterKit** + **tiptap-markdown**.
|
Éditeur de texte riche basé sur **TipTap v3** + **StarterKit** + **tiptap-markdown**.
|
||||||
Sortie en **markdown** (par défaut) ou en **HTML**. Aligné sur le thème Malio
|
Sortie en **HTML** (par défaut) ou en **markdown**. Aligné sur le thème Malio
|
||||||
(couleurs `m-*`, icônes `mdi:*`, états error / success / hint).
|
(couleurs `m-*`, icônes `mdi:*`, états error / success / hint).
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
@@ -144,10 +155,10 @@ Sortie en **markdown** (par défaut) ou en **HTML**. Aligné sur le thème Malio
|
|||||||
### outputFormat
|
### outputFormat
|
||||||
|
|
||||||
- Type: `'markdown' | 'html'`
|
- Type: `'markdown' | 'html'`
|
||||||
- Défaut: `'markdown'`
|
- Défaut: `'html'`
|
||||||
- Description: Format émis dans `update:modelValue`.
|
- Description: Format émis dans `update:modelValue`.
|
||||||
- `markdown` : utilise `tiptap-markdown` (`getMarkdown()`).
|
|
||||||
- `html` : utilise `editor.getHTML()`.
|
- `html` : utilise `editor.getHTML()`.
|
||||||
|
- `markdown` : utilise `tiptap-markdown` (`getMarkdown()`).
|
||||||
|
|
||||||
### groupClass / labelClass / editorClass
|
### groupClass / labelClass / editorClass
|
||||||
|
|
||||||
@@ -166,8 +177,15 @@ Boutons (icônes `mdi:*`) :
|
|||||||
- Citation
|
- Citation
|
||||||
- Code inline, Bloc de code
|
- Code inline, Bloc de code
|
||||||
- Lien (prompt URL ; vide pour retirer)
|
- Lien (prompt URL ; vide pour retirer)
|
||||||
|
- Couleur du texte (palette de 8 swatches + reset)
|
||||||
|
- Surlignage (palette de 8 swatches + reset)
|
||||||
- Annuler / Rétablir
|
- Annuler / Rétablir
|
||||||
|
|
||||||
|
Les palettes couleur/surlignage s'ouvrent en popover sous leur bouton.
|
||||||
|
Fermeture : clic sur un swatch, clic en dehors, ou touche **Échap**.
|
||||||
|
|
||||||
|
> Les couleurs et surlignages ne sont **pas persistés en markdown** (spec Markdown ne couvre pas la couleur). Pour préserver les couleurs au save/reload, utiliser `output-format="html"`.
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
## Accessibilité
|
## Accessibilité
|
||||||
@@ -199,4 +217,5 @@ const successValue = ref('Tout est bon de mon côté.')
|
|||||||
const disabledValue = ref('Contenu indisponible.')
|
const disabledValue = ref('Contenu indisponible.')
|
||||||
const readonlyValue = ref('## Compte-rendu\n\n- Point 1\n- Point 2\n\n> Citation importante')
|
const readonlyValue = ref('## Compte-rendu\n\n- Point 1\n- Point 2\n\n> Citation importante')
|
||||||
const htmlValue = ref('<p>Contenu <strong>riche</strong>.</p>')
|
const htmlValue = ref('<p>Contenu <strong>riche</strong>.</p>')
|
||||||
|
const colorValue = ref('<p>Sélectionner du texte puis utiliser les boutons <span style="color: #bf2600">couleur</span> ou <mark data-color="#fff0b3" style="background-color: #fff0b3">surlignage</mark>.</p>')
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
78
package-lock.json
generated
78
package-lock.json
generated
@@ -10,7 +10,10 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxt/icon": "^2.2.1",
|
"@nuxt/icon": "^2.2.1",
|
||||||
"@nuxtjs/tailwindcss": "^6.14.0",
|
"@nuxtjs/tailwindcss": "^6.14.0",
|
||||||
|
"@tiptap/extension-color": "^3.22.5",
|
||||||
|
"@tiptap/extension-highlight": "^3.22.5",
|
||||||
"@tiptap/extension-placeholder": "^3.22.5",
|
"@tiptap/extension-placeholder": "^3.22.5",
|
||||||
|
"@tiptap/extension-text-style": "^3.22.5",
|
||||||
"@tiptap/pm": "^3.22.5",
|
"@tiptap/pm": "^3.22.5",
|
||||||
"@tiptap/starter-kit": "^3.22.5",
|
"@tiptap/starter-kit": "^3.22.5",
|
||||||
"@tiptap/vue-3": "^3.22.5",
|
"@tiptap/vue-3": "^3.22.5",
|
||||||
@@ -183,7 +186,6 @@
|
|||||||
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.29.0",
|
"@babel/code-frame": "^7.29.0",
|
||||||
"@babel/generator": "^7.29.0",
|
"@babel/generator": "^7.29.0",
|
||||||
@@ -809,7 +811,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.19.0"
|
"node": ">=20.19.0"
|
||||||
},
|
},
|
||||||
@@ -850,7 +851,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.19.0"
|
"node": ">=20.19.0"
|
||||||
}
|
}
|
||||||
@@ -1575,7 +1575,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz",
|
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz",
|
||||||
"integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==",
|
"integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@floating-ui/core": "^1.7.5",
|
"@floating-ui/core": "^1.7.5",
|
||||||
"@floating-ui/utils": "^0.2.11"
|
"@floating-ui/utils": "^0.2.11"
|
||||||
@@ -2670,7 +2669,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.3.1.tgz",
|
||||||
"integrity": "sha512-UjBFt72dnpc+83BV3OIbCT0YHLevJtgJCHpxMX0YRKWLDhhbcDdUse87GtsQBrjvOzK7WUNUYLDS/hQLYev5rA==",
|
"integrity": "sha512-UjBFt72dnpc+83BV3OIbCT0YHLevJtgJCHpxMX0YRKWLDhhbcDdUse87GtsQBrjvOzK7WUNUYLDS/hQLYev5rA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"c12": "^3.3.3",
|
"c12": "^3.3.3",
|
||||||
"consola": "^3.4.2",
|
"consola": "^3.4.2",
|
||||||
@@ -2758,7 +2756,6 @@
|
|||||||
"integrity": "sha512-S+wHJdYDuyk9I43Ej27y5BeWMZgi7R/UVql3b3qtT35d0fbpXW7fUenzhLRCCDC6O10sjguc6fcMcR9sMKvV8g==",
|
"integrity": "sha512-S+wHJdYDuyk9I43Ej27y5BeWMZgi7R/UVql3b3qtT35d0fbpXW7fUenzhLRCCDC6O10sjguc6fcMcR9sMKvV8g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/shared": "^3.5.27",
|
"@vue/shared": "^3.5.27",
|
||||||
"defu": "^6.1.4",
|
"defu": "^6.1.4",
|
||||||
@@ -5049,7 +5046,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.22.5.tgz",
|
||||||
"integrity": "sha512-L1lhWz6ujGny8LduTJ7MBWYhzigwOvfUJUrJ7IzOJSuy3+OAzisdGDD1GV7LEO/hU0Hr2Mkm1wajRIHExvS9HQ==",
|
"integrity": "sha512-L1lhWz6ujGny8LduTJ7MBWYhzigwOvfUJUrJ7IzOJSuy3+OAzisdGDD1GV7LEO/hU0Hr2Mkm1wajRIHExvS9HQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
"url": "https://github.com/sponsors/ueberdosis"
|
"url": "https://github.com/sponsors/ueberdosis"
|
||||||
@@ -5142,6 +5138,19 @@
|
|||||||
"@tiptap/pm": "3.22.5"
|
"@tiptap/pm": "3.22.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tiptap/extension-color": {
|
||||||
|
"version": "3.22.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tiptap/extension-color/-/extension-color-3.22.5.tgz",
|
||||||
|
"integrity": "sha512-4aTygOUlTFBYCvJy67SeKVdXCQw7du3Rj+N5ZutVnDnrpfzUBWsO7f+I+iDS8eMQFbWxVFLlWxGMcTbjtk1a+Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ueberdosis"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@tiptap/extension-text-style": "3.22.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tiptap/extension-document": {
|
"node_modules/@tiptap/extension-document": {
|
||||||
"version": "3.22.5",
|
"version": "3.22.5",
|
||||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.22.5.tgz",
|
||||||
@@ -5223,6 +5232,19 @@
|
|||||||
"@tiptap/core": "3.22.5"
|
"@tiptap/core": "3.22.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tiptap/extension-highlight": {
|
||||||
|
"version": "3.22.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tiptap/extension-highlight/-/extension-highlight-3.22.5.tgz",
|
||||||
|
"integrity": "sha512-byWruAOKcqRN0OuzVSKqLLrced3M9AZaR2pD1BV3aUZHzMzeBjLBfByh8s4lExH2Z547xQUdHHnUflBQ572I5A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ueberdosis"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@tiptap/core": "3.22.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tiptap/extension-horizontal-rule": {
|
"node_modules/@tiptap/extension-horizontal-rule": {
|
||||||
"version": "3.22.5",
|
"version": "3.22.5",
|
||||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.22.5.tgz",
|
||||||
@@ -5272,7 +5294,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.22.5.tgz",
|
||||||
"integrity": "sha512-cVO3ZHCgxAWZ4zrFSs81FO2nyCk1wb2EHkpLpW98FzbJLkN9rDkazhW99P3HRWy/CvUldOT+8ecI1YrQtBojMg==",
|
"integrity": "sha512-cVO3ZHCgxAWZ4zrFSs81FO2nyCk1wb2EHkpLpW98FzbJLkN9rDkazhW99P3HRWy/CvUldOT+8ecI1YrQtBojMg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
"url": "https://github.com/sponsors/ueberdosis"
|
"url": "https://github.com/sponsors/ueberdosis"
|
||||||
@@ -5373,6 +5394,19 @@
|
|||||||
"@tiptap/core": "3.22.5"
|
"@tiptap/core": "3.22.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tiptap/extension-text-style": {
|
||||||
|
"version": "3.22.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-3.22.5.tgz",
|
||||||
|
"integrity": "sha512-jt63jy8YbhZJUGMxTUzeivLhowGtFp6YbCFrrmZJ7G6IHu8X8LJzO81ksz5nT5l8DKpldGwnINUfA6iE91JIAg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ueberdosis"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@tiptap/core": "3.22.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tiptap/extension-underline": {
|
"node_modules/@tiptap/extension-underline": {
|
||||||
"version": "3.22.5",
|
"version": "3.22.5",
|
||||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.22.5.tgz",
|
||||||
@@ -5391,7 +5425,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.22.5.tgz",
|
||||||
"integrity": "sha512-Ifg4MzKCj3uRqe3ieTwYnomu2y4p7EXr2avVSKZYfh12i2dyWe2Gkn1KuZDREANVE+gHqFlQjJRYzhJFwzSCrg==",
|
"integrity": "sha512-Ifg4MzKCj3uRqe3ieTwYnomu2y4p7EXr2avVSKZYfh12i2dyWe2Gkn1KuZDREANVE+gHqFlQjJRYzhJFwzSCrg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
"url": "https://github.com/sponsors/ueberdosis"
|
"url": "https://github.com/sponsors/ueberdosis"
|
||||||
@@ -5406,7 +5439,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.22.5.tgz",
|
"resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.22.5.tgz",
|
||||||
"integrity": "sha512-Cr9Mv4igxvI2tKMiahw48sZxva3PfDzypErH8IB82N+9qa9n9ygVMt0BOaDg53hLKxEEVeYr2S/wCcJIVFgBTw==",
|
"integrity": "sha512-Cr9Mv4igxvI2tKMiahw48sZxva3PfDzypErH8IB82N+9qa9n9ygVMt0BOaDg53hLKxEEVeYr2S/wCcJIVFgBTw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"prosemirror-changeset": "^2.3.0",
|
"prosemirror-changeset": "^2.3.0",
|
||||||
"prosemirror-commands": "^1.6.2",
|
"prosemirror-commands": "^1.6.2",
|
||||||
@@ -5550,8 +5582,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/jsonfile": {
|
"node_modules/@types/jsonfile": {
|
||||||
"version": "6.1.4",
|
"version": "6.1.4",
|
||||||
@@ -5574,7 +5605,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
|
||||||
"integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
|
"integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/linkify-it": "^5",
|
"@types/linkify-it": "^5",
|
||||||
"@types/mdurl": "^2"
|
"@types/mdurl": "^2"
|
||||||
@@ -5655,7 +5685,6 @@
|
|||||||
"integrity": "sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==",
|
"integrity": "sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.56.0",
|
"@typescript-eslint/scope-manager": "8.56.0",
|
||||||
"@typescript-eslint/types": "8.56.0",
|
"@typescript-eslint/types": "8.56.0",
|
||||||
@@ -6500,7 +6529,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.28.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.28.tgz",
|
||||||
"integrity": "sha512-6TnKMiNkd6u6VeVDhZn/07KhEZuBSn43Wd2No5zaP5s3xm8IqFTHBj84HJah4UepSUJTro5SoqqlOY22FKY96g==",
|
"integrity": "sha512-6TnKMiNkd6u6VeVDhZn/07KhEZuBSn43Wd2No5zaP5s3xm8IqFTHBj84HJah4UepSUJTro5SoqqlOY22FKY96g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "^7.29.0",
|
"@babel/parser": "^7.29.0",
|
||||||
"@vue/compiler-core": "3.5.28",
|
"@vue/compiler-core": "3.5.28",
|
||||||
@@ -6723,7 +6751,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -7227,7 +7254,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.9.0",
|
"baseline-browser-mapping": "^2.9.0",
|
||||||
"caniuse-lite": "^1.0.30001759",
|
"caniuse-lite": "^1.0.30001759",
|
||||||
@@ -7623,7 +7649,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz",
|
||||||
"integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==",
|
"integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"consola": "^3.2.3"
|
"consola": "^3.2.3"
|
||||||
}
|
}
|
||||||
@@ -8824,7 +8849,6 @@
|
|||||||
"integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==",
|
"integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"esbuild": "bin/esbuild"
|
"esbuild": "bin/esbuild"
|
||||||
},
|
},
|
||||||
@@ -8894,7 +8918,6 @@
|
|||||||
"integrity": "sha512-O0piBKY36YSJhlFSG8p9VUdPV/SxxS4FYDWVpr/9GJuMaepzwlf4J8I4ov1b+ySQfDTPhc3DtLaxcT1fN0yqCg==",
|
"integrity": "sha512-O0piBKY36YSJhlFSG8p9VUdPV/SxxS4FYDWVpr/9GJuMaepzwlf4J8I4ov1b+ySQfDTPhc3DtLaxcT1fN0yqCg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.8.0",
|
"@eslint-community/eslint-utils": "^4.8.0",
|
||||||
"@eslint-community/regexpp": "^4.12.2",
|
"@eslint-community/regexpp": "^4.12.2",
|
||||||
@@ -10295,7 +10318,6 @@
|
|||||||
"integrity": "sha512-hzhFiqlL9Ko1B2APCamGIchM3Bjng5+CTX7kLL1q/NB2Lp4Uqpe4ZZicc7RU4CTCe4Vj7Q/Eb3UE/IacL1Ta5g==",
|
"integrity": "sha512-hzhFiqlL9Ko1B2APCamGIchM3Bjng5+CTX7kLL1q/NB2Lp4Uqpe4ZZicc7RU4CTCe4Vj7Q/Eb3UE/IacL1Ta5g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@akryum/tinypool": "^0.3.1",
|
"@akryum/tinypool": "^0.3.1",
|
||||||
"@histoire/app": "^1.0.0-beta.1",
|
"@histoire/app": "^1.0.0-beta.1",
|
||||||
@@ -11958,7 +11980,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz",
|
||||||
"integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==",
|
"integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"argparse": "^2.0.1",
|
"argparse": "^2.0.1",
|
||||||
"entities": "^4.4.0",
|
"entities": "^4.4.0",
|
||||||
@@ -12724,7 +12745,6 @@
|
|||||||
"integrity": "sha512-bl+0rFcT5Ax16aiWFBFPyWcsTob19NTZaDL5P6t0MQdK63AtgS6fN6fwvwdbXtnTk6/YdCzlmuLzXhSM22h0OA==",
|
"integrity": "sha512-bl+0rFcT5Ax16aiWFBFPyWcsTob19NTZaDL5P6t0MQdK63AtgS6fN6fwvwdbXtnTk6/YdCzlmuLzXhSM22h0OA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dxup/nuxt": "^0.3.2",
|
"@dxup/nuxt": "^0.3.2",
|
||||||
"@nuxt/cli": "^3.33.0",
|
"@nuxt/cli": "^3.33.0",
|
||||||
@@ -13079,7 +13099,6 @@
|
|||||||
"integrity": "sha512-7rQ3QdJwobMQLMZwQaPuPYMEF2fDRZwf51lZ//V+bA37nejjKW5ifMHbbCwvA889Y4RLhT+/wLJpPRhAoBaZYw==",
|
"integrity": "sha512-7rQ3QdJwobMQLMZwQaPuPYMEF2fDRZwf51lZ//V+bA37nejjKW5ifMHbbCwvA889Y4RLhT+/wLJpPRhAoBaZYw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oxc-project/types": "^0.112.0"
|
"@oxc-project/types": "^0.112.0"
|
||||||
},
|
},
|
||||||
@@ -13455,7 +13474,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.11",
|
"nanoid": "^3.3.11",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
@@ -14024,7 +14042,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz",
|
||||||
"integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==",
|
"integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cssesc": "^3.0.0",
|
"cssesc": "^3.0.0",
|
||||||
"util-deprecate": "^1.0.2"
|
"util-deprecate": "^1.0.2"
|
||||||
@@ -14767,7 +14784,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz",
|
||||||
"integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==",
|
"integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/estree": "1.0.8"
|
"@types/estree": "1.0.8"
|
||||||
},
|
},
|
||||||
@@ -15783,7 +15799,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz",
|
||||||
"integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==",
|
"integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alloc/quick-lru": "^5.2.0",
|
"@alloc/quick-lru": "^5.2.0",
|
||||||
"arg": "^5.0.2",
|
"arg": "^5.0.2",
|
||||||
@@ -16314,7 +16329,6 @@
|
|||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -16715,7 +16729,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"napi-postinstall": "^0.3.0"
|
"napi-postinstall": "^0.3.0"
|
||||||
},
|
},
|
||||||
@@ -17011,7 +17024,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
|
||||||
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
|
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.27.0",
|
"esbuild": "^0.27.0",
|
||||||
"fdir": "^6.5.0",
|
"fdir": "^6.5.0",
|
||||||
@@ -17503,7 +17515,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.28.tgz",
|
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.28.tgz",
|
||||||
"integrity": "sha512-BRdrNfeoccSoIZeIhyPBfvWSLFP4q8J3u8Ju8Ug5vu3LdD+yTM13Sg4sKtljxozbnuMu1NB1X5HBHRYUzFocKg==",
|
"integrity": "sha512-BRdrNfeoccSoIZeIhyPBfvWSLFP4q8J3u8Ju8Ug5vu3LdD+yTM13Sg4sKtljxozbnuMu1NB1X5HBHRYUzFocKg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/compiler-dom": "3.5.28",
|
"@vue/compiler-dom": "3.5.28",
|
||||||
"@vue/compiler-sfc": "3.5.28",
|
"@vue/compiler-sfc": "3.5.28",
|
||||||
@@ -17550,7 +17561,6 @@
|
|||||||
"integrity": "sha512-Vxi9pJdbN3ZnVGLODVtZ7y4Y2kzAAE2Cm0CZ3ZDRvydVYxZ6VrnBhLikBsRS+dpwj4Jv4UCv21PTEwF5rQ9WXg==",
|
"integrity": "sha512-Vxi9pJdbN3ZnVGLODVtZ7y4Y2kzAAE2Cm0CZ3ZDRvydVYxZ6VrnBhLikBsRS+dpwj4Jv4UCv21PTEwF5rQ9WXg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "^4.4.0",
|
"debug": "^4.4.0",
|
||||||
"eslint-scope": "^8.2.0 || ^9.0.0",
|
"eslint-scope": "^8.2.0 || ^9.0.0",
|
||||||
@@ -17588,7 +17598,6 @@
|
|||||||
"integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==",
|
"integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/devtools-api": "^6.6.4"
|
"@vue/devtools-api": "^6.6.4"
|
||||||
},
|
},
|
||||||
@@ -17823,7 +17832,6 @@
|
|||||||
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
|
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"yaml": "bin.mjs"
|
"yaml": "bin.mjs"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -42,7 +42,10 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxt/icon": "^2.2.1",
|
"@nuxt/icon": "^2.2.1",
|
||||||
"@nuxtjs/tailwindcss": "^6.14.0",
|
"@nuxtjs/tailwindcss": "^6.14.0",
|
||||||
|
"@tiptap/extension-color": "^3.22.5",
|
||||||
|
"@tiptap/extension-highlight": "^3.22.5",
|
||||||
"@tiptap/extension-placeholder": "^3.22.5",
|
"@tiptap/extension-placeholder": "^3.22.5",
|
||||||
|
"@tiptap/extension-text-style": "^3.22.5",
|
||||||
"@tiptap/pm": "^3.22.5",
|
"@tiptap/pm": "^3.22.5",
|
||||||
"@tiptap/starter-kit": "^3.22.5",
|
"@tiptap/starter-kit": "^3.22.5",
|
||||||
"@tiptap/vue-3": "^3.22.5",
|
"@tiptap/vue-3": "^3.22.5",
|
||||||
|
|||||||
Reference in New Issue
Block a user