diff --git a/src/shared/components/BlockEditor/README.md b/src/shared/components/BlockEditor/README.md index 990329f..259a0af 100644 --- a/src/shared/components/BlockEditor/README.md +++ b/src/shared/components/BlockEditor/README.md @@ -287,6 +287,15 @@ descendants. Les styles CSS inline (`font-weight`, `font-style`, ## Bloc image +Le formulaire d'insertion accepte deux sources : + +- **URL externe** : champ libre + bouton « Insérer ». +- **Bibliothèque media** : bouton « Choisir un média » qui ouvre le `MediaPicker` + de `@zen/core/features/media`. À la sélection, le bloc est inséré avec + `block.src = "/zen/api/media/file/"`. Les nouveaux uploads passent par + ce picker en visibilité `public` (les blocs image vivent dans du contenu + publié — un média privé serait illisible côté frontal). + Une fois l'URL insérée, l'image affiche au survol une **toolbar flottante** (coin haut-droit) reprenant le style `BOX_CLASS` partagé : @@ -316,6 +325,7 @@ quand l'`` y est imbriqué pour récupérer `href` / `target`. ## Limitations connues - Pas d'imbrication de listes. -- Image : URL uniquement, pas d'upload de fichier. La caption est une - string plate (pas de formatage inline pour l'instant). +- Image : insertion par URL externe ou via le `MediaPicker` du module + `media` (les uploads y sont gérés). La caption est une string plate + (pas de formatage inline pour l'instant). - Tables : Phase 3. diff --git a/src/shared/components/BlockEditor/blockTypes/Image.client.js b/src/shared/components/BlockEditor/blockTypes/Image.client.js index cdbebb1..c2c2af4 100644 --- a/src/shared/components/BlockEditor/blockTypes/Image.client.js +++ b/src/shared/components/BlockEditor/blockTypes/Image.client.js @@ -18,6 +18,9 @@ import { SEPARATOR_VERTICAL_CLASS, } from '../inline/menuStyles.js'; import { newBlockId } from '../utils/ids.js'; +// Import relatif pour éviter une dépendance circulaire avec @zen/core (le bloc +// image vit dans `shared` et tire MediaPicker depuis `features/media`). +import MediaPicker from '../../../../features/media/components/MediaPicker.client.js'; // Bloc image. État vide = formulaire d'insertion d'URL. État rempli = image // rendue + toolbar flottante (alignement, lien, remplacer, supprimer) + @@ -44,6 +47,7 @@ function getAlign(block) { function ImageUrlForm({ initialUrl, onSubmit, onCancel, disabled }) { const [url, setUrl] = useState(initialUrl ?? ''); + const [pickerOpen, setPickerOpen] = useState(false); const inputRef = useRef(null); useEffect(() => { @@ -67,36 +71,57 @@ function ImageUrlForm({ initialUrl, onSubmit, onCancel, disabled }) { } return ( -
- - setUrl(e.target.value)} - onKeyDown={handleKeyDown} - disabled={disabled} - className="flex-1 px-2 py-1 text-sm rounded border border-neutral-200 dark:border-neutral-700 bg-white dark:bg-neutral-900 text-neutral-900 dark:text-white outline-none focus:border-blue-500" - /> - - {onCancel && ( + <> +
+ + setUrl(e.target.value)} + onKeyDown={handleKeyDown} + disabled={disabled} + className="flex-1 px-2 py-1 text-sm rounded border border-neutral-200 dark:border-neutral-700 bg-white dark:bg-neutral-900 text-neutral-900 dark:text-white outline-none focus:border-blue-500" + /> - )} -
+ + {onCancel && ( + + )} +
+ setPickerOpen(false)} + onSelect={(media) => { + if (media?.slug) onSubmit?.(`/zen/api/media/file/${media.slug}`); + }} + accept="image/*" + visibility="any" + uploadVisibility="public" + title="Insérer une image depuis la bibliothèque" + /> + ); }