From a8e28afbad83a9ae9fa80be3d5a9ad4ef4e78f37 Mon Sep 17 00:00:00 2001 From: Lipis Date: Mon, 18 Jan 2021 17:00:42 +0200 Subject: [PATCH 01/39] chore: Update translations from Crowdin (#2790) Co-authored-by: Kostas Bariotis --- src/locales/ar-SA.json | 42 +++++++++-------- src/locales/bg-BG.json | 42 +++++++++-------- src/locales/ca-ES.json | 56 +++++++++++++---------- src/locales/de-DE.json | 28 +++++++----- src/locales/el-GR.json | 28 +++++++----- src/locales/es-ES.json | 30 +++++++----- src/locales/fa-IR.json | 42 +++++++++-------- src/locales/fi-FI.json | 32 +++++++------ src/locales/fr-FR.json | 88 +++++++++++++++++++----------------- src/locales/he-IL.json | 42 +++++++++-------- src/locales/hi-IN.json | 42 +++++++++-------- src/locales/hu-HU.json | 42 +++++++++-------- src/locales/id-ID.json | 42 +++++++++-------- src/locales/it-IT.json | 44 ++++++++++-------- src/locales/ja-JP.json | 42 +++++++++-------- src/locales/ko-KR.json | 42 +++++++++-------- src/locales/my-MM.json | 42 +++++++++-------- src/locales/nb-NO.json | 32 +++++++------ src/locales/nl-NL.json | 34 ++++++++------ src/locales/nn-NO.json | 42 +++++++++-------- src/locales/pa-IN.json | 42 +++++++++-------- src/locales/percentages.json | 38 ++++++++-------- src/locales/pl-PL.json | 42 +++++++++-------- src/locales/pt-BR.json | 30 +++++++----- src/locales/pt-PT.json | 28 +++++++----- src/locales/ro-RO.json | 30 +++++++----- src/locales/ru-RU.json | 54 ++++++++++++---------- src/locales/sk-SK.json | 42 +++++++++-------- src/locales/sv-SE.json | 28 +++++++----- src/locales/tr-TR.json | 42 +++++++++-------- src/locales/uk-UA.json | 32 +++++++------ src/locales/zh-CN.json | 42 +++++++++-------- src/locales/zh-TW.json | 38 +++++++++------- 33 files changed, 757 insertions(+), 565 deletions(-) diff --git a/src/locales/ar-SA.json b/src/locales/ar-SA.json index 6e69ed5fc..8c4de3578 100644 --- a/src/locales/ar-SA.json +++ b/src/locales/ar-SA.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "خطأ" }, - "shortcutsDialog": { - "title": "اختصارات لوحة المفاتيح", - "shapes": "الأشكال", - "or": "أو", - "click": "انقر", - "drag": "اسحب", - "curvedArrow": "سهم منحنى", - "curvedLine": "خط منحنى", - "editor": "المحرر", - "view": "المشهد", - "blog": "اقرأ مدونتنا", - "howto": "اتبع دليلنا", - "github": "عثرت على مشكلة؟ إرسال", - "textNewLine": "إضافة سطر جديد (نص)", - "textFinish": "الانتهاء من تحرير (النص)", - "zoomToFit": "تكبير لتلائم جميع العناصر", - "zoomToSelection": "تقريب للمحدد", - "preventBinding": "منع ربط السهم" + "helpDialog": { + "blog": "", + "click": "", + "curvedArrow": "", + "curvedLine": "", + "documentation": "", + "drag": "", + "editor": "", + "github": "", + "howto": "", + "or": "", + "preventBinding": "", + "shapes": "", + "shortcuts": "", + "textFinish": "", + "textNewLine": "", + "title": "", + "view": "", + "zoomToFit": "", + "zoomToSelection": "" }, "encrypted": { "tooltip": "رسوماتك مشفرة من النهاية إلى النهاية حتى أن خوادم Excalidraw لن تراها أبدا." @@ -232,5 +234,9 @@ "title": "إحصائيات للمهووسين", "total": "المجموع", "width": "العرض" + }, + "toast": { + "copyStyles": "", + "copyToClipboardAsPng": "" } } diff --git a/src/locales/bg-BG.json b/src/locales/bg-BG.json index 2101a395d..e63599b22 100644 --- a/src/locales/bg-BG.json +++ b/src/locales/bg-BG.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "Грешка" }, - "shortcutsDialog": { - "title": "Клавиши за бърз достъп", - "shapes": "Фигури", - "or": "или", - "click": "клик", - "drag": "плъзнете", - "curvedArrow": "Извита стрелка", - "curvedLine": "Извита линия", - "editor": "Редактор", - "view": "Преглед", - "blog": "Прочетете нашия блог", - "howto": "Следвайте нашите ръководства", - "github": "Намерихте проблем? Изпратете", - "textNewLine": "Добавяне на нов ред (текст)", - "textFinish": "Завършете редактиране (текст)", - "zoomToFit": "Приближи докато се виждат всички елементи", - "zoomToSelection": "Приближи селекцията", - "preventBinding": "Спри прилепяне на стрелките" + "helpDialog": { + "blog": "", + "click": "", + "curvedArrow": "", + "curvedLine": "", + "documentation": "", + "drag": "", + "editor": "", + "github": "", + "howto": "", + "or": "", + "preventBinding": "", + "shapes": "", + "shortcuts": "", + "textFinish": "", + "textNewLine": "", + "title": "", + "view": "", + "zoomToFit": "", + "zoomToSelection": "" }, "encrypted": { "tooltip": "Вашите рисунки са криптирани от край до край, така че сървърите на Excalidraw няма да могат да ги виждат." @@ -232,5 +234,9 @@ "title": "Статистика за хакери", "total": "Общо", "width": "Широчина" + }, + "toast": { + "copyStyles": "", + "copyToClipboardAsPng": "" } } diff --git a/src/locales/ca-ES.json b/src/locales/ca-ES.json index 9fedba288..09e17206f 100644 --- a/src/locales/ca-ES.json +++ b/src/locales/ca-ES.json @@ -30,17 +30,17 @@ "edges": "Vores", "sharp": "Agut", "round": "Arrodonit", - "arrowheads": "Punta de fletxa", + "arrowheads": "Puntes de fletxa", "arrowhead_none": "Cap", "arrowhead_arrow": "Fletxa", - "arrowhead_bar": "Línia", + "arrowhead_bar": "Barra", "arrowhead_dot": "Punt", "fontSize": "Mida de lletra", "fontFamily": "Tipus de lletra", "onlySelected": "Només seleccionats", "withBackground": "Amb fons", "exportEmbedScene": "Incrustar escena al fitxer exportat", - "exportEmbedScene_details": "Les dades de l’escena es desaran al fitxer PNG/SVG exportat de manera que es pugui restaurar l’escena.\nAugmentarà la mida del fitxer exportat.", + "exportEmbedScene_details": "Les dades de l’escena es desaran al fitxer PNG/SVG de manera que es pugui restaurar l’escena.\nAugmentarà la mida del fitxer exportat.", "addWatermark": "Afegir \"Fet amb Excalidraw\"", "handDrawn": "Dibuixat a mà", "normal": "Normal", @@ -61,7 +61,7 @@ "architect": "Arquitecte", "artist": "Artista", "cartoonist": "Dibuixant", - "fileTitle": "Títol de fitxer", + "fileTitle": "Títol del fitxer", "colorPicker": "Selector de colors", "canvasBackground": "Fons del llenç", "drawingCanvas": "Llenç de dibuix", @@ -127,7 +127,7 @@ "alerts": { "clearReset": "Tot el llenç s'esborrarà. Estàs segur?", "couldNotCreateShareableLink": "No s'ha pogut crear un enllaç per compartir.", - "couldNotCreateShareableLinkTooBig": "No s’ha pogut crear un enllaç compartible: l’escena és massa gran", + "couldNotCreateShareableLinkTooBig": "No s’ha pogut crear un enllaç per compartir: l’escena és massa gran", "couldNotLoadInvalidFile": "No s'ha pogut carregar un fitxer no vàlid", "importBackendFailed": "Importació fallida.", "cannotExportEmptyCanvas": "No es pot exportar un llenç buit.", @@ -162,7 +162,7 @@ "freeDraw": "Fer clic i arrosegar, deixar anar al punt final", "text": "Consell: també pots afegir text fent doble clic a qualsevol lloc amb l'eina de selecció", "linearElementMulti": "Fer clic a l'ultim punt, o polsar Escape o Enter per acabar", - "lockAngle": "Pots restringir l’angle mantenint premuda MAJÚS", + "lockAngle": "Per restringir els angles, mantenir premut el majúscul (SHIFT)", "resize": "Per restringir les proporcions mentres es canvia la mida, mantenir premut el majúscul (SHIFT); per canviar la mida des del centre, mantenir premut ALT", "rotate": "Per restringir els angles mentre gira, mantenir premut el majúscul (SHIFT)", "lineEditor_info": "Fes doble clic o premi Enter per editar punts", @@ -171,7 +171,7 @@ }, "canvasError": { "cannotShowPreview": "No es pot mostrar la vista prèvia", - "canvasTooBig": "El llenç pot ser massa gran.", + "canvasTooBig": "Pot ser que el llenç sigui massa gran.", "canvasTooBigTip": "Consell: prova d’acostar una mica els elements més allunyats." }, "errorSplash": { @@ -199,24 +199,26 @@ "errorDialog": { "title": "Error" }, - "shortcutsDialog": { - "title": "Dreceres de teclat", - "shapes": "Formes", - "or": "o", - "click": "fer clic", - "drag": "arrosegar", - "curvedArrow": "Fletxa curva", - "curvedLine": "Línea curva", - "editor": "Editor", - "view": "Vista", - "blog": "Llegir el nostre blog", - "howto": "Seguir els nostres guies", - "github": "Has trobat un problema? Enviar-ho", - "textNewLine": "Afegir línea nova (text)", - "textFinish": "Acabar d'editar (text)", - "zoomToFit": "Zoom per veure tots els elements", - "zoomToSelection": "Amplia la selecció", - "preventBinding": "Prevenir vinculació de la fletxa" + "helpDialog": { + "blog": "", + "click": "", + "curvedArrow": "", + "curvedLine": "", + "documentation": "", + "drag": "", + "editor": "", + "github": "", + "howto": "", + "or": "", + "preventBinding": "", + "shapes": "", + "shortcuts": "", + "textFinish": "", + "textNewLine": "", + "title": "", + "view": "", + "zoomToFit": "", + "zoomToSelection": "" }, "encrypted": { "tooltip": "Els vostres dibuixos estan xifrats de punta a punta de manera que els servidors d’Excalidraw no els veuran mai." @@ -232,5 +234,9 @@ "title": "Estadístiques per nerds", "total": "Total", "width": "Amplada" + }, + "toast": { + "copyStyles": "", + "copyToClipboardAsPng": "" } } diff --git a/src/locales/de-DE.json b/src/locales/de-DE.json index 15f420b88..e04ae760d 100644 --- a/src/locales/de-DE.json +++ b/src/locales/de-DE.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "Fehler" }, - "shortcutsDialog": { - "title": "Tastaturkürzel", - "shapes": "Formen", - "or": "oder", + "helpDialog": { + "blog": "Lies unseren Blog", "click": "klicken", - "drag": "ziehen", "curvedArrow": "Gebogener Pfeil", "curvedLine": "Gebogene Linie", + "documentation": "Dokumentation", + "drag": "ziehen", "editor": "Editor", - "view": "Ansicht", - "blog": "Unseren Blog lesen", - "howto": "Folge unseren Anleitungen", "github": "Ein Problem gefunden? Informiere uns", - "textNewLine": "Neue Zeile hinzufügen (Text)", + "howto": "Folge unseren Anleitungen", + "or": "oder", + "preventBinding": "Pfeil-Bindung verhindern", + "shapes": "Formen", + "shortcuts": "Tastaturkürzel", "textFinish": "Bearbeiten beenden (Text)", + "textNewLine": "Neue Zeile hinzufügen (Text)", + "title": "Hilfe", + "view": "Ansicht", "zoomToFit": "Zoomen um alle Elemente einzupassen", - "zoomToSelection": "Zoomauswahl", - "preventBinding": "Pfeil-Bindung verhindern" + "zoomToSelection": "Auf Auswahl zoomen" }, "encrypted": { "tooltip": "Da deine Zeichnungen Ende-zu-Ende verschlüsselt werden, sehen auch unsere Excalidraw-Server sie niemals." @@ -232,5 +234,9 @@ "title": "Statistiken für Nerds", "total": "Gesamt", "width": "Breite" + }, + "toast": { + "copyStyles": "Formatierung kopiert.", + "copyToClipboardAsPng": "In die Zwischenablage als PNG kopiert." } } diff --git a/src/locales/el-GR.json b/src/locales/el-GR.json index 5c91f44b3..ea3e28611 100644 --- a/src/locales/el-GR.json +++ b/src/locales/el-GR.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "Σφάλμα" }, - "shortcutsDialog": { - "title": "Συντομεύσεις πληκτρολογίου", - "shapes": "Σχήματα", - "or": "ή", + "helpDialog": { + "blog": "Διαβάστε το Blog μας", "click": "κλικ", - "drag": "σύρε", "curvedArrow": "Κυρτό βέλος", "curvedLine": "Κυρτή γραμμή", + "documentation": "Εγχειρίδιο", + "drag": "σύρε", "editor": "Επεξεργαστής", - "view": "Προβολή", - "blog": "Διαβάστε το ιστολόγιο μας", - "howto": "Ακολουθήστε τους οδηγούς μας", "github": "Βρήκατε πρόβλημα; Υποβάλετε το", - "textNewLine": "Προσθήκη νέας γραμμής (κείμενο)", + "howto": "Ακολουθήστε τους οδηγούς μας", + "or": "ή", + "preventBinding": "Αποτροπή δέσμευσης βέλων", + "shapes": "Σχήματα", + "shortcuts": "Συντομεύσεις πληκτρολογίου", "textFinish": "Ολοκλήρωση επεξεργασίας (κείμενο)", + "textNewLine": "Προσθήκη νέας γραμμής (κείμενο)", + "title": "Βοήθεια", + "view": "Προβολή", "zoomToFit": "Zoom ώστε να χωρέσουν όλα τα στοιχεία", - "zoomToSelection": "Εστίαση στην επιλογή", - "preventBinding": "Αποτροπή δέσμευσης βέλων" + "zoomToSelection": "Ζουμ στην επιλογή" }, "encrypted": { "tooltip": "Τα σχέδιά σου είναι κρυπτογραφημένα από άκρο σε άκρο, έτσι δεν θα έιναι ποτέ ορατά μέσα από τους διακομιστές του Excalidraw." @@ -232,5 +234,9 @@ "title": "Στατιστικά για σπασίκλες", "total": "Σύνολο ", "width": "Πλάτος" + }, + "toast": { + "copyStyles": "Αντιγράφηκαν στυλ.", + "copyToClipboardAsPng": "Αντιγράφτηκε στο πρόχειρο ως PNG." } } diff --git a/src/locales/es-ES.json b/src/locales/es-ES.json index f83d779b4..ecb7f461f 100644 --- a/src/locales/es-ES.json +++ b/src/locales/es-ES.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "Error" }, - "shortcutsDialog": { - "title": "Atajos del teclado", - "shapes": "Formas", - "or": "o", - "click": "clic", - "drag": "arrastrar", + "helpDialog": { + "blog": "Lee nuestro blog", + "click": "click", "curvedArrow": "Flecha curvada", "curvedLine": "Línea curva", + "documentation": "Documentación", + "drag": "arrastrar", "editor": "Editor", - "view": "Vista", - "blog": "Lee nuestro blog", - "howto": "Siga nuestras guías", "github": "¿Has encontrado un problema? Envíalo", - "textNewLine": "Añadir nueva línea (texto)", + "howto": "Siga nuestras guías", + "or": "o", + "preventBinding": "Evitar yuxtaposición de flechas", + "shapes": "Formas", + "shortcuts": "Atajos del teclado", "textFinish": "Finalizar edición (texto)", + "textNewLine": "Añadir nueva línea (texto)", + "title": "Ayuda", + "view": "Vista", "zoomToFit": "Ajustar la vista para mostrar todos los elementos", - "zoomToSelection": "Hacer zoom a la selección", - "preventBinding": "Evitar yuxtaposición de flechas" + "zoomToSelection": "Hacer zoom a la selección" }, "encrypted": { "tooltip": "Tus dibujos están cifrados de punto a punto, por lo que los servidores de Excalidraw nunca los verán." @@ -232,5 +234,9 @@ "title": "Estadísticas para nerds", "total": "Total", "width": "Ancho" + }, + "toast": { + "copyStyles": "Estilos copiados.", + "copyToClipboardAsPng": "Copiado al portapapeles como PNG." } } diff --git a/src/locales/fa-IR.json b/src/locales/fa-IR.json index 229949301..a209e6138 100644 --- a/src/locales/fa-IR.json +++ b/src/locales/fa-IR.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "خطا" }, - "shortcutsDialog": { - "title": "میانبرهای صفحه کلید", - "shapes": "شکل‌ها", - "or": "یا", - "click": "کلیک", - "drag": "کشیدن", - "curvedArrow": "فلش خمیده", - "curvedLine": "منحنی", - "editor": "ویرایشگر", - "view": "نمایش", - "blog": "بلاگ ما را بخوانید", - "howto": "راهنمای ما را دنبال کنید", - "github": "اشکالی می بینید؟ گزارش دهید", - "textNewLine": "یک خط جدید اضافه کنید (متن)", - "textFinish": "پایان ویرایش (متن)", - "zoomToFit": "بزرگنمایی برای دیدن تمام آیتم ها", - "zoomToSelection": "بزرگنمایی قسمت انتخاب شده", - "preventBinding": "مانع شدن از چسبیدن فلش ها" + "helpDialog": { + "blog": "", + "click": "", + "curvedArrow": "", + "curvedLine": "", + "documentation": "", + "drag": "", + "editor": "", + "github": "", + "howto": "", + "or": "", + "preventBinding": "", + "shapes": "", + "shortcuts": "", + "textFinish": "", + "textNewLine": "", + "title": "", + "view": "", + "zoomToFit": "", + "zoomToSelection": "" }, "encrypted": { "tooltip": "شما در یک محیط رمزگزاری شده دو طرفه در حال طراحی هستید پس Excalidraw هرگز طرح های شما را نمیبند." @@ -232,5 +234,9 @@ "title": "آمار برای نردها", "total": "مجموع", "width": "عرض" + }, + "toast": { + "copyStyles": "", + "copyToClipboardAsPng": "" } } diff --git a/src/locales/fi-FI.json b/src/locales/fi-FI.json index da4e000b3..ae1e65a0e 100644 --- a/src/locales/fi-FI.json +++ b/src/locales/fi-FI.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "Virhe" }, - "shortcutsDialog": { - "title": "Pikanäppäimet", - "shapes": "Muodot", - "or": "tai", + "helpDialog": { + "blog": "Lue blogiamme", "click": "klikkaa", - "drag": "vedä", "curvedArrow": "Kaareva nuoli", "curvedLine": "Kaareva viiva", - "editor": "Editori", - "view": "Näkymä", - "blog": "Lue blogiamme", - "howto": "Seuraa oppaitamme", + "documentation": "Käyttöohjeet", + "drag": "vedä", + "editor": "Muokkausohjelma", "github": "Löysitkö ongelman? Kerro meille", - "textNewLine": "Lisää uusi rivi (teksti)", + "howto": "Seuraa oppaitamme", + "or": "tai", + "preventBinding": "Estä nuolten kiinnitys", + "shapes": "Muodot", + "shortcuts": "Pikanäppäimet", "textFinish": "Lopeta muokkaus (teksti)", - "zoomToFit": "Zoomaa kaikki elementit näkyviin", - "zoomToSelection": "Zoomaa valintaan", - "preventBinding": "Estä nuolten sitominen" + "textNewLine": "Lisää uusi rivi (teksti)", + "title": "Ohjeet", + "view": "Näkymä", + "zoomToFit": "Näytä kaikki elementit", + "zoomToSelection": "Näytä valinta" }, "encrypted": { "tooltip": "Piirroksesi ovat päästä päähän salattuja, joten Excalidrawin palvelimet eivät koskaan näe niitä." @@ -232,5 +234,9 @@ "title": "Nörttien tilastot", "total": "Yhteensä", "width": "Leveys" + }, + "toast": { + "copyStyles": "Tyylit kopioitu.", + "copyToClipboardAsPng": "Kopioitu leikepöydälle PNG-tiedostona." } } diff --git a/src/locales/fr-FR.json b/src/locales/fr-FR.json index 04bc89eae..81aa95f01 100644 --- a/src/locales/fr-FR.json +++ b/src/locales/fr-FR.json @@ -19,7 +19,7 @@ "stroke": "Contour", "background": "Arrière-plan", "fill": "Remplissage", - "strokeWidth": "Largeur du contour", + "strokeWidth": "Largeur du trait", "strokeStyle": "Style du trait", "strokeStyle_solid": "Plein", "strokeStyle_dashed": "Tirets", @@ -28,10 +28,10 @@ "opacity": "Opacité", "textAlign": "Alignement du texte", "edges": "Angles", - "sharp": "Aigu", - "round": "Rond", - "arrowheads": "Extrémités de ligne", - "arrowhead_none": "Aucun", + "sharp": "Pointus", + "round": "Arrondis", + "arrowheads": "Extrémités de flèche", + "arrowhead_none": "Aucune", "arrowhead_arrow": "Flèche", "arrowhead_bar": "Barre", "arrowhead_dot": "Point", @@ -42,7 +42,7 @@ "exportEmbedScene": "Intégrer la scène au fichier exporté", "exportEmbedScene_details": "Les données de scène seront enregistrées dans le fichier PNG/SVG exporté, afin que la scène puisse être restaurée à partir de celui-ci.\nCela augmentera la taille du fichier exporté.", "addWatermark": "Ajouter \"Fait avec Excalidraw\"", - "handDrawn": "Manuscrite", + "handDrawn": "À main levée", "normal": "Normale", "code": "Code", "small": "Petit", @@ -64,7 +64,7 @@ "fileTitle": "Titre du fichier", "colorPicker": "Sélecteur de couleur", "canvasBackground": "Arrière-plan du canevas", - "drawingCanvas": "Canvas de dessin", + "drawingCanvas": "Zone de dessin", "layers": "Calques", "actions": "Actions", "language": "Langue", @@ -81,9 +81,9 @@ "addToLibrary": "Ajouter à la bibliothèque", "removeFromLibrary": "Supprimer de la bibliothèque", "libraryLoadingMessage": "Chargement de la bibliothèque...", - "libraries": "Explorer les bibliothèques", + "libraries": "Parcourir les bibliothèques", "loadingScene": "Chargement de la scène...", - "align": "Alignement", + "align": "Aligner", "alignTop": "Aligner en haut", "alignBottom": "Aligner en bas", "alignLeft": "Aligner à gauche", @@ -99,7 +99,7 @@ "exportToPng": "Exporter en PNG", "exportToSvg": "Exporter en SVG", "copyToClipboard": "Copier dans le presse-papier", - "copyPngToClipboard": "Copier le PNG dans le presse-papier", + "copyPngToClipboard": "Copier le PNG vers le presse-papier", "scale": "Échelle", "save": "Sauvegarder", "saveAs": "Enregistrer sous", @@ -116,12 +116,12 @@ "edit": "Modifier", "undo": "Annuler", "redo": "Rétablir", - "roomDialog": "Démarrer le collaboration en temps réel", - "createNewRoom": "Créer un nouveau salon", + "roomDialog": "Démarrer la collaboration en direct", + "createNewRoom": "Créer une nouvelle salle", "fullScreen": "Plein écran", "darkMode": "Mode sombre", - "lightMode": "Mode Clair", - "zenMode": "Mode Zen", + "lightMode": "Mode clair", + "zenMode": "Mode zen", "exitZenMode": "Quitter le mode zen" }, "alerts": { @@ -136,8 +136,8 @@ "uploadedSecurly": "Le téléchargement a été sécurisé avec un chiffrement de bout en bout, ce qui signifie que ni Excalidraw ni personne d'autre ne peut en lire le contenu.", "loadSceneOverridePrompt": "Le chargement d'un dessin externe remplacera votre contenu actuel. Souhaitez-vous continuer ?", "errorLoadingLibrary": "Une erreur s'est produite lors du chargement de la bibliothèque tierce.", - "confirmAddLibrary": "Cela va ajouter {{numShapes}} forme(s) à votre bibliothèque. Êtes-vous sûr(e) ?", - "imageDoesNotContainScene": "L'importation des images n'est pas prise en charge pour le moment.\n\nVoulez-vous importer une scène ? Cette image ne semble pas contenir de données de scène. Avez-vous activé cette option lors de l'exportation ?", + "confirmAddLibrary": "Cela va ajouter {{numShapes}} forme(s) à votre bibliothèque. Êtes-vous sûr·e ?", + "imageDoesNotContainScene": "L'importation d'images n'est pas prise en charge pour le moment.\n\nVouliez-vous importer une scène ? Cette image ne semble pas contenir de données de scène. Avez-vous activé cette option lors de l'exportation ?", "cannotRestoreFromImage": "Impossible de restaurer la scène depuis ce fichier image" }, "toolBar": { @@ -160,63 +160,65 @@ "hints": { "linearElement": "Cliquez pour démarrer plusieurs points, faites glisser pour une seule ligne", "freeDraw": "Cliquez et faites glissez, relâchez quand vous avez terminé", - "text": "Astuce : vous pouvez également ajouter du texte en double-cliquant n'importe où avec l'outil de sélection", + "text": "Astuce : vous pouvez aussi ajouter du texte en double-cliquant n'importe où avec l'outil de sélection", "linearElementMulti": "Cliquez sur le dernier point ou appuyez sur Échap ou Entrée pour terminer", - "lockAngle": "Vous pouvez contraindre l'angle en maintenant SHIFT", - "resize": "Vous pouvez conserver les proportions en maintenant la touche SHIFT pendant le redimensionnement,\nen maintenant la touche ALT pour redimensionner par rapport au centre", - "rotate": "Vous pouvez contraindre les angles en maintenant MAJ enfoncé pendant la rotation", + "lockAngle": "Vous pouvez restreindre l'angle en maintenant MAJ", + "resize": "Vous pouvez conserver les proportions en maintenant la touche MAJ pendant le redimensionnement,\nmaintenez la touche ALT pour redimensionner par rapport au centre", + "rotate": "Vous pouvez restreindre les angles en maintenant MAJ pendant la rotation", "lineEditor_info": "Double-cliquez ou appuyez sur Entrée pour éditer les points", "lineEditor_pointSelected": "Appuyez sur Supprimer pour supprimer le point, Ctrl ou Cmd+D pour le dupliquer, ou faites-le glisser pour le déplacer", - "lineEditor_nothingSelected": "Sélectionnez un point à déplacer ou à supprimer, ou maintenez Alt enfoncé et cliquez pour ajouter de nouveaux points" + "lineEditor_nothingSelected": "Sélectionnez un point à déplacer ou supprimer, ou maintenez Alt et cliquez pour ajouter de nouveaux points" }, "canvasError": { "cannotShowPreview": "Impossible d’afficher l’aperçu", "canvasTooBig": "Le canevas est peut-être trop grand.", - "canvasTooBigTip": "Conseil : essayez de rapprocher un peu plus les éléments les plus éloignés." + "canvasTooBigTip": "Astuce : essayez de rapprocher un peu les éléments les plus éloignés." }, "errorSplash": { "headingMain_pre": "Une erreur est survenue. Essayez ", - "headingMain_button": "rechargement de la page.", + "headingMain_button": "de recharger la page.", "clearCanvasMessage": "Si le rechargement ne résout pas l'erreur, essayez ", "clearCanvasMessage_button": "effacement du canevas.", "clearCanvasCaveat": " Cela entraînera une perte du travail ", "trackedToSentry_pre": "L'erreur avec l'identifiant ", "trackedToSentry_post": " a été enregistrée dans notre système.", - "openIssueMessage_pre": "Nous avons été très prudents de ne pas inclure les informations de votre scène dans l'erreur. Si votre scène n'est pas privée, veuillez envisager de poursuivre sur notre ", + "openIssueMessage_pre": "Nous avons fait très attention à ne pas inclure les informations de votre scène dans l'erreur. Si votre scène n'est pas privée, veuillez envisager de poursuivre sur notre ", "openIssueMessage_button": "outil de suivi des bugs.", "openIssueMessage_post": " Veuillez inclure les informations ci-dessous en les copiant-collant dans le ticket GitHub.", "sceneContent": "Contenu de la scène :" }, "roomDialog": { - "desc_intro": "Vous pouvez inviter des personnes dans votre scène actuelle à collaborer avec vous.", - "desc_privacy": "Ne vous inquiétez pas, la session utilise le chiffrement de bout en bout, donc tout ce que vous dessinez restera privé. Même notre serveur ne sera pas en mesure de voir ce que vous faites.", + "desc_intro": "Vous pouvez inviter des personnes à collaborer avec vous sur votre scène actuelle.", + "desc_privacy": "Pas d'inquiétude, la session utilise le chiffrement de bout en bout, donc tout ce que vous dessinez restera privé. Même notre serveur ne pourra voir ce que vous faites.", "button_startSession": "Démarrer la session", "button_stopSession": "Arrêter la session", "desc_inProgressIntro": "La session de collaboration en direct est maintenant en cours.", - "desc_shareLink": "Partagez ce lien avec ceux avec qui vous souhaitez collaborer :", - "desc_exitSession": "Arrêter la session vous déconnectera du salon, mais vous pourrez continuer à travailler avec la scène, localement. Notez que cela n'affectera pas les autres personnes, et ils seront toujours en mesure de collaborer sur leur version." + "desc_shareLink": "Partagez ce lien avec les personnes avec lesquelles vous souhaitez collaborer :", + "desc_exitSession": "Arrêter la session vous déconnectera de la salle, mais vous pourrez continuer à travailler avec la scène, localement. Notez que cela n'affectera pas les autres personnes, et ils pourront toujours collaborer sur leur version." }, "errorDialog": { "title": "Erreur" }, - "shortcutsDialog": { - "title": "Raccourcis clavier", - "shapes": "Formes", - "or": "ou", - "click": "cliquer", - "drag": "glisser", + "helpDialog": { + "blog": "Lire notre blog", + "click": "clic", "curvedArrow": "Flèche courbée", "curvedLine": "Ligne courbée", + "documentation": "Documentation", + "drag": "glisser", "editor": "Éditeur", - "view": "Afficher", - "blog": "Lisez notre blog", + "github": "Problème trouvé ? Soumettre", "howto": "Suivez nos guides", - "github": "Vous avez trouvé un problème ? Envoyer", - "textNewLine": "Ajouter une nouvelle ligne (texte)", + "or": "ou", + "preventBinding": "Empêcher la liaison de flèche", + "shapes": "Formes", + "shortcuts": "Raccourcis clavier", "textFinish": "Terminer l'édition (texte)", - "zoomToFit": "Zoomer pour visualiser tous les éléments", - "zoomToSelection": "Zoomer sur la sélection", - "preventBinding": "Empêcher la liaison de la flèche" + "textNewLine": "Ajouter une nouvelle ligne (texte)", + "title": "Aide", + "view": "Affichage", + "zoomToFit": "Zoomer pour voir tous les éléments", + "zoomToSelection": "Zoomer sur la sélection" }, "encrypted": { "tooltip": "Vos dessins sont chiffrés de bout en bout, les serveurs d'Excalidraw ne les verront jamais." @@ -232,5 +234,9 @@ "title": "Stats pour les nerds", "total": "Total", "width": "Largeur" + }, + "toast": { + "copyStyles": "Styles copiés.", + "copyToClipboardAsPng": "Copié vers le presse-papier en PNG." } } diff --git a/src/locales/he-IL.json b/src/locales/he-IL.json index 9d8fb25b2..c4b08559b 100644 --- a/src/locales/he-IL.json +++ b/src/locales/he-IL.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "שגיאה" }, - "shortcutsDialog": { - "title": "קיצורי מקלדת", - "shapes": "צורות", - "or": "או", - "click": "לחץ", - "drag": "גרור", - "curvedArrow": "חץ מעוקל", - "curvedLine": "קו מעוקל", - "editor": "עורך", - "view": "תצוגה", - "blog": "קרא את הבלוג שלנו", - "howto": "עקוב אחר המדריכים שלנו", - "github": "מצאת בעיה? דווח", - "textNewLine": "הוסף שורה חדשה (טקסט)", - "textFinish": "סיים עריכה (טקסט)", - "zoomToFit": "זום להתאמת כל האלמנטים למסך", - "zoomToSelection": "התמקד בבחירה", - "preventBinding": "מנע השתלבות חצים" + "helpDialog": { + "blog": "", + "click": "", + "curvedArrow": "", + "curvedLine": "", + "documentation": "", + "drag": "", + "editor": "", + "github": "", + "howto": "", + "or": "", + "preventBinding": "", + "shapes": "", + "shortcuts": "", + "textFinish": "", + "textNewLine": "", + "title": "", + "view": "", + "zoomToFit": "", + "zoomToSelection": "" }, "encrypted": { "tooltip": "הרישומים שלך מוצפנים מקצה לקצה כך שהשרתים של Excalidraw לא יראו אותם לעולם." @@ -232,5 +234,9 @@ "title": "סטטיסטיקות לחנונים", "total": "סה״כ", "width": "רוחב" + }, + "toast": { + "copyStyles": "", + "copyToClipboardAsPng": "" } } diff --git a/src/locales/hi-IN.json b/src/locales/hi-IN.json index a87fa7586..d15ba6a82 100644 --- a/src/locales/hi-IN.json +++ b/src/locales/hi-IN.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "गलती" }, - "shortcutsDialog": { - "title": "कीबोर्ड के शॉर्टकट्स", - "shapes": "आकृतियाँ", - "or": "या", - "click": "क्लिक करें", - "drag": "खींचें", - "curvedArrow": "घुमावदार तीर", - "curvedLine": "घुमावदार रेखा", - "editor": "संपादक", - "view": "दृश्य", - "blog": "हमारा ब्लॉग पढे", - "howto": "हमारे गाइड का पालन करें", - "github": "एक मुद्दा मिला? प्रस्तुत करे", - "textNewLine": "नई पंक्ति (पाठ) जोड़ें", - "textFinish": "संपादन समाप्त करें (पाठ)", - "zoomToFit": "सभी तत्वों को फिट करने के लिए ज़ूम करें", - "zoomToSelection": "सिलेक्शन तक ज़ूम करे", - "preventBinding": "तीर बंधन रोकें" + "helpDialog": { + "blog": "", + "click": "", + "curvedArrow": "", + "curvedLine": "", + "documentation": "", + "drag": "", + "editor": "", + "github": "", + "howto": "", + "or": "", + "preventBinding": "", + "shapes": "", + "shortcuts": "", + "textFinish": "", + "textNewLine": "", + "title": "", + "view": "", + "zoomToFit": "", + "zoomToSelection": "" }, "encrypted": { "tooltip": "आपके चित्र अंत-से-अंत एन्क्रिप्टेड हैं, इसलिए एक्सक्लूसिव्रॉव के सर्वर उन्हें कभी नहीं देखेंगे।" @@ -232,5 +234,9 @@ "title": "बेवकूफ के लिए आँकड़े", "total": "कुल", "width": "चौड़ाई" + }, + "toast": { + "copyStyles": "", + "copyToClipboardAsPng": "" } } diff --git a/src/locales/hu-HU.json b/src/locales/hu-HU.json index d6c503453..3b3756b03 100644 --- a/src/locales/hu-HU.json +++ b/src/locales/hu-HU.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "Hiba" }, - "shortcutsDialog": { - "title": "Gyorsbillentyűk", - "shapes": "Formák", - "or": "vagy", - "click": "klikk", - "drag": "húzd", - "curvedArrow": "Ívelt nyíl", - "curvedLine": "Ívelt vonal", - "editor": "Szerkesztő", - "view": "Nézet", - "blog": "Olvasd a blogunkat", - "howto": "Kövesd az útmutatóinkat", - "github": "Hibát találtál? Küld be", - "textNewLine": "Új sor hozzáadása (szöveg)", - "textFinish": "Szerkesztés befejezése (szöveg)", - "zoomToFit": "Az összes elem látótérbe hozása", - "zoomToSelection": "Kijelölésre nagyítás", - "preventBinding": "A nyíl ne ragadjon" + "helpDialog": { + "blog": "", + "click": "", + "curvedArrow": "", + "curvedLine": "", + "documentation": "", + "drag": "", + "editor": "", + "github": "", + "howto": "", + "or": "", + "preventBinding": "", + "shapes": "", + "shortcuts": "", + "textFinish": "", + "textNewLine": "", + "title": "", + "view": "", + "zoomToFit": "", + "zoomToSelection": "" }, "encrypted": { "tooltip": "A rajzaidat végpontok közötti titkosítással tároljuk, tehát az Excalidraw szervereiről se tud más belenézni." @@ -232,5 +234,9 @@ "title": "Statisztikák", "total": "Összesen", "width": "Szélesség" + }, + "toast": { + "copyStyles": "", + "copyToClipboardAsPng": "" } } diff --git a/src/locales/id-ID.json b/src/locales/id-ID.json index 76fadab92..35ba440ec 100644 --- a/src/locales/id-ID.json +++ b/src/locales/id-ID.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "Kesalahan" }, - "shortcutsDialog": { - "title": "Pintasan keyboard", - "shapes": "Bentuk", - "or": "atau", - "click": "klik", - "drag": "seret", - "curvedArrow": "Panah lengkung", - "curvedLine": "Garis lengkung", - "editor": "Editor", - "view": "Tampilan", - "blog": "Baca blog kami", - "howto": "Ikuti panduan kami", - "github": "Menemukan sebuah masalah? Kirimkan", - "textNewLine": "Tambahkan baris baru (teks)", - "textFinish": "Selesai mengedit (teks)", - "zoomToFit": "Perbesar agar sesuai dengan semua elemen", - "zoomToSelection": "Perbesar ke seleksi", - "preventBinding": "Cegah pengikatan panah" + "helpDialog": { + "blog": "", + "click": "", + "curvedArrow": "", + "curvedLine": "", + "documentation": "", + "drag": "", + "editor": "", + "github": "", + "howto": "", + "or": "", + "preventBinding": "", + "shapes": "", + "shortcuts": "", + "textFinish": "", + "textNewLine": "", + "title": "", + "view": "", + "zoomToFit": "", + "zoomToSelection": "" }, "encrypted": { "tooltip": "Gambar anda terenkripsi end-to-end sehingga server Excalidraw tidak akan pernah dapat melihatnya." @@ -232,5 +234,9 @@ "title": "Statistik untuk nerd", "total": "Total", "width": "Lebar" + }, + "toast": { + "copyStyles": "Gaya tersalin.", + "copyToClipboardAsPng": "Tersalin ke clipboard sebagai PNG." } } diff --git a/src/locales/it-IT.json b/src/locales/it-IT.json index 0faf287fd..455b36cc1 100644 --- a/src/locales/it-IT.json +++ b/src/locales/it-IT.json @@ -163,7 +163,7 @@ "text": "Suggerimento: puoi anche aggiungere del testo facendo doppio clic ovunque con lo strumento di selezione", "linearElementMulti": "Clicca sull'ultimo punto o premi Esc o Invio per finire", "lockAngle": "Puoi limitare l'angolo tenendo premuto SHIFT", - "resize": "Per vincolare le proporzioni, tenir premuto MAIUSC durante il ridimensionamento;\nper ridimensionare dal centro, tenir premuto ALT", + "resize": "Per vincolare le proporzioni, tieni premuto MAIUSC durante il ridimensionamento;\nper ridimensionare dal centro, tieni premuto ALT", "rotate": "Puoi mantenere gli angoli tenendo premuto SHIFT durante la rotazione", "lineEditor_info": "Fai doppio click o premi invio per modificare i punti", "lineEditor_pointSelected": "Premere Elimina per rimuovere il punto, CtrlOrCmd+D per duplicare o trascinare per spostare", @@ -199,24 +199,26 @@ "errorDialog": { "title": "Errore" }, - "shortcutsDialog": { - "title": "Scorciatoie da tastiera", - "shapes": "Forme", - "or": "oppure", - "click": "click", - "drag": "trascina", - "curvedArrow": "Freccia curva", - "curvedLine": "Linea curva", - "editor": "Editor", - "view": "Vista", - "blog": "Leggi il nostro blog", - "howto": "Segui le nostre guide", - "github": "Hai trovato un problema? Segnalalo", - "textNewLine": "Aggiungi nuova riga (testo)", - "textFinish": "Completa la modifica (testo)", - "zoomToFit": "Adatta zoom per mostrare tutti gli elementi", - "zoomToSelection": "Zoom alla selezione", - "preventBinding": "Prevenire l'associazione freccia" + "helpDialog": { + "blog": "", + "click": "", + "curvedArrow": "", + "curvedLine": "", + "documentation": "", + "drag": "", + "editor": "", + "github": "", + "howto": "", + "or": "", + "preventBinding": "", + "shapes": "", + "shortcuts": "", + "textFinish": "", + "textNewLine": "", + "title": "", + "view": "", + "zoomToFit": "", + "zoomToSelection": "" }, "encrypted": { "tooltip": "I tuoi disegni sono crittografati end-to-end in modo che i server di Excalidraw non li possano mai vedere." @@ -232,5 +234,9 @@ "title": "Statistiche per nerd", "total": "Totale", "width": "Larghezza" + }, + "toast": { + "copyStyles": "Stili copiati.", + "copyToClipboardAsPng": "Copiato negli appunti come PNG." } } diff --git a/src/locales/ja-JP.json b/src/locales/ja-JP.json index 59e93fc51..6599251cb 100644 --- a/src/locales/ja-JP.json +++ b/src/locales/ja-JP.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "エラー" }, - "shortcutsDialog": { - "title": "キーボードショートカット", - "shapes": "図形", - "or": "または", - "click": "クリック", - "drag": "ドラッグ", - "curvedArrow": "曲がった矢印", - "curvedLine": "曲線", - "editor": "エディタ", - "view": "表示", - "blog": "公式ブログを読む", - "howto": "ヘルプ・マニュアル", - "github": "不具合報告はこちら", - "textNewLine": "テキストの改行", - "textFinish": "テキストの編集を終える", - "zoomToFit": "すべての図形が収まるよう拡大/縮小", - "zoomToSelection": "", - "preventBinding": "矢印を結合しない" + "helpDialog": { + "blog": "", + "click": "", + "curvedArrow": "", + "curvedLine": "", + "documentation": "", + "drag": "", + "editor": "", + "github": "", + "howto": "", + "or": "", + "preventBinding": "", + "shapes": "", + "shortcuts": "", + "textFinish": "", + "textNewLine": "", + "title": "", + "view": "", + "zoomToFit": "", + "zoomToSelection": "" }, "encrypted": { "tooltip": "描画内容はエンドツーエンド暗号化が施されており、Excalidrawサーバーが内容を見ることはできません。" @@ -232,5 +234,9 @@ "title": "", "total": "合計", "width": "幅" + }, + "toast": { + "copyStyles": "", + "copyToClipboardAsPng": "" } } diff --git a/src/locales/ko-KR.json b/src/locales/ko-KR.json index 61c026ce0..97774308d 100644 --- a/src/locales/ko-KR.json +++ b/src/locales/ko-KR.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "오류" }, - "shortcutsDialog": { - "title": "키보드 단축키", - "shapes": "모양", - "or": "또는", - "click": "클릭", - "drag": "드래그", - "curvedArrow": "곡선 화살표", - "curvedLine": "곡선", - "editor": "편집", - "view": "보기", - "blog": "블로그 읽어보기", - "howto": "가이드 참고하기", - "github": "이슈 제보하기", - "textNewLine": "줄바꿈 (텍스트)", - "textFinish": "편집 완료 (텍스트)", - "zoomToFit": "모든 요소가 보이도록 확대/축소", - "zoomToSelection": "선택 영역으로 확대/축소", - "preventBinding": "화살표가 붙지 않게 하기" + "helpDialog": { + "blog": "", + "click": "", + "curvedArrow": "", + "curvedLine": "", + "documentation": "", + "drag": "", + "editor": "", + "github": "", + "howto": "", + "or": "", + "preventBinding": "", + "shapes": "", + "shortcuts": "", + "textFinish": "", + "textNewLine": "", + "title": "", + "view": "", + "zoomToFit": "", + "zoomToSelection": "" }, "encrypted": { "tooltip": "그림은 종단 간 암호화되므로 Excalidraw의 서버는 절대로 내용을 알 수 없습니다." @@ -232,5 +234,9 @@ "title": "덕후들을 위한 통계", "total": "합계", "width": "너비" + }, + "toast": { + "copyStyles": "", + "copyToClipboardAsPng": "" } } diff --git a/src/locales/my-MM.json b/src/locales/my-MM.json index dd355f5d7..b4093175a 100644 --- a/src/locales/my-MM.json +++ b/src/locales/my-MM.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "ချို့ယွင်းချက်" }, - "shortcutsDialog": { - "title": "ကီးဘုတ်ရှော့ကတ်များ", - "shapes": "ပုံသဏ္ဌာန်", - "or": "(သို့)", - "click": "ကလစ်နှိပ်", - "drag": "တရွတ်ဆွဲ", - "curvedArrow": "မြှားကွေး", - "curvedLine": "မျဉ်းကွေး", - "editor": "တည်းဖြတ်", - "view": "မြင်ကွင်း", - "blog": "ဘလော့ဂ်တွင်လေ့လာပါ", - "howto": "အညွှန်း", - "github": "ချို့ယွင်းမှုအတွက်အသိပေးရန်", - "textNewLine": "စာသားဖြည့်သွင်း", - "textFinish": "စာသားဖြည့်သွင်းပြီး", - "zoomToFit": "ကားချပ်အပြည့်ဖေါ်", - "zoomToSelection": "", - "preventBinding": "မြှားများမပေါင်းစေရန်" + "helpDialog": { + "blog": "", + "click": "", + "curvedArrow": "", + "curvedLine": "", + "documentation": "", + "drag": "", + "editor": "", + "github": "", + "howto": "", + "or": "", + "preventBinding": "", + "shapes": "", + "shortcuts": "", + "textFinish": "", + "textNewLine": "", + "title": "", + "view": "", + "zoomToFit": "", + "zoomToSelection": "" }, "encrypted": { "tooltip": "ရေးဆွဲထားသောပုံများအား နှစ်ဘက်စွန်းတိုင်လျှို့ဝှက်ထားသဖြင့် Excalidraw ၏ဆာဗာများပင်လျှင်မြင်တွေ့ရမည်မဟုတ်ပါ။" @@ -232,5 +234,9 @@ "title": "အက္ခရာများအတွက်အချက်အလက်များ", "total": "စုစုပေါင်း", "width": "အကျယ်" + }, + "toast": { + "copyStyles": "", + "copyToClipboardAsPng": "" } } diff --git a/src/locales/nb-NO.json b/src/locales/nb-NO.json index 7c0075672..189136121 100644 --- a/src/locales/nb-NO.json +++ b/src/locales/nb-NO.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "Feil" }, - "shortcutsDialog": { - "title": "Tastatursnarveier", - "shapes": "Figurer", - "or": "eller", + "helpDialog": { + "blog": "Les bloggen vår", "click": "klikk", - "drag": "dra", "curvedArrow": "Buet pil", "curvedLine": "Buet linje", - "editor": "Redigering", - "view": "Visning", - "blog": "Les bloggen vår", - "howto": "Følg våre veiledninger", + "documentation": "Dokumentasjon", + "drag": "dra", + "editor": "Redigeringsvisning", "github": "Funnet et problem? Send inn", - "textNewLine": "Legg til ny linje (tekst)", + "howto": "Følg våre veiledninger", + "or": "eller", + "preventBinding": "Forhindre pilbinding", + "shapes": "Former", + "shortcuts": "Tastatursnarveier", "textFinish": "Fullfør redigering (tekst)", - "zoomToFit": "Zoom for å passe alle elementene", - "zoomToSelection": "Zoom til utvalg", - "preventBinding": "Forhindre pilbinding" + "textNewLine": "Legg til ny linje (tekst)", + "title": "Hjelp", + "view": "Vis", + "zoomToFit": "Zoom for å se alle elementer", + "zoomToSelection": "Zoom til utvalg" }, "encrypted": { "tooltip": "Dine tegninger er ende-til-ende-krypterte slik at Excalidraw sine servere aldri vil se dem." @@ -232,5 +234,9 @@ "title": "Statistikk for nerder", "total": "Totalt", "width": "Bredde" + }, + "toast": { + "copyStyles": "Kopierte stiler.", + "copyToClipboardAsPng": "Kopiert til utklippstavlen som PNG." } } diff --git a/src/locales/nl-NL.json b/src/locales/nl-NL.json index 59269210c..d075254d0 100644 --- a/src/locales/nl-NL.json +++ b/src/locales/nl-NL.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "Fout" }, - "shortcutsDialog": { - "title": "Sneltoetsen", - "shapes": "Vormen", - "or": "of", - "click": "klik", - "drag": "slepen", - "curvedArrow": "Gebogen pijl", - "curvedLine": "Gebogen lijn", - "editor": "Editor", - "view": "Weergave", + "helpDialog": { "blog": "Lees onze blog", + "click": "klik", + "curvedArrow": "Gebogen pijl", + "curvedLine": "Kromme lijn", + "documentation": "Documentatie", + "drag": "slepen", + "editor": "Editor", + "github": "Probleem gevonden? Verzenden", "howto": "Volg onze handleidingen", - "github": "Probleem gevonden? Stuur een nieuwe issue", - "textNewLine": "Nieuwe regel toevoegen (tekst)", + "or": "of", + "preventBinding": "Pijlbinding voorkomen", + "shapes": "Vormen", + "shortcuts": "Sneltoetsen", "textFinish": "Voltooi bewerken (tekst)", + "textNewLine": "Nieuwe regel toevoegen (tekst)", + "title": "Help", + "view": "Weergave", "zoomToFit": "Zoom in op alle elementen", - "zoomToSelection": "Inzoomen op selectie", - "preventBinding": "Pijlbinding voorkomen" + "zoomToSelection": "Inzoomen op selectie" }, "encrypted": { "tooltip": "Je tekeningen zijn beveiligd met end-to-end encryptie, dus Excalidraw's servers zullen nooit zien wat je tekent." @@ -232,5 +234,9 @@ "title": "Statistieken voor nerds", "total": "Totaal", "width": "Breedte" + }, + "toast": { + "copyStyles": "Stijlen gekopieerd.", + "copyToClipboardAsPng": "Gekopieerd naar klembord als PNG." } } diff --git a/src/locales/nn-NO.json b/src/locales/nn-NO.json index d6732d919..7048e77cb 100644 --- a/src/locales/nn-NO.json +++ b/src/locales/nn-NO.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "Feil" }, - "shortcutsDialog": { - "title": "Tastatursnarvegar", - "shapes": "Figurar", - "or": "eller", - "click": "klikk", - "drag": "drag", - "curvedArrow": "Boga pil", - "curvedLine": "Boga linje", - "editor": "Redigering", - "view": "Vising", - "blog": "Les bloggen vår", - "howto": "Følg vegleiinga vår", - "github": "Funne eit problem? Send inn", - "textNewLine": "Legg til ny linje (tekst)", - "textFinish": "Fullfør redigering (tekst)", - "zoomToFit": "Zoom for å sjå alle elementa", - "zoomToSelection": "Zoom til utval", - "preventBinding": "Hindre pilkobling" + "helpDialog": { + "blog": "", + "click": "", + "curvedArrow": "", + "curvedLine": "", + "documentation": "", + "drag": "", + "editor": "", + "github": "", + "howto": "", + "or": "", + "preventBinding": "", + "shapes": "", + "shortcuts": "", + "textFinish": "", + "textNewLine": "", + "title": "", + "view": "", + "zoomToFit": "", + "zoomToSelection": "" }, "encrypted": { "tooltip": "Teikningane dine er ende-til-ende-krypterte slik at Excalidraw sine serverar aldri får sjå dei." @@ -232,5 +234,9 @@ "title": "Statistikk for nerdar", "total": "Totalt", "width": "Breidde" + }, + "toast": { + "copyStyles": "", + "copyToClipboardAsPng": "" } } diff --git a/src/locales/pa-IN.json b/src/locales/pa-IN.json index 8cf973761..22c8ff996 100644 --- a/src/locales/pa-IN.json +++ b/src/locales/pa-IN.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "ਗਲਤੀ" }, - "shortcutsDialog": { - "title": "ਕੀਬੋਰਡ ਸ਼ਾਰਟਕੱਟ", - "shapes": "ਆਕ੍ਰਿਤੀਆਂ", - "or": "ਜਾਂ", - "click": "ਕਲਿੱਕ", - "drag": "ਘਸੀਟੋ", - "curvedArrow": "ਵਿੰਗਾ ਤੀਰ", - "curvedLine": "ਵਿੰਗੀ ਲਕੀਰ", - "editor": "ਸੋਧਕ", - "view": "ਦਿੱਖ", - "blog": "ਸਾਡਾ ਬਲੌਗ ਪੜ੍ਹੋ", - "howto": "ਸਾਡੀਆਂ ਗਾਈਡਾਂ ਦੀ ਪਾਲਣਾ ਕਰੋ", - "github": "ਕੋਈ ਸਮੱਸਿਆ ਲੱਭੀ? ਜਮ੍ਹਾਂ ਕਰਵਾਓ", - "textNewLine": "ਨਵੀਂ ਪੰਕਤੀ ਜੋੜੋ (ਪਾਠ)", - "textFinish": "ਸੋਧ ਮੁਕੰਮਲ ਕਰੋ (ਪਾਠ)", - "zoomToFit": "ਸਾਰੇ ਐਲੀਮੈਂਟਾਂ ਨੂੰ ਫਿੱਟ ਕਰਨ ਲਈ ਜ਼ੂਮ ਕਰੋ", - "zoomToSelection": "ਚੋਣ ਤੱਕ ਜ਼ੂਮ ਕਰੋ", - "preventBinding": "ਤੀਰ ਬੱਝਣਾ ਰੋਕੋ" + "helpDialog": { + "blog": "", + "click": "", + "curvedArrow": "", + "curvedLine": "", + "documentation": "", + "drag": "", + "editor": "", + "github": "", + "howto": "", + "or": "", + "preventBinding": "", + "shapes": "", + "shortcuts": "", + "textFinish": "", + "textNewLine": "", + "title": "", + "view": "", + "zoomToFit": "", + "zoomToSelection": "" }, "encrypted": { "tooltip": "ਤੁਹਾਡੀ ਡਰਾਇੰਗਾਂ ਸਿਰੇ-ਤੋਂ-ਸਿਰੇ ਤੱਕ ਇਨਕਰਿਪਟ ਕੀਤੀਆਂ ਹੋਈਆਂ ਹਨ, ਇਸ ਲਈ Excalidraw ਦੇ ਸਰਵਰ ਉਹਨਾਂ ਨੂੰ ਕਦੇ ਵੀ ਨਹੀਂ ਦੇਖਣਗੇ।" @@ -232,5 +234,9 @@ "title": "ਪੜਾਕੂਆਂ ਲਈ ਅੰਕੜੇ", "total": "ਕੁੱਲ", "width": "ਚੌੜਾਈ" + }, + "toast": { + "copyStyles": "ਕਾਪੀ ਕੀਤੇ ਸਟਾਇਲ।", + "copyToClipboardAsPng": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ PNG ਵਜੋਂ ਕਾਪੀ ਕੀਤਾ।" } } diff --git a/src/locales/percentages.json b/src/locales/percentages.json index dda257967..00db38424 100644 --- a/src/locales/percentages.json +++ b/src/locales/percentages.json @@ -1,35 +1,35 @@ { - "ar-SA": 100, - "bg-BG": 100, - "ca-ES": 100, + "ar-SA": 90, + "bg-BG": 90, + "ca-ES": 90, "de-DE": 100, "el-GR": 100, "en": 100, "es-ES": 100, - "fa-IR": 100, + "fa-IR": 90, "fi-FI": 100, "fr-FR": 100, - "he-IL": 100, - "hi-IN": 100, - "hu-HU": 100, - "id-ID": 100, - "it-IT": 100, - "ja-JP": 90, - "ko-KR": 100, - "my-MM": 93, + "he-IL": 90, + "hi-IN": 90, + "hu-HU": 90, + "id-ID": 91, + "it-IT": 91, + "ja-JP": 81, + "ko-KR": 90, + "my-MM": 83, "nb-NO": 100, "nl-NL": 100, - "nn-NO": 100, - "pa-IN": 100, - "pl-PL": 100, + "nn-NO": 90, + "pa-IN": 91, + "pl-PL": 90, "pt-BR": 100, "pt-PT": 100, "ro-RO": 100, - "ru-RU": 100, - "sk-SK": 100, + "ru-RU": 91, + "sk-SK": 91, "sv-SE": 100, - "tr-TR": 100, + "tr-TR": 90, "uk-UA": 100, - "zh-CN": 100, + "zh-CN": 90, "zh-TW": 100 } diff --git a/src/locales/pl-PL.json b/src/locales/pl-PL.json index f36276402..f462ad9b6 100644 --- a/src/locales/pl-PL.json +++ b/src/locales/pl-PL.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "Wystąpił błąd" }, - "shortcutsDialog": { - "title": "Skróty klawiszowe", - "shapes": "Kształty", - "or": "lub", - "click": "klik", - "drag": "przeciągnij", - "curvedArrow": "Zakrzywiona strzałka", - "curvedLine": "Zakrzywiona linia", - "editor": "Edytor", - "view": "Widok", - "blog": "Przeczytaj naszego bloga", - "howto": "Skorzystaj z instrukcji", - "github": "Znalazłeś problem? Zgłoś go", - "textNewLine": "Dodaj nową linię (tekst)", - "textFinish": "Zakończ edycję (tekst)", - "zoomToFit": "Powiększ, aby wyświetlić wszystkie elementy", - "zoomToSelection": "Przybliż zaznaczenie", - "preventBinding": "Zablokuj przywiązanie strzałek do obiektu" + "helpDialog": { + "blog": "", + "click": "", + "curvedArrow": "", + "curvedLine": "", + "documentation": "", + "drag": "", + "editor": "", + "github": "", + "howto": "", + "or": "", + "preventBinding": "", + "shapes": "", + "shortcuts": "", + "textFinish": "", + "textNewLine": "", + "title": "", + "view": "", + "zoomToFit": "", + "zoomToSelection": "" }, "encrypted": { "tooltip": "Twoje rysunki są zabezpieczone szyfrowaniem end-to-end, tak więc nawet w Excalidraw nie jesteśmy w stanie zobaczyć tego co tworzysz." @@ -232,5 +234,9 @@ "title": "Statystyki dla nerdów", "total": "Łącznie", "width": "Szerokość" + }, + "toast": { + "copyStyles": "", + "copyToClipboardAsPng": "" } } diff --git a/src/locales/pt-BR.json b/src/locales/pt-BR.json index 0f0af4758..cfbb667ed 100644 --- a/src/locales/pt-BR.json +++ b/src/locales/pt-BR.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "Erro" }, - "shortcutsDialog": { - "title": "Atalhos de teclado", - "shapes": "Formas", - "or": "ou", + "helpDialog": { + "blog": "Leia o nosso blog", "click": "clicar", - "drag": "arrastar", "curvedArrow": "Seta curva", "curvedLine": "Linha curva", + "documentation": "Documentação", + "drag": "arrastar", "editor": "Editor", - "view": "Visualizar", - "blog": "Leia o nosso blog", - "howto": "Siga os nossos guias", "github": "Encontrou algum problema? Nos informe", - "textNewLine": "Adicionar nova linha (texto)", + "howto": "Siga nossos guias", + "or": "ou", + "preventBinding": "Evitar fixação de seta", + "shapes": "Formas", + "shortcuts": "Atalhos de teclado", "textFinish": "Finalizar edição (texto)", - "zoomToFit": "Ajustar para caber todos os elementos", - "zoomToSelection": "Ampliar a seleção", - "preventBinding": "Prevenir fixação de seta" + "textNewLine": "Adicionar nova linha (texto)", + "title": "Ajudar", + "view": "Visualizar", + "zoomToFit": "Ampliar para encaixar todos os elementos", + "zoomToSelection": "Ampliar a seleção" }, "encrypted": { "tooltip": "Seus desenhos são criptografados de ponta a ponta, então os servidores do Excalidraw nunca os verão." @@ -232,5 +234,9 @@ "title": "Estatísticas para nerds", "total": "Total", "width": "Largura" + }, + "toast": { + "copyStyles": "Estilos copiados.", + "copyToClipboardAsPng": "Copiado para a área de transferência como PNG." } } diff --git a/src/locales/pt-PT.json b/src/locales/pt-PT.json index d217b41cd..994eb7a86 100644 --- a/src/locales/pt-PT.json +++ b/src/locales/pt-PT.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "Erro" }, - "shortcutsDialog": { - "title": "Atalhos de teclado", - "shapes": "Formas", - "or": "ou", + "helpDialog": { + "blog": "Leia o nosso blog", "click": "clicar", - "drag": "arrastar", "curvedArrow": "Seta curva", "curvedLine": "Linha curva", + "documentation": "Documentação", + "drag": "arrastar", "editor": "Editor", - "view": "Visualizar", - "blog": "Leia o nosso blog", - "howto": "Siga os nossos guias", "github": "Encontrou algum problema? Nos informe", - "textNewLine": "Adicionar nova linha (texto)", + "howto": "Siga os nossos guias", + "or": "ou", + "preventBinding": "Prevenir fixação de seta", + "shapes": "Formas", + "shortcuts": "Atalhos de teclado", "textFinish": "Finalizar edição (texto)", + "textNewLine": "Adicionar nova linha (texto)", + "title": "Ajuda", + "view": "Visualizar", "zoomToFit": "Ajustar para caber todos os elementos", - "zoomToSelection": "Ampliar a seleção", - "preventBinding": "Prevenir fixação de seta" + "zoomToSelection": "Ampliar a seleção" }, "encrypted": { "tooltip": "Seus desenhos são criptografados de ponta a ponta, então os servidores do Excalidraw nunca os verão." @@ -232,5 +234,9 @@ "title": "Estatísticas para nerds", "total": "Total", "width": "Largura" + }, + "toast": { + "copyStyles": "Estilos copiados.", + "copyToClipboardAsPng": "Copiado para o clipboard como PNG." } } diff --git a/src/locales/ro-RO.json b/src/locales/ro-RO.json index 8b283af6a..9a42ac643 100644 --- a/src/locales/ro-RO.json +++ b/src/locales/ro-RO.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "Eroare" }, - "shortcutsDialog": { - "title": "Comenzi rapide de la tastatură", - "shapes": "Forme", - "or": "sau", + "helpDialog": { + "blog": "Citește blogul nostru", "click": "clic", - "drag": "glisare", "curvedArrow": "Săgeată curbată", "curvedLine": "Linie curbată", + "documentation": "Documentație", + "drag": "glisare", "editor": "Editor", - "view": "Vizualizare", - "blog": "Citește blogul nostru", - "howto": "Urmărește ghidurile noastre", "github": "Ai întâmpinat o problemă? Trimite un raport", - "textNewLine": "Adaugă o linie nouă (text)", + "howto": "Urmărește ghidurile noastre", + "or": "sau", + "preventBinding": "Împiedică legarea săgeții", + "shapes": "Forme", + "shortcuts": "Comenzi rapide de la tastatură", "textFinish": "Finalizează editarea (text)", - "zoomToFit": "Apropiere/depărtare pentru a cuprinde totul", - "zoomToSelection": "Panoramare la selecție", - "preventBinding": "Împiedică legarea săgeții" + "textNewLine": "Adaugă o linie nouă (text)", + "title": "Ajutor", + "view": "Vizualizare", + "zoomToFit": "Panoramare pentru a cuprinde totul", + "zoomToSelection": "Panoramare la selecție" }, "encrypted": { "tooltip": "Desenele tale sunt criptate integral, astfel că serverele Excalidraw nu le vor vedea niciodată." @@ -232,5 +234,9 @@ "title": "Statistici pentru pasionați", "total": "Total", "width": "Lățime" + }, + "toast": { + "copyStyles": "Stiluri copiate.", + "copyToClipboardAsPng": "Copiat în memoria temporară ca PNG." } } diff --git a/src/locales/ru-RU.json b/src/locales/ru-RU.json index f89b180d8..97bb6d6d3 100644 --- a/src/locales/ru-RU.json +++ b/src/locales/ru-RU.json @@ -41,8 +41,8 @@ "withBackground": "С фоном", "exportEmbedScene": "Встроить информацию о сцене в экспортируемый файл", "exportEmbedScene_details": "Сцена будет сохранена в PNG/SVG файл так, чтобы всю сцену можно будет восстановить из этого файла. Это увеличит размер файла.", - "addWatermark": "Добавить \"Сделано с Excalidraw\"", - "handDrawn": "Нарисованный от руки", + "addWatermark": "Добавить «Создано в Excalidraw»", + "handDrawn": "От руки", "normal": "Обычный", "code": "Код", "small": "Малый", @@ -64,11 +64,11 @@ "fileTitle": "Название файла", "colorPicker": "Выбор цвета", "canvasBackground": "Фон холста", - "drawingCanvas": "Холст для рисования", + "drawingCanvas": "Полотно", "layers": "Слои", "actions": "Действия", "language": "Язык", - "createRoom": "Создать многопользовательскую сессию", + "createRoom": "Начать сеанс совместной работы", "duplicateSelection": "Дубликат", "untitled": "Безымянный", "name": "Имя", @@ -189,34 +189,36 @@ }, "roomDialog": { "desc_intro": "Вы можете пригласить людей в текущую сцену для совместной работы.", - "desc_privacy": "Не беспокойтесь, сессия использует сквозное шифрование, поэтому всё что вы нарисуете останется приватным. Ваша информация не будет доступна даже на наших серверах.", + "desc_privacy": "Не беспокойтесь — во время сеанса используется сквозное шифрование. Всё, что вы нарисуете, останется конфиденциальным и не будет доступно даже нашему серверу.", "button_startSession": "Начать сеанс", "button_stopSession": "Завершить сеанс", - "desc_inProgressIntro": "Совместная сессия теперь активна.", + "desc_inProgressIntro": "Сеанс совместной работы запущен.", "desc_shareLink": "Поделитесь этой ссылкой со всеми участниками:", "desc_exitSession": "Завершив сеанс, вы выйдете из комнаты, но сможете продолжить работать с документом локально. Это не повлияет на работу других пользователей — они смогут продолжить совместную работу с их версией документа." }, "errorDialog": { "title": "Ошибка" }, - "shortcutsDialog": { - "title": "Сочетания клавиш", - "shapes": "Фигуры", - "or": "или", - "click": "нажать", - "drag": "перетащить", - "curvedArrow": "Изогнутая стрелка", - "curvedLine": "Изогнутая линия", - "editor": "Редактор", - "view": "Просмотр", - "blog": "Прочитайте наш блог", - "howto": "Следуйте нашим инструкциям", - "github": "Нашли проблему? Отправьте", - "textNewLine": "Добавить новую строку (текст)", - "textFinish": "Закончить редактирование (текст)", - "zoomToFit": "Отмастштабировать, чтобы поместились все элементы", - "zoomToSelection": "Перейти к выделенному", - "preventBinding": "Предотвратить привязку стрелок" + "helpDialog": { + "blog": "", + "click": "", + "curvedArrow": "", + "curvedLine": "", + "documentation": "", + "drag": "", + "editor": "", + "github": "", + "howto": "", + "or": "", + "preventBinding": "", + "shapes": "", + "shortcuts": "", + "textFinish": "", + "textNewLine": "", + "title": "", + "view": "", + "zoomToFit": "", + "zoomToSelection": "" }, "encrypted": { "tooltip": "Ваши данные защищены сквозным (End-to-end) шифрованием. Серверы Excalidraw никогда не получат доступ к ним." @@ -232,5 +234,9 @@ "title": "Статистика для ботаников", "total": "Всего", "width": "Ширина" + }, + "toast": { + "copyStyles": "Скопированы стили.", + "copyToClipboardAsPng": "Скопировано в буфер обмена в формате PNG." } } diff --git a/src/locales/sk-SK.json b/src/locales/sk-SK.json index 3b7193208..c7def05fe 100644 --- a/src/locales/sk-SK.json +++ b/src/locales/sk-SK.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "Chyba" }, - "shortcutsDialog": { - "title": "Klávesové skratky", - "shapes": "Tvary", - "or": "alebo", - "click": "kliknutie", - "drag": "potiahnutie", - "curvedArrow": "Zakrivená šípka", - "curvedLine": "Zakrivená čiara", - "editor": "Editovanie", - "view": "Zobrazenie", - "blog": "Prečítajte si náš blog", - "howto": "Postupujte podľa naších návodov", - "github": "Objavili ste problém? Nahláste ho", - "textNewLine": "Vložiť nový riadok (text)", - "textFinish": "Ukončenie editovania (text)", - "zoomToFit": "Priblížiť aby boli zahrnuté všetky prvky", - "zoomToSelection": "Priblížiť na výber", - "preventBinding": "Zakázať pripájanie šípky" + "helpDialog": { + "blog": "", + "click": "", + "curvedArrow": "", + "curvedLine": "", + "documentation": "", + "drag": "", + "editor": "", + "github": "", + "howto": "", + "or": "", + "preventBinding": "", + "shapes": "", + "shortcuts": "", + "textFinish": "", + "textNewLine": "", + "title": "", + "view": "", + "zoomToFit": "", + "zoomToSelection": "" }, "encrypted": { "tooltip": "Vaše kresby používajú end-to-end šifrovanie, takže ich Excalidraw server nedokáže prečítať." @@ -232,5 +234,9 @@ "title": "Štatistiky", "total": "Celkom", "width": "Šírka" + }, + "toast": { + "copyStyles": "Štýly skopírované.", + "copyToClipboardAsPng": "Skopírované do schránky ako PNG." } } diff --git a/src/locales/sv-SE.json b/src/locales/sv-SE.json index e749a977e..71046e852 100644 --- a/src/locales/sv-SE.json +++ b/src/locales/sv-SE.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "Fel" }, - "shortcutsDialog": { - "title": "Tangentbordsgenvägar", - "shapes": "Former", - "or": "eller", + "helpDialog": { + "blog": "Läs vår blogg", "click": "klicka", - "drag": "dra", "curvedArrow": "Böjd pil", "curvedLine": "Böjd linje", + "documentation": "Dokumentation", + "drag": "dra", "editor": "Redigerare", - "view": "Visa", - "blog": "Läs vår blogg", - "howto": "Följ våra guider", "github": "Hittat ett problem? Rapportera", - "textNewLine": "Lägg till ny rad (text)", + "howto": "Följ våra guider", + "or": "eller", + "preventBinding": "Förhindra pilbindning", + "shapes": "Former", + "shortcuts": "Tangentbordsgenvägar", "textFinish": "Slutför redigering (text)", + "textNewLine": "Lägg till ny rad (text)", + "title": "Hjälp", + "view": "Visa", "zoomToFit": "Zooma för att rymma alla element", - "zoomToSelection": "Zooma till markering", - "preventBinding": "Förhindra pilbindning" + "zoomToSelection": "Zooma till markering" }, "encrypted": { "tooltip": "Dina skisser är krypterade från ände till ände så Excalidraws servrar kommer aldrig att se dem." @@ -232,5 +234,9 @@ "title": "Statistik för nördar", "total": "Totalt", "width": "Bredd" + }, + "toast": { + "copyStyles": "Kopierade stilar.", + "copyToClipboardAsPng": "Kopierat till urklipp som PNG." } } diff --git a/src/locales/tr-TR.json b/src/locales/tr-TR.json index 6382029a4..f9ed1cd1b 100644 --- a/src/locales/tr-TR.json +++ b/src/locales/tr-TR.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "Hata" }, - "shortcutsDialog": { - "title": "Klavye kısayolları", - "shapes": "Şekiller", - "or": "veya", - "click": "tıkla", - "drag": "sürükle", - "curvedArrow": "Eğri ok", - "curvedLine": "Eğri çizgi", - "editor": "Düzenleyici", - "view": "Görüntüle", - "blog": "Blog'umuzu okuyun", - "howto": "Rehberlerimizi takip edin", - "github": "Bir hata mı buldun? Bildir", - "textNewLine": "Yeni satır ekle (yazı)", - "textFinish": "(Yazıyı) düzenlemeyi bitir", - "zoomToFit": "Tüm öğeleri sığdırmak için yakınlaştır", - "zoomToSelection": "Seçime yaklaş", - "preventBinding": "Ok bağlamayı önleyin" + "helpDialog": { + "blog": "", + "click": "", + "curvedArrow": "", + "curvedLine": "", + "documentation": "", + "drag": "", + "editor": "", + "github": "", + "howto": "", + "or": "", + "preventBinding": "", + "shapes": "", + "shortcuts": "", + "textFinish": "", + "textNewLine": "", + "title": "", + "view": "", + "zoomToFit": "", + "zoomToSelection": "" }, "encrypted": { "tooltip": "Çizimleriniz uçtan-uca şifrelenmiştir, Excalidraw'ın sunucuları bile onları göremez." @@ -232,5 +234,9 @@ "title": "İnekler için istatistikler", "total": "Toplam", "width": "Genişlik" + }, + "toast": { + "copyStyles": "", + "copyToClipboardAsPng": "" } } diff --git a/src/locales/uk-UA.json b/src/locales/uk-UA.json index a9b9a7fd4..0783cf140 100644 --- a/src/locales/uk-UA.json +++ b/src/locales/uk-UA.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "Помилка" }, - "shortcutsDialog": { - "title": "Гарячі клавіші", - "shapes": "Фігури", - "or": "або", + "helpDialog": { + "blog": "Наш блог", "click": "натиснути", + "curvedArrow": "Крива стрілка", + "curvedLine": "Крива лінія", + "documentation": "Документація", "drag": "перетягнути", - "curvedArrow": "Вигнута стрілка", - "curvedLine": "Вигнута лінія", "editor": "Редактор", - "view": "Вигляд", - "blog": "Читайте наш блог", + "github": "Знайшли помилку? Повідомте", "howto": "Дотримуйтесь наших інструкцій", - "github": "Знайшли помилку? Повідомте!", - "textNewLine": "Додати новий рядок (текст)", + "or": "або", + "preventBinding": "Запобігти зв'язування зі стрілками", + "shapes": "Фігури", + "shortcuts": "Гарячі клавіші", "textFinish": "Завершити редагування (текст)", - "zoomToFit": "Збільшити щоб умістити все", - "zoomToSelection": "Перейти до виділеного", - "preventBinding": "Запобігти зв'язування зі стрілками" + "textNewLine": "Додати новий рядок (текст)", + "title": "Допомога", + "view": "Вигляд", + "zoomToFit": "Збільшити щоб умістити всі елементи", + "zoomToSelection": "Наблизити вибране" }, "encrypted": { "tooltip": "Ваші креслення захищені наскрізним шифруванням — сервери Excalidraw ніколи їх не побачать." @@ -232,5 +234,9 @@ "title": "Статистика", "total": "Всього", "width": "Ширина" + }, + "toast": { + "copyStyles": "Скопійовані стилі.", + "copyToClipboardAsPng": "Скопійовано в буфер обміну як PNG." } } diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json index 036e37f71..8a1ca6efd 100644 --- a/src/locales/zh-CN.json +++ b/src/locales/zh-CN.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "错误" }, - "shortcutsDialog": { - "title": "快捷键列表", - "shapes": "形状", - "or": "或", - "click": "点击", - "drag": "拖动", - "curvedArrow": "曲线(带有箭头)", - "curvedLine": "曲线(无箭头)", - "editor": "编辑器", - "view": "视图", - "blog": "浏览我们的博客", - "howto": "跟随我们的指南", - "github": "发现问题?请提出来", - "textNewLine": "文本换行", - "textFinish": "完成编辑文本", - "zoomToFit": "缩放以适应所有元素", - "zoomToSelection": "缩放至选择部分", - "preventBinding": "防止箭头吸附" + "helpDialog": { + "blog": "", + "click": "", + "curvedArrow": "", + "curvedLine": "", + "documentation": "", + "drag": "", + "editor": "", + "github": "", + "howto": "", + "or": "", + "preventBinding": "", + "shapes": "", + "shortcuts": "", + "textFinish": "", + "textNewLine": "", + "title": "", + "view": "", + "zoomToFit": "", + "zoomToSelection": "" }, "encrypted": { "tooltip": "您的绘图采用的端到端加密,其内容对于Excalidraw服务器是不可见的。" @@ -232,5 +234,9 @@ "title": "详细统计信息", "total": "总计", "width": "宽度" + }, + "toast": { + "copyStyles": "", + "copyToClipboardAsPng": "" } } diff --git a/src/locales/zh-TW.json b/src/locales/zh-TW.json index eed021e2d..192bc6a32 100644 --- a/src/locales/zh-TW.json +++ b/src/locales/zh-TW.json @@ -199,24 +199,26 @@ "errorDialog": { "title": "錯誤" }, - "shortcutsDialog": { - "title": "鍵盤快速鍵", - "shapes": "形狀", - "or": "或", - "click": "點擊", - "drag": "拖曳", - "curvedArrow": "箭頭曲線", - "curvedLine": "曲線", - "editor": "編輯器", - "view": "檢視", + "helpDialog": { "blog": "閱讀部落格", - "howto": "官方指南", - "github": "發現問題?回報 issue", - "textNewLine": "換行(文字)", - "textFinish": "完成編輯(文字)", + "click": "點擊", + "curvedArrow": "曲箭頭", + "curvedLine": "曲線", + "documentation": "文件", + "drag": "拖曳", + "editor": "編輯器", + "github": "發現異常?回報問題", + "howto": "參照我們的說明", + "or": "或", + "preventBinding": "避免箭號連結", + "shapes": "形狀", + "shortcuts": "鍵盤快速鍵", + "textFinish": "完成編輯 (文字)", + "textNewLine": "換行 (文字)", + "title": "說明", + "view": "檢視", "zoomToFit": "放大至填滿畫面", - "zoomToSelection": "縮放至選取區", - "preventBinding": "防止箭頭綁定" + "zoomToSelection": "縮放至選取區" }, "encrypted": { "tooltip": "你的作品已使用 end-to-end 方式加密,Excalidraw 的伺服器也無法取得其內容。" @@ -232,5 +234,9 @@ "title": "詳細統計", "total": "合計", "width": "寬度" + }, + "toast": { + "copyStyles": "已複製樣式", + "copyToClipboardAsPng": "已複製 PNG 至剪貼簿" } } From fb4d97ef7867ead32e16cd0fc657a6244a4b8cc8 Mon Sep 17 00:00:00 2001 From: Luc Leray Date: Mon, 18 Jan 2021 18:22:02 +0100 Subject: [PATCH 02/39] fix: Use `VERCEL_GIT_COMMIT_SHA` env variable (#2816) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e7e2c900f..cd1404714 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "scripts": { "build-node": "node ./scripts/build-node.js", "build:app:docker": "REACT_APP_DISABLE_SENTRY=true react-scripts build", - "build:app": "REACT_APP_GIT_SHA=$NOW_GITHUB_COMMIT_SHA react-scripts build", + "build:app": "REACT_APP_GIT_SHA=$VERCEL_GIT_COMMIT_SHA react-scripts build", "build:version": "node ./scripts/build-version.js", "build": "npm run build:app && npm run build:version", "eject": "react-scripts eject", From 8c2bc9433603041ca7a1055420905310857652ca Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Tue, 19 Jan 2021 19:59:05 +0530 Subject: [PATCH 03/39] build(webpack): bundle css files with js (#2819) --- src/packages/excalidraw/entry.js | 6 ++++++ src/packages/excalidraw/webpack.prod.config.js | 11 ++--------- 2 files changed, 8 insertions(+), 9 deletions(-) create mode 100644 src/packages/excalidraw/entry.js diff --git a/src/packages/excalidraw/entry.js b/src/packages/excalidraw/entry.js new file mode 100644 index 000000000..8a0d08d9b --- /dev/null +++ b/src/packages/excalidraw/entry.js @@ -0,0 +1,6 @@ +import Excalidraw from "./index"; + +import "../../../public/fonts.css"; + +export default Excalidraw; +export * from "./index"; diff --git a/src/packages/excalidraw/webpack.prod.config.js b/src/packages/excalidraw/webpack.prod.config.js index bb04502d0..434c20599 100644 --- a/src/packages/excalidraw/webpack.prod.config.js +++ b/src/packages/excalidraw/webpack.prod.config.js @@ -1,5 +1,4 @@ const path = require("path"); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const TerserPlugin = require("terser-webpack-plugin"); const BundleAnalyzerPlugin = require("webpack-bundle-analyzer") .BundleAnalyzerPlugin; @@ -7,8 +6,7 @@ const BundleAnalyzerPlugin = require("webpack-bundle-analyzer") module.exports = { mode: "production", entry: { - "excalidraw.min": "./index.tsx", - "fonts.min": "../../../public/fonts.css", + "excalidraw.min": "./entry.js", }, output: { path: path.resolve(__dirname, "dist"), @@ -26,11 +24,7 @@ module.exports = { { test: /\.(sa|sc|c)ss$/, exclude: /node_modules/, - use: [ - MiniCssExtractPlugin.loader, - { loader: "css-loader" }, - "sass-loader", - ], + use: ["style-loader", { loader: "css-loader" }, "sass-loader"], }, { test: /\.(ts|tsx|js|jsx|mjs)$/, @@ -94,7 +88,6 @@ module.exports = { }, }, plugins: [ - new MiniCssExtractPlugin({ filename: "[name].css" }), ...(process.env.ANALYZER === "true" ? [new BundleAnalyzerPlugin()] : []), ], externals: { From 3922ee8c11620acf9c11e94603afbb68d5eeeaa7 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Tue, 19 Jan 2021 22:08:04 +0530 Subject: [PATCH 04/39] docs: update changelog and readme and release 0.2.1 (#2821) --- src/packages/excalidraw/CHANGELOG.md | 8 ++++++++ src/packages/excalidraw/README.md | 3 --- src/packages/excalidraw/package.json | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/packages/excalidraw/CHANGELOG.md b/src/packages/excalidraw/CHANGELOG.md index 18d774d77..7b8de509c 100644 --- a/src/packages/excalidraw/CHANGELOG.md +++ b/src/packages/excalidraw/CHANGELOG.md @@ -12,6 +12,14 @@ The change should be grouped under one of the below section and must contain PR Please add the latest change on the top under the correct section. --> +## 0.2.1 + +## Excalidraw API + +### Build + +- Bundle css files with js [#2819](https://github.com/excalidraw/excalidraw/pull/2819). The host would not need to import css files separately. + ## 0.2.0 ## Excalidraw API diff --git a/src/packages/excalidraw/README.md b/src/packages/excalidraw/README.md index 12adfb6bf..9cad15d76 100644 --- a/src/packages/excalidraw/README.md +++ b/src/packages/excalidraw/README.md @@ -31,9 +31,6 @@ import React, { useEffect, useState, createRef } from "react"; import Excalidraw from "@excalidraw/excalidraw"; import InitialData from "./initialData"; -import "@excalidraw/excalidraw/dist/excalidraw.min.css"; -import "@excalidraw/excalidraw/dist/fonts.min.css"; - import "./styles.css"; export default function App() { diff --git a/src/packages/excalidraw/package.json b/src/packages/excalidraw/package.json index ac8e795a8..53de442e0 100644 --- a/src/packages/excalidraw/package.json +++ b/src/packages/excalidraw/package.json @@ -1,6 +1,6 @@ { "name": "@excalidraw/excalidraw", - "version": "0.2.0", + "version": "0.2.1", "main": "dist/excalidraw.min.js", "files": [ "dist/*" From 49bd683401a529a4e0a9d34577d0d97cc8b23033 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Wed, 20 Jan 2021 21:27:33 +0530 Subject: [PATCH 05/39] fix(analytics.ts): add safe check for process so Excalidraw can be loaded via script (#2824) * fix(analytics.ts): add safe check for process so Excalidraw can be loaded via script * fix --- src/analytics.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/analytics.ts b/src/analytics.ts index 30a3887e3..a48a0a1f4 100644 --- a/src/analytics.ts +++ b/src/analytics.ts @@ -1,5 +1,6 @@ export const trackEvent = - process.env.REACT_APP_GOOGLE_ANALYTICS_ID && + typeof process !== "undefined" && + process.env?.REACT_APP_GOOGLE_ANALYTICS_ID && typeof window !== "undefined" && window.gtag ? (category: string, name: string, label?: string, value?: number) => { @@ -9,7 +10,7 @@ export const trackEvent = value, }); } - : typeof process !== "undefined" && process?.env?.JEST_WORKER_ID + : typeof process !== "undefined" && process.env?.JEST_WORKER_ID ? (category: string, name: string, label?: string, value?: number) => {} : (category: string, name: string, label?: string, value?: number) => { // Uncomment the next line to track locally From 6e767fc9491b89ee295e5af6d34a17056fe37846 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Thu, 21 Jan 2021 16:43:47 +0530 Subject: [PATCH 06/39] fix(actionmenu): toggle help dialog when "shift+?" is pressed (#2828) --- src/actions/actionMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/actions/actionMenu.tsx b/src/actions/actionMenu.tsx index c56999d78..8cfae3981 100644 --- a/src/actions/actionMenu.tsx +++ b/src/actions/actionMenu.tsx @@ -74,7 +74,7 @@ export const actionShortcuts = register({ return { appState: { ...appState, - showHelpDialog: true, + showHelpDialog: !appState.showHelpDialog, }, commitToHistory: false, }; From 9dc930b44744ba708b7e11d61d45dc06c5f2afee Mon Sep 17 00:00:00 2001 From: David Luzar Date: Thu, 21 Jan 2021 16:21:54 +0100 Subject: [PATCH 07/39] feat: add ctrl-y to redo (#2831) --- src/actions/actionHistory.tsx | 16 ++++++++++------ src/components/HelpDialog.tsx | 11 +++++++++-- src/keys.ts | 2 ++ src/packages/excalidraw/CHANGELOG.md | 8 ++++++++ 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/actions/actionHistory.tsx b/src/actions/actionHistory.tsx index 9e3f62321..c0971c2ef 100644 --- a/src/actions/actionHistory.tsx +++ b/src/actions/actionHistory.tsx @@ -6,7 +6,7 @@ import { t } from "../i18n"; import { SceneHistory, HistoryEntry } from "../history"; import { ExcalidrawElement } from "../element/types"; import { AppState } from "../types"; -import { KEYS } from "../keys"; +import { isWindows, KEYS } from "../keys"; import { getElementMap } from "../element"; import { newElementWith } from "../element/mutateElement"; import { fixBindingsAfterDeletion } from "../element/binding"; @@ -59,16 +59,16 @@ const writeData = ( return { commitToHistory }; }; -const testUndo = (shift: boolean) => (event: KeyboardEvent) => - event[KEYS.CTRL_OR_CMD] && /z/i.test(event.key) && event.shiftKey === shift; - type ActionCreator = (history: SceneHistory) => Action; export const createUndoAction: ActionCreator = (history) => ({ name: "undo", perform: (elements, appState) => writeData(elements, appState, () => history.undoOnce()), - keyTest: testUndo(false), + keyTest: (event) => + event[KEYS.CTRL_OR_CMD] && + event.key.toLowerCase() === KEYS.Z && + !event.shiftKey, PanelComponent: ({ updateData }) => ( ({ name: "redo", perform: (elements, appState) => writeData(elements, appState, () => history.redoOnce()), - keyTest: testUndo(true), + keyTest: (event) => + (event[KEYS.CTRL_OR_CMD] && + event.shiftKey && + event.key.toLowerCase() === KEYS.Z) || + (isWindows && event.ctrlKey && !event.shiftKey && event.key === KEYS.Y), PanelComponent: ({ updateData }) => ( void }) => { /> +## [Unreleased] + +## Excalidraw Library + +### Features + +- Support `Ctrl-Y` shortcut to redo on Windows [#2831](https://github.com/excalidraw/excalidraw/pull/2831). + ## 0.2.1 ## Excalidraw API From 26acebcdb6f58e607d50eb5cd15f5b7fb456e0fd Mon Sep 17 00:00:00 2001 From: Lipis Date: Fri, 22 Jan 2021 18:06:21 +0200 Subject: [PATCH 08/39] chore: Update translations from Crowdin (#2817) --- .github/workflows/locales-coverage.yml | 4 +-- src/locales/bg-BG.json | 8 +++--- src/locales/it-IT.json | 38 +++++++++++++------------- src/locales/percentages.json | 6 ++-- src/locales/sk-SK.json | 38 +++++++++++++------------- 5 files changed, 47 insertions(+), 47 deletions(-) diff --git a/.github/workflows/locales-coverage.yml b/.github/workflows/locales-coverage.yml index f43d93afc..037d39110 100644 --- a/.github/workflows/locales-coverage.yml +++ b/.github/workflows/locales-coverage.yml @@ -24,8 +24,8 @@ jobs: npm run locales-coverage FILE_CHANGED=$(git diff src/locales/percentages.json) if [ ! -z "${FILE_CHANGED}" ]; then - git config --global user.name 'Kostas Bariotis' - git config --global user.email 'konmpar@gmail.com' + git config --global user.name 'Excalidraw Bot' + git config --global user.email 'bot@excalidraw.com' git add src/locales/percentages.json git commit -am "Auto commit: Calculate translation coverage" git push diff --git a/src/locales/bg-BG.json b/src/locales/bg-BG.json index e63599b22..3d7b4b386 100644 --- a/src/locales/bg-BG.json +++ b/src/locales/bg-BG.json @@ -201,7 +201,7 @@ }, "helpDialog": { "blog": "", - "click": "", + "click": "клик", "curvedArrow": "", "curvedLine": "", "documentation": "", @@ -209,16 +209,16 @@ "editor": "", "github": "", "howto": "", - "or": "", + "or": "или", "preventBinding": "", "shapes": "", "shortcuts": "", "textFinish": "", "textNewLine": "", "title": "", - "view": "", + "view": "Преглед", "zoomToFit": "", - "zoomToSelection": "" + "zoomToSelection": "Приближи селекцията" }, "encrypted": { "tooltip": "Вашите рисунки са криптирани от край до край, така че сървърите на Excalidraw няма да могат да ги виждат." diff --git a/src/locales/it-IT.json b/src/locales/it-IT.json index 455b36cc1..e06437376 100644 --- a/src/locales/it-IT.json +++ b/src/locales/it-IT.json @@ -200,25 +200,25 @@ "title": "Errore" }, "helpDialog": { - "blog": "", - "click": "", - "curvedArrow": "", - "curvedLine": "", - "documentation": "", - "drag": "", - "editor": "", - "github": "", - "howto": "", - "or": "", - "preventBinding": "", - "shapes": "", - "shortcuts": "", - "textFinish": "", - "textNewLine": "", - "title": "", - "view": "", - "zoomToFit": "", - "zoomToSelection": "" + "blog": "Leggi il nostro blog", + "click": "click", + "curvedArrow": "Freccia curva", + "curvedLine": "Linea curva", + "documentation": "Documentazione", + "drag": "trascina", + "editor": "Editor", + "github": "Trovato un problema? Segnalalo", + "howto": "Segui le nostre guide", + "or": "oppure", + "preventBinding": "Impedisci legame della freccia", + "shapes": "Forme", + "shortcuts": "Scorciatoie da tastiera", + "textFinish": "Termina la modifica (testo)", + "textNewLine": "Aggiungi nuova riga (testo)", + "title": "Guida", + "view": "Vista", + "zoomToFit": "Adatta zoom per mostrare tutti gli elementi", + "zoomToSelection": "Zoom alla selezione" }, "encrypted": { "tooltip": "I tuoi disegni sono crittografati end-to-end in modo che i server di Excalidraw non li possano mai vedere." diff --git a/src/locales/percentages.json b/src/locales/percentages.json index 00db38424..c31020c3e 100644 --- a/src/locales/percentages.json +++ b/src/locales/percentages.json @@ -1,6 +1,6 @@ { "ar-SA": 90, - "bg-BG": 90, + "bg-BG": 92, "ca-ES": 90, "de-DE": 100, "el-GR": 100, @@ -13,7 +13,7 @@ "hi-IN": 90, "hu-HU": 90, "id-ID": 91, - "it-IT": 91, + "it-IT": 100, "ja-JP": 81, "ko-KR": 90, "my-MM": 83, @@ -26,7 +26,7 @@ "pt-PT": 100, "ro-RO": 100, "ru-RU": 91, - "sk-SK": 91, + "sk-SK": 100, "sv-SE": 100, "tr-TR": 90, "uk-UA": 100, diff --git a/src/locales/sk-SK.json b/src/locales/sk-SK.json index c7def05fe..57729a9e4 100644 --- a/src/locales/sk-SK.json +++ b/src/locales/sk-SK.json @@ -200,25 +200,25 @@ "title": "Chyba" }, "helpDialog": { - "blog": "", - "click": "", - "curvedArrow": "", - "curvedLine": "", - "documentation": "", - "drag": "", - "editor": "", - "github": "", - "howto": "", - "or": "", - "preventBinding": "", - "shapes": "", - "shortcuts": "", - "textFinish": "", - "textNewLine": "", - "title": "", - "view": "", - "zoomToFit": "", - "zoomToSelection": "" + "blog": "Prečítajte si náš blog", + "click": "kliknutie", + "curvedArrow": "Zakrivená šípka", + "curvedLine": "Zakrivená čiara", + "documentation": "Dokumentácia", + "drag": "potiahnutie", + "editor": "Editovanie", + "github": "Objavili ste problém? Nahláste ho", + "howto": "Postupujte podľa naších návodov", + "or": "alebo", + "preventBinding": "Zakázať pripájanie šípky", + "shapes": "Tvary", + "shortcuts": "Klávesové skratky", + "textFinish": "Ukončenie editovania (text)", + "textNewLine": "Vložiť nový riadok (text)", + "title": "Pomocník", + "view": "Zobrazenie", + "zoomToFit": "Priblížiť aby boli zahrnuté všetky prvky", + "zoomToSelection": "Priblížiť na výber" }, "encrypted": { "tooltip": "Vaše kresby používajú end-to-end šifrovanie, takže ich Excalidraw server nedokáže prečítať." From d63ec678db2401c646aa6ca61b8b42fc66275882 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Jan 2021 10:52:41 +0200 Subject: [PATCH 09/39] chore(deps): bump @sentry/integrations from 5.30.0 to 6.0.1 (#2854) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 24 ++++++++++++------------ package.json | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 50291bcea..fc71aa975 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2744,12 +2744,12 @@ } }, "@sentry/integrations": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-5.30.0.tgz", - "integrity": "sha512-Fqh4ALLoQWdd+1ih0iBduANWFyNmFWMxwvBu3V/wLDRi8OcquI0lEzWai1InzTJTiNhRHPnhuU++l/vkO0OCww==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-6.0.1.tgz", + "integrity": "sha512-5HGwKW0otSVXSLAJ9ezqlux4AYdeX6ElzQgpm6roWEBXEWf/5OyD0n+M3+yHq4NdQXk2kkfL/0DCyNdy8zZX2Q==", "requires": { - "@sentry/types": "5.30.0", - "@sentry/utils": "5.30.0", + "@sentry/types": "6.0.1", + "@sentry/utils": "6.0.1", "localforage": "1.8.1", "tslib": "^1.9.3" } @@ -2772,16 +2772,16 @@ } }, "@sentry/types": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", - "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==" + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.0.1.tgz", + "integrity": "sha512-cEoe19vtam75Tf6eWmaobfbeV8XwBdr5FJoSVTomzcSsEiP2FHGOEhlE7kVBigzeH5Lri0aibiW6BDi1hIqHdg==" }, "@sentry/utils": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", - "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.0.1.tgz", + "integrity": "sha512-bjGuBYnG6fulZ8mLhPGBxttNu96DCN6d7Glw2sfLf4aurn1kjJ/58hP2c8dH0OqWO5e+rGYTsZ5Dr5kqVKNGTg==", "requires": { - "@sentry/types": "5.30.0", + "@sentry/types": "6.0.1", "tslib": "^1.9.3" } }, diff --git a/package.json b/package.json index cd1404714..930a1ebc5 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ }, "dependencies": { "@sentry/browser": "5.30.0", - "@sentry/integrations": "5.30.0", + "@sentry/integrations": "6.0.1", "@testing-library/jest-dom": "5.11.9", "@testing-library/react": "11.2.3", "@types/jest": "26.0.20", From 70791dfa7ba1d289d0a4a92410a5585cae00d62a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Jan 2021 10:52:52 +0200 Subject: [PATCH 10/39] chore(deps): bump firebase from 8.2.3 to 8.2.4 (#2853) Bumps [firebase](https://github.com/firebase/firebase-js-sdk) from 8.2.3 to 8.2.4. - [Release notes](https://github.com/firebase/firebase-js-sdk/releases) - [Changelog](https://github.com/firebase/firebase-js-sdk/blob/master/CHANGELOG.md) - [Commits](https://github.com/firebase/firebase-js-sdk/compare/firebase@8.2.3...firebase@8.2.4) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 30 +++++++++++++++--------------- package.json | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index fc71aa975..7aa748aad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1334,9 +1334,9 @@ "integrity": "sha512-L/ZnJRAq7F++utfuoTKX4CLBG5YR7tFO3PLzG1/oXXKEezJ0kRL3CMRoueBEmTCzVb/6SIs2Qlaw++uDgi5Xyg==" }, "@firebase/auth": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-0.16.1.tgz", - "integrity": "sha512-7juD7D/kaxNti/xa5G+ZGJJs+bdJUWOW0MlNBtXwiG+TjMh69EDmwJnQmmc9h/32QVvXt1qo1OGWOoMMpF/2Gg==", + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-0.16.2.tgz", + "integrity": "sha512-68TlDL0yh3kF8PiCzI8m8RWd/bf/xCLUsdz1NZ2Dwea0sp6e2WAhu0sem1GfhwuEwL+Ns4jCdX7qbe/OQlkVEA==", "requires": { "@firebase/auth-types": "0.10.1" } @@ -1368,9 +1368,9 @@ } }, "@firebase/database": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.8.3.tgz", - "integrity": "sha512-i29rr3kcPltIkA8La9M1lgsSxx9bfu5lCQ0T+tbJptZ3UpqpcL1NzCcZa24cJjiLgq3HQNPyLvUvCtcPSFDlRg==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.9.0.tgz", + "integrity": "sha512-j9NgRCsoahvAtQ8LPxMidGsiwsklbtUlDOQ6MhU6/Hk9DVYtEnVT3qSe42xOwBGDfMe191b1B2HsiEOsglWgag==", "requires": { "@firebase/auth-interop-types": "0.1.5", "@firebase/component": "0.1.21", @@ -1405,9 +1405,9 @@ } }, "@firebase/firestore": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-2.1.2.tgz", - "integrity": "sha512-8yUdBLLr6UhE+IjPR+fxLBD0bDnEqF9GalohfURZeLQPaL3b+LtqqGCLvvXC4MKT0lJAHOV8J9LA6rHj8vI0/Q==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-2.1.3.tgz", + "integrity": "sha512-+No0hcaJ7hUYD/Vyv8xvEAnIqUQHJAFF5alL3clfyqmYa7bKtffjnZs2Pvm0fEIQ+LK4ovo2be2NmwK4iV0q5g==", "requires": { "@firebase/component": "0.1.21", "@firebase/firestore-types": "2.1.0", @@ -9067,16 +9067,16 @@ } }, "firebase": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/firebase/-/firebase-8.2.3.tgz", - "integrity": "sha512-WdbcGSiLxiW/kGZT+EyqD9z3Md7kR35+k9qMjDn/twiIrm6Hh7Qi/Z69cqxhKW6+4uK5ghXIF28CjK67OyD9Qw==", + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-8.2.4.tgz", + "integrity": "sha512-+skMZY0kXKCFVAlbwoKnRDfOhmg9rp2lDZBJk/h4PYxh/joPNTXYCKFYqUkXfwSW4jQBlLP+PtjrZKeedg6mdA==", "requires": { "@firebase/analytics": "0.6.2", "@firebase/app": "0.6.13", "@firebase/app-types": "0.6.1", - "@firebase/auth": "0.16.1", - "@firebase/database": "0.8.3", - "@firebase/firestore": "2.1.2", + "@firebase/auth": "0.16.2", + "@firebase/database": "0.9.0", + "@firebase/firestore": "2.1.3", "@firebase/functions": "0.6.1", "@firebase/installations": "0.4.19", "@firebase/messaging": "0.7.3", diff --git a/package.json b/package.json index 930a1ebc5..9d80ddf81 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "@types/socket.io-client": "1.4.35", "browser-nativefs": "0.12.0", "clsx": "1.1.1", - "firebase": "8.2.3", + "firebase": "8.2.4", "i18next-browser-languagedetector": "6.0.1", "lodash.throttle": "4.1.1", "nanoid": "3.1.20", From d3367bfe122a15ef08044abd16f57e0e02a01a4b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Jan 2021 10:53:23 +0200 Subject: [PATCH 11/39] chore(deps-dev): bump eslint-config-prettier from 7.1.0 to 7.2.0 (#2851) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7aa748aad..b1214f407 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7987,9 +7987,9 @@ } }, "eslint-config-prettier": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.1.0.tgz", - "integrity": "sha512-9sm5/PxaFG7qNJvJzTROMM1Bk1ozXVTKI0buKOyb0Bsr1hrwi0H/TzxF/COtf1uxikIK8SwhX7K6zg78jAzbeA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz", + "integrity": "sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg==", "dev": true }, "eslint-config-react-app": { diff --git a/package.json b/package.json index 9d80ddf81..138249aeb 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "devDependencies": { "@types/lodash.throttle": "4.1.6", "@types/pako": "1.0.1", - "eslint-config-prettier": "7.1.0", + "eslint-config-prettier": "7.2.0", "eslint-plugin-prettier": "3.3.1", "firebase-tools": "9.2.1", "husky": "4.3.8", From a31cfe1f07dd5883a4e0209a96dd0609d967abe2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Jan 2021 10:53:35 +0200 Subject: [PATCH 12/39] chore(deps-dev): bump firebase-tools from 9.2.1 to 9.2.2 (#2850) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 18 +++++++++--------- package.json | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index b1214f407..bf2b4ff31 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,9 +4,9 @@ "lockfileVersion": 1, "dependencies": { "@apidevtools/json-schema-ref-parser": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.6.tgz", - "integrity": "sha512-M3YgsLjI0lZxvrpeGVk9Ap032W6TPQkH6pRAZz81Ac3WUNF79VQooAFnp8umjvVzUmD93NkogxEwbSce7qMsUg==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.7.tgz", + "integrity": "sha512-QdwOGF1+eeyFh+17v2Tz626WX0nucd1iKOm6JUTUvCZdbolblCOOQCxGrQPY0f7jEhn36PiAWqZnsC2r5vmUWg==", "dev": true, "requires": { "@jsdevtools/ono": "^7.1.3", @@ -9088,9 +9088,9 @@ } }, "firebase-tools": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/firebase-tools/-/firebase-tools-9.2.1.tgz", - "integrity": "sha512-sD4wfB5hs/8IKXV6AJOmkpvXf/St7gVc9QeW4Qz21PG7CkirgRf6FqcYkPKtBcro4wfj48dihnYx/IO1+XPTGg==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/firebase-tools/-/firebase-tools-9.2.2.tgz", + "integrity": "sha512-AFjf7S9NjEM+u8ZByJEKASxRG1g+LLg/A0CrzA3V91P92MN+8cyrCigEs7mCdtFknLaShrCgzROyo/OEwd4xdA==", "dev": true, "requires": { "@google-cloud/pubsub": "^2.7.0", @@ -11562,9 +11562,9 @@ }, "dependencies": { "ip-regex": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.2.0.tgz", - "integrity": "sha512-n5cDDeTWWRwK1EBoWwRti+8nP4NbytBBY0pldmnIkq6Z55KNFmWofh4rl9dPZpj+U/nVq7gweR3ylrvMt4YZ5A==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz", + "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==", "dev": true } } diff --git a/package.json b/package.json index 138249aeb..c1f698f7b 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "@types/pako": "1.0.1", "eslint-config-prettier": "7.2.0", "eslint-plugin-prettier": "3.3.1", - "firebase-tools": "9.2.1", + "firebase-tools": "9.2.2", "husky": "4.3.8", "jest-canvas-mock": "2.3.0", "lint-staged": "10.5.3", From c2e2bb495c76b7f8f4bda4bf077cd83e20d623db Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Jan 2021 10:54:36 +0200 Subject: [PATCH 13/39] chore(deps-dev): bump webpack from 5.15.0 to 5.17.0 in /src/packages/utils (#2846) Bumps [webpack](https://github.com/webpack/webpack) from 5.15.0 to 5.17.0. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.15.0...v5.17.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/packages/utils/package-lock.json | 20 ++++++++++---------- src/packages/utils/package.json | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/packages/utils/package-lock.json b/src/packages/utils/package-lock.json index a870701b8..0a831eeee 100644 --- a/src/packages/utils/package-lock.json +++ b/src/packages/utils/package-lock.json @@ -1097,9 +1097,9 @@ } }, "@types/estree": { - "version": "0.0.45", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.45.tgz", - "integrity": "sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g==", + "version": "0.0.46", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz", + "integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==", "dev": true }, "@types/json-schema": { @@ -1109,9 +1109,9 @@ "dev": true }, "@types/node": { - "version": "14.14.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.21.tgz", - "integrity": "sha512-cHYfKsnwllYhjOzuC5q1VpguABBeecUp24yFluHpn/BQaVxB1CuQ1FSRZCzrPxrkIfWISXV2LbeoBthLWg0+0A==", + "version": "14.14.22", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.22.tgz", + "integrity": "sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw==", "dev": true }, "@webassemblyjs/ast": { @@ -2924,13 +2924,13 @@ } }, "webpack": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.15.0.tgz", - "integrity": "sha512-y/xG+ONDz78yn3VvP6gAvGr1/gkxOgitvHSXBmquyN8KDtrGEyE3K9WkXOPB7QmfcOBCpO4ELXwNcCYQnEmexA==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.17.0.tgz", + "integrity": "sha512-R+IdNEaYcYaACpXZOt7reyc8txBK7J06lOPkX1SbgmeoAnUbyBZivJIksrDBnmMA3wlTWvPcX7DubxELyPB8rA==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.0", - "@types/estree": "^0.0.45", + "@types/estree": "^0.0.46", "@webassemblyjs/ast": "1.11.0", "@webassemblyjs/wasm-edit": "1.11.0", "@webassemblyjs/wasm-parser": "1.11.0", diff --git a/src/packages/utils/package.json b/src/packages/utils/package.json index 6145e6bef..7ba01efde 100644 --- a/src/packages/utils/package.json +++ b/src/packages/utils/package.json @@ -46,7 +46,7 @@ "cross-env": "7.0.3", "file-loader": "6.2.0", "ts-loader": "8.0.14", - "webpack": "5.15.0", + "webpack": "5.17.0", "webpack-bundle-analyzer": "4.3.0", "webpack-cli": "4.3.1" }, From 9dd58288debec50f831a681468477038debc8a52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Jan 2021 10:54:48 +0200 Subject: [PATCH 14/39] chore(deps-dev): bump webpack-bundle-analyzer from 4.3.0 to 4.4.0 in /src/packages/excalidraw (#2845) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/packages/excalidraw/package-lock.json | 26 +++++++++++------------ src/packages/excalidraw/package.json | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/packages/excalidraw/package-lock.json b/src/packages/excalidraw/package-lock.json index adf8c95a1..6daadf94e 100644 --- a/src/packages/excalidraw/package-lock.json +++ b/src/packages/excalidraw/package-lock.json @@ -1,6 +1,6 @@ { "name": "@excalidraw/excalidraw", - "version": "0.2.0", + "version": "0.2.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1379,9 +1379,9 @@ "dev": true }, "acorn-walk": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.0.0.tgz", - "integrity": "sha512-oZRad/3SMOI/pxbbmqyurIx7jHw1wZDcR9G44L8pUVFEomX/0dH89SrM1KaDXuv1NpzAXz6Op/Xu/Qd5XXzdEA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.0.1.tgz", + "integrity": "sha512-zn/7dYtoTVkG4EoMU55QlQU4F+m+T7Kren6Vj3C2DapWPnakG/DL9Ns5aPAPW5Ixd3uxXrV/BoMKKVFIazPcdg==", "dev": true }, "ajv": { @@ -2435,9 +2435,9 @@ } }, "mime": { - "version": "2.4.7", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.7.tgz", - "integrity": "sha512-dhNd1uA2u397uQk3Nv5LM4lm93WYDUXFn3Fu291FJerns4jyTudqhIWe4W04YLy7Uk1tm1Ore04NpjRvQp/NPA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.0.tgz", + "integrity": "sha512-ft3WayFSFUVBuJj7BMLKAQcSlItKtfjsKDDsii3rqFDAZ7t11zRe8ASw/GlmivGwVUYtwkQrxiGGpL6gFvB0ag==", "dev": true }, "mime-db": { @@ -3380,9 +3380,9 @@ } }, "webpack-bundle-analyzer": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.3.0.tgz", - "integrity": "sha512-J3TPm54bPARx6QG8z4cKBszahnUglcv70+N+8gUqv2I5KOFHJbzBiLx+pAp606so0X004fxM7hqRu10MLjJifA==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.4.0.tgz", + "integrity": "sha512-9DhNa+aXpqdHk8LkLPTBU/dMfl84Y+WE2+KnfI6rSpNRNVKa0VGLjPd2pjFubDeqnWmulFggxmWBxhfJXZnR0g==", "dev": true, "requires": { "acorn": "^8.0.4", @@ -3519,9 +3519,9 @@ } }, "ws": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz", - "integrity": "sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.2.tgz", + "integrity": "sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA==", "dev": true }, "yallist": { diff --git a/src/packages/excalidraw/package.json b/src/packages/excalidraw/package.json index 53de442e0..4757689ca 100644 --- a/src/packages/excalidraw/package.json +++ b/src/packages/excalidraw/package.json @@ -59,7 +59,7 @@ "terser-webpack-plugin": "5.1.1", "ts-loader": "8.0.14", "webpack": "5.15.0", - "webpack-bundle-analyzer": "4.3.0", + "webpack-bundle-analyzer": "4.4.0", "webpack-cli": "4.3.1" }, "bugs": "https://github.com/excalidraw/excalidraw/issues", From 0815f3282e584c20dfd81dbc2f3f42a762130ee2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Jan 2021 10:55:38 +0200 Subject: [PATCH 15/39] chore(deps-dev): bump webpack-cli from 4.3.1 to 4.4.0 in /src/packages/utils (#2849) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/packages/utils/package-lock.json | 79 +++++++++++++++++++++++----- src/packages/utils/package.json | 2 +- 2 files changed, 68 insertions(+), 13 deletions(-) diff --git a/src/packages/utils/package-lock.json b/src/packages/utils/package-lock.json index 0a831eeee..cd715b52a 100644 --- a/src/packages/utils/package-lock.json +++ b/src/packages/utils/package-lock.json @@ -1260,6 +1260,12 @@ "@xtuc/long": "4.2.2" } }, + "@webpack-cli/configtest": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.0.tgz", + "integrity": "sha512-Un0SdBoN1h4ACnIO7EiCjWuyhNI0Jl96JC+63q6xi4HDUYRZn8Auluea9D+v9NWKc5J4sICVEltdBaVjLX39xw==", + "dev": true + }, "@webpack-cli/info": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.1.tgz", @@ -1270,9 +1276,9 @@ } }, "@webpack-cli/serve": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.2.1.tgz", - "integrity": "sha512-Zj1z6AyS+vqV6Hfi7ngCjFGdHV5EwZNIHo6QfFTNe9PyW+zBU1zJ9BiOW1pmUEq950RC4+Dym6flyA/61/vhyw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.2.2.tgz", + "integrity": "sha512-03GkWxcgFfm8+WIwcsqJb9agrSDNDDoxaNnexPnCCexP5SCE4IgFd9lNpSy+K2nFqVMpgTFw6SwbmVAVTndVew==", "dev": true }, "@xtuc/ieee754": { @@ -1620,6 +1626,17 @@ "tslib": "^1.9.0" } }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -2083,6 +2100,15 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, "is-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", @@ -2101,6 +2127,12 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, "jest-worker": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", @@ -2162,6 +2194,12 @@ "minimist": "^1.2.5" } }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, "loader-runner": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", @@ -2591,6 +2629,15 @@ "randombytes": "^2.1.0" } }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -3105,14 +3152,15 @@ } }, "webpack-cli": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.3.1.tgz", - "integrity": "sha512-/F4+9QNZM/qKzzL9/06Am8NXIkGV+/NqQ62Dx7DSqudxxpAgBqYn6V7+zp+0Y7JuWksKUbczRY3wMTd+7Uj6OA==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.4.0.tgz", + "integrity": "sha512-/Qh07CXfXEkMu5S8wEpjuaw2Zj/CC0hf/qbTDp6N8N7JjdGuaOjZ7kttz+zhuJO/J5m7alQEhNk9lsc4rC6xgQ==", "dev": true, "requires": { "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.0.0", "@webpack-cli/info": "^1.2.1", - "@webpack-cli/serve": "^1.2.1", + "@webpack-cli/serve": "^1.2.2", "colorette": "^1.2.1", "commander": "^6.2.0", "enquirer": "^2.3.6", @@ -3122,7 +3170,7 @@ "interpret": "^2.2.0", "rechoir": "^0.7.0", "v8-compile-cache": "^2.2.0", - "webpack-merge": "^4.2.2" + "webpack-merge": "^5.7.3" }, "dependencies": { "commander": { @@ -3134,12 +3182,13 @@ } }, "webpack-merge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz", - "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==", + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.7.3.tgz", + "integrity": "sha512-6/JUQv0ELQ1igjGDzHkXbVDRxkfA57Zw7PfiupdLFJYrgFqY5ZP8xxbpp2lU3EPwYx89ht5Z/aDkD40hFCm5AA==", "dev": true, "requires": { - "lodash": "^4.17.15" + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" } }, "webpack-sources": { @@ -3169,6 +3218,12 @@ "isexe": "^2.0.0" } }, + "wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, "ws": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz", diff --git a/src/packages/utils/package.json b/src/packages/utils/package.json index 7ba01efde..6293d0fd9 100644 --- a/src/packages/utils/package.json +++ b/src/packages/utils/package.json @@ -48,7 +48,7 @@ "ts-loader": "8.0.14", "webpack": "5.17.0", "webpack-bundle-analyzer": "4.3.0", - "webpack-cli": "4.3.1" + "webpack-cli": "4.4.0" }, "bugs": "https://github.com/excalidraw/excalidraw/issues", "repository": "https://github.com/excalidraw/excalidraw", From 3010253f72963a1dbd76a4c7ff3b1ac578e7ee35 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Jan 2021 08:57:12 +0000 Subject: [PATCH 16/39] chore(deps): bump @sentry/browser from 5.30.0 to 6.0.1 (#2852) Bumps [@sentry/browser](https://github.com/getsentry/sentry-javascript) from 5.30.0 to 6.0.1. - [Release notes](https://github.com/getsentry/sentry-javascript/releases) - [Changelog](https://github.com/getsentry/sentry-javascript/blob/master/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-javascript/compare/5.30.0...6.0.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 101 +++++++++++----------------------------------- package.json | 2 +- 2 files changed, 24 insertions(+), 79 deletions(-) diff --git a/package-lock.json b/package-lock.json index bf2b4ff31..dd83dfcda 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2663,84 +2663,36 @@ } }, "@sentry/browser": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.30.0.tgz", - "integrity": "sha512-rOb58ZNVJWh1VuMuBG1mL9r54nZqKeaIlwSlvzJfc89vyfd7n6tQ1UXMN383QBz/MS5H5z44Hy5eE+7pCrYAfw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.0.1.tgz", + "integrity": "sha512-iP8Bqxj4Ye8CXA4ja77buPZfXsKiZYUgHFzBQxVMihTHA8ZZLgBMPLQI6uFfHuJJW+1/yLzOf8BhvF2zknAebg==", "requires": { - "@sentry/core": "5.30.0", - "@sentry/types": "5.30.0", - "@sentry/utils": "5.30.0", + "@sentry/core": "6.0.1", + "@sentry/types": "6.0.1", + "@sentry/utils": "6.0.1", "tslib": "^1.9.3" - }, - "dependencies": { - "@sentry/types": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", - "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==" - }, - "@sentry/utils": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", - "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", - "requires": { - "@sentry/types": "5.30.0", - "tslib": "^1.9.3" - } - } } }, "@sentry/core": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", - "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.0.1.tgz", + "integrity": "sha512-EoxgodyClasI8PA4GyU8Cp88W3R5ebpiLsE7fCcBcOU0DOBRkO8GAZ5IzfCDtYDJ50c9npivum5Oyj2wf8CXYw==", "requires": { - "@sentry/hub": "5.30.0", - "@sentry/minimal": "5.30.0", - "@sentry/types": "5.30.0", - "@sentry/utils": "5.30.0", + "@sentry/hub": "6.0.1", + "@sentry/minimal": "6.0.1", + "@sentry/types": "6.0.1", + "@sentry/utils": "6.0.1", "tslib": "^1.9.3" - }, - "dependencies": { - "@sentry/types": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", - "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==" - }, - "@sentry/utils": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", - "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", - "requires": { - "@sentry/types": "5.30.0", - "tslib": "^1.9.3" - } - } } }, "@sentry/hub": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", - "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.0.1.tgz", + "integrity": "sha512-pGckNdhKcr7qYVXgSgA/QVGArATcmQu54YFAR5xTnkWVHpAwNmh0fc4CJCc4JBwS/LXSU1Y0nYiLQduVfnv8Cg==", "requires": { - "@sentry/types": "5.30.0", - "@sentry/utils": "5.30.0", + "@sentry/types": "6.0.1", + "@sentry/utils": "6.0.1", "tslib": "^1.9.3" - }, - "dependencies": { - "@sentry/types": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", - "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==" - }, - "@sentry/utils": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", - "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", - "requires": { - "@sentry/types": "5.30.0", - "tslib": "^1.9.3" - } - } } }, "@sentry/integrations": { @@ -2755,20 +2707,13 @@ } }, "@sentry/minimal": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", - "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.0.1.tgz", + "integrity": "sha512-TQ/M5A+OsxtQJ8dzHwrclxKXpJNdQeM1PUoYhff4BvsOXJScvZb7+Yn0OUEQXEc9pSMNt62tnQy4ct80iAMTHw==", "requires": { - "@sentry/hub": "5.30.0", - "@sentry/types": "5.30.0", + "@sentry/hub": "6.0.1", + "@sentry/types": "6.0.1", "tslib": "^1.9.3" - }, - "dependencies": { - "@sentry/types": { - "version": "5.30.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", - "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==" - } } }, "@sentry/types": { diff --git a/package.json b/package.json index c1f698f7b..c0d2bf0bc 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ ] }, "dependencies": { - "@sentry/browser": "5.30.0", + "@sentry/browser": "6.0.1", "@sentry/integrations": "6.0.1", "@testing-library/jest-dom": "5.11.9", "@testing-library/react": "11.2.3", From b888f7e7bacd44ddc9cb9fecddeb5739750154c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Jan 2021 08:58:30 +0000 Subject: [PATCH 17/39] chore(deps-dev): bump webpack-bundle-analyzer from 4.3.0 to 4.4.0 in /src/packages/utils (#2848) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/packages/utils/package-lock.json | 24 ++++++++++++------------ src/packages/utils/package.json | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/packages/utils/package-lock.json b/src/packages/utils/package-lock.json index cd715b52a..d75c39a9c 100644 --- a/src/packages/utils/package-lock.json +++ b/src/packages/utils/package-lock.json @@ -1300,9 +1300,9 @@ "dev": true }, "acorn-walk": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.0.0.tgz", - "integrity": "sha512-oZRad/3SMOI/pxbbmqyurIx7jHw1wZDcR9G44L8pUVFEomX/0dH89SrM1KaDXuv1NpzAXz6Op/Xu/Qd5XXzdEA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.0.1.tgz", + "integrity": "sha512-zn/7dYtoTVkG4EoMU55QlQU4F+m+T7Kren6Vj3C2DapWPnakG/DL9Ns5aPAPW5Ixd3uxXrV/BoMKKVFIazPcdg==", "dev": true }, "ajv": { @@ -2305,9 +2305,9 @@ } }, "mime": { - "version": "2.4.7", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.7.tgz", - "integrity": "sha512-dhNd1uA2u397uQk3Nv5LM4lm93WYDUXFn3Fu291FJerns4jyTudqhIWe4W04YLy7Uk1tm1Ore04NpjRvQp/NPA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.0.tgz", + "integrity": "sha512-ft3WayFSFUVBuJj7BMLKAQcSlItKtfjsKDDsii3rqFDAZ7t11zRe8ASw/GlmivGwVUYtwkQrxiGGpL6gFvB0ag==", "dev": true }, "mime-db": { @@ -3078,9 +3078,9 @@ } }, "webpack-bundle-analyzer": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.3.0.tgz", - "integrity": "sha512-J3TPm54bPARx6QG8z4cKBszahnUglcv70+N+8gUqv2I5KOFHJbzBiLx+pAp606so0X004fxM7hqRu10MLjJifA==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.4.0.tgz", + "integrity": "sha512-9DhNa+aXpqdHk8LkLPTBU/dMfl84Y+WE2+KnfI6rSpNRNVKa0VGLjPd2pjFubDeqnWmulFggxmWBxhfJXZnR0g==", "dev": true, "requires": { "acorn": "^8.0.4", @@ -3225,9 +3225,9 @@ "dev": true }, "ws": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz", - "integrity": "sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.2.tgz", + "integrity": "sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA==", "dev": true }, "yallist": { diff --git a/src/packages/utils/package.json b/src/packages/utils/package.json index 6293d0fd9..cc6f0ee70 100644 --- a/src/packages/utils/package.json +++ b/src/packages/utils/package.json @@ -47,7 +47,7 @@ "file-loader": "6.2.0", "ts-loader": "8.0.14", "webpack": "5.17.0", - "webpack-bundle-analyzer": "4.3.0", + "webpack-bundle-analyzer": "4.4.0", "webpack-cli": "4.4.0" }, "bugs": "https://github.com/excalidraw/excalidraw/issues", From df745c109856c7161766dbf2a59d9551e0413d0b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Jan 2021 08:59:37 +0000 Subject: [PATCH 18/39] chore(deps-dev): bump webpack from 5.15.0 to 5.17.0 in /src/packages/excalidraw (#2844) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/packages/excalidraw/package-lock.json | 14 +++++++------- src/packages/excalidraw/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/packages/excalidraw/package-lock.json b/src/packages/excalidraw/package-lock.json index 6daadf94e..204a3475e 100644 --- a/src/packages/excalidraw/package-lock.json +++ b/src/packages/excalidraw/package-lock.json @@ -1182,9 +1182,9 @@ } }, "@types/estree": { - "version": "0.0.45", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.45.tgz", - "integrity": "sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g==", + "version": "0.0.46", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz", + "integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==", "dev": true }, "@types/json-schema": { @@ -3257,13 +3257,13 @@ } }, "webpack": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.15.0.tgz", - "integrity": "sha512-y/xG+ONDz78yn3VvP6gAvGr1/gkxOgitvHSXBmquyN8KDtrGEyE3K9WkXOPB7QmfcOBCpO4ELXwNcCYQnEmexA==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.17.0.tgz", + "integrity": "sha512-R+IdNEaYcYaACpXZOt7reyc8txBK7J06lOPkX1SbgmeoAnUbyBZivJIksrDBnmMA3wlTWvPcX7DubxELyPB8rA==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.0", - "@types/estree": "^0.0.45", + "@types/estree": "^0.0.46", "@webassemblyjs/ast": "1.11.0", "@webassemblyjs/wasm-edit": "1.11.0", "@webassemblyjs/wasm-parser": "1.11.0", diff --git a/src/packages/excalidraw/package.json b/src/packages/excalidraw/package.json index 4757689ca..a9ae4f635 100644 --- a/src/packages/excalidraw/package.json +++ b/src/packages/excalidraw/package.json @@ -58,7 +58,7 @@ "sass-loader": "10.1.1", "terser-webpack-plugin": "5.1.1", "ts-loader": "8.0.14", - "webpack": "5.15.0", + "webpack": "5.17.0", "webpack-bundle-analyzer": "4.4.0", "webpack-cli": "4.3.1" }, From 03f6d9c7834a09e50b6af7e4e241fcdb408b6220 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 24 Jan 2021 09:00:02 +0000 Subject: [PATCH 19/39] chore(deps-dev): bump webpack-cli from 4.3.1 to 4.4.0 in /src/packages/excalidraw (#2847) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/packages/excalidraw/package-lock.json | 79 +++++++++++++++++++---- src/packages/excalidraw/package.json | 2 +- 2 files changed, 68 insertions(+), 13 deletions(-) diff --git a/src/packages/excalidraw/package-lock.json b/src/packages/excalidraw/package-lock.json index 204a3475e..e3f3f6605 100644 --- a/src/packages/excalidraw/package-lock.json +++ b/src/packages/excalidraw/package-lock.json @@ -1345,6 +1345,12 @@ "@xtuc/long": "4.2.2" } }, + "@webpack-cli/configtest": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.0.tgz", + "integrity": "sha512-Un0SdBoN1h4ACnIO7EiCjWuyhNI0Jl96JC+63q6xi4HDUYRZn8Auluea9D+v9NWKc5J4sICVEltdBaVjLX39xw==", + "dev": true + }, "@webpack-cli/info": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.1.tgz", @@ -1355,9 +1361,9 @@ } }, "@webpack-cli/serve": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.2.1.tgz", - "integrity": "sha512-Zj1z6AyS+vqV6Hfi7ngCjFGdHV5EwZNIHo6QfFTNe9PyW+zBU1zJ9BiOW1pmUEq950RC4+Dym6flyA/61/vhyw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.2.2.tgz", + "integrity": "sha512-03GkWxcgFfm8+WIwcsqJb9agrSDNDDoxaNnexPnCCexP5SCE4IgFd9lNpSy+K2nFqVMpgTFw6SwbmVAVTndVew==", "dev": true }, "@xtuc/ieee754": { @@ -1711,6 +1717,17 @@ "tslib": "^1.9.0" } }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -2245,6 +2262,15 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, "is-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", @@ -2263,6 +2289,12 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, "jest-worker": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", @@ -2324,6 +2356,12 @@ "minimist": "^1.2.5" } }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, "klona": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", @@ -2918,6 +2956,15 @@ "randombytes": "^2.1.0" } }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -3454,14 +3501,15 @@ } }, "webpack-cli": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.3.1.tgz", - "integrity": "sha512-/F4+9QNZM/qKzzL9/06Am8NXIkGV+/NqQ62Dx7DSqudxxpAgBqYn6V7+zp+0Y7JuWksKUbczRY3wMTd+7Uj6OA==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.4.0.tgz", + "integrity": "sha512-/Qh07CXfXEkMu5S8wEpjuaw2Zj/CC0hf/qbTDp6N8N7JjdGuaOjZ7kttz+zhuJO/J5m7alQEhNk9lsc4rC6xgQ==", "dev": true, "requires": { "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.0.0", "@webpack-cli/info": "^1.2.1", - "@webpack-cli/serve": "^1.2.1", + "@webpack-cli/serve": "^1.2.2", "colorette": "^1.2.1", "commander": "^6.2.0", "enquirer": "^2.3.6", @@ -3471,7 +3519,7 @@ "interpret": "^2.2.0", "rechoir": "^0.7.0", "v8-compile-cache": "^2.2.0", - "webpack-merge": "^4.2.2" + "webpack-merge": "^5.7.3" }, "dependencies": { "commander": { @@ -3483,12 +3531,13 @@ } }, "webpack-merge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz", - "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==", + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.7.3.tgz", + "integrity": "sha512-6/JUQv0ELQ1igjGDzHkXbVDRxkfA57Zw7PfiupdLFJYrgFqY5ZP8xxbpp2lU3EPwYx89ht5Z/aDkD40hFCm5AA==", "dev": true, "requires": { - "lodash": "^4.17.15" + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" } }, "webpack-sources": { @@ -3518,6 +3567,12 @@ "isexe": "^2.0.0" } }, + "wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, "ws": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.2.tgz", diff --git a/src/packages/excalidraw/package.json b/src/packages/excalidraw/package.json index a9ae4f635..76b938f63 100644 --- a/src/packages/excalidraw/package.json +++ b/src/packages/excalidraw/package.json @@ -60,7 +60,7 @@ "ts-loader": "8.0.14", "webpack": "5.17.0", "webpack-bundle-analyzer": "4.4.0", - "webpack-cli": "4.3.1" + "webpack-cli": "4.4.0" }, "bugs": "https://github.com/excalidraw/excalidraw/issues", "repository": "https://github.com/excalidraw/excalidraw", From 0a0be839b929bece4a22d45906a594550c647dea Mon Sep 17 00:00:00 2001 From: David Luzar Date: Mon, 25 Jan 2021 10:47:35 +0100 Subject: [PATCH 20/39] refactor: rewrite collabWrapper to remove TDZs and simplify (#2834) --- src/components/App.tsx | 2 + src/components/Dialog.tsx | 13 +- src/createInverseContext.tsx | 42 ++++++ src/excalidraw-app/collab/CollabWrapper.tsx | 132 ++++++++++++----- src/excalidraw-app/collab/Portal.tsx | 83 ++--------- src/excalidraw-app/index.tsx | 85 ++++++----- src/hooks/useCallbackRefState.ts | 7 + src/packages/excalidraw/CHANGELOG.md | 4 + src/packages/excalidraw/README.md | 15 +- .../regressionTests.test.tsx.snap | 134 +++++++++--------- src/tests/dragCreate.test.tsx | 20 +-- src/tests/move.test.tsx | 6 +- src/tests/multiPointCreate.test.tsx | 10 +- src/tests/selection.test.tsx | 16 +-- src/tests/test-utils.ts | 2 +- src/types.ts | 5 +- 16 files changed, 312 insertions(+), 264 deletions(-) create mode 100644 src/createInverseContext.tsx create mode 100644 src/hooks/useCallbackRefState.ts diff --git a/src/components/App.tsx b/src/components/App.tsx index 2c0583b26..bf1c989b3 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -248,6 +248,7 @@ export type ExcalidrawImperativeAPI = { }; setScrollToCenter: InstanceType["setScrollToCenter"]; getSceneElements: InstanceType["getSceneElements"]; + getAppState: () => InstanceType["state"]; readyPromise: ResolvablePromise; ready: true; }; @@ -298,6 +299,7 @@ class App extends React.Component { }, setScrollToCenter: this.setScrollToCenter, getSceneElements: this.getSceneElements, + getAppState: () => this.state, } as const; if (typeof excalidrawRef === "function") { excalidrawRef(api); diff --git a/src/components/Dialog.tsx b/src/components/Dialog.tsx index 217b625c4..507dc1772 100644 --- a/src/components/Dialog.tsx +++ b/src/components/Dialog.tsx @@ -1,5 +1,6 @@ import clsx from "clsx"; -import React, { useCallback, useEffect, useState } from "react"; +import React, { useEffect } from "react"; +import { useCallbackRefState } from "../hooks/useCallbackRefState"; import { t } from "../i18n"; import useIsMobile from "../is-mobile"; import { KEYS } from "../keys"; @@ -8,14 +9,6 @@ import { back, close } from "./icons"; import { Island } from "./Island"; import { Modal } from "./Modal"; -const useRefState = () => { - const [refValue, setRefValue] = useState(null); - const refCallback = useCallback((value: T) => { - setRefValue(value); - }, []); - return [refValue, refCallback] as const; -}; - export const Dialog = (props: { children: React.ReactNode; className?: string; @@ -24,7 +17,7 @@ export const Dialog = (props: { title: React.ReactNode; autofocus?: boolean; }) => { - const [islandNode, setIslandNode] = useRefState(); + const [islandNode, setIslandNode] = useCallbackRefState(); useEffect(() => { if (!islandNode) { diff --git a/src/createInverseContext.tsx b/src/createInverseContext.tsx new file mode 100644 index 000000000..ac6cc223e --- /dev/null +++ b/src/createInverseContext.tsx @@ -0,0 +1,42 @@ +import React from "react"; + +export const createInverseContext = ( + initialValue: T, +) => { + const Context = React.createContext(initialValue) as React.Context & { + _updateProviderValue?: (value: T) => void; + }; + + class InverseConsumer extends React.Component { + state = { value: initialValue }; + constructor(props: any) { + super(props); + Context._updateProviderValue = (value: T) => this.setState({ value }); + } + render() { + return ( + + {this.props.children} + + ); + } + } + + class InverseProvider extends React.Component<{ value: T }> { + componentDidMount() { + Context._updateProviderValue?.(this.props.value); + } + componentDidUpdate() { + Context._updateProviderValue?.(this.props.value); + } + render() { + return {() => this.props.children}; + } + } + + return { + Context, + Consumer: InverseConsumer, + Provider: InverseProvider, + }; +}; diff --git a/src/excalidraw-app/collab/CollabWrapper.tsx b/src/excalidraw-app/collab/CollabWrapper.tsx index d27adb35d..c308a70d6 100644 --- a/src/excalidraw-app/collab/CollabWrapper.tsx +++ b/src/excalidraw-app/collab/CollabWrapper.tsx @@ -6,10 +6,11 @@ import { APP_NAME, ENV, EVENT } from "../../constants"; import { ImportedDataState } from "../../data/types"; import { ExcalidrawElement } from "../../element/types"; import { + getElementMap, getSceneVersion, getSyncableElements, } from "../../packages/excalidraw/index"; -import { AppState, Collaborator, Gesture } from "../../types"; +import { Collaborator, Gesture } from "../../types"; import { resolvablePromise, withBatchedUpdates } from "../../utils"; import { INITIAL_SCENE_UPDATE_TIMEOUT, @@ -31,6 +32,7 @@ import { } from "../data/localStorage"; import Portal from "./Portal"; import RoomDialog from "./RoomDialog"; +import { createInverseContext } from "../../createInverseContext"; interface CollabState { isCollaborating: boolean; @@ -56,17 +58,21 @@ type ReconciledElements = readonly ExcalidrawElement[] & { }; interface Props { - children: (collab: CollabAPI) => React.ReactNode; - // NOTE not type-safe because the refObject may in fact not be initialized - // with ExcalidrawImperativeAPI yet - excalidrawRef: React.MutableRefObject; + excalidrawAPI: ExcalidrawImperativeAPI; } +const { + Context: CollabContext, + Consumer: CollabContextConsumer, + Provider: CollabContextProvider, +} = createInverseContext<{ api: CollabAPI | null }>({ api: null }); + +export { CollabContext, CollabContextConsumer }; + class CollabWrapper extends PureComponent { portal: Portal; + excalidrawAPI: Props["excalidrawAPI"]; private socketInitializationTimer?: NodeJS.Timeout; - private excalidrawRef: Props["excalidrawRef"]; - excalidrawAppState?: AppState; private lastBroadcastedOrReceivedSceneVersion: number = -1; private collaborators = new Map(); @@ -80,7 +86,7 @@ class CollabWrapper extends PureComponent { activeRoomLink: "", }; this.portal = new Portal(this); - this.excalidrawRef = props.excalidrawRef; + this.excalidrawAPI = props.excalidrawAPI; } componentDidMount() { @@ -142,7 +148,7 @@ class CollabWrapper extends PureComponent { saveCollabRoomToFirebase = async ( syncableElements: ExcalidrawElement[] = getSyncableElements( - this.excalidrawRef.current!.getSceneElementsIncludingDeleted(), + this.excalidrawAPI.getSceneElementsIncludingDeleted(), ), ) => { try { @@ -154,13 +160,13 @@ class CollabWrapper extends PureComponent { openPortal = async () => { window.history.pushState({}, APP_NAME, await generateCollaborationLink()); - const elements = this.excalidrawRef.current!.getSceneElements(); + const elements = this.excalidrawAPI.getSceneElements(); // remove deleted elements from elements array & history to ensure we don't // expose potentially sensitive user data in case user manually deletes // existing elements (or clears scene), which would otherwise be persisted // to database even if deleted before creating the room. - this.excalidrawRef.current!.history.clear(); - this.excalidrawRef.current!.updateScene({ + this.excalidrawAPI.history.clear(); + this.excalidrawAPI.updateScene({ elements, commitToHistory: true, }); @@ -175,7 +181,7 @@ class CollabWrapper extends PureComponent { private destroySocketClient = () => { this.collaborators = new Map(); - this.excalidrawRef.current!.updateScene({ + this.excalidrawAPI.updateScene({ collaborators: this.collaborators, }); this.setState({ @@ -265,7 +271,7 @@ class CollabWrapper extends PureComponent { user.selectedElementIds = selectedElementIds; user.username = username; collaborators.set(socketId, user); - this.excalidrawRef.current!.updateScene({ + this.excalidrawAPI.updateScene({ collaborators, }); break; @@ -300,7 +306,55 @@ class CollabWrapper extends PureComponent { private reconcileElements = ( elements: readonly ExcalidrawElement[], ): ReconciledElements => { - const newElements = this.portal.reconcileElements(elements); + const currentElements = this.getSceneElementsIncludingDeleted(); + // create a map of ids so we don't have to iterate + // over the array more than once. + const localElementMap = getElementMap(currentElements); + + const appState = this.excalidrawAPI.getAppState(); + + // Reconcile + const newElements: readonly ExcalidrawElement[] = elements + .reduce((elements, element) => { + // if the remote element references one that's currently + // edited on local, skip it (it'll be added in the next step) + if ( + element.id === appState.editingElement?.id || + element.id === appState.resizingElement?.id || + element.id === appState.draggingElement?.id + ) { + return elements; + } + + if ( + localElementMap.hasOwnProperty(element.id) && + localElementMap[element.id].version > element.version + ) { + elements.push(localElementMap[element.id]); + delete localElementMap[element.id]; + } else if ( + localElementMap.hasOwnProperty(element.id) && + localElementMap[element.id].version === element.version && + localElementMap[element.id].versionNonce !== element.versionNonce + ) { + // resolve conflicting edits deterministically by taking the one with the lowest versionNonce + if (localElementMap[element.id].versionNonce < element.versionNonce) { + elements.push(localElementMap[element.id]); + } else { + // it should be highly unlikely that the two versionNonces are the same. if we are + // really worried about this, we can replace the versionNonce with the socket id. + elements.push(element); + } + delete localElementMap[element.id]; + } else { + elements.push(element); + delete localElementMap[element.id]; + } + + return elements; + }, [] as Mutable) + // add local elements that weren't deleted or on remote + .concat(...Object.values(localElementMap)); // Avoid broadcasting to the rest of the collaborators the scene // we just received! @@ -319,10 +373,10 @@ class CollabWrapper extends PureComponent { }: { init?: boolean; initFromSnapshot?: boolean } = {}, ) => { if (init || initFromSnapshot) { - this.excalidrawRef.current!.setScrollToCenter(elements); + this.excalidrawAPI.setScrollToCenter(elements); } - this.excalidrawRef.current!.updateScene({ + this.excalidrawAPI.updateScene({ elements, commitToHistory: !!init, }); @@ -331,7 +385,7 @@ class CollabWrapper extends PureComponent { // when we receive any messages from another peer. This UX can be pretty rough -- if you // undo, a user makes a change, and then try to redo, your element(s) will be lost. However, // right now we think this is the right tradeoff. - this.excalidrawRef.current!.history.clear(); + this.excalidrawAPI.history.clear(); }; setCollaborators(sockets: string[]) { @@ -347,7 +401,7 @@ class CollabWrapper extends PureComponent { } } this.collaborators = collaborators; - this.excalidrawRef.current!.updateScene({ collaborators }); + this.excalidrawAPI.updateScene({ collaborators }); }); } @@ -360,7 +414,7 @@ class CollabWrapper extends PureComponent { }; public getSceneElementsIncludingDeleted = () => { - return this.excalidrawRef.current!.getSceneElementsIncludingDeleted(); + return this.excalidrawAPI.getSceneElementsIncludingDeleted(); }; onPointerUpdate = (payload: { @@ -373,11 +427,7 @@ class CollabWrapper extends PureComponent { this.portal.broadcastMouseLocation(payload); }; - broadcastElements = ( - elements: readonly ExcalidrawElement[], - state: AppState, - ) => { - this.excalidrawAppState = state; + broadcastElements = (elements: readonly ExcalidrawElement[]) => { if ( getSceneVersion(elements) > this.getLastBroadcastedOrReceivedSceneVersion() @@ -396,7 +446,7 @@ class CollabWrapper extends PureComponent { this.portal.broadcastScene( SCENE.UPDATE, getSyncableElements( - this.excalidrawRef.current!.getSceneElementsIncludingDeleted(), + this.excalidrawAPI.getSceneElementsIncludingDeleted(), ), true, ); @@ -425,8 +475,23 @@ class CollabWrapper extends PureComponent { }); }; + /** PRIVATE. Use `this.getContextValue()` instead. */ + private contextValue: CollabAPI | null = null; + + /** Getter of context value. Returned object is stable. */ + getContextValue = (): CollabAPI => { + this.contextValue = this.contextValue || ({} as CollabAPI); + + this.contextValue.isCollaborating = this.state.isCollaborating; + this.contextValue.username = this.state.username; + this.contextValue.onPointerUpdate = this.onPointerUpdate; + this.contextValue.initializeSocketClient = this.initializeSocketClient; + this.contextValue.onCollabButtonClick = this.onCollabButtonClick; + this.contextValue.broadcastElements = this.broadcastElements; + return this.contextValue; + }; + render() { - const { children } = this.props; const { modalIsShown, username, errorMessage, activeRoomLink } = this.state; return ( @@ -450,14 +515,11 @@ class CollabWrapper extends PureComponent { onClose={() => this.setState({ errorMessage: "" })} /> )} - {children({ - isCollaborating: this.state.isCollaborating, - username: this.state.username, - onPointerUpdate: this.onPointerUpdate, - initializeSocketClient: this.initializeSocketClient, - onCollabButtonClick: this.onCollabButtonClick, - broadcastElements: this.broadcastElements, - })} + ); } diff --git a/src/excalidraw-app/collab/Portal.tsx b/src/excalidraw-app/collab/Portal.tsx index 2b66b0bd0..92086a27b 100644 --- a/src/excalidraw-app/collab/Portal.tsx +++ b/src/excalidraw-app/collab/Portal.tsx @@ -6,23 +6,20 @@ import { import CollabWrapper from "./CollabWrapper"; -import { - getElementMap, - getSyncableElements, -} from "../../packages/excalidraw/index"; +import { getSyncableElements } from "../../packages/excalidraw/index"; import { ExcalidrawElement } from "../../element/types"; import { BROADCAST, SCENE } from "../app_constants"; class Portal { - app: CollabWrapper; + collab: CollabWrapper; socket: SocketIOClient.Socket | null = null; socketInitialized: boolean = false; // we don't want the socket to emit any updates until it is fully initialized roomId: string | null = null; roomKey: string | null = null; broadcastedElementVersions: Map = new Map(); - constructor(app: CollabWrapper) { - this.app = app; + constructor(collab: CollabWrapper) { + this.collab = collab; } open(socket: SocketIOClient.Socket, id: string, key: string) { @@ -30,7 +27,7 @@ class Portal { this.roomId = id; this.roomKey = key; - // Initialize socket listeners (moving from App) + // Initialize socket listeners this.socket.on("init-room", () => { if (this.socket) { this.socket.emit("join-room", this.roomId); @@ -39,12 +36,12 @@ class Portal { this.socket.on("new-user", async (_socketId: string) => { this.broadcastScene( SCENE.INIT, - getSyncableElements(this.app.getSceneElementsIncludingDeleted()), + getSyncableElements(this.collab.getSceneElementsIncludingDeleted()), /* syncAll */ true, ); }); this.socket.on("room-user-change", (clients: string[]) => { - this.app.setCollaborators(clients); + this.collab.setCollaborators(clients); }); } @@ -125,10 +122,10 @@ class Portal { data as SocketUpdateData, ); - if (syncAll && this.app.state.isCollaborating) { + if (syncAll && this.collab.state.isCollaborating) { await Promise.all([ broadcastPromise, - this.app.saveCollabRoomToFirebase(syncableElements), + this.collab.saveCollabRoomToFirebase(syncableElements), ]); } else { await broadcastPromise; @@ -146,9 +143,9 @@ class Portal { socketId: this.socket.id, pointer: payload.pointer, button: payload.button || "up", - selectedElementIds: - this.app.excalidrawAppState?.selectedElementIds || {}, - username: this.app.state.username, + selectedElementIds: this.collab.excalidrawAPI.getAppState() + .selectedElementIds, + username: this.collab.state.username, }, }; return this._broadcastSocketData( @@ -157,62 +154,6 @@ class Portal { ); } }; - - reconcileElements = ( - sceneElements: readonly ExcalidrawElement[], - ): readonly ExcalidrawElement[] => { - const currentElements = this.app.getSceneElementsIncludingDeleted(); - // create a map of ids so we don't have to iterate - // over the array more than once. - const localElementMap = getElementMap(currentElements); - - // Reconcile - return ( - sceneElements - .reduce((elements, element) => { - // if the remote element references one that's currently - // edited on local, skip it (it'll be added in the next step) - if ( - element.id === this.app.excalidrawAppState?.editingElement?.id || - element.id === this.app.excalidrawAppState?.resizingElement?.id || - element.id === this.app.excalidrawAppState?.draggingElement?.id - ) { - return elements; - } - - if ( - localElementMap.hasOwnProperty(element.id) && - localElementMap[element.id].version > element.version - ) { - elements.push(localElementMap[element.id]); - delete localElementMap[element.id]; - } else if ( - localElementMap.hasOwnProperty(element.id) && - localElementMap[element.id].version === element.version && - localElementMap[element.id].versionNonce !== element.versionNonce - ) { - // resolve conflicting edits deterministically by taking the one with the lowest versionNonce - if ( - localElementMap[element.id].versionNonce < element.versionNonce - ) { - elements.push(localElementMap[element.id]); - } else { - // it should be highly unlikely that the two versionNonces are the same. if we are - // really worried about this, we can replace the versionNonce with the socket id. - elements.push(element); - } - delete localElementMap[element.id]; - } else { - elements.push(element); - delete localElementMap[element.id]; - } - - return elements; - }, [] as Mutable) - // add local elements that weren't deleted or on remote - .concat(...Object.values(localElementMap)) - ); - }; } export default Portal; diff --git a/src/excalidraw-app/index.tsx b/src/excalidraw-app/index.tsx index e90664e8e..fcc7f45f7 100644 --- a/src/excalidraw-app/index.tsx +++ b/src/excalidraw-app/index.tsx @@ -1,6 +1,7 @@ import LanguageDetector from "i18next-browser-languagedetector"; import React, { useCallback, + useContext, useEffect, useLayoutEffect, useRef, @@ -17,12 +18,13 @@ import { ExcalidrawElement, NonDeletedExcalidrawElement, } from "../element/types"; +import { useCallbackRefState } from "../hooks/useCallbackRefState"; import { Language, t } from "../i18n"; import Excalidraw, { defaultLang, languages, } from "../packages/excalidraw/index"; -import { AppState, ExcalidrawAPIRefValue } from "../types"; +import { AppState } from "../types"; import { debounce, getVersion, @@ -30,7 +32,11 @@ import { resolvablePromise, } from "../utils"; import { SAVE_TO_LOCAL_STORAGE_TIMEOUT } from "./app_constants"; -import CollabWrapper, { CollabAPI } from "./collab/CollabWrapper"; +import CollabWrapper, { + CollabAPI, + CollabContext, + CollabContextConsumer, +} from "./collab/CollabWrapper"; import { LanguageList } from "./components/LanguageList"; import { exportToBackend, getCollaborationLinkData, loadScene } from "./data"; import { loadFromFirebase } from "./data/firebase"; @@ -49,15 +55,6 @@ languageDetector.init({ checkWhitelist: false, }); -const excalidrawRef: React.MutableRefObject< - MarkRequired -> = { - current: { - readyPromise: resolvablePromise(), - ready: false, - }, -}; - const saveDebounced = debounce( (elements: readonly ExcalidrawElement[], state: AppState) => { saveToLocalStorage(elements, state); @@ -191,7 +188,7 @@ const initializeScene = async (opts: { return null; }; -function ExcalidrawWrapper(props: { collab: CollabAPI }) { +function ExcalidrawWrapper() { // dimensions // --------------------------------------------------------------------------- @@ -226,35 +223,40 @@ function ExcalidrawWrapper(props: { collab: CollabAPI }) { initialStatePromiseRef.current.promise = resolvablePromise(); } - const { collab } = props; - useEffect(() => { // Delayed so that the app has a time to load the latest SW setTimeout(() => { trackEvent("load", "version", getVersion()); }, VERSION_TIMEOUT); + }, []); - excalidrawRef.current!.readyPromise.then((excalidrawApi) => { - initializeScene({ - resetScene: excalidrawApi.resetScene, - initializeSocketClient: collab.initializeSocketClient, - }).then((scene) => { - initialStatePromiseRef.current.promise.resolve(scene); - }); + const [ + excalidrawAPI, + excalidrawRefCallback, + ] = useCallbackRefState(); + + const collabAPI = useContext(CollabContext)?.api; + + useEffect(() => { + if (!collabAPI || !excalidrawAPI) { + return; + } + + initializeScene({ + resetScene: excalidrawAPI.resetScene, + initializeSocketClient: collabAPI.initializeSocketClient, + }).then((scene) => { + initialStatePromiseRef.current.promise.resolve(scene); }); const onHashChange = (_: HashChangeEvent) => { - const api = excalidrawRef.current!; - if (!api.ready) { - return; - } if (window.location.hash.length > 1) { initializeScene({ - resetScene: api.resetScene, - initializeSocketClient: collab.initializeSocketClient, + resetScene: excalidrawAPI.resetScene, + initializeSocketClient: collabAPI.initializeSocketClient, }).then((scene) => { if (scene) { - api.updateScene(scene); + excalidrawAPI.updateScene(scene); } }); } @@ -273,7 +275,7 @@ function ExcalidrawWrapper(props: { collab: CollabAPI }) { window.removeEventListener(EVENT.BLUR, onBlur, false); clearTimeout(titleTimeout); }; - }, [collab.initializeSocketClient]); + }, [collabAPI, excalidrawAPI]); useEffect(() => { languageDetector.cacheUserLanguage(langCode); @@ -284,8 +286,8 @@ function ExcalidrawWrapper(props: { collab: CollabAPI }) { appState: AppState, ) => { saveDebounced(elements, appState); - if (collab.isCollaborating) { - collab.broadcastElements(elements, appState); + if (collabAPI?.isCollaborating) { + collabAPI.broadcastElements(elements); } }; @@ -343,19 +345,20 @@ function ExcalidrawWrapper(props: { collab: CollabAPI }) { return ( <> + {excalidrawAPI && } {errorMessage && ( - - } - > - {(collab) => } - + + + ); } diff --git a/src/hooks/useCallbackRefState.ts b/src/hooks/useCallbackRefState.ts new file mode 100644 index 000000000..4a8552b58 --- /dev/null +++ b/src/hooks/useCallbackRefState.ts @@ -0,0 +1,7 @@ +import { useCallback, useState } from "react"; + +export const useCallbackRefState = () => { + const [refValue, setRefValue] = useState(null); + const refCallback = useCallback((value: T | null) => setRefValue(value), []); + return [refValue, refCallback] as const; +}; diff --git a/src/packages/excalidraw/CHANGELOG.md b/src/packages/excalidraw/CHANGELOG.md index 7ab2dd7cd..ba90fd513 100644 --- a/src/packages/excalidraw/CHANGELOG.md +++ b/src/packages/excalidraw/CHANGELOG.md @@ -14,6 +14,10 @@ Please add the latest change on the top under the correct section. ## [Unreleased] +## Excalidraw API + +- Expose `getAppState` on `excalidrawRef` [#2834](https://github.com/excalidraw/excalidraw/pull/2834). + ## Excalidraw Library ### Features diff --git a/src/packages/excalidraw/README.md b/src/packages/excalidraw/README.md index 9cad15d76..409c3fba0 100644 --- a/src/packages/excalidraw/README.md +++ b/src/packages/excalidraw/README.md @@ -147,7 +147,7 @@ export default function App() {
 import { getSceneVersion } from "@excalidraw/excalidraw";
-getSceneVersion(elements:  ExcalidrawElement [])
+getSceneVersion(elements:  ExcalidrawElement[])
 
This function returns the current scene version. @@ -157,7 +157,7 @@ This function returns the current scene version. **_Signature_**
-getSyncableElements(elements:  ExcalidrawElement []):ExcalidrawElement []
+getSyncableElements(elements:  ExcalidrawElement[]):ExcalidrawElement[]
 
**How to use** @@ -173,7 +173,7 @@ This function returns all the deleted elements of the scene. **_Signature_**
-getElementsMap(elements:  ExcalidrawElement []): {[id: string]: ExcalidrawElement}
+getElementsMap(elements:  ExcalidrawElement[]): {[id: string]: ExcalidrawElement}
 
**How to use** @@ -220,7 +220,7 @@ This helps to load Excalidraw with `initialData`. It must be an object or a [pro | name | type | | --- | --- | -| elements | [ExcalidrawElement []](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78) | +| elements | [ExcalidrawElement[]](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78) | | appState | [AppState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L37) | ```json @@ -268,8 +268,9 @@ You can pass a `ref` when you want to access some excalidraw APIs. We expose the | readyPromise | [resolvablePromise](https://github.com/excalidraw/excalidraw/blob/master/src/utils.ts#L317) | This promise will be resolved with the api once excalidraw has rendered. This will be helpful when you want do some action on the host app once this promise resolves. For this to work you will have to pass ref as shown [here](#readyPromise) | | updateScene |
(sceneData)) => void 
| updates the scene with the sceneData | | resetScene | `({ resetLoadingState: boolean }) => void` | Resets the scene. If `resetLoadingState` is passed as true then it will also force set the loading state to false. | -| getSceneElementsIncludingDeleted |
 () => ExcalidrawElement []
| Returns all the elements including the deleted in the scene | -| getSceneElements |
 () => ExcalidrawElement []
| Returns all the elements excluding the deleted in the scene | +| getSceneElementsIncludingDeleted |
 () => ExcalidrawElement[]
| Returns all the elements including the deleted in the scene | +| getSceneElements |
 () => ExcalidrawElement[]
| Returns all the elements excluding the deleted in the scene | +| getAppState |
 () => AppState
| Returns current appState | | history | `{ clear: () => void }` | This is the history API. `history.clear()` will clear the history | | setScrollToCenter |
 (ExcalidrawElement[]) => void 
| sets the elements to center | @@ -324,7 +325,7 @@ import { defaultLang, languages } from "@excalidraw/excalidraw"; | name | type | | --- | --- | | defaultLang | string | -| languages | [Language []](https://github.com/excalidraw/excalidraw/blob/master/src/i18n.ts#L8) | +| languages | [Language[]](https://github.com/excalidraw/excalidraw/blob/master/src/i18n.ts#L8) | #### `renderFooter` diff --git a/src/tests/__snapshots__/regressionTests.test.tsx.snap b/src/tests/__snapshots__/regressionTests.test.tsx.snap index ce23cf2de..8c8bf78a5 100644 --- a/src/tests/__snapshots__/regressionTests.test.tsx.snap +++ b/src/tests/__snapshots__/regressionTests.test.tsx.snap @@ -457,7 +457,7 @@ Object { exports[`given element A and group of elements B and given both are selected when user clicks on B, on pointer up only elements from B should be selected: [end of test] number of elements 1`] = `3`; -exports[`given element A and group of elements B and given both are selected when user clicks on B, on pointer up only elements from B should be selected: [end of test] number of renders 1`] = `25`; +exports[`given element A and group of elements B and given both are selected when user clicks on B, on pointer up only elements from B should be selected: [end of test] number of renders 1`] = `26`; exports[`given element A and group of elements B and given both are selected when user shift-clicks on B, on pointer up only element A should be selected: [end of test] appState 1`] = ` Object { @@ -922,7 +922,7 @@ Object { exports[`given element A and group of elements B and given both are selected when user shift-clicks on B, on pointer up only element A should be selected: [end of test] number of elements 1`] = `3`; -exports[`given element A and group of elements B and given both are selected when user shift-clicks on B, on pointer up only element A should be selected: [end of test] number of renders 1`] = `21`; +exports[`given element A and group of elements B and given both are selected when user shift-clicks on B, on pointer up only element A should be selected: [end of test] number of renders 1`] = `22`; exports[`regression tests Cmd/Ctrl-click exclusively select element under pointer: [end of test] appState 1`] = ` Object { @@ -1696,7 +1696,7 @@ Object { exports[`regression tests Cmd/Ctrl-click exclusively select element under pointer: [end of test] number of elements 1`] = `3`; -exports[`regression tests Cmd/Ctrl-click exclusively select element under pointer: [end of test] number of renders 1`] = `40`; +exports[`regression tests Cmd/Ctrl-click exclusively select element under pointer: [end of test] number of renders 1`] = `41`; exports[`regression tests Drags selected element when hitting only bounding box and keeps element selected: [end of test] appState 1`] = ` Object { @@ -1898,7 +1898,7 @@ Object { exports[`regression tests Drags selected element when hitting only bounding box and keeps element selected: [end of test] number of elements 1`] = `1`; -exports[`regression tests Drags selected element when hitting only bounding box and keeps element selected: [end of test] number of renders 1`] = `9`; +exports[`regression tests Drags selected element when hitting only bounding box and keeps element selected: [end of test] number of renders 1`] = `10`; exports[`regression tests adjusts z order when grouping: [end of test] appState 1`] = ` Object { @@ -2354,7 +2354,7 @@ Object { exports[`regression tests adjusts z order when grouping: [end of test] number of elements 1`] = `3`; -exports[`regression tests adjusts z order when grouping: [end of test] number of renders 1`] = `19`; +exports[`regression tests adjusts z order when grouping: [end of test] number of renders 1`] = `20`; exports[`regression tests alt-drag duplicates an element: [end of test] appState 1`] = ` Object { @@ -2605,7 +2605,7 @@ Object { exports[`regression tests alt-drag duplicates an element: [end of test] number of elements 1`] = `2`; -exports[`regression tests alt-drag duplicates an element: [end of test] number of renders 1`] = `9`; +exports[`regression tests alt-drag duplicates an element: [end of test] number of renders 1`] = `10`; exports[`regression tests arrow keys: [end of test] appState 1`] = ` Object { @@ -2767,7 +2767,7 @@ Object { exports[`regression tests arrow keys: [end of test] number of elements 1`] = `1`; -exports[`regression tests arrow keys: [end of test] number of renders 1`] = `18`; +exports[`regression tests arrow keys: [end of test] number of renders 1`] = `19`; exports[`regression tests can drag element that covers another element, while another elem is selected: [end of test] appState 1`] = ` Object { @@ -3242,7 +3242,7 @@ Object { exports[`regression tests can drag element that covers another element, while another elem is selected: [end of test] number of elements 1`] = `3`; -exports[`regression tests can drag element that covers another element, while another elem is selected: [end of test] number of renders 1`] = `17`; +exports[`regression tests can drag element that covers another element, while another elem is selected: [end of test] number of renders 1`] = `18`; exports[`regression tests change the properties of a shape: [end of test] appState 1`] = ` Object { @@ -3548,7 +3548,7 @@ Object { exports[`regression tests change the properties of a shape: [end of test] number of elements 1`] = `1`; -exports[`regression tests change the properties of a shape: [end of test] number of renders 1`] = `10`; +exports[`regression tests change the properties of a shape: [end of test] number of renders 1`] = `11`; exports[`regression tests click on an element and drag it: [dragged] appState 1`] = ` Object { @@ -3750,7 +3750,7 @@ Object { exports[`regression tests click on an element and drag it: [dragged] number of elements 1`] = `1`; -exports[`regression tests click on an element and drag it: [dragged] number of renders 1`] = `9`; +exports[`regression tests click on an element and drag it: [dragged] number of renders 1`] = `10`; exports[`regression tests click on an element and drag it: [end of test] appState 1`] = ` Object { @@ -3992,7 +3992,7 @@ Object { exports[`regression tests click on an element and drag it: [end of test] number of elements 1`] = `1`; -exports[`regression tests click on an element and drag it: [end of test] number of renders 1`] = `12`; +exports[`regression tests click on an element and drag it: [end of test] number of renders 1`] = `13`; exports[`regression tests click to select a shape: [end of test] appState 1`] = ` Object { @@ -4242,7 +4242,7 @@ Object { exports[`regression tests click to select a shape: [end of test] number of elements 1`] = `2`; -exports[`regression tests click to select a shape: [end of test] number of renders 1`] = `12`; +exports[`regression tests click to select a shape: [end of test] number of renders 1`] = `13`; exports[`regression tests click-drag to select a group: [end of test] appState 1`] = ` Object { @@ -4601,7 +4601,7 @@ Object { exports[`regression tests click-drag to select a group: [end of test] number of elements 1`] = `3`; -exports[`regression tests click-drag to select a group: [end of test] number of renders 1`] = `18`; +exports[`regression tests click-drag to select a group: [end of test] number of renders 1`] = `19`; exports[`regression tests deselects group of selected elements on pointer down when pointer doesn't hit any element: [end of test] appState 1`] = ` Object { @@ -4894,7 +4894,7 @@ Object { exports[`regression tests deselects group of selected elements on pointer down when pointer doesn't hit any element: [end of test] number of elements 1`] = `2`; -exports[`regression tests deselects group of selected elements on pointer down when pointer doesn't hit any element: [end of test] number of renders 1`] = `13`; +exports[`regression tests deselects group of selected elements on pointer down when pointer doesn't hit any element: [end of test] number of renders 1`] = `14`; exports[`regression tests deselects group of selected elements on pointer up when pointer hits common bounding box without hitting any element: [end of test] appState 1`] = ` Object { @@ -5199,7 +5199,7 @@ Object { exports[`regression tests deselects group of selected elements on pointer up when pointer hits common bounding box without hitting any element: [end of test] number of elements 1`] = `2`; -exports[`regression tests deselects group of selected elements on pointer up when pointer hits common bounding box without hitting any element: [end of test] number of renders 1`] = `14`; +exports[`regression tests deselects group of selected elements on pointer up when pointer hits common bounding box without hitting any element: [end of test] number of renders 1`] = `15`; exports[`regression tests deselects selected element on pointer down when pointer doesn't hit any element: [end of test] appState 1`] = ` Object { @@ -5405,7 +5405,7 @@ Object { exports[`regression tests deselects selected element on pointer down when pointer doesn't hit any element: [end of test] number of elements 1`] = `1`; -exports[`regression tests deselects selected element on pointer down when pointer doesn't hit any element: [end of test] number of renders 1`] = `7`; +exports[`regression tests deselects selected element on pointer down when pointer doesn't hit any element: [end of test] number of renders 1`] = `8`; exports[`regression tests deselects selected element, on pointer up, when click hits element bounding box but doesn't hit the element: [end of test] appState 1`] = ` Object { @@ -5589,7 +5589,7 @@ Object { exports[`regression tests deselects selected element, on pointer up, when click hits element bounding box but doesn't hit the element: [end of test] number of elements 1`] = `1`; -exports[`regression tests deselects selected element, on pointer up, when click hits element bounding box but doesn't hit the element: [end of test] number of renders 1`] = `8`; +exports[`regression tests deselects selected element, on pointer up, when click hits element bounding box but doesn't hit the element: [end of test] number of renders 1`] = `9`; exports[`regression tests double click to edit a group: [end of test] appState 1`] = ` Object { @@ -6040,7 +6040,7 @@ Object { exports[`regression tests double click to edit a group: [end of test] number of elements 1`] = `3`; -exports[`regression tests double click to edit a group: [end of test] number of renders 1`] = `17`; +exports[`regression tests double click to edit a group: [end of test] number of renders 1`] = `18`; exports[`regression tests drags selected elements from point inside common bounding box that doesn't hit any element and keeps elements selected after dragging: [end of test] appState 1`] = ` Object { @@ -6356,7 +6356,7 @@ Object { exports[`regression tests drags selected elements from point inside common bounding box that doesn't hit any element and keeps elements selected after dragging: [end of test] number of elements 1`] = `2`; -exports[`regression tests drags selected elements from point inside common bounding box that doesn't hit any element and keeps elements selected after dragging: [end of test] number of renders 1`] = `15`; +exports[`regression tests drags selected elements from point inside common bounding box that doesn't hit any element and keeps elements selected after dragging: [end of test] number of renders 1`] = `16`; exports[`regression tests draw every type of shape: [end of test] appState 1`] = ` Object { @@ -8388,7 +8388,7 @@ Object { exports[`regression tests draw every type of shape: [end of test] number of elements 1`] = `8`; -exports[`regression tests draw every type of shape: [end of test] number of renders 1`] = `50`; +exports[`regression tests draw every type of shape: [end of test] number of renders 1`] = `51`; exports[`regression tests given a group of selected elements with an element that is not selected inside the group common bounding box when element that is not selected is clicked should switch selection to not selected element on pointer up: [end of test] appState 1`] = ` Object { @@ -8748,7 +8748,7 @@ Object { exports[`regression tests given a group of selected elements with an element that is not selected inside the group common bounding box when element that is not selected is clicked should switch selection to not selected element on pointer up: [end of test] number of elements 1`] = `3`; -exports[`regression tests given a group of selected elements with an element that is not selected inside the group common bounding box when element that is not selected is clicked should switch selection to not selected element on pointer up: [end of test] number of renders 1`] = `18`; +exports[`regression tests given a group of selected elements with an element that is not selected inside the group common bounding box when element that is not selected is clicked should switch selection to not selected element on pointer up: [end of test] number of renders 1`] = `19`; exports[`regression tests given a selected element A and a not selected element B with higher z-index than A and given B partialy overlaps A when there's a shift-click on the overlapped section B is added to the selection: [end of test] appState 1`] = ` Object { @@ -9001,7 +9001,7 @@ Object { exports[`regression tests given a selected element A and a not selected element B with higher z-index than A and given B partialy overlaps A when there's a shift-click on the overlapped section B is added to the selection: [end of test] number of elements 1`] = `2`; -exports[`regression tests given a selected element A and a not selected element B with higher z-index than A and given B partialy overlaps A when there's a shift-click on the overlapped section B is added to the selection: [end of test] number of renders 1`] = `16`; +exports[`regression tests given a selected element A and a not selected element B with higher z-index than A and given B partialy overlaps A when there's a shift-click on the overlapped section B is added to the selection: [end of test] number of renders 1`] = `17`; exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when clicking intersection between A and B B should be selected on pointer up: [end of test] appState 1`] = ` Object { @@ -9252,7 +9252,7 @@ Object { exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when clicking intersection between A and B B should be selected on pointer up: [end of test] number of elements 1`] = `2`; -exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when clicking intersection between A and B B should be selected on pointer up: [end of test] number of renders 1`] = `16`; +exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when clicking intersection between A and B B should be selected on pointer up: [end of test] number of renders 1`] = `17`; exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when dragging on intersection between A and B A should be dragged and keep being selected: [end of test] appState 1`] = ` Object { @@ -9565,7 +9565,7 @@ Object { exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when dragging on intersection between A and B A should be dragged and keep being selected: [end of test] number of elements 1`] = `2`; -exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when dragging on intersection between A and B A should be dragged and keep being selected: [end of test] number of renders 1`] = `17`; +exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when dragging on intersection between A and B A should be dragged and keep being selected: [end of test] number of renders 1`] = `18`; exports[`regression tests key 2 selects rectangle tool: [end of test] appState 1`] = ` Object { @@ -9727,7 +9727,7 @@ Object { exports[`regression tests key 2 selects rectangle tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key 2 selects rectangle tool: [end of test] number of renders 1`] = `6`; +exports[`regression tests key 2 selects rectangle tool: [end of test] number of renders 1`] = `7`; exports[`regression tests key 3 selects diamond tool: [end of test] appState 1`] = ` Object { @@ -9889,7 +9889,7 @@ Object { exports[`regression tests key 3 selects diamond tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key 3 selects diamond tool: [end of test] number of renders 1`] = `6`; +exports[`regression tests key 3 selects diamond tool: [end of test] number of renders 1`] = `7`; exports[`regression tests key 4 selects ellipse tool: [end of test] appState 1`] = ` Object { @@ -10051,7 +10051,7 @@ Object { exports[`regression tests key 4 selects ellipse tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key 4 selects ellipse tool: [end of test] number of renders 1`] = `6`; +exports[`regression tests key 4 selects ellipse tool: [end of test] number of renders 1`] = `7`; exports[`regression tests key 5 selects arrow tool: [end of test] appState 1`] = ` Object { @@ -10243,7 +10243,7 @@ Object { exports[`regression tests key 5 selects arrow tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key 5 selects arrow tool: [end of test] number of renders 1`] = `7`; +exports[`regression tests key 5 selects arrow tool: [end of test] number of renders 1`] = `8`; exports[`regression tests key 6 selects line tool: [end of test] appState 1`] = ` Object { @@ -10435,7 +10435,7 @@ Object { exports[`regression tests key 6 selects line tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key 6 selects line tool: [end of test] number of renders 1`] = `6`; +exports[`regression tests key 6 selects line tool: [end of test] number of renders 1`] = `7`; exports[`regression tests key 7 selects draw tool: [end of test] appState 1`] = ` Object { @@ -10627,7 +10627,7 @@ Object { exports[`regression tests key 7 selects draw tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key 7 selects draw tool: [end of test] number of renders 1`] = `6`; +exports[`regression tests key 7 selects draw tool: [end of test] number of renders 1`] = `7`; exports[`regression tests key a selects arrow tool: [end of test] appState 1`] = ` Object { @@ -10819,7 +10819,7 @@ Object { exports[`regression tests key a selects arrow tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key a selects arrow tool: [end of test] number of renders 1`] = `7`; +exports[`regression tests key a selects arrow tool: [end of test] number of renders 1`] = `8`; exports[`regression tests key d selects diamond tool: [end of test] appState 1`] = ` Object { @@ -10981,7 +10981,7 @@ Object { exports[`regression tests key d selects diamond tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key d selects diamond tool: [end of test] number of renders 1`] = `6`; +exports[`regression tests key d selects diamond tool: [end of test] number of renders 1`] = `7`; exports[`regression tests key e selects ellipse tool: [end of test] appState 1`] = ` Object { @@ -11143,7 +11143,7 @@ Object { exports[`regression tests key e selects ellipse tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key e selects ellipse tool: [end of test] number of renders 1`] = `6`; +exports[`regression tests key e selects ellipse tool: [end of test] number of renders 1`] = `7`; exports[`regression tests key l selects line tool: [end of test] appState 1`] = ` Object { @@ -11335,7 +11335,7 @@ Object { exports[`regression tests key l selects line tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key l selects line tool: [end of test] number of renders 1`] = `6`; +exports[`regression tests key l selects line tool: [end of test] number of renders 1`] = `7`; exports[`regression tests key r selects rectangle tool: [end of test] appState 1`] = ` Object { @@ -11497,7 +11497,7 @@ Object { exports[`regression tests key r selects rectangle tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key r selects rectangle tool: [end of test] number of renders 1`] = `6`; +exports[`regression tests key r selects rectangle tool: [end of test] number of renders 1`] = `7`; exports[`regression tests key x selects draw tool: [end of test] appState 1`] = ` Object { @@ -11689,7 +11689,7 @@ Object { exports[`regression tests key x selects draw tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key x selects draw tool: [end of test] number of renders 1`] = `6`; +exports[`regression tests key x selects draw tool: [end of test] number of renders 1`] = `7`; exports[`regression tests make a group and duplicate it: [end of test] appState 1`] = ` Object { @@ -12403,7 +12403,7 @@ Object { exports[`regression tests make a group and duplicate it: [end of test] number of elements 1`] = `6`; -exports[`regression tests make a group and duplicate it: [end of test] number of renders 1`] = `21`; +exports[`regression tests make a group and duplicate it: [end of test] number of renders 1`] = `22`; exports[`regression tests noop interaction after undo shouldn't create history entry: [end of test] appState 1`] = ` Object { @@ -12654,7 +12654,7 @@ Object { exports[`regression tests noop interaction after undo shouldn't create history entry: [end of test] number of elements 1`] = `2`; -exports[`regression tests noop interaction after undo shouldn't create history entry: [end of test] number of renders 1`] = `18`; +exports[`regression tests noop interaction after undo shouldn't create history entry: [end of test] number of renders 1`] = `19`; exports[`regression tests pinch-to-zoom works: [end of test] appState 1`] = ` Object { @@ -12754,7 +12754,7 @@ Object { exports[`regression tests pinch-to-zoom works: [end of test] number of elements 1`] = `0`; -exports[`regression tests pinch-to-zoom works: [end of test] number of renders 1`] = `8`; +exports[`regression tests pinch-to-zoom works: [end of test] number of renders 1`] = `9`; exports[`regression tests rerenders UI on language change: [end of test] appState 1`] = ` Object { @@ -12852,7 +12852,7 @@ Object { exports[`regression tests rerenders UI on language change: [end of test] number of elements 1`] = `0`; -exports[`regression tests rerenders UI on language change: [end of test] number of renders 1`] = `7`; +exports[`regression tests rerenders UI on language change: [end of test] number of renders 1`] = `8`; exports[`regression tests selecting 'Add to library' in context menu adds element to library: [end of test] appState 1`] = ` Object { @@ -13014,7 +13014,7 @@ Object { exports[`regression tests selecting 'Add to library' in context menu adds element to library: [end of test] number of elements 1`] = `1`; -exports[`regression tests selecting 'Add to library' in context menu adds element to library: [end of test] number of renders 1`] = `6`; +exports[`regression tests selecting 'Add to library' in context menu adds element to library: [end of test] number of renders 1`] = `7`; exports[`regression tests selecting 'Bring forward' in context menu brings element forward: [end of test] appState 1`] = ` Object { @@ -13320,7 +13320,7 @@ Object { exports[`regression tests selecting 'Bring forward' in context menu brings element forward: [end of test] number of elements 1`] = `2`; -exports[`regression tests selecting 'Bring forward' in context menu brings element forward: [end of test] number of renders 1`] = `12`; +exports[`regression tests selecting 'Bring forward' in context menu brings element forward: [end of test] number of renders 1`] = `13`; exports[`regression tests selecting 'Bring to front' in context menu brings element to front: [end of test] appState 1`] = ` Object { @@ -13626,7 +13626,7 @@ Object { exports[`regression tests selecting 'Bring to front' in context menu brings element to front: [end of test] number of elements 1`] = `2`; -exports[`regression tests selecting 'Bring to front' in context menu brings element to front: [end of test] number of renders 1`] = `12`; +exports[`regression tests selecting 'Bring to front' in context menu brings element to front: [end of test] number of renders 1`] = `13`; exports[`regression tests selecting 'Copy styles' in context menu copies styles: [end of test] appState 1`] = ` Object { @@ -13788,7 +13788,7 @@ Object { exports[`regression tests selecting 'Copy styles' in context menu copies styles: [end of test] number of elements 1`] = `1`; -exports[`regression tests selecting 'Copy styles' in context menu copies styles: [end of test] number of renders 1`] = `7`; +exports[`regression tests selecting 'Copy styles' in context menu copies styles: [end of test] number of renders 1`] = `8`; exports[`regression tests selecting 'Delete' in context menu deletes element: [end of test] appState 1`] = ` Object { @@ -13982,7 +13982,7 @@ Object { exports[`regression tests selecting 'Delete' in context menu deletes element: [end of test] number of elements 1`] = `1`; -exports[`regression tests selecting 'Delete' in context menu deletes element: [end of test] number of renders 1`] = `7`; +exports[`regression tests selecting 'Delete' in context menu deletes element: [end of test] number of renders 1`] = `8`; exports[`regression tests selecting 'Duplicate' in context menu duplicates element: [end of test] appState 1`] = ` Object { @@ -14229,7 +14229,7 @@ Object { exports[`regression tests selecting 'Duplicate' in context menu duplicates element: [end of test] number of elements 1`] = `2`; -exports[`regression tests selecting 'Duplicate' in context menu duplicates element: [end of test] number of renders 1`] = `7`; +exports[`regression tests selecting 'Duplicate' in context menu duplicates element: [end of test] number of renders 1`] = `8`; exports[`regression tests selecting 'Group selection' in context menu groups selected elements: [end of test] appState 1`] = ` Object { @@ -14551,7 +14551,7 @@ Object { exports[`regression tests selecting 'Group selection' in context menu groups selected elements: [end of test] number of elements 1`] = `2`; -exports[`regression tests selecting 'Group selection' in context menu groups selected elements: [end of test] number of renders 1`] = `13`; +exports[`regression tests selecting 'Group selection' in context menu groups selected elements: [end of test] number of renders 1`] = `14`; exports[`regression tests selecting 'Paste styles' in context menu pastes styles: [end of test] appState 1`] = ` Object { @@ -15388,7 +15388,7 @@ Object { exports[`regression tests selecting 'Paste styles' in context menu pastes styles: [end of test] number of elements 1`] = `2`; -exports[`regression tests selecting 'Paste styles' in context menu pastes styles: [end of test] number of renders 1`] = `22`; +exports[`regression tests selecting 'Paste styles' in context menu pastes styles: [end of test] number of renders 1`] = `23`; exports[`regression tests selecting 'Send backward' in context menu sends element backward: [end of test] appState 1`] = ` Object { @@ -15694,7 +15694,7 @@ Object { exports[`regression tests selecting 'Send backward' in context menu sends element backward: [end of test] number of elements 1`] = `2`; -exports[`regression tests selecting 'Send backward' in context menu sends element backward: [end of test] number of renders 1`] = `11`; +exports[`regression tests selecting 'Send backward' in context menu sends element backward: [end of test] number of renders 1`] = `12`; exports[`regression tests selecting 'Send to back' in context menu sends element to back: [end of test] appState 1`] = ` Object { @@ -16000,7 +16000,7 @@ Object { exports[`regression tests selecting 'Send to back' in context menu sends element to back: [end of test] number of elements 1`] = `2`; -exports[`regression tests selecting 'Send to back' in context menu sends element to back: [end of test] number of renders 1`] = `11`; +exports[`regression tests selecting 'Send to back' in context menu sends element to back: [end of test] number of renders 1`] = `12`; exports[`regression tests selecting 'Ungroup selection' in context menu ungroups selected group: [end of test] appState 1`] = ` Object { @@ -16377,7 +16377,7 @@ Object { exports[`regression tests selecting 'Ungroup selection' in context menu ungroups selected group: [end of test] number of elements 1`] = `2`; -exports[`regression tests selecting 'Ungroup selection' in context menu ungroups selected group: [end of test] number of renders 1`] = `14`; +exports[`regression tests selecting 'Ungroup selection' in context menu ungroups selected group: [end of test] number of renders 1`] = `15`; exports[`regression tests shift click on selected element should deselect it on pointer up: [end of test] appState 1`] = ` Object { @@ -16542,7 +16542,7 @@ Object { exports[`regression tests shift click on selected element should deselect it on pointer up: [end of test] number of elements 1`] = `1`; -exports[`regression tests shift click on selected element should deselect it on pointer up: [end of test] number of renders 1`] = `8`; +exports[`regression tests shift click on selected element should deselect it on pointer up: [end of test] number of renders 1`] = `9`; exports[`regression tests shift-click to multiselect, then drag: [end of test] appState 1`] = ` Object { @@ -16861,7 +16861,7 @@ Object { exports[`regression tests shift-click to multiselect, then drag: [end of test] number of elements 1`] = `2`; -exports[`regression tests shift-click to multiselect, then drag: [end of test] number of renders 1`] = `17`; +exports[`regression tests shift-click to multiselect, then drag: [end of test] number of renders 1`] = `18`; exports[`regression tests should show fill icons when element has non transparent background: [end of test] appState 1`] = ` Object { @@ -17098,7 +17098,7 @@ Object { exports[`regression tests should show fill icons when element has non transparent background: [end of test] number of elements 1`] = `1`; -exports[`regression tests should show fill icons when element has non transparent background: [end of test] number of renders 1`] = `10`; +exports[`regression tests should show fill icons when element has non transparent background: [end of test] number of renders 1`] = `11`; exports[`regression tests shows 'Group selection' in context menu for multiple selected elements: [end of test] appState 1`] = ` Object { @@ -17351,7 +17351,7 @@ Object { exports[`regression tests shows 'Group selection' in context menu for multiple selected elements: [end of test] number of elements 1`] = `2`; -exports[`regression tests shows 'Group selection' in context menu for multiple selected elements: [end of test] number of renders 1`] = `14`; +exports[`regression tests shows 'Group selection' in context menu for multiple selected elements: [end of test] number of renders 1`] = `15`; exports[`regression tests shows 'Ungroup selection' in context menu for group inside selected elements: [end of test] appState 1`] = ` Object { @@ -17676,7 +17676,7 @@ Object { exports[`regression tests shows 'Ungroup selection' in context menu for group inside selected elements: [end of test] number of elements 1`] = `2`; -exports[`regression tests shows 'Ungroup selection' in context menu for group inside selected elements: [end of test] number of renders 1`] = `15`; +exports[`regression tests shows 'Ungroup selection' in context menu for group inside selected elements: [end of test] number of renders 1`] = `16`; exports[`regression tests shows context menu for canvas: [end of test] appState 1`] = ` Object { @@ -17774,7 +17774,7 @@ Object { exports[`regression tests shows context menu for canvas: [end of test] number of elements 1`] = `0`; -exports[`regression tests shows context menu for canvas: [end of test] number of renders 1`] = `2`; +exports[`regression tests shows context menu for canvas: [end of test] number of renders 1`] = `3`; exports[`regression tests shows context menu for element: [end of test] appState 1`] = ` Object { @@ -17936,7 +17936,7 @@ Object { exports[`regression tests shows context menu for element: [end of test] number of elements 1`] = `1`; -exports[`regression tests shows context menu for element: [end of test] number of renders 1`] = `6`; +exports[`regression tests shows context menu for element: [end of test] number of renders 1`] = `7`; exports[`regression tests single-clicking on a subgroup of a selected group should not alter selection: [end of test] appState 1`] = ` Object { @@ -18755,7 +18755,7 @@ Object { exports[`regression tests single-clicking on a subgroup of a selected group should not alter selection: [end of test] number of elements 1`] = `4`; -exports[`regression tests single-clicking on a subgroup of a selected group should not alter selection: [end of test] number of renders 1`] = `36`; +exports[`regression tests single-clicking on a subgroup of a selected group should not alter selection: [end of test] number of renders 1`] = `37`; exports[`regression tests spacebar + drag scrolls the canvas: [end of test] appState 1`] = ` Object { @@ -18853,7 +18853,7 @@ Object { exports[`regression tests spacebar + drag scrolls the canvas: [end of test] number of elements 1`] = `0`; -exports[`regression tests spacebar + drag scrolls the canvas: [end of test] number of renders 1`] = `5`; +exports[`regression tests spacebar + drag scrolls the canvas: [end of test] number of renders 1`] = `6`; exports[`regression tests supports nested groups: [end of test] appState 1`] = ` Object { @@ -19583,7 +19583,7 @@ Object { exports[`regression tests supports nested groups: [end of test] number of elements 1`] = `3`; -exports[`regression tests supports nested groups: [end of test] number of renders 1`] = `29`; +exports[`regression tests supports nested groups: [end of test] number of renders 1`] = `30`; exports[`regression tests switches from group of selected elements to another element on pointer down: [end of test] appState 1`] = ` Object { @@ -19986,7 +19986,7 @@ Object { exports[`regression tests switches from group of selected elements to another element on pointer down: [end of test] number of elements 1`] = `3`; -exports[`regression tests switches from group of selected elements to another element on pointer down: [end of test] number of renders 1`] = `17`; +exports[`regression tests switches from group of selected elements to another element on pointer down: [end of test] number of renders 1`] = `18`; exports[`regression tests switches selected element on pointer down: [end of test] appState 1`] = ` Object { @@ -20279,7 +20279,7 @@ Object { exports[`regression tests switches selected element on pointer down: [end of test] number of elements 1`] = `2`; -exports[`regression tests switches selected element on pointer down: [end of test] number of renders 1`] = `11`; +exports[`regression tests switches selected element on pointer down: [end of test] number of renders 1`] = `12`; exports[`regression tests two-finger scroll works: [end of test] appState 1`] = ` Object { @@ -20379,7 +20379,7 @@ Object { exports[`regression tests two-finger scroll works: [end of test] number of elements 1`] = `0`; -exports[`regression tests two-finger scroll works: [end of test] number of renders 1`] = `10`; +exports[`regression tests two-finger scroll works: [end of test] number of renders 1`] = `11`; exports[`regression tests undo/redo drawing an element: [end of test] appState 1`] = ` Object { @@ -20875,7 +20875,7 @@ Object { exports[`regression tests undo/redo drawing an element: [end of test] number of elements 1`] = `3`; -exports[`regression tests undo/redo drawing an element: [end of test] number of renders 1`] = `27`; +exports[`regression tests undo/redo drawing an element: [end of test] number of renders 1`] = `28`; exports[`regression tests updates fontSize & fontFamily appState: [end of test] appState 1`] = ` Object { @@ -20973,7 +20973,7 @@ Object { exports[`regression tests updates fontSize & fontFamily appState: [end of test] number of elements 1`] = `0`; -exports[`regression tests updates fontSize & fontFamily appState: [end of test] number of renders 1`] = `4`; +exports[`regression tests updates fontSize & fontFamily appState: [end of test] number of renders 1`] = `5`; exports[`regression tests zoom hotkeys: [end of test] appState 1`] = ` Object { @@ -21071,4 +21071,4 @@ Object { exports[`regression tests zoom hotkeys: [end of test] number of elements 1`] = `0`; -exports[`regression tests zoom hotkeys: [end of test] number of renders 1`] = `4`; +exports[`regression tests zoom hotkeys: [end of test] number of renders 1`] = `5`; diff --git a/src/tests/dragCreate.test.tsx b/src/tests/dragCreate.test.tsx index ae08977c3..7a55ed89a 100644 --- a/src/tests/dragCreate.test.tsx +++ b/src/tests/dragCreate.test.tsx @@ -37,7 +37,7 @@ describe("add element to the scene when pointer dragging long enough", () => { // finish (position does not matter) fireEvent.pointerUp(canvas); - expect(renderScene).toHaveBeenCalledTimes(6); + expect(renderScene).toHaveBeenCalledTimes(7); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); @@ -68,7 +68,7 @@ describe("add element to the scene when pointer dragging long enough", () => { // finish (position does not matter) fireEvent.pointerUp(canvas); - expect(renderScene).toHaveBeenCalledTimes(6); + expect(renderScene).toHaveBeenCalledTimes(7); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); @@ -99,7 +99,7 @@ describe("add element to the scene when pointer dragging long enough", () => { // finish (position does not matter) fireEvent.pointerUp(canvas); - expect(renderScene).toHaveBeenCalledTimes(6); + expect(renderScene).toHaveBeenCalledTimes(7); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); @@ -130,7 +130,7 @@ describe("add element to the scene when pointer dragging long enough", () => { // finish (position does not matter) fireEvent.pointerUp(canvas); - expect(renderScene).toHaveBeenCalledTimes(6); + expect(renderScene).toHaveBeenCalledTimes(7); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); @@ -165,7 +165,7 @@ describe("add element to the scene when pointer dragging long enough", () => { // finish (position does not matter) fireEvent.pointerUp(canvas); - expect(renderScene).toHaveBeenCalledTimes(6); + expect(renderScene).toHaveBeenCalledTimes(7); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); @@ -198,7 +198,7 @@ describe("do not add element to the scene if size is too small", () => { // finish (position does not matter) fireEvent.pointerUp(canvas); - expect(renderScene).toHaveBeenCalledTimes(5); + expect(renderScene).toHaveBeenCalledTimes(6); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(0); }); @@ -217,7 +217,7 @@ describe("do not add element to the scene if size is too small", () => { // finish (position does not matter) fireEvent.pointerUp(canvas); - expect(renderScene).toHaveBeenCalledTimes(5); + expect(renderScene).toHaveBeenCalledTimes(6); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(0); }); @@ -236,7 +236,7 @@ describe("do not add element to the scene if size is too small", () => { // finish (position does not matter) fireEvent.pointerUp(canvas); - expect(renderScene).toHaveBeenCalledTimes(5); + expect(renderScene).toHaveBeenCalledTimes(6); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(0); }); @@ -258,7 +258,7 @@ describe("do not add element to the scene if size is too small", () => { // we need to finalize it because arrows and lines enter multi-mode fireEvent.keyDown(document, { key: KEYS.ENTER }); - expect(renderScene).toHaveBeenCalledTimes(6); + expect(renderScene).toHaveBeenCalledTimes(7); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(0); }); @@ -280,7 +280,7 @@ describe("do not add element to the scene if size is too small", () => { // we need to finalize it because arrows and lines enter multi-mode fireEvent.keyDown(document, { key: KEYS.ENTER }); - expect(renderScene).toHaveBeenCalledTimes(6); + expect(renderScene).toHaveBeenCalledTimes(7); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(0); }); diff --git a/src/tests/move.test.tsx b/src/tests/move.test.tsx index e97ace31f..e356f89a3 100644 --- a/src/tests/move.test.tsx +++ b/src/tests/move.test.tsx @@ -38,7 +38,7 @@ describe("move element", () => { fireEvent.pointerMove(canvas, { clientX: 60, clientY: 70 }); fireEvent.pointerUp(canvas); - expect(renderScene).toHaveBeenCalledTimes(6); + expect(renderScene).toHaveBeenCalledTimes(7); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); @@ -77,7 +77,7 @@ describe("move element", () => { // select the second rectangles new Pointer("mouse").clickOn(rectB); - expect(renderScene).toHaveBeenCalledTimes(20); + expect(renderScene).toHaveBeenCalledTimes(21); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(3); expect(h.state.selectedElementIds[rectB.id]).toBeTruthy(); @@ -120,7 +120,7 @@ describe("duplicate element on move when ALT is clicked", () => { fireEvent.pointerMove(canvas, { clientX: 60, clientY: 70 }); fireEvent.pointerUp(canvas); - expect(renderScene).toHaveBeenCalledTimes(6); + expect(renderScene).toHaveBeenCalledTimes(7); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); diff --git a/src/tests/multiPointCreate.test.tsx b/src/tests/multiPointCreate.test.tsx index 406c5888b..93bbc6639 100644 --- a/src/tests/multiPointCreate.test.tsx +++ b/src/tests/multiPointCreate.test.tsx @@ -30,7 +30,7 @@ describe("remove shape in non linear elements", () => { fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 }); fireEvent.pointerUp(canvas, { clientX: 30, clientY: 30 }); - expect(renderScene).toHaveBeenCalledTimes(5); + expect(renderScene).toHaveBeenCalledTimes(6); expect(h.elements.length).toEqual(0); }); @@ -44,7 +44,7 @@ describe("remove shape in non linear elements", () => { fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 }); fireEvent.pointerUp(canvas, { clientX: 30, clientY: 30 }); - expect(renderScene).toHaveBeenCalledTimes(5); + expect(renderScene).toHaveBeenCalledTimes(6); expect(h.elements.length).toEqual(0); }); @@ -58,7 +58,7 @@ describe("remove shape in non linear elements", () => { fireEvent.pointerDown(canvas, { clientX: 30, clientY: 20 }); fireEvent.pointerUp(canvas, { clientX: 30, clientY: 30 }); - expect(renderScene).toHaveBeenCalledTimes(5); + expect(renderScene).toHaveBeenCalledTimes(6); expect(h.elements.length).toEqual(0); }); }); @@ -88,7 +88,7 @@ describe("multi point mode in linear elements", () => { fireEvent.pointerUp(canvas); fireEvent.keyDown(document, { key: KEYS.ENTER }); - expect(renderScene).toHaveBeenCalledTimes(12); + expect(renderScene).toHaveBeenCalledTimes(13); expect(h.elements.length).toEqual(1); const element = h.elements[0] as ExcalidrawLinearElement; @@ -129,7 +129,7 @@ describe("multi point mode in linear elements", () => { fireEvent.pointerUp(canvas); fireEvent.keyDown(document, { key: KEYS.ENTER }); - expect(renderScene).toHaveBeenCalledTimes(12); + expect(renderScene).toHaveBeenCalledTimes(13); expect(h.elements.length).toEqual(1); const element = h.elements[0] as ExcalidrawLinearElement; diff --git a/src/tests/selection.test.tsx b/src/tests/selection.test.tsx index 0d2350d1f..004c4bcd9 100644 --- a/src/tests/selection.test.tsx +++ b/src/tests/selection.test.tsx @@ -28,7 +28,7 @@ describe("selection element", () => { const canvas = container.querySelector("canvas")!; fireEvent.pointerDown(canvas, { clientX: 60, clientY: 100 }); - expect(renderScene).toHaveBeenCalledTimes(3); + expect(renderScene).toHaveBeenCalledTimes(4); const selectionElement = h.state.selectionElement!; expect(selectionElement).not.toBeNull(); expect(selectionElement.type).toEqual("selection"); @@ -49,7 +49,7 @@ describe("selection element", () => { fireEvent.pointerDown(canvas, { clientX: 60, clientY: 100 }); fireEvent.pointerMove(canvas, { clientX: 150, clientY: 30 }); - expect(renderScene).toHaveBeenCalledTimes(4); + expect(renderScene).toHaveBeenCalledTimes(5); const selectionElement = h.state.selectionElement!; expect(selectionElement).not.toBeNull(); expect(selectionElement.type).toEqual("selection"); @@ -71,7 +71,7 @@ describe("selection element", () => { fireEvent.pointerMove(canvas, { clientX: 150, clientY: 30 }); fireEvent.pointerUp(canvas); - expect(renderScene).toHaveBeenCalledTimes(5); + expect(renderScene).toHaveBeenCalledTimes(6); expect(h.state.selectionElement).toBeNull(); }); }); @@ -96,7 +96,7 @@ describe("select single element on the scene", () => { fireEvent.pointerDown(canvas, { clientX: 45, clientY: 20 }); fireEvent.pointerUp(canvas); - expect(renderScene).toHaveBeenCalledTimes(9); + expect(renderScene).toHaveBeenCalledTimes(10); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); @@ -123,7 +123,7 @@ describe("select single element on the scene", () => { fireEvent.pointerDown(canvas, { clientX: 45, clientY: 20 }); fireEvent.pointerUp(canvas); - expect(renderScene).toHaveBeenCalledTimes(9); + expect(renderScene).toHaveBeenCalledTimes(10); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); @@ -150,7 +150,7 @@ describe("select single element on the scene", () => { fireEvent.pointerDown(canvas, { clientX: 45, clientY: 20 }); fireEvent.pointerUp(canvas); - expect(renderScene).toHaveBeenCalledTimes(9); + expect(renderScene).toHaveBeenCalledTimes(10); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); @@ -190,7 +190,7 @@ describe("select single element on the scene", () => { fireEvent.pointerDown(canvas, { clientX: 40, clientY: 40 }); fireEvent.pointerUp(canvas); - expect(renderScene).toHaveBeenCalledTimes(9); + expect(renderScene).toHaveBeenCalledTimes(10); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); @@ -229,7 +229,7 @@ describe("select single element on the scene", () => { fireEvent.pointerDown(canvas, { clientX: 40, clientY: 40 }); fireEvent.pointerUp(canvas); - expect(renderScene).toHaveBeenCalledTimes(9); + expect(renderScene).toHaveBeenCalledTimes(10); expect(h.state.selectionElement).toBeNull(); expect(h.elements.length).toEqual(1); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); diff --git a/src/tests/test-utils.ts b/src/tests/test-utils.ts index 1822ecc57..f78295be6 100644 --- a/src/tests/test-utils.ts +++ b/src/tests/test-utils.ts @@ -100,5 +100,5 @@ const initLocalStorage = (data: ImportedDataState) => { }; export const updateSceneData = (data: SceneData) => { - (window.h.collab as any).excalidrawRef.current.updateScene(data); + (window.h.collab as any).excalidrawAPI.updateScene(data); }; diff --git a/src/types.ts b/src/types.ts index b94872def..fc18c8c8a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -146,10 +146,7 @@ export type LibraryItems = readonly LibraryItem[]; // NOTE ready/readyPromise props are optional for host apps' sake (our own // implem guarantees existence) export type ExcalidrawAPIRefValue = - | (ExcalidrawImperativeAPI & { - readyPromise?: ResolvablePromise; - ready?: true; - }) + | ExcalidrawImperativeAPI | { readyPromise?: ResolvablePromise; ready?: false; From e75f5f20e74cfa6bd5169ece64705d3a06dde40f Mon Sep 17 00:00:00 2001 From: David Luzar Date: Mon, 25 Jan 2021 10:47:48 +0100 Subject: [PATCH 21/39] fix: remote pointers not accounting for offset (#2855) --- src/packages/excalidraw/CHANGELOG.md | 4 ++++ src/renderer/renderScene.ts | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/packages/excalidraw/CHANGELOG.md b/src/packages/excalidraw/CHANGELOG.md index ba90fd513..73bb66552 100644 --- a/src/packages/excalidraw/CHANGELOG.md +++ b/src/packages/excalidraw/CHANGELOG.md @@ -24,6 +24,10 @@ Please add the latest change on the top under the correct section. - Support `Ctrl-Y` shortcut to redo on Windows [#2831](https://github.com/excalidraw/excalidraw/pull/2831). +### Fixes + +- Fix remote pointers not accounting for offset [#2855](https://github.com/excalidraw/excalidraw/pull/2855). + ## 0.2.1 ## Excalidraw API diff --git a/src/renderer/renderScene.ts b/src/renderer/renderScene.ts index 9947300a2..5fed97493 100644 --- a/src/renderer/renderScene.ts +++ b/src/renderer/renderScene.ts @@ -418,7 +418,9 @@ export const renderScene = ( // Paint remote pointers for (const clientId in sceneState.remotePointerViewportCoords) { let { x, y } = sceneState.remotePointerViewportCoords[clientId]; - const username = sceneState.remotePointerUsernames[clientId]; + + x -= appState.offsetLeft; + y -= appState.offsetTop; const width = 9; const height = 14; @@ -473,6 +475,8 @@ export const renderScene = ( context.fill(); context.stroke(); + const username = sceneState.remotePointerUsernames[clientId]; + if (!isOutOfBounds && username) { const offsetX = x + width; const offsetY = y + height; From f6492895dfdb655603ff3c2af1b701403c37a2e6 Mon Sep 17 00:00:00 2001 From: Excalidraw Bot <77840495+excalibot@users.noreply.github.com> Date: Tue, 26 Jan 2021 14:48:36 +0200 Subject: [PATCH 22/39] chore: Update translations from Crowdin (#2839) Co-authored-by: Excalidraw Bot <77840495+excalidrawbot@users.noreply.github.com> --- src/locales/id-ID.json | 38 ++++++++++++++++++------------------ src/locales/percentages.json | 4 ++-- src/locales/ru-RU.json | 38 ++++++++++++++++++------------------ 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/locales/id-ID.json b/src/locales/id-ID.json index 35ba440ec..0ae898d49 100644 --- a/src/locales/id-ID.json +++ b/src/locales/id-ID.json @@ -200,25 +200,25 @@ "title": "Kesalahan" }, "helpDialog": { - "blog": "", - "click": "", - "curvedArrow": "", - "curvedLine": "", - "documentation": "", - "drag": "", - "editor": "", - "github": "", - "howto": "", - "or": "", - "preventBinding": "", - "shapes": "", - "shortcuts": "", - "textFinish": "", - "textNewLine": "", - "title": "", - "view": "", - "zoomToFit": "", - "zoomToSelection": "" + "blog": "Baca blog kami", + "click": "klik", + "curvedArrow": "Panah lengkung", + "curvedLine": "Garis lengkung", + "documentation": "Dokumentasi", + "drag": "seret", + "editor": "Editor", + "github": "Menemukan masalah? Kirimkan", + "howto": "Ikuti panduan kami", + "or": "atau", + "preventBinding": "Cegah pengikatan panah", + "shapes": "Bentuk", + "shortcuts": "Pintasan keyboard", + "textFinish": "Selesai mengedit (teks)", + "textNewLine": "Tambahkan baris baru (teks)", + "title": "Bantuan", + "view": "Tampilan", + "zoomToFit": "Perbesar agar sesuai dengan semua elemen", + "zoomToSelection": "Perbesar ke seleksi" }, "encrypted": { "tooltip": "Gambar anda terenkripsi end-to-end sehingga server Excalidraw tidak akan pernah dapat melihatnya." diff --git a/src/locales/percentages.json b/src/locales/percentages.json index c31020c3e..dd2840a33 100644 --- a/src/locales/percentages.json +++ b/src/locales/percentages.json @@ -12,7 +12,7 @@ "he-IL": 90, "hi-IN": 90, "hu-HU": 90, - "id-ID": 91, + "id-ID": 100, "it-IT": 100, "ja-JP": 81, "ko-KR": 90, @@ -25,7 +25,7 @@ "pt-BR": 100, "pt-PT": 100, "ro-RO": 100, - "ru-RU": 91, + "ru-RU": 100, "sk-SK": 100, "sv-SE": 100, "tr-TR": 90, diff --git a/src/locales/ru-RU.json b/src/locales/ru-RU.json index 97bb6d6d3..f24ba3a48 100644 --- a/src/locales/ru-RU.json +++ b/src/locales/ru-RU.json @@ -200,25 +200,25 @@ "title": "Ошибка" }, "helpDialog": { - "blog": "", - "click": "", - "curvedArrow": "", - "curvedLine": "", - "documentation": "", - "drag": "", - "editor": "", - "github": "", - "howto": "", - "or": "", - "preventBinding": "", - "shapes": "", - "shortcuts": "", - "textFinish": "", - "textNewLine": "", - "title": "", - "view": "", - "zoomToFit": "", - "zoomToSelection": "" + "blog": "Прочитайте наш блог", + "click": "нажать", + "curvedArrow": "Изогнутая стрелка", + "curvedLine": "Изогнутая линия", + "documentation": "Документация", + "drag": "перетащить", + "editor": "Редактор", + "github": "Нашли проблему? Отправьте", + "howto": "Следуйте нашим инструкциям", + "or": "или", + "preventBinding": "Предотвращать привязку стрелок", + "shapes": "Фигуры", + "shortcuts": "Горячие клавиши", + "textFinish": "Закончить редактирование (текст)", + "textNewLine": "Добавить новую строку (текст)", + "title": "Помощь", + "view": "Просмотр", + "zoomToFit": "Отмастштабировать, чтобы поместились все элементы", + "zoomToSelection": "Увеличить до выделенного" }, "encrypted": { "tooltip": "Ваши данные защищены сквозным (End-to-end) шифрованием. Серверы Excalidraw никогда не получат доступ к ним." From b1c8c538eeed9760b9228c90af754dd051768414 Mon Sep 17 00:00:00 2001 From: Lipis Date: Tue, 26 Jan 2021 22:22:41 +0200 Subject: [PATCH 23/39] fix: Change the timeout for reporting the version to 30s (#2858) --- src/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants.ts b/src/constants.ts index f783bb5fa..db408fd42 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -90,4 +90,4 @@ export const TAP_TWICE_TIMEOUT = 300; export const TOUCH_CTX_MENU_TIMEOUT = 500; export const TITLE_TIMEOUT = 10000; export const TOAST_TIMEOUT = 5000; -export const VERSION_TIMEOUT = 15000; +export const VERSION_TIMEOUT = 30000; From 4392a4644a1e620455371f677160fa9eaad813ab Mon Sep 17 00:00:00 2001 From: Excalidraw Bot <77840495+excalibot@users.noreply.github.com> Date: Wed, 27 Jan 2021 14:22:37 +0200 Subject: [PATCH 24/39] chore: Update translations from Crowdin (#2861) --- src/locales/pa-IN.json | 38 ++++++++++++------------- src/locales/percentages.json | 4 +-- src/locales/zh-CN.json | 54 ++++++++++++++++++------------------ 3 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/locales/pa-IN.json b/src/locales/pa-IN.json index 22c8ff996..ea4b39a4f 100644 --- a/src/locales/pa-IN.json +++ b/src/locales/pa-IN.json @@ -200,25 +200,25 @@ "title": "ਗਲਤੀ" }, "helpDialog": { - "blog": "", - "click": "", - "curvedArrow": "", - "curvedLine": "", - "documentation": "", - "drag": "", - "editor": "", - "github": "", - "howto": "", - "or": "", - "preventBinding": "", - "shapes": "", - "shortcuts": "", - "textFinish": "", - "textNewLine": "", - "title": "", - "view": "", - "zoomToFit": "", - "zoomToSelection": "" + "blog": "ਸਾਡਾ ਬਲੌਗ ਪੜ੍ਹੋ", + "click": "ਕਲਿੱਕ", + "curvedArrow": "ਵਿੰਗਾ ਤੀਰ", + "curvedLine": "ਵਿੰਗੀ ਲਕੀਰ", + "documentation": "ਕਾਗਜ਼ਾਤ", + "drag": "ਘਸੀਟੋ", + "editor": "ਸੋਧਕ", + "github": "ਕੋਈ ਸਮੱਸਿਆ ਲੱਭੀ? ਜਮ੍ਹਾਂ ਕਰਵਾਓ", + "howto": "ਸਾਡੀਆਂ ਗਾਈਡਾਂ ਦੀ ਪਾਲਣਾ ਕਰੋ", + "or": "ਜਾਂ", + "preventBinding": "ਤੀਰ ਬੱਝਣਾ ਰੋਕੋ", + "shapes": "ਆਕ੍ਰਿਤੀਆਂ", + "shortcuts": "ਕੀਬੋਰਡ ਸ਼ਾਰਟਕੱਟ", + "textFinish": "ਸੋਧ ਮੁਕੰਮਲ ਕਰੋ (ਪਾਠ)", + "textNewLine": "ਨਵੀਂ ਪੰਕਤੀ ਜੋੜੋ (ਪਾਠ)", + "title": "ਮਦਦ", + "view": "ਦਿੱਖ", + "zoomToFit": "ਸਾਰੇ ਐਲੀਮੈਂਟਾਂ ਨੂੰ ਫਿੱਟ ਕਰਨ ਲਈ ਜ਼ੂਮ ਕਰੋ", + "zoomToSelection": "ਚੋਣ ਤੱਕ ਜ਼ੂਮ ਕਰੋ" }, "encrypted": { "tooltip": "ਤੁਹਾਡੀ ਡਰਾਇੰਗਾਂ ਸਿਰੇ-ਤੋਂ-ਸਿਰੇ ਤੱਕ ਇਨਕਰਿਪਟ ਕੀਤੀਆਂ ਹੋਈਆਂ ਹਨ, ਇਸ ਲਈ Excalidraw ਦੇ ਸਰਵਰ ਉਹਨਾਂ ਨੂੰ ਕਦੇ ਵੀ ਨਹੀਂ ਦੇਖਣਗੇ।" diff --git a/src/locales/percentages.json b/src/locales/percentages.json index dd2840a33..206cefd44 100644 --- a/src/locales/percentages.json +++ b/src/locales/percentages.json @@ -20,7 +20,7 @@ "nb-NO": 100, "nl-NL": 100, "nn-NO": 90, - "pa-IN": 91, + "pa-IN": 100, "pl-PL": 90, "pt-BR": 100, "pt-PT": 100, @@ -30,6 +30,6 @@ "sv-SE": 100, "tr-TR": 90, "uk-UA": 100, - "zh-CN": 90, + "zh-CN": 100, "zh-TW": 100 } diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json index 8a1ca6efd..d77df2813 100644 --- a/src/locales/zh-CN.json +++ b/src/locales/zh-CN.json @@ -60,10 +60,10 @@ "extraBold": "超粗", "architect": "朴素", "artist": "艺术", - "cartoonist": "漫画师", + "cartoonist": "漫画家", "fileTitle": "文件标题", "colorPicker": "调色盘", - "canvasBackground": "Canvas 背景", + "canvasBackground": "画布背景", "drawingCanvas": "绘制 Canvas", "layers": "图层", "actions": "操作", @@ -128,10 +128,10 @@ "clearReset": "这将会清除整个 画板。您是否要继续?", "couldNotCreateShareableLink": "无法创建共享链接", "couldNotCreateShareableLinkTooBig": "无法创建可共享链接:画布过大", - "couldNotLoadInvalidFile": "无法加载错误文件", - "importBackendFailed": "从后端导入失败", - "cannotExportEmptyCanvas": "无法导出空画布。", - "couldNotCopyToClipboard": "无法复制到剪贴板。请尝试使用 Chrome 浏览器。", + "couldNotLoadInvalidFile": "无法加载无效的文件", + "importBackendFailed": "从后端导入失败。", + "cannotExportEmptyCanvas": "无法导出空白画布。", + "couldNotCopyToClipboard": "无法复制到剪贴板,请尝试使用 Chrome 浏览器。", "decryptFailed": "无法解密数据。", "uploadedSecurly": "上传已被端到端加密保护,这意味着 Excalidraw 的服务器和第三方都无法读取内容。", "loadSceneOverridePrompt": "加载外部绘图将取代您现有的内容。您想要继续吗?", @@ -200,25 +200,25 @@ "title": "错误" }, "helpDialog": { - "blog": "", - "click": "", - "curvedArrow": "", - "curvedLine": "", - "documentation": "", - "drag": "", - "editor": "", - "github": "", - "howto": "", - "or": "", - "preventBinding": "", - "shapes": "", - "shortcuts": "", - "textFinish": "", - "textNewLine": "", - "title": "", - "view": "", - "zoomToFit": "", - "zoomToSelection": "" + "blog": "浏览我们的博客", + "click": "单击", + "curvedArrow": "曲线箭头", + "curvedLine": "曲线", + "documentation": "文档", + "drag": "拖动", + "editor": "编辑器", + "github": "提交问题", + "howto": "帮助文档", + "or": "或", + "preventBinding": "禁用箭头吸附", + "shapes": "形状", + "shortcuts": "快捷键列表", + "textFinish": "完成文本编辑", + "textNewLine": "文本换行", + "title": "帮助", + "view": "视图", + "zoomToFit": "缩放以适应所有元素", + "zoomToSelection": "缩放到选区" }, "encrypted": { "tooltip": "您的绘图采用的端到端加密,其内容对于Excalidraw服务器是不可见的。" @@ -236,7 +236,7 @@ "width": "宽度" }, "toast": { - "copyStyles": "", - "copyToClipboardAsPng": "" + "copyStyles": "复制样式", + "copyToClipboardAsPng": "复制为 PNG 到剪贴板" } } From b5e26ba81f2ae4330ed57419a926c5d620e346ff Mon Sep 17 00:00:00 2001 From: Thomas Steiner Date: Wed, 27 Jan 2021 19:47:55 +0100 Subject: [PATCH 25/39] refactor: Rename browser-nativefs to browser-fs-access (#2862) --- package-lock.json | 8 ++++---- package.json | 4 ++-- src/data/index.ts | 2 +- src/data/json.ts | 2 +- src/global.d.ts | 2 +- src/types.ts | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index dd83dfcda..3b5db98e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5100,10 +5100,10 @@ "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" }, - "browser-nativefs": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/browser-nativefs/-/browser-nativefs-0.12.0.tgz", - "integrity": "sha512-ZCHJcQI6bBm9YjB+6wMT1nWg+/mnWnz7r3gJ8sx7RjgLtWROFq+BuD12cAncD6y45MIbUqFM8eMKXoHXOxSFxA==" + "browser-fs-access": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/browser-fs-access/-/browser-fs-access-0.13.0.tgz", + "integrity": "sha512-qP8zFVhRQThxYgBXdlFHbzIrWb1us0G5kL2ZL0vW4BO5llKE4qBAcQsQrw4KN+6vjw8sKeWaGWJtzijfRT4N0Q==" }, "browser-process-hrtime": { "version": "1.0.0", diff --git a/package.json b/package.json index c0d2bf0bc..ee23da2f5 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "@types/react": "17.0.0", "@types/react-dom": "17.0.0", "@types/socket.io-client": "1.4.35", - "browser-nativefs": "0.12.0", + "browser-fs-access": "0.13.0", "clsx": "1.1.1", "firebase": "8.2.4", "i18next-browser-languagedetector": "6.0.1", @@ -72,7 +72,7 @@ }, "jest": { "transformIgnorePatterns": [ - "node_modules/(?!(roughjs|points-on-curve|path-data-parser|points-on-path|browser-nativefs)/)" + "node_modules/(?!(roughjs|points-on-curve|path-data-parser|points-on-path|browser-fs-access)/)" ], "resetMocks": false }, diff --git a/src/data/index.ts b/src/data/index.ts index a91411c95..7dae58be7 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -1,4 +1,4 @@ -import { fileSave } from "browser-nativefs"; +import { fileSave } from "browser-fs-access"; import { copyCanvasToClipboardAsPng, copyTextToSystemClipboard, diff --git a/src/data/json.ts b/src/data/json.ts index d4d3205a1..65688c32e 100644 --- a/src/data/json.ts +++ b/src/data/json.ts @@ -1,4 +1,4 @@ -import { fileOpen, fileSave } from "browser-nativefs"; +import { fileOpen, fileSave } from "browser-fs-access"; import { cleanAppStateForExport } from "../appState"; import { MIME_TYPES } from "../constants"; import { clearElementsForExport } from "../element"; diff --git a/src/global.d.ts b/src/global.d.ts index 8bce07a71..5596d3ea0 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -85,6 +85,6 @@ type ForwardRef = Parameters< // --------------------------------------------------------------------------— interface Blob { - handle?: import("browser-nativefs").FileSystemHandle; + handle?: import("browser-fs-acces").FileSystemHandle; name?: string; } diff --git a/src/types.ts b/src/types.ts index fc18c8c8a..6b3b20444 100644 --- a/src/types.ts +++ b/src/types.ts @@ -98,7 +98,7 @@ export type AppState = { offsetLeft: number; isLibraryOpen: boolean; - fileHandle: import("browser-nativefs").FileSystemHandle | null; + fileHandle: import("browser-fs-access").FileSystemHandle | null; collaborators: Map; showStats: boolean; currentChartType: ChartType; From 978e85a33bc9b76764841f696215c6ebb8199c6d Mon Sep 17 00:00:00 2001 From: Kartik Prajapati Date: Thu, 28 Jan 2021 00:41:17 +0530 Subject: [PATCH 26/39] feat: Add separators on context menu (#2659) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dwelle Co-authored-by: Lipis --- src/actions/actionAddToLibrary.ts | 1 - src/actions/actionClipboard.tsx | 108 ++++++++++++++++ src/actions/actionDeleteSelected.tsx | 1 - src/actions/actionGroup.tsx | 2 - src/actions/actionStyles.ts | 2 - src/actions/actionToggleGridMode.tsx | 21 ++++ src/actions/actionToggleStats.tsx | 17 +++ src/actions/actionToggleZenMode.tsx | 20 +++ src/actions/index.ts | 12 ++ src/actions/manager.tsx | 47 ++----- src/actions/shortcuts.ts | 4 +- src/actions/types.ts | 14 ++- src/components/App.tsx | 177 ++++++++++++++------------- src/components/ContextMenu.scss | 8 +- src/components/ContextMenu.tsx | 72 +++++++---- src/is-mobile.tsx | 2 +- src/keys.ts | 1 + src/tests/regressionTests.test.tsx | 18 +-- 18 files changed, 354 insertions(+), 173 deletions(-) create mode 100644 src/actions/actionClipboard.tsx create mode 100644 src/actions/actionToggleGridMode.tsx create mode 100644 src/actions/actionToggleStats.tsx create mode 100644 src/actions/actionToggleZenMode.tsx diff --git a/src/actions/actionAddToLibrary.ts b/src/actions/actionAddToLibrary.ts index a0abbf5ca..8fb7eac93 100644 --- a/src/actions/actionAddToLibrary.ts +++ b/src/actions/actionAddToLibrary.ts @@ -17,6 +17,5 @@ export const actionAddToLibrary = register({ }); return false; }, - contextMenuOrder: 6, contextItemLabel: "labels.addToLibrary", }); diff --git a/src/actions/actionClipboard.tsx b/src/actions/actionClipboard.tsx new file mode 100644 index 000000000..727fab289 --- /dev/null +++ b/src/actions/actionClipboard.tsx @@ -0,0 +1,108 @@ +import { CODES, KEYS } from "../keys"; +import { register } from "./register"; +import { copyToClipboard } from "../clipboard"; +import { actionDeleteSelected } from "./actionDeleteSelected"; +import { getSelectedElements } from "../scene/selection"; +import { exportCanvas } from "../data/index"; +import { getNonDeletedElements } from "../element"; + +export const actionCopy = register({ + name: "copy", + perform: (elements, appState) => { + copyToClipboard(getNonDeletedElements(elements), appState); + + return { + commitToHistory: false, + }; + }, + contextItemLabel: "labels.copy", + keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.code === CODES.C, +}); + +export const actionCut = register({ + name: "cut", + perform: (elements, appState, data, app) => { + actionCopy.perform(elements, appState, data, app); + return actionDeleteSelected.perform(elements, appState, data, app); + }, + contextItemLabel: "labels.cut", + keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.code === CODES.X, +}); + +export const actionCopyAsSvg = register({ + name: "copyAsSvg", + perform: async (elements, appState, _data, app) => { + if (!app.canvas) { + return { + commitToHistory: false, + }; + } + const selectedElements = getSelectedElements( + getNonDeletedElements(elements), + appState, + ); + try { + await exportCanvas( + "clipboard-svg", + selectedElements.length + ? selectedElements + : getNonDeletedElements(elements), + appState, + app.canvas, + appState, + ); + return { + commitToHistory: false, + }; + } catch (error) { + console.error(error); + return { + appState: { + ...appState, + errorMessage: error.message, + }, + commitToHistory: false, + }; + } + }, + contextItemLabel: "labels.copyAsSvg", +}); + +export const actionCopyAsPng = register({ + name: "copyAsPng", + perform: async (elements, appState, _data, app) => { + if (!app.canvas) { + return { + commitToHistory: false, + }; + } + const selectedElements = getSelectedElements( + getNonDeletedElements(elements), + appState, + ); + try { + await exportCanvas( + "clipboard", + selectedElements.length + ? selectedElements + : getNonDeletedElements(elements), + appState, + app.canvas, + appState, + ); + return { + commitToHistory: false, + }; + } catch (error) { + console.error(error); + return { + appState: { + ...appState, + errorMessage: error.message, + }, + commitToHistory: false, + }; + } + }, + contextItemLabel: "labels.copyAsPng", +}); diff --git a/src/actions/actionDeleteSelected.tsx b/src/actions/actionDeleteSelected.tsx index 88e014503..dd2ad42cd 100644 --- a/src/actions/actionDeleteSelected.tsx +++ b/src/actions/actionDeleteSelected.tsx @@ -136,7 +136,6 @@ export const actionDeleteSelected = register({ }; }, contextItemLabel: "labels.delete", - contextMenuOrder: 999999, keyTest: (event) => event.key === KEYS.BACKSPACE || event.key === KEYS.DELETE, PanelComponent: ({ elements, appState, updateData }) => ( enableActionGroup(elements, appState), @@ -174,7 +173,6 @@ export const actionUngroup = register({ }, keyTest: (event) => event.shiftKey && event[KEYS.CTRL_OR_CMD] && event.code === CODES.G, - contextMenuOrder: 5, contextItemLabel: "labels.ungroup", contextItemPredicate: (elements, appState) => getSelectedGroupIds(appState).length > 0, diff --git a/src/actions/actionStyles.ts b/src/actions/actionStyles.ts index dab50b637..4a8b54afc 100644 --- a/src/actions/actionStyles.ts +++ b/src/actions/actionStyles.ts @@ -34,7 +34,6 @@ export const actionCopyStyles = register({ contextItemLabel: "labels.copyStyles", keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.altKey && event.code === CODES.C, - contextMenuOrder: 0, }); export const actionPasteStyles = register({ @@ -74,5 +73,4 @@ export const actionPasteStyles = register({ contextItemLabel: "labels.pasteStyles", keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.altKey && event.code === CODES.V, - contextMenuOrder: 1, }); diff --git a/src/actions/actionToggleGridMode.tsx b/src/actions/actionToggleGridMode.tsx new file mode 100644 index 000000000..22e8e5581 --- /dev/null +++ b/src/actions/actionToggleGridMode.tsx @@ -0,0 +1,21 @@ +import { CODES, KEYS } from "../keys"; +import { register } from "./register"; +import { GRID_SIZE } from "../constants"; + +export const actionToggleGridMode = register({ + name: "gridMode", + perform(elements, appState) { + this.checked = !this.checked; + return { + appState: { + ...appState, + gridSize: this.checked ? GRID_SIZE : null, + }, + commitToHistory: false, + }; + }, + checked: false, + contextItemLabel: "labels.gridMode", + // Wrong event code + keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.code === CODES.QUOTE, +}); diff --git a/src/actions/actionToggleStats.tsx b/src/actions/actionToggleStats.tsx new file mode 100644 index 000000000..1d75caf82 --- /dev/null +++ b/src/actions/actionToggleStats.tsx @@ -0,0 +1,17 @@ +import { register } from "./register"; + +export const actionToggleStats = register({ + name: "stats", + perform(elements, appState) { + this.checked = !this.checked; + return { + appState: { + ...appState, + showStats: !appState.showStats, + }, + commitToHistory: false, + }; + }, + checked: false, + contextItemLabel: "stats.title", +}); diff --git a/src/actions/actionToggleZenMode.tsx b/src/actions/actionToggleZenMode.tsx new file mode 100644 index 000000000..32ddd6fec --- /dev/null +++ b/src/actions/actionToggleZenMode.tsx @@ -0,0 +1,20 @@ +import { CODES, KEYS } from "../keys"; +import { register } from "./register"; + +export const actionToggleZenMode = register({ + name: "zenMode", + perform(elements, appState) { + this.checked = !this.checked; + return { + appState: { + ...appState, + zenModeEnabled: this.checked, + }, + commitToHistory: false, + }; + }, + checked: false, + contextItemLabel: "buttons.zenMode", + // Wrong event code + keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.code === CODES.QUOTE, +}); diff --git a/src/actions/index.ts b/src/actions/index.ts index c5c444482..b335e44e6 100644 --- a/src/actions/index.ts +++ b/src/actions/index.ts @@ -65,3 +65,15 @@ export { distributeHorizontally, distributeVertically, } from "./actionDistribute"; + +export { + actionCopy, + actionCut, + actionCopyAsPng, + actionCopyAsSvg, +} from "./actionClipboard"; + +export { actionToggleGridMode } from "./actionToggleGridMode"; +export { actionToggleZenMode } from "./actionToggleZenMode"; + +export { actionToggleStats } from "./actionToggleStats"; diff --git a/src/actions/manager.tsx b/src/actions/manager.tsx index 236a14414..d48e3b0e9 100644 --- a/src/actions/manager.tsx +++ b/src/actions/manager.tsx @@ -3,14 +3,15 @@ import { Action, ActionsManagerInterface, UpdaterFn, - ActionFilterFn, ActionName, ActionResult, } from "./types"; import { ExcalidrawElement } from "../element/types"; import { AppState } from "../types"; -import { t } from "../i18n"; -import { ShortcutName } from "./shortcuts"; + +// This is the component, but for now we don't care about anything but its +// `canvas` state. +type App = { canvas: HTMLCanvasElement | null }; export class ActionManager implements ActionsManagerInterface { actions = {} as ActionsManagerInterface["actions"]; @@ -18,13 +19,14 @@ export class ActionManager implements ActionsManagerInterface { updater: (actionResult: ActionResult | Promise) => void; getAppState: () => Readonly; - getElementsIncludingDeleted: () => readonly ExcalidrawElement[]; + app: App; constructor( updater: UpdaterFn, getAppState: () => AppState, getElementsIncludingDeleted: () => readonly ExcalidrawElement[], + app: App, ) { this.updater = (actionResult) => { if (actionResult && "then" in actionResult) { @@ -37,6 +39,7 @@ export class ActionManager implements ActionsManagerInterface { }; this.getAppState = getAppState; this.getElementsIncludingDeleted = getElementsIncludingDeleted; + this.app = app; } registerAction(action: Action) { @@ -70,6 +73,7 @@ export class ActionManager implements ActionsManagerInterface { this.getElementsIncludingDeleted(), this.getAppState(), null, + this.app, ), ); return true; @@ -81,43 +85,11 @@ export class ActionManager implements ActionsManagerInterface { this.getElementsIncludingDeleted(), this.getAppState(), null, + this.app, ), ); } - getContextMenuItems(actionFilter: ActionFilterFn = (action) => action) { - return Object.values(this.actions) - .filter(actionFilter) - .filter((action) => "contextItemLabel" in action) - .filter((action) => - action.contextItemPredicate - ? action.contextItemPredicate( - this.getElementsIncludingDeleted(), - this.getAppState(), - ) - : true, - ) - .sort( - (a, b) => - (a.contextMenuOrder !== undefined ? a.contextMenuOrder : 999) - - (b.contextMenuOrder !== undefined ? b.contextMenuOrder : 999), - ) - .map((action) => ({ - // take last bit of the label "labels." - shortcutName: action.contextItemLabel?.split(".").pop() as ShortcutName, - label: action.contextItemLabel ? t(action.contextItemLabel) : "", - action: () => { - this.updater( - action.perform( - this.getElementsIncludingDeleted(), - this.getAppState(), - null, - ), - ); - }, - })); - } - // Id is an attribute that we can use to pass in data like keys. // This is needed for dynamically generated action components // like the user list. We can use this key to extract more @@ -132,6 +104,7 @@ export class ActionManager implements ActionsManagerInterface { this.getElementsIncludingDeleted(), this.getAppState(), formState, + this.app, ), ); }; diff --git a/src/actions/shortcuts.ts b/src/actions/shortcuts.ts index a12b30ac7..a05c598d5 100644 --- a/src/actions/shortcuts.ts +++ b/src/actions/shortcuts.ts @@ -9,7 +9,7 @@ export type ShortcutName = | "copyStyles" | "pasteStyles" | "selectAll" - | "delete" + | "deleteSelectedElements" | "duplicateSelection" | "sendBackward" | "bringForward" @@ -31,7 +31,7 @@ const shortcutMap: Record = { copyStyles: [getShortcutKey("CtrlOrCmd+Alt+C")], pasteStyles: [getShortcutKey("CtrlOrCmd+Alt+V")], selectAll: [getShortcutKey("CtrlOrCmd+A")], - delete: [getShortcutKey("Del")], + deleteSelectedElements: [getShortcutKey("Del")], duplicateSelection: [ getShortcutKey("CtrlOrCmd+D"), getShortcutKey(`Alt+${t("helpDialog.drag")}`), diff --git a/src/actions/types.ts b/src/actions/types.ts index ca30f5678..6d373faae 100644 --- a/src/actions/types.ts +++ b/src/actions/types.ts @@ -16,12 +16,18 @@ type ActionFn = ( elements: readonly ExcalidrawElement[], appState: Readonly, formData: any, + app: { canvas: HTMLCanvasElement | null }, ) => ActionResult | Promise; export type UpdaterFn = (res: ActionResult) => void; export type ActionFilterFn = (action: Action) => void; export type ActionName = + | "copy" + | "cut" + | "paste" + | "copyAsPng" + | "copyAsSvg" | "sendBackward" | "bringForward" | "sendToBack" @@ -29,6 +35,9 @@ export type ActionName = | "copyStyles" | "selectAll" | "pasteStyles" + | "gridMode" + | "zenMode" + | "stats" | "changeStrokeColor" | "changeBackgroundColor" | "changeFillStyle" @@ -93,19 +102,16 @@ export interface Action { elements: readonly ExcalidrawElement[], ) => boolean; contextItemLabel?: string; - contextMenuOrder?: number; contextItemPredicate?: ( elements: readonly ExcalidrawElement[], appState: AppState, ) => boolean; + checked?: boolean; } export interface ActionsManagerInterface { actions: Record; registerAction: (action: Action) => void; handleKeyDown: (event: KeyboardEvent) => boolean; - getContextMenuItems: ( - actionFilter: ActionFilterFn, - ) => { label: string; action: () => void }[]; renderAction: (name: ActionName) => React.ReactElement | null; } diff --git a/src/components/App.tsx b/src/components/App.tsx index bf1c989b3..0d400927b 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -3,7 +3,28 @@ import React from "react"; import { RoughCanvas } from "roughjs/bin/canvas"; import rough from "roughjs/bin/rough"; import "../actions"; -import { actionDeleteSelected, actionFinalize } from "../actions"; +import { + actionAddToLibrary, + actionBringForward, + actionBringToFront, + actionCopy, + actionCopyAsPng, + actionCopyAsSvg, + actionCopyStyles, + actionCut, + actionDeleteSelected, + actionDuplicateSelection, + actionFinalize, + actionGroup, + actionPasteStyles, + actionSelectAll, + actionSendBackward, + actionSendToBack, + actionToggleGridMode, + actionToggleStats, + actionToggleZenMode, + actionUngroup, +} from "../actions"; import { createRedoAction, createUndoAction } from "../actions/actionHistory"; import { ActionManager } from "../actions/manager"; import { actions } from "../actions/register"; @@ -18,7 +39,6 @@ import { } from "../clipboard"; import { APP_NAME, - CANVAS_ONLY_ACTIONS, CURSOR_TYPE, DEFAULT_VERTICAL_ALIGN, DRAGGING_THRESHOLD, @@ -26,7 +46,6 @@ import { ELEMENT_TRANSLATE_AMOUNT, ENV, EVENT, - GRID_SIZE, LINE_CONFIRM_THRESHOLD, MIME_TYPES, POINTER_BUTTON, @@ -314,6 +333,7 @@ class App extends React.Component { this.syncActionResult, () => this.state, () => this.scene.getElementsIncludingDeleted(), + this, ); this.actionManager.registerAll(actions); @@ -927,25 +947,6 @@ class App extends React.Component { } }; - private copyToClipboardAsSvg = async () => { - const selectedElements = getSelectedElements( - this.scene.getElements(), - this.state, - ); - try { - await exportCanvas( - "clipboard-svg", - selectedElements.length ? selectedElements : this.scene.getElements(), - this.state, - this.canvas!, - this.state, - ); - } catch (error) { - console.error(error); - this.setState({ errorMessage: error.message }); - } - }; - private static resetTapTwice() { didTapTwice = false; } @@ -1148,15 +1149,11 @@ class App extends React.Component { }; toggleZenMode = () => { - this.setState({ - zenModeEnabled: !this.state.zenModeEnabled, - }); + this.actionManager.executeAction(actionToggleZenMode); }; toggleGridMode = () => { - this.setState({ - gridSize: this.state.gridSize ? null : GRID_SIZE, - }); + this.actionManager.executeAction(actionToggleGridMode); }; toggleStats = () => { @@ -3618,52 +3615,52 @@ class App extends React.Component { this.state, ); + const maybeGroupAction = actionGroup.contextItemPredicate!( + this.actionManager.getElementsIncludingDeleted(), + this.actionManager.getAppState(), + ); + + const maybeUngroupAction = actionUngroup.contextItemPredicate!( + this.actionManager.getElementsIncludingDeleted(), + this.actionManager.getAppState(), + ); + + const separator = "separator"; + const elements = this.scene.getElements(); const element = this.getElementAtPosition(x, y); if (!element) { ContextMenu.push({ options: [ navigator.clipboard && { - shortcutName: "paste", - label: t("labels.paste"), - action: () => this.pasteFromClipboard(null), + name: "paste", + perform: (elements, appStates) => { + this.pasteFromClipboard(null); + return { + commitToHistory: false, + }; + }, + contextItemLabel: "labels.paste", }, + separator, probablySupportsClipboardBlob && - elements.length > 0 && { - shortcutName: "copyAsPng", - label: t("labels.copyAsPng"), - action: this.copyToClipboardAsPng, - }, + elements.length > 0 && + actionCopyAsPng, probablySupportsClipboardWriteText && - elements.length > 0 && { - shortcutName: "copyAsSvg", - label: t("labels.copyAsSvg"), - action: this.copyToClipboardAsSvg, - }, - ...this.actionManager.getContextMenuItems((action) => - CANVAS_ONLY_ACTIONS.includes(action.name), - ), - { - checked: this.state.gridSize !== null, - shortcutName: "gridMode", - label: t("labels.gridMode"), - action: this.toggleGridMode, - }, - { - checked: this.state.zenModeEnabled, - shortcutName: "zenMode", - label: t("buttons.zenMode"), - action: this.toggleZenMode, - }, - { - checked: this.state.showStats, - shortcutName: "stats", - label: t("stats.title"), - action: this.toggleStats, - }, + elements.length > 0 && + actionCopyAsSvg, + ((probablySupportsClipboardBlob && elements.length > 0) || + (probablySupportsClipboardWriteText && elements.length > 0)) && + separator, + actionSelectAll, + separator, + actionToggleGridMode, + actionToggleZenMode, + actionToggleStats, ], top: clientY, left: clientX, + actionManager: this.actionManager, }); return; } @@ -3674,37 +3671,41 @@ class App extends React.Component { ContextMenu.push({ options: [ - { - shortcutName: "cut", - label: t("labels.cut"), - action: this.cutAll, - }, + actionCut, + navigator.clipboard && actionCopy, navigator.clipboard && { - shortcutName: "copy", - label: t("labels.copy"), - action: this.copyAll, + name: "paste", + perform: (elements, appStates) => { + this.pasteFromClipboard(null); + return { + commitToHistory: false, + }; + }, + contextItemLabel: "labels.paste", }, - navigator.clipboard && { - shortcutName: "paste", - label: t("labels.paste"), - action: () => this.pasteFromClipboard(null), - }, - probablySupportsClipboardBlob && { - shortcutName: "copyAsPng", - label: t("labels.copyAsPng"), - action: this.copyToClipboardAsPng, - }, - probablySupportsClipboardWriteText && { - shortcutName: "copyAsSvg", - label: t("labels.copyAsSvg"), - action: this.copyToClipboardAsSvg, - }, - ...this.actionManager.getContextMenuItems( - (action) => !CANVAS_ONLY_ACTIONS.includes(action.name), - ), + separator, + probablySupportsClipboardBlob && actionCopyAsPng, + probablySupportsClipboardWriteText && actionCopyAsSvg, + separator, + actionCopyStyles, + actionPasteStyles, + separator, + maybeGroupAction && actionGroup, + maybeUngroupAction && actionUngroup, + (maybeGroupAction || maybeUngroupAction) && separator, + actionAddToLibrary, + separator, + actionSendBackward, + actionBringForward, + actionSendToBack, + actionBringToFront, + separator, + actionDuplicateSelection, + actionDeleteSelected, ], top: clientY, left: clientX, + actionManager: this.actionManager, }); }; diff --git a/src/components/ContextMenu.scss b/src/components/ContextMenu.scss index 913a7ecc8..8661cb937 100644 --- a/src/components/ContextMenu.scss +++ b/src/components/ContextMenu.scss @@ -9,9 +9,10 @@ list-style: none; user-select: none; margin: -0.25rem 0 0 0.125rem; - padding: 0.25rem 0; + padding: 0.5rem 0; background-color: var(--popup-secondary-background-color); border: 1px solid var(--button-gray-3); + cursor: default; } .context-menu button { @@ -88,4 +89,9 @@ } } } + + .context-menu-option-separator { + border: none; + border-top: 1px solid $oc-gray-5; + } } diff --git a/src/components/ContextMenu.tsx b/src/components/ContextMenu.tsx index e8ec95072..567d9dd4e 100644 --- a/src/components/ContextMenu.tsx +++ b/src/components/ContextMenu.tsx @@ -2,31 +2,37 @@ import React from "react"; import { render, unmountComponentAtNode } from "react-dom"; import clsx from "clsx"; import { Popover } from "./Popover"; +import { t } from "../i18n"; import "./ContextMenu.scss"; import { getShortcutFromShortcutName, ShortcutName, } from "../actions/shortcuts"; +import { Action } from "../actions/types"; +import { ActionManager } from "../actions/manager"; -type ContextMenuOption = { - checked?: boolean; - shortcutName: ShortcutName; - label: string; - action(): void; -}; +type ContextMenuOption = "separator" | Action; -type Props = { +type ContextMenuProps = { options: ContextMenuOption[]; onCloseRequest?(): void; top: number; left: number; + actionManager: ActionManager; }; -const ContextMenu = ({ options, onCloseRequest, top, left }: Props) => { +const ContextMenu = ({ + options, + onCloseRequest, + top, + left, + actionManager, +}: ContextMenuProps) => { const isDarkTheme = !!document .querySelector(".excalidraw") ?.classList.contains("Appearance_dark"); + return (
{ className="context-menu" onContextMenu={(event) => event.preventDefault()} > - {options.map(({ action, checked, shortcutName, label }, idx) => ( -
  • - -
  • - ))} + {options.map((option, idx) => { + if (option === "separator") { + return
    ; + } + + const actionName = option.name; + const label = option.contextItemLabel + ? t(option.contextItemLabel) + : ""; + return ( +
  • + +
  • + ); + })}
    @@ -78,8 +94,9 @@ const getContextMenuNode = (): HTMLDivElement => { type ContextMenuParams = { options: (ContextMenuOption | false | null | undefined)[]; - top: number; - left: number; + top: ContextMenuProps["top"]; + left: ContextMenuProps["left"]; + actionManager: ContextMenuProps["actionManager"]; }; const handleClose = () => { @@ -101,6 +118,7 @@ export default { left={params.left} options={options} onCloseRequest={handleClose} + actionManager={params.actionManager} />, getContextMenuNode(), ); diff --git a/src/is-mobile.tsx b/src/is-mobile.tsx index c20bf89de..e12419fd1 100644 --- a/src/is-mobile.tsx +++ b/src/is-mobile.tsx @@ -12,7 +12,7 @@ export const IsMobileProvider = ({ query.current = window.matchMedia ? window.matchMedia( // keep up to date with _variables.scss - "(max-width: 640px), (max-height: 500px) and (max-width: 1000px)", + "(max-width: 600px), (max-height: 500px) and (max-width: 1000px)", ) : (({ matches: false, diff --git a/src/keys.ts b/src/keys.ts index 54ec2e0ea..4acc6ab9e 100644 --- a/src/keys.ts +++ b/src/keys.ts @@ -19,6 +19,7 @@ export const CODES = { F: "KeyF", H: "KeyH", V: "KeyV", + X: "KeyX", Z: "KeyZ", } as const; diff --git a/src/tests/regressionTests.test.tsx b/src/tests/regressionTests.test.tsx index 95fb5662e..2c73cef05 100644 --- a/src/tests/regressionTests.test.tsx +++ b/src/tests/regressionTests.test.tsx @@ -618,6 +618,7 @@ describe("regression tests", () => { clientY: 1, }); const contextMenu = document.querySelector(".context-menu"); + const contextMenuOptions = document.querySelectorAll(".context-menu li"); const expectedShortcutNames: ShortcutName[] = [ "selectAll", "gridMode", @@ -626,7 +627,7 @@ describe("regression tests", () => { ]; expect(contextMenu).not.toBeNull(); - expect(contextMenu?.children.length).toBe(expectedShortcutNames.length); + expect(contextMenuOptions.length).toBe(expectedShortcutNames.length); expectedShortcutNames.forEach((shortcutName) => { expect( contextMenu?.querySelector(`li[data-testid="${shortcutName}"]`), @@ -645,11 +646,12 @@ describe("regression tests", () => { clientY: 1, }); const contextMenu = document.querySelector(".context-menu"); + const contextMenuOptions = document.querySelectorAll(".context-menu li"); const expectedShortcutNames: ShortcutName[] = [ "cut", "copyStyles", "pasteStyles", - "delete", + "deleteSelectedElements", "addToLibrary", "sendBackward", "bringForward", @@ -659,7 +661,7 @@ describe("regression tests", () => { ]; expect(contextMenu).not.toBeNull(); - expect(contextMenu?.children.length).toBe(expectedShortcutNames.length); + expect(contextMenuOptions.length).toBe(expectedShortcutNames.length); expectedShortcutNames.forEach((shortcutName) => { expect( contextMenu?.querySelector(`li[data-testid="${shortcutName}"]`), @@ -689,11 +691,12 @@ describe("regression tests", () => { }); const contextMenu = document.querySelector(".context-menu"); + const contextMenuOptions = document.querySelectorAll(".context-menu li"); const expectedShortcutNames: ShortcutName[] = [ "cut", "copyStyles", "pasteStyles", - "delete", + "deleteSelectedElements", "group", "addToLibrary", "sendBackward", @@ -704,7 +707,7 @@ describe("regression tests", () => { ]; expect(contextMenu).not.toBeNull(); - expect(contextMenu?.children.length).toBe(expectedShortcutNames.length); + expect(contextMenuOptions.length).toBe(expectedShortcutNames.length); expectedShortcutNames.forEach((shortcutName) => { expect( contextMenu?.querySelector(`li[data-testid="${shortcutName}"]`), @@ -738,11 +741,12 @@ describe("regression tests", () => { }); const contextMenu = document.querySelector(".context-menu"); + const contextMenuOptions = document.querySelectorAll(".context-menu li"); const expectedShortcutNames: ShortcutName[] = [ "cut", "copyStyles", "pasteStyles", - "delete", + "deleteSelectedElements", "ungroup", "addToLibrary", "sendBackward", @@ -753,7 +757,7 @@ describe("regression tests", () => { ]; expect(contextMenu).not.toBeNull(); - expect(contextMenu?.children.length).toBe(expectedShortcutNames.length); + expect(contextMenuOptions.length).toBe(expectedShortcutNames.length); expectedShortcutNames.forEach((shortcutName) => { expect( contextMenu?.querySelector(`li[data-testid="${shortcutName}"]`), From d4e12a2962584f5c11dc3785532e21bb2c9c988f Mon Sep 17 00:00:00 2001 From: David Luzar Date: Thu, 28 Jan 2021 12:58:35 +0100 Subject: [PATCH 27/39] reuse scss variables in js for SSOT (#2867) --- src/components/Avatar.scss | 2 +- src/components/CollabButton.scss | 2 +- src/components/ColorPicker.scss | 2 +- src/components/ContextMenu.scss | 2 +- src/components/Dialog.scss | 2 +- src/components/ExportDialog.scss | 2 +- src/components/HelpDialog.scss | 2 +- src/components/HintViewer.scss | 2 +- src/components/IconPicker.scss | 2 +- src/components/Modal.scss | 2 +- src/components/PasteChartDialog.scss | 2 +- src/components/Stats.scss | 2 +- src/components/TextInput.scss | 2 +- src/components/Toast.scss | 2 +- src/components/ToolIcon.scss | 2 +- src/components/Tooltip.scss | 2 +- src/css/styles.scss | 2 +- src/css/{_variables.scss => variables.module.scss} | 4 ++++ src/excalidraw-app/collab/RoomDialog.scss | 2 +- src/is-mobile.tsx | 6 ++---- 20 files changed, 24 insertions(+), 22 deletions(-) rename src/css/{_variables.scss => variables.module.scss} (73%) diff --git a/src/components/Avatar.scss b/src/components/Avatar.scss index 61f084b72..d077d916b 100644 --- a/src/components/Avatar.scss +++ b/src/components/Avatar.scss @@ -1,4 +1,4 @@ -@import "../css/_variables"; +@import "../css/variables.module"; .excalidraw { .Avatar { diff --git a/src/components/CollabButton.scss b/src/components/CollabButton.scss index fd51cc055..5d9a86de3 100644 --- a/src/components/CollabButton.scss +++ b/src/components/CollabButton.scss @@ -1,4 +1,4 @@ -@import "../css/_variables"; +@import "../css/variables.module"; .excalidraw { .CollabButton.is-collaborating { diff --git a/src/components/ColorPicker.scss b/src/components/ColorPicker.scss index 23a6aac82..cb29e66d1 100644 --- a/src/components/ColorPicker.scss +++ b/src/components/ColorPicker.scss @@ -1,4 +1,4 @@ -@import "../css/_variables"; +@import "../css/variables.module"; .excalidraw { .color-picker { diff --git a/src/components/ContextMenu.scss b/src/components/ContextMenu.scss index 8661cb937..f4ec1142e 100644 --- a/src/components/ContextMenu.scss +++ b/src/components/ContextMenu.scss @@ -1,4 +1,4 @@ -@import "../css/_variables"; +@import "../css/variables.module"; .excalidraw { .context-menu { diff --git a/src/components/Dialog.scss b/src/components/Dialog.scss index c00a90884..37d19219b 100644 --- a/src/components/Dialog.scss +++ b/src/components/Dialog.scss @@ -1,4 +1,4 @@ -@import "../css/_variables"; +@import "../css/variables.module"; .excalidraw { .Dialog { diff --git a/src/components/ExportDialog.scss b/src/components/ExportDialog.scss index 3086d72b1..c47cdf400 100644 --- a/src/components/ExportDialog.scss +++ b/src/components/ExportDialog.scss @@ -1,4 +1,4 @@ -@import "../css/_variables"; +@import "../css/variables.module"; .excalidraw { .ExportDialog__preview { diff --git a/src/components/HelpDialog.scss b/src/components/HelpDialog.scss index 88e1eb696..6b5701b84 100644 --- a/src/components/HelpDialog.scss +++ b/src/components/HelpDialog.scss @@ -1,4 +1,4 @@ -@import "../css/_variables"; +@import "../css/variables.module"; .excalidraw { .HelpDialog h3 { diff --git a/src/components/HintViewer.scss b/src/components/HintViewer.scss index 87b502b64..7f87354cb 100644 --- a/src/components/HintViewer.scss +++ b/src/components/HintViewer.scss @@ -1,4 +1,4 @@ -@import "../css/_variables"; +@import "../css/variables.module"; // this is loosely based on the longest hint text $wide-viewport-width: 1000px; diff --git a/src/components/IconPicker.scss b/src/components/IconPicker.scss index ced5c5c23..284c36526 100644 --- a/src/components/IconPicker.scss +++ b/src/components/IconPicker.scss @@ -1,4 +1,4 @@ -@import "../css/_variables"; +@import "../css/variables.module"; .excalidraw { .picker-container { diff --git a/src/components/Modal.scss b/src/components/Modal.scss index 2b34500da..2666f3514 100644 --- a/src/components/Modal.scss +++ b/src/components/Modal.scss @@ -1,4 +1,4 @@ -@import "../css/_variables"; +@import "../css/variables.module"; .excalidraw { .Modal { diff --git a/src/components/PasteChartDialog.scss b/src/components/PasteChartDialog.scss index 9d45fb2df..dc76306a8 100644 --- a/src/components/PasteChartDialog.scss +++ b/src/components/PasteChartDialog.scss @@ -1,4 +1,4 @@ -@import "../css/_variables"; +@import "../css/variables.module"; .excalidraw { .PasteChartDialog { diff --git a/src/components/Stats.scss b/src/components/Stats.scss index a6849f3bc..84864f933 100644 --- a/src/components/Stats.scss +++ b/src/components/Stats.scss @@ -1,4 +1,4 @@ -@import "../css/_variables"; +@import "../css/variables.module"; .Stats { position: fixed; diff --git a/src/components/TextInput.scss b/src/components/TextInput.scss index 3ff96c87c..930372ff0 100644 --- a/src/components/TextInput.scss +++ b/src/components/TextInput.scss @@ -1,4 +1,4 @@ -@import "../css/_variables.scss"; +@import "../css/variables.module"; .excalidraw { .TextInput { diff --git a/src/components/Toast.scss b/src/components/Toast.scss index 493e2fbd7..70cc80180 100644 --- a/src/components/Toast.scss +++ b/src/components/Toast.scss @@ -1,4 +1,4 @@ -@import "../css/_variables"; +@import "../css/variables.module"; .excalidraw { .Toast { diff --git a/src/components/ToolIcon.scss b/src/components/ToolIcon.scss index 91e8e1bc5..df07ca025 100644 --- a/src/components/ToolIcon.scss +++ b/src/components/ToolIcon.scss @@ -1,5 +1,5 @@ @import "open-color/open-color.scss"; -@import "../css/variables"; +@import "../css/variables.module"; .excalidraw { .ToolIcon { diff --git a/src/components/Tooltip.scss b/src/components/Tooltip.scss index 9fe048f6a..cf99e01af 100644 --- a/src/components/Tooltip.scss +++ b/src/components/Tooltip.scss @@ -1,4 +1,4 @@ -@import "../css/_variables"; +@import "../css/variables.module"; .excalidraw { .Tooltip { position: relative; diff --git a/src/css/styles.scss b/src/css/styles.scss index da616124e..2bfed7edc 100644 --- a/src/css/styles.scss +++ b/src/css/styles.scss @@ -1,4 +1,4 @@ -@import "./_variables"; +@import "./variables.module"; @import "./theme"; .excalidraw { diff --git a/src/css/_variables.scss b/src/css/variables.module.scss similarity index 73% rename from src/css/_variables.scss rename to src/css/variables.module.scss index 4e4ac861d..5b9ee7a8c 100644 --- a/src/css/_variables.scss +++ b/src/css/variables.module.scss @@ -2,3 +2,7 @@ // keep up to date with is-mobile.tsx $is-mobile-query: "(max-width: 600px), (max-height: 500px) and (max-width: 1000px)"; + +:export { + isMobileQuery: unquote($is-mobile-query); +} diff --git a/src/excalidraw-app/collab/RoomDialog.scss b/src/excalidraw-app/collab/RoomDialog.scss index de784d93d..5a045136a 100644 --- a/src/excalidraw-app/collab/RoomDialog.scss +++ b/src/excalidraw-app/collab/RoomDialog.scss @@ -1,4 +1,4 @@ -@import "../../css/_variables"; +@import "../../css/variables.module"; .excalidraw { .RoomDialog-linkContainer { diff --git a/src/is-mobile.tsx b/src/is-mobile.tsx index e12419fd1..4e34f7107 100644 --- a/src/is-mobile.tsx +++ b/src/is-mobile.tsx @@ -1,4 +1,5 @@ import React, { useState, useEffect, useRef, useContext } from "react"; +import variables from "./css/variables.module.scss"; const context = React.createContext(false); @@ -10,10 +11,7 @@ export const IsMobileProvider = ({ const query = useRef(); if (!query.current) { query.current = window.matchMedia - ? window.matchMedia( - // keep up to date with _variables.scss - "(max-width: 600px), (max-height: 500px) and (max-width: 1000px)", - ) + ? window.matchMedia(variables.isMobileQuery) : (({ matches: false, addListener: () => {}, From ed0bec41dcf0ca84048b5dc3aeac48c0310266a3 Mon Sep 17 00:00:00 2001 From: Lipis Date: Thu, 28 Jan 2021 15:50:48 +0200 Subject: [PATCH 28/39] chore: Update workflows to use the latest Node (#2863) --- .github/workflows/build-docker.yml | 2 +- .github/workflows/build-packages.yml | 4 ++-- .github/workflows/cancel.yml | 8 +++++--- .github/workflows/lint.yml | 12 +++--------- .github/workflows/locales-coverage.yml | 4 ++-- .github/workflows/semantic-pr-title.yml | 1 + .github/workflows/sentry-production.yml | 5 +++-- .github/workflows/test.yml | 12 +++--------- 8 files changed, 20 insertions(+), 28 deletions(-) diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index 3fcdde198..8ae0ea649 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -6,7 +6,7 @@ on: - master jobs: - build-docker: + build: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/build-packages.yml b/.github/workflows/build-packages.yml index 92ab34f41..86936cbb2 100644 --- a/.github/workflows/build-packages.yml +++ b/.github/workflows/build-packages.yml @@ -13,10 +13,10 @@ jobs: steps: - uses: actions/checkout@v1 - - name: Setup Node.js 12.x + - name: Setup Node.js 14.x uses: actions/setup-node@v1 with: - node-version: 12.x + node-version: 14.x - name: Install dependencies run: | diff --git a/.github/workflows/cancel.yml b/.github/workflows/cancel.yml index 19496c5bf..1e2ed41b6 100644 --- a/.github/workflows/cancel.yml +++ b/.github/workflows/cancel.yml @@ -1,9 +1,11 @@ -name: Cancel -on: [push] +name: Cancel previous runs + +on: push + jobs: cancel: - name: "Cancel Previous Runs" runs-on: ubuntu-latest + timeout-minutes: 3 steps: - uses: styfle/cancel-workflow-action@0.6.0 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 1abc8bfd7..a11350a4e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,10 +1,6 @@ name: Lint -on: - push: - branches: - - master - pull_request: +on: push jobs: lint: @@ -13,10 +9,10 @@ jobs: steps: - uses: actions/checkout@v1 - - name: Setup Node.js 12.x + - name: Setup Node.js 14.x uses: actions/setup-node@v1 with: - node-version: 12.x + node-version: 14.x - name: Install and lint run: | @@ -24,5 +20,3 @@ jobs: npm run test:other npm run test:code npm run test:typecheck - env: - CI: true diff --git a/.github/workflows/locales-coverage.yml b/.github/workflows/locales-coverage.yml index 037d39110..c7b6fc799 100644 --- a/.github/workflows/locales-coverage.yml +++ b/.github/workflows/locales-coverage.yml @@ -14,10 +14,10 @@ jobs: with: token: ${{ secrets.PUSH_TRANSLATIONS_COVERAGE_PAT }} - - name: Setup Node.js 12.x + - name: Setup Node.js 14.x uses: actions/setup-node@v1 with: - node-version: 12.x + node-version: 14.x - name: Create report file run: | diff --git a/.github/workflows/semantic-pr-title.yml b/.github/workflows/semantic-pr-title.yml index be84d2294..78a2674df 100644 --- a/.github/workflows/semantic-pr-title.yml +++ b/.github/workflows/semantic-pr-title.yml @@ -10,6 +10,7 @@ on: jobs: main: runs-on: ubuntu-latest + steps: - uses: amannn/action-semantic-pull-request@v3.0.0 env: diff --git a/.github/workflows/sentry-production.yml b/.github/workflows/sentry-production.yml index 8b9797289..7408949db 100644 --- a/.github/workflows/sentry-production.yml +++ b/.github/workflows/sentry-production.yml @@ -8,13 +8,14 @@ on: jobs: release: runs-on: ubuntu-latest + steps: - uses: actions/checkout@v1.0.0 - - name: Setup Node.js 12.x + - name: Setup Node.js 14.x uses: actions/setup-node@v1 with: - node-version: 12.x + node-version: 14.x - name: Install and build run: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fd99330d8..57434ceed 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,10 +1,6 @@ name: Tests -on: - push: - branches: - - master - pull_request: +on: push jobs: test: @@ -13,14 +9,12 @@ jobs: steps: - uses: actions/checkout@v1 - - name: Setup Node.js 12.x + - name: Setup Node.js 14.x uses: actions/setup-node@v1 with: - node-version: 12.x + node-version: 14.x - name: Install and test run: | npm ci npm run test:app - env: - CI: true From 6e9df2bae72be4ea5e539910834ee5f625ed9294 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Fri, 29 Jan 2021 02:21:10 +0530 Subject: [PATCH 29/39] fix(app.tsx): show correct state of Nerd stats in context menu when nerd stats dialog closed (#2874) fixes #2873 --- src/components/App.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/App.tsx b/src/components/App.tsx index 0d400927b..33949c418 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -1160,9 +1160,7 @@ class App extends React.Component { if (!this.state.showStats) { trackEvent("dialog", "stats"); } - this.setState({ - showStats: !this.state.showStats, - }); + this.actionManager.executeAction(actionToggleStats); }; setScrollToCenter = (remoteElements: readonly ExcalidrawElement[]) => { From e8685c5236e32f474b744bd8d2e180e1de14dc02 Mon Sep 17 00:00:00 2001 From: Arun Date: Fri, 29 Jan 2021 02:32:00 +0530 Subject: [PATCH 30/39] feat: Remove copy & paste from context menu on desktop (#2872) * Remove copy & paste from context menu on desktop * fix build * Make requested changes * More changes * make into function * update changelog * fix tests Co-authored-by: dwelle --- src/components/App.tsx | 49 +++++++++++++++------------- src/is-mobile.tsx | 20 ++++++++---- src/packages/excalidraw/CHANGELOG.md | 1 + src/tests/regressionTests.test.tsx | 3 -- 4 files changed, 41 insertions(+), 32 deletions(-) diff --git a/src/components/App.tsx b/src/components/App.tsx index 33949c418..c8e321bed 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -174,6 +174,7 @@ import { viewportCoordsToSceneCoords, withBatchedUpdates, } from "../utils"; +import { isMobile } from "../is-mobile"; import ContextMenu from "./ContextMenu"; import LayerUI from "./LayerUI"; import { Stats } from "./Stats"; @@ -3625,22 +3626,25 @@ class App extends React.Component { const separator = "separator"; + const _isMobile = isMobile(); + const elements = this.scene.getElements(); const element = this.getElementAtPosition(x, y); if (!element) { ContextMenu.push({ options: [ - navigator.clipboard && { - name: "paste", - perform: (elements, appStates) => { - this.pasteFromClipboard(null); - return { - commitToHistory: false, - }; + _isMobile && + navigator.clipboard && { + name: "paste", + perform: (elements, appStates) => { + this.pasteFromClipboard(null); + return { + commitToHistory: false, + }; + }, + contextItemLabel: "labels.paste", }, - contextItemLabel: "labels.paste", - }, - separator, + _isMobile && navigator.clipboard && separator, probablySupportsClipboardBlob && elements.length > 0 && actionCopyAsPng, @@ -3669,19 +3673,20 @@ class App extends React.Component { ContextMenu.push({ options: [ - actionCut, - navigator.clipboard && actionCopy, - navigator.clipboard && { - name: "paste", - perform: (elements, appStates) => { - this.pasteFromClipboard(null); - return { - commitToHistory: false, - }; + _isMobile && actionCut, + _isMobile && navigator.clipboard && actionCopy, + _isMobile && + navigator.clipboard && { + name: "paste", + perform: (elements, appStates) => { + this.pasteFromClipboard(null); + return { + commitToHistory: false, + }; + }, + contextItemLabel: "labels.paste", }, - contextItemLabel: "labels.paste", - }, - separator, + _isMobile && separator, probablySupportsClipboardBlob && actionCopyAsPng, probablySupportsClipboardWriteText && actionCopyAsSvg, separator, diff --git a/src/is-mobile.tsx b/src/is-mobile.tsx index 4e34f7107..466fcd0d6 100644 --- a/src/is-mobile.tsx +++ b/src/is-mobile.tsx @@ -3,6 +3,16 @@ import variables from "./css/variables.module.scss"; const context = React.createContext(false); +const getIsMobileMatcher = () => { + return window.matchMedia + ? window.matchMedia(variables.isMobileQuery) + : (({ + matches: false, + addListener: () => {}, + removeListener: () => {}, + } as any) as MediaQueryList); +}; + export const IsMobileProvider = ({ children, }: { @@ -10,13 +20,7 @@ export const IsMobileProvider = ({ }) => { const query = useRef(); if (!query.current) { - query.current = window.matchMedia - ? window.matchMedia(variables.isMobileQuery) - : (({ - matches: false, - addListener: () => {}, - removeListener: () => {}, - } as any) as MediaQueryList); + query.current = getIsMobileMatcher(); } const [isMobile, setMobile] = useState(query.current.matches); @@ -29,6 +33,8 @@ export const IsMobileProvider = ({ return {children}; }; +export const isMobile = () => getIsMobileMatcher().matches; + export default function useIsMobile() { return useContext(context); } diff --git a/src/packages/excalidraw/CHANGELOG.md b/src/packages/excalidraw/CHANGELOG.md index 73bb66552..c5b20007a 100644 --- a/src/packages/excalidraw/CHANGELOG.md +++ b/src/packages/excalidraw/CHANGELOG.md @@ -22,6 +22,7 @@ Please add the latest change on the top under the correct section. ### Features +- Remove `copy`, `cut`, and `paste` actions from contextmenu [#2872](https://github.com/excalidraw/excalidraw/pull/2872) - Support `Ctrl-Y` shortcut to redo on Windows [#2831](https://github.com/excalidraw/excalidraw/pull/2831). ### Fixes diff --git a/src/tests/regressionTests.test.tsx b/src/tests/regressionTests.test.tsx index 2c73cef05..9cb8b383d 100644 --- a/src/tests/regressionTests.test.tsx +++ b/src/tests/regressionTests.test.tsx @@ -648,7 +648,6 @@ describe("regression tests", () => { const contextMenu = document.querySelector(".context-menu"); const contextMenuOptions = document.querySelectorAll(".context-menu li"); const expectedShortcutNames: ShortcutName[] = [ - "cut", "copyStyles", "pasteStyles", "deleteSelectedElements", @@ -693,7 +692,6 @@ describe("regression tests", () => { const contextMenu = document.querySelector(".context-menu"); const contextMenuOptions = document.querySelectorAll(".context-menu li"); const expectedShortcutNames: ShortcutName[] = [ - "cut", "copyStyles", "pasteStyles", "deleteSelectedElements", @@ -743,7 +741,6 @@ describe("regression tests", () => { const contextMenu = document.querySelector(".context-menu"); const contextMenuOptions = document.querySelectorAll(".context-menu li"); const expectedShortcutNames: ShortcutName[] = [ - "cut", "copyStyles", "pasteStyles", "deleteSelectedElements", From 4624ec2bd6ac9275b65fa158f0b019177ca6e283 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Fri, 29 Jan 2021 23:38:37 +0530 Subject: [PATCH 31/39] fix: apply initialData appState for zenmode and grid stats and refactor check param for actions (#2871) * fix: pass default value for grid mode / zen mode so it sets the value from initialData appState fixes #2870 * change checked from boolean to be a function which recieves appState and returns boolean * fix * use clsx Co-authored-by: dwelle --- src/actions/actionToggleGridMode.tsx | 7 +++---- src/actions/actionToggleStats.tsx | 5 ++--- src/actions/actionToggleZenMode.tsx | 9 ++++----- src/actions/types.ts | 2 +- src/components/App.tsx | 3 ++- src/components/ContextMenu.tsx | 13 +++++++++---- 6 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/actions/actionToggleGridMode.tsx b/src/actions/actionToggleGridMode.tsx index 22e8e5581..e99e3a015 100644 --- a/src/actions/actionToggleGridMode.tsx +++ b/src/actions/actionToggleGridMode.tsx @@ -1,21 +1,20 @@ import { CODES, KEYS } from "../keys"; import { register } from "./register"; import { GRID_SIZE } from "../constants"; +import { AppState } from "../types"; export const actionToggleGridMode = register({ name: "gridMode", perform(elements, appState) { - this.checked = !this.checked; return { appState: { ...appState, - gridSize: this.checked ? GRID_SIZE : null, + gridSize: this.checked!(appState) ? null : GRID_SIZE, }, commitToHistory: false, }; }, - checked: false, + checked: (appState: AppState) => appState.gridSize !== null, contextItemLabel: "labels.gridMode", - // Wrong event code keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.code === CODES.QUOTE, }); diff --git a/src/actions/actionToggleStats.tsx b/src/actions/actionToggleStats.tsx index 1d75caf82..3c03b80c6 100644 --- a/src/actions/actionToggleStats.tsx +++ b/src/actions/actionToggleStats.tsx @@ -3,15 +3,14 @@ import { register } from "./register"; export const actionToggleStats = register({ name: "stats", perform(elements, appState) { - this.checked = !this.checked; return { appState: { ...appState, - showStats: !appState.showStats, + showStats: !this.checked!(appState), }, commitToHistory: false, }; }, - checked: false, + checked: (appState) => appState.showStats, contextItemLabel: "stats.title", }); diff --git a/src/actions/actionToggleZenMode.tsx b/src/actions/actionToggleZenMode.tsx index 32ddd6fec..38da9cdef 100644 --- a/src/actions/actionToggleZenMode.tsx +++ b/src/actions/actionToggleZenMode.tsx @@ -4,17 +4,16 @@ import { register } from "./register"; export const actionToggleZenMode = register({ name: "zenMode", perform(elements, appState) { - this.checked = !this.checked; return { appState: { ...appState, - zenModeEnabled: this.checked, + zenModeEnabled: !this.checked!(appState), }, commitToHistory: false, }; }, - checked: false, + checked: (appState) => appState.zenModeEnabled, contextItemLabel: "buttons.zenMode", - // Wrong event code - keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.code === CODES.QUOTE, + keyTest: (event) => + !event[KEYS.CTRL_OR_CMD] && event.altKey && event.code === CODES.Z, }); diff --git a/src/actions/types.ts b/src/actions/types.ts index 6d373faae..66f8dece0 100644 --- a/src/actions/types.ts +++ b/src/actions/types.ts @@ -106,7 +106,7 @@ export interface Action { elements: readonly ExcalidrawElement[], appState: AppState, ) => boolean; - checked?: boolean; + checked?: (appState: Readonly) => boolean; } export interface ActionsManagerInterface { diff --git a/src/components/App.tsx b/src/components/App.tsx index c8e321bed..795d2defb 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -1254,7 +1254,6 @@ class App extends React.Component { if (!event[KEYS.CTRL_OR_CMD] && event.altKey && event.code === CODES.Z) { this.toggleZenMode(); } - if (event[KEYS.CTRL_OR_CMD] && event.code === CODES.QUOTE) { this.toggleGridMode(); } @@ -3663,6 +3662,7 @@ class App extends React.Component { top: clientY, left: clientX, actionManager: this.actionManager, + appState: this.state, }); return; } @@ -3709,6 +3709,7 @@ class App extends React.Component { top: clientY, left: clientX, actionManager: this.actionManager, + appState: this.state, }); }; diff --git a/src/components/ContextMenu.tsx b/src/components/ContextMenu.tsx index 567d9dd4e..17556665d 100644 --- a/src/components/ContextMenu.tsx +++ b/src/components/ContextMenu.tsx @@ -11,6 +11,7 @@ import { } from "../actions/shortcuts"; import { Action } from "../actions/types"; import { ActionManager } from "../actions/manager"; +import { AppState } from "../types"; type ContextMenuOption = "separator" | Action; @@ -20,6 +21,7 @@ type ContextMenuProps = { top: number; left: number; actionManager: ActionManager; + appState: Readonly; }; const ContextMenu = ({ @@ -28,11 +30,11 @@ const ContextMenu = ({ top, left, actionManager, + appState, }: ContextMenuProps) => { const isDarkTheme = !!document .querySelector(".excalidraw") ?.classList.contains("Appearance_dark"); - return (